Table of Contents
ex_gui_color_picker.c
the colour picker dialog and the colour swatch Headless: the builtin font and memory bitmaps. Builds a picker, opens it on a colour and checks the sliders show it without calling back; clicks the middle of the green slider and checks the callback gets the new green and the old rest; closes it and checks the callback is forgotten. Then draws swatches and reads their pixels, and writes colours as hex. ```c
#define ALLEGRO_UNSTABLE 1
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
#include <allegro5/allegro_primitives.h>
#include "nilorea/n_common.h" #include "nilorea/n_log.h" #include "nilorea/n_gui.h" #include "nilorea/n_gui_color.h"
static int log_level = LOG_ERR; static int failures = 0;
static int changes = 0; static float changed[4] = {0.0f, 0.0f, 0.0f, 0.0f};
static void expect_true(const char* what, int ok) { if (!ok) { n_log(LOG_ERR, "FAIL: %s", what); failures++; } else { n_log(LOG_INFO, "ok: %s", what); } }
static int process_args(int argc, char** argv) { int opt = 0;
while ((opt = getopt(argc, argv, "V:")) != -1) {
if (opt == 'V') {
log_level = atoi(optarg);
} else {
return -1;
}
}
return 0;
}
static void on_change(const float rgba[4], void* user_data) { int c = 0;
changes++;
for (c = 0; c < 4; c++) changed[c] = rgba[c];
if (user_data) (*(int*)user_data)++;
}
static void click_middle(N_GUI_CTX* gui, int window_id, int widget_id) { N_GUI_WINDOW* win = n_gui_get_window(gui, window_id); N_GUI_WIDGET* wgt = n_gui_get_widget(gui, widget_id); ALLEGRO_EVENT ev;
if (!win || !wgt) return;
memset(&ev, 0, sizeof(ev));
ev.mouse.x = (int)(win->x + wgt->x + wgt->w / 2.0f);
ev.mouse.y = (int)(win->y + win->titlebar_h + wgt->y + wgt->h / 2.0f);
ev.mouse.button = 1;
ev.type = ALLEGRO_EVENT_MOUSE_AXES;
n_gui_process_event(gui, ev);
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
n_gui_process_event(gui, ev);
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_UP;
n_gui_process_event(gui, ev);
}
static ALLEGRO_COLOR swatch_centre(const float rgba[4]) { ALLEGRO_BITMAP* target = NULL; ALLEGRO_COLOR px; int old = al_get_new_bitmap_flags();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
target = al_create_bitmap(40, 40);
al_set_new_bitmap_flags(old);
al_set_target_bitmap(target);
al_clear_to_color(al_map_rgb(0, 0, 0));
n_gui_draw_color_swatch(0.0f, 0.0f, 40.0f, 40.0f, rgba);
/* 20,20 is the corner of four checker squares; 21,21 is inside one */
px = al_get_pixel(target, 21, 21);
al_set_target_bitmap(NULL);
al_destroy_bitmap(target);
return px;
}
int main(int argc, char** argv) { const float start[4] = {1.0f, 0.0f, 0.0f, 128.0f / 255.0f}; float now[4] = {0.0f, 0.0f, 0.0f, 0.0f}; char hex[16] = ""; int counted = 0; unsigned char r = 0, g = 0, b = 0;
set_log_level(LOG_ERR);
if (process_args(argc, argv) != 0) {
fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
return 2;
}
set_log_level(log_level);
if (!al_init() || !al_init_font_addon() || !al_init_primitives_addon()) {
n_log(LOG_ERR, "allegro init failed");
return 1;
}
ALLEGRO_FONT* font = al_create_builtin_font();
if (!font) return 1;
N_GUI_CTX* gui = n_gui_new_ctx(font);
if (!gui) {
al_destroy_font(font);
return 1;
}
n_gui_set_display_size(gui, 640.0f, 480.0f);
N_GUI_COLOR_PICKER* picker = n_gui_color_picker_new(gui, NULL, 1.0f);
expect_true("a picker is built", picker != NULL);
if (picker) {
int win = n_gui_color_picker_window(picker);
N_GUI_WINDOW* w = n_gui_get_window(gui, win);
expect_true("it starts closed", n_gui_color_picker_is_open(picker) == 0);
expect_true("a channel out of range has no slider", n_gui_color_picker_slider(picker, 4) == -1);
n_gui_color_picker_open(picker, "Test: Colour", start, on_change, &counted);
expect_true("open opens it", n_gui_color_picker_is_open(picker) == 1);
expect_true("the sliders show the colour",
n_gui_slider_get_value(gui, n_gui_color_picker_slider(picker, 0)) == 255.0 &&
n_gui_slider_get_value(gui, n_gui_color_picker_slider(picker, 1)) == 0.0 &&
n_gui_slider_get_value(gui, n_gui_color_picker_slider(picker, 3)) == 128.0);
expect_true("opening does not call back", changes == 0);
expect_true("it is centred on the display",
w && (int)(w->x + w->w / 2.0f + 0.5f) == 320);
click_middle(gui, win, n_gui_color_picker_slider(picker, 1));
expect_true("moving green calls back once", changes == 1 && counted == 1);
expect_true("with the new green, in steps of 1/255",
changed[1] > 0.3f && changed[1] < 0.7f &&
(float)(int)(changed[1] * 255.0f + 0.5f) == changed[1] * 255.0f);
expect_true("and the rest as they were",
changed[0] == 1.0f && changed[2] == 0.0f && changed[3] == start[3]);
expect_true("get returns what was handed on",
n_gui_color_picker_get(picker, now) == TRUE && memcmp(now, changed, sizeof(now)) == 0);
n_gui_color_picker_close(picker);
expect_true("close closes it", n_gui_color_picker_is_open(picker) == 0);
click_middle(gui, win, n_gui_color_picker_slider(picker, 2));
expect_true("a closed picker does not call back", changes == 1);
n_gui_color_picker_free(&picker);
expect_true("free sets the handle to NULL", picker == NULL);
}
n_gui_color_picker_free(&picker);
n_gui_color_picker_free(NULL);
{
const float blue[4] = {0.0f, 0.0f, 1.0f, 1.0f};
const float clear[4] = {1.0f, 0.0f, 0.0f, 0.0f};
al_unmap_rgb(swatch_centre(blue), &r, &g, &b);
expect_true("an opaque swatch is its colour", r == 0 && g == 0 && b == 255);
al_unmap_rgb(swatch_centre(clear), &r, &g, &b);
expect_true("a see-through swatch shows the checkerboard grey", r == g && g == b && r > 100);
}
n_gui_color_to_hex(start, hex, sizeof(hex));
expect_true("hex writes #RRGGBBAA", strcmp(hex, "#FF000080") == 0);
{
const float wild[4] = {-1.0f, 2.0f, 0.5f, 1.0f};
n_gui_color_to_hex(wild, hex, sizeof(hex));
expect_true("hex clamps and rounds", strcmp(hex, "#00FF80FF") == 0);
}
n_gui_color_to_hex(NULL, hex, sizeof(hex));
expect_true("hex of NULL is empty", hex[0] == '\0');
n_gui_destroy_ctx(&gui);
al_destroy_font(font);
if (failures) {
fprintf(stderr, "ex_gui_color_picker: %d failure(s)\n", failures);
return 1;
}
printf("ex_gui_color_picker: ok\n");
return 0;
}
_Filename: ex_gui_color_picker.c_
Modules
- AABB3D
- ACCEPT_POOL
- ALLEGRO4
- ALLEGRO5
- ANIM_LIB
- ASTAR
- ATLAS_LIB
- AVRO
- CLOCK_SYNC
- COMMONS
- CONFIGFILE
- CYPHER_BASE64
- CYPHER_VIGENERE
- DEAD_RECKONING
- ENUMS
- EXCEPTIONS
- GAME_ENV
- GIT
- GUI
- HASH_TABLE
- ISOMETRIC_ENGINE
- LIST
- LOG
- LOGNODUP
- LZ4
- NETWORKING
- NETWORK_MSG
- N_COOKIES
- N_DIFF
- N_DIGEST
- N_DISK_CACHE
- N_DNS
- N_ECC
- N_ENTROPY
- N_FILES
- N_FLUIDS
- N_GUI_COLOR
- N_GUI_COLORWHEEL
- N_GUI_CURVE
- N_GUI_GRID
- N_GUI_POPUP
- N_HEX
- N_HTTP3
- N_HTTP_COOKIE
- N_HTTP_FORM
- N_HTTP_MIME
- N_HTTP_REQ
- N_HTTP_RESP
- N_HTTP_ROUTER
- N_HTTP_SERVER
- N_ICC
- N_JSON
- N_KAFKA
- N_LINALG
- N_MODULE
- N_OPENSSL_COMPAT
- N_PRETTY
- N_PTH
- N_QUERY
- N_RANDOM
- N_SHA256
- N_STR
- N_TIFF
- N_TIME
- N_USER
- N_X509
- N_ZIP
- PARTICLES
- PCRE
- PHYSICS
- SIGNALS
- STACK
- THREADS
- TRAJECTORY
- TREE
- ZLIB