6 ex__gui__color__picker_8c
gullradriel edited this page 2026-10-09 00:55:18 +02:00

examples/ex_gui_color_picker.c

Functions

Name
ALLEGRO_COLOR swatch_centre(const float rgba[4])
draw a swatch into a memory bitmap and read the pixel at its centre
int process_args(int argc, char ** argv)
read -V LOGLEVEL
void on_change(const float rgba[4], void * user_data)
the picker's callback
int main(int argc, char ** argv)
void expect_true(const char * what, int ok)
record one check
void click_middle(N_GUI_CTX * gui, int window_id, int widget_id)
click the middle of a widget, in display coordinates

Attributes

Name
int log_level
int failures
int changes
how many times the picker called back, and with what
float[4] changed

Defines

Name
ALLEGRO_UNSTABLE

Functions Documentation

function swatch_centre

static ALLEGRO_COLOR swatch_centre(
    const float rgba[4]
)

draw a swatch into a memory bitmap and read the pixel at its centre

function process_args

static int process_args(
    int argc,
    char ** argv
)

read -V LOGLEVEL

function on_change

static void on_change(
    const float rgba[4],
    void * user_data
)

the picker's callback

function main

int main(
    int argc,
    char ** argv
)

function expect_true

static void expect_true(
    const char * what,
    int ok
)

record one check

function click_middle

static void click_middle(
    N_GUI_CTX * gui,
    int window_id,
    int widget_id
)

click the middle of a widget, in display coordinates

Attributes Documentation

variable log_level

static int log_level = 3;

variable failures

static int failures = 0;

variable changes

static int changes = 0;

how many times the picker called back, and with what

variable changed

static float[4] changed = {0.0f, 0.0f, 0.0f, 0.0f};

Macros Documentation

define ALLEGRO_UNSTABLE

#define ALLEGRO_UNSTABLE 1

Source code



#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;
}