Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_combobox_wheel.c

The mouse wheel scrolls an open combobox list (headless).

The mouse wheel scrolls an open combobox list (headless). An open combobox with more items than it shows has a scrollbar, and the wheel over its items has to move the list, as it does in every desktop toolkit. It used to step the highlight instead, one item a notch, and the list only moved once the highlight reached its edge; a pointer resting on an item put the highlight back under it, so the wheel ran over the visible items and the rest stayed out of reach. Reported from AfterAPro's plugin list: "working fine for what's visible but does not scroll".

Each check opens the list, turns the wheel with the pointer on one row and then clicks that same row: the item that click selects is the one the row shows, which says how far the list scrolled.

Author
Castagnier Mickael
Version
1.0
Date
25/09/2026
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define ALLEGRO_UNSTABLE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nilorea/n_gui.h"
#include "nilorea/n_log.h"
static int failures = 0;
#define CB_X 10
#define CB_Y 10
#define CB_W 200
#define CB_H 30
#define ITEMS 9
static void expect_true(const char* label, int cond) {
if (!cond) {
n_log(LOG_ERR, "%s: FAILED", label);
} else {
n_log(LOG_INFO, "%s: OK", label);
}
}
static ALLEGRO_EVENT mouse_event(int type, int x, int y, int dz) {
ALLEGRO_EVENT ev;
memset(&ev, 0, sizeof(ev));
ev.type = (unsigned int)type;
ev.mouse.x = x;
ev.mouse.y = y;
ev.mouse.dz = dz;
ev.mouse.button = 1;
return ev;
}
static void click_at(N_GUI_CTX* gui, int x, int y) {
n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_AXES, x, y, 0));
n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, x, y, 0));
n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_UP, x, y, 0));
}
static int row_y(int row) {
return CB_Y + CB_H + row * CB_H + CB_H / 2;
}
static int wheel_then_click(N_GUI_CTX* gui, int cb, int row, int notches) {
int i = 0;
int x = CB_X + CB_W / 3;
click_at(gui, x, CB_Y + CB_H / 2); /* open it */
n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_AXES, x, row_y(row), 0));
for (i = 0; i < abs(notches); i++)
n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_AXES, x, row_y(row), notches > 0 ? -1 : 1));
}
int main(void) {
ALLEGRO_FONT* font;
int win, cb, i;
char name[16];
if (!al_init() || !al_init_font_addon()) {
n_log(LOG_ERR, "allegro init failed");
return 1;
}
font = al_create_builtin_font(); /* no display needed */
if (!font) {
n_log(LOG_ERR, "al_create_builtin_font failed");
return 1;
}
if (!gui) {
n_log(LOG_ERR, "n_gui_new_ctx failed");
al_destroy_font(font);
return 1;
}
n_gui_set_display_size(gui, 800.0f, 600.0f);
win = n_gui_add_window(gui, "W", 0.0f, 0.0f, 400.0f, 500.0f);
cb = n_gui_add_combobox(gui, win, (float)CB_X, (float)CB_Y, (float)CB_W, (float)CB_H, NULL, NULL);
for (i = 0; i < ITEMS; i++) {
snprintf(name, sizeof(name), "item %d", i);
}
expect_true("with no wheel, a row selects the item it shows", wheel_then_click(gui, cb, 1, 0) == 1);
expect_true("three notches down scroll the list by three items", wheel_then_click(gui, cb, 1, 3) == 4);
expect_true("the wheel reaches the last item and stops there", wheel_then_click(gui, cb, 5, 20) == ITEMS - 1);
expect_true("and comes back up to the first", wheel_then_click(gui, cb, 0, -20) == 0);
al_destroy_font(font);
if (failures) {
n_log(LOG_ERR, "ex_gui_combobox_wheel: %d failure(s)", failures);
return 1;
}
n_log(LOG_NOTICE, "ex_gui_combobox_wheel: all checks passed");
return 0;
}
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
static void expect_true(const char *label, int cond)
Definition ex_atlas.c:53
static ALLEGRO_EVENT mouse_event(int type, int x, int y, int dz)
Build a left-button mouse event at (x, y).
#define CB_W
Where the combobox is and how tall one row of it is.
static int wheel_then_click(N_GUI_CTX *gui, int cb, int row, int notches)
Open the list, turn the wheel over one row, then click that row.
static int row_y(int row)
The screen y of the middle of one row of the open list.
#define CB_Y
Where the combobox is and how tall one row of it is.
static void click_at(N_GUI_CTX *gui, int x, int y)
Move to (x, y) and click there.
#define CB_H
Where the combobox is and how tall one row of it is.
#define CB_X
Where the combobox is and how tall one row of it is.
#define ITEMS
How many items: more than the six it shows.
static N_GUI_CTX * gui
static void type(N_GUI_CTX *gui, const char *s)
Type a whole string into whatever has focus.
static const char * row(N_GUI_TREE *tree, int index)
the text of a visible row, "" past the end
FONT * font
the default 8x8 font, valid after allegro_init()
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
set the display (viewport) size so global scrollbars can be computed.
Definition n_gui.c:12348
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
Definition n_gui.c:13611
int n_gui_combobox_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a combo box
Definition n_gui.c:6012
#define N_GUI_WIN_FRAMELESS
frameless window: no title bar drawn, drag via window body unless N_GUI_WIN_FIXED_POSITION is also se...
Definition n_gui.h:276
int n_gui_add_combobox(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, void(*on_select)(int, int, void *), void *user_data)
Add a combo box widget (dropdown selector).
Definition n_gui.c:3547
int n_gui_add_window(N_GUI_CTX *ctx, const char *title, float x, float y, float w, float h)
Add a new pseudo-window to the context.
Definition n_gui.c:1277
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
Definition n_gui.c:1103
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:1209
void n_gui_open_window(N_GUI_CTX *ctx, int window_id)
Open (show) a window.
Definition n_gui.c:1436
int n_gui_combobox_get_selected(N_GUI_CTX *ctx, int widget_id)
get the selected item index in a combobox widget
Definition n_gui.c:6034
void n_gui_window_set_flags(N_GUI_CTX *ctx, int window_id, int flags)
Set feature flags on a window.
Definition n_gui.c:2515
void n_gui_combobox_set_selected(N_GUI_CTX *ctx, int widget_id, int index)
set the selected item in a combobox widget
Definition n_gui.c:6116
The top-level GUI context that holds all windows.
Definition n_gui.h:1669
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:104
#define LOG_INFO
informational
Definition n_log.h:106
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.
Generic log system.