Table of Contents
ex_gui_custom_mouse.c
a custom widget that takes the mouse, and one that owns its state Headless: events are made by hand and fed to n_gui_process_event(). A custom widget with n_gui_custom_set_mouse() is told of a move over it, a press of either button, a drag that leaves it, the release, and the wheel, in its own coordinates; a press elsewhere, or on a widget drawn over it, tells it nothing. n_gui_custom_set_destroy() hands it a heap pointer that n_gui_destroy_ctx() frees. ```c
#define ALLEGRO_UNSTABLE 1
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
#include "nilorea/n_common.h" #include "nilorea/n_log.h" #include "nilorea/n_gui.h"
static int log_level = LOG_ERR; static int failures = 0;
static N_GUI_MOUSE_EVENT last; static int told = 0; static int wheel_answer = 1; static int destroyed = 0;
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 int on_mouse(int widget_id, const N_GUI_MOUSE_EVENT* ev, void* user_data) { (void)widget_id; (void)user_data; last = *ev; told++; return ev->type == N_GUI_MOUSE_WHEEL ? wheel_answer : 1; }
static void destroy_state(void* state) { destroyed++; free(state); }
static int feed(N_GUI_CTX* gui, int type, int x, int y, int button, int dz) { ALLEGRO_EVENT ev;
memset(&ev, 0, sizeof(ev));
ev.type = (ALLEGRO_EVENT_TYPE)type;
ev.mouse.x = x;
ev.mouse.y = y;
ev.mouse.dx = (type == ALLEGRO_EVENT_MOUSE_AXES && dz == 0) ? 1 : 0;
ev.mouse.dz = dz;
ev.mouse.button = (unsigned int)button;
return n_gui_process_event(gui, ev);
}
static int was(int type, int button, float x, float y) { return last.type == type && last.button == button && last.x == x && last.y == y; }
int main(int argc, char** argv) { int before = 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()) {
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, 400.0f, 300.0f);
int win = n_gui_add_window(gui, "W", 0.0f, 0.0f, 400.0f, 300.0f);
n_gui_window_set_flags(gui, win, N_GUI_WIN_FRAMELESS);
n_gui_open_window(gui, win);
int area = n_gui_add_custom(gui, win, 50.0f, 50.0f, 100.0f, 80.0f, NULL, NULL);
n_gui_custom_set_mouse(gui, area, on_mouse, NULL);
feed(gui, ALLEGRO_EVENT_MOUSE_AXES, 60, 70, 0, 0);
expect_true("a move over it is a MOVE, in its coordinates", told == 1 && was(N_GUI_MOUSE_MOVE, 0, 10.0f, 20.0f));
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 60, 70, 1, 0);
expect_true("a left press is a DOWN with button 1", was(N_GUI_MOUSE_DOWN, 1, 10.0f, 20.0f));
feed(gui, ALLEGRO_EVENT_MOUSE_AXES, 200, 200, 0, 0);
expect_true("a drag out of it is still reported, as a DRAG", was(N_GUI_MOUSE_DRAG, 1, 150.0f, 150.0f));
/* Allegro reports a move before a release somewhere new, so the pointer
is where the last move left it */
feed(gui, ALLEGRO_EVENT_MOUSE_AXES, 210, 190, 0, 0);
expect_true("so is the next move of the drag", was(N_GUI_MOUSE_DRAG, 1, 160.0f, 140.0f));
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_UP, 210, 190, 1, 0);
expect_true("the release is an UP where the pointer is", was(N_GUI_MOUSE_UP, 1, 160.0f, 140.0f));
before = told;
feed(gui, ALLEGRO_EVENT_MOUSE_AXES, 220, 220, 0, 0);
expect_true("a move elsewhere after it is not reported", told == before);
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 70, 60, 2, 0);
expect_true("a right press is a DOWN with button 2", was(N_GUI_MOUSE_DOWN, 2, 20.0f, 10.0f));
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_UP, 70, 60, 2, 0);
before = told;
expect_true("a wheel it takes is consumed", feed(gui, ALLEGRO_EVENT_MOUSE_AXES, 60, 70, 0, 1) == 1);
expect_true("and reported with its steps", told == before + 1 && last.type == N_GUI_MOUSE_WHEEL && last.dz == 1);
wheel_answer = 0;
before = told;
feed(gui, ALLEGRO_EVENT_MOUSE_AXES, 60, 70, 0, -1);
expect_true("a wheel it declines is still reported", told == before + 1 && last.dz == -1);
before = told;
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 300, 250, 1, 0);
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_UP, 300, 250, 1, 0);
expect_true("a press elsewhere tells it nothing", told == before);
/* a widget drawn over part of it takes the press there */
n_gui_add_button(gui, win, "over", 50.0f, 50.0f, 30.0f, 20.0f, N_GUI_SHAPE_RECT, NULL, NULL);
before = told;
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 55, 55, 1, 0);
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_UP, 55, 55, 1, 0);
expect_true("a press on a widget over it does not reach it", told == before);
n_gui_custom_set_mouse(gui, area, NULL, NULL);
before = told;
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, 100, 100, 1, 0);
feed(gui, ALLEGRO_EVENT_MOUSE_BUTTON_UP, 100, 100, 1, 0);
expect_true("with the callback taken away it is told nothing", told == before);
/* ownership */
int* state = malloc(sizeof(int));
int owner = n_gui_add_custom(gui, win, 200.0f, 10.0f, 20.0f, 20.0f, NULL, state);
n_gui_custom_set_destroy(gui, owner, destroy_state);
n_gui_custom_set_destroy(gui, area, NULL);
n_gui_destroy_ctx(&gui);
expect_true("owned state is destroyed with the widget, once", destroyed == 1);
al_destroy_font(font);
if (failures) {
fprintf(stderr, "ex_gui_custom_mouse: %d failure(s)\n", failures);
return 1;
}
printf("ex_gui_custom_mouse: ok\n");
return 0;
}
_Filename: ex_gui_custom_mouse.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