A slider's handle stays inside the widget at every value (headless).
A slider's handle stays inside the widget at every value (headless). The handle is a circle centred on the value's position. Centring it on the widget's own left edge at the minimum puts half the circle outside the widget, where the clipping rectangle cuts it off, so a slider sitting at its minimum drew a half moon rather than a handle; the maximum had the same fault on the other side.
The centre travels along a strip inset by the handle's radius at each end instead. The same strip is what a press or a drag is measured against, so the handle still lands under the pointer; measuring the drag against the whole widget while drawing the handle on the inset strip would put the two a radius apart at the ends, which is worse than the fault it fixed.
#define ALLEGRO_UNSTABLE 1
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
if (!cond) {
} else {
}
}
static void expect_near(
const char* label,
double got,
double want) {
if (fabs(got - want) > 1e-6) {
n_log(
LOG_ERR,
"%s: FAILED, got %g wanted %g", label, got, want);
} else {
}
}
ALLEGRO_EVENT ev;
memset(&ev, 0, sizeof(ev));
ev.type = (
unsigned int)
type;
ev.mouse.x = x;
ev.mouse.y = y;
ev.mouse.button = 1;
return ev;
}
const double values[5] = {0.0, 0.25, 0.5, 0.75, 1.0};
char label[128];
int i = 0;
for (i = 0; i < 5; i++) {
float pos = 0.0f, r = 0.0f;
return;
}
snprintf(label, sizeof(label), "%s at %.2f keeps its left edge inside", what,
values[i]);
snprintf(label, sizeof(label), "%s at %.2f keeps its right edge inside", what,
values[i]);
}
}
int win, wide, narrow, tall, tiny;
float r = 0.0f, pos = 0.0f;
if (!al_init() || !al_init_font_addon()) {
return 1;
}
font = al_create_builtin_font();
return 1;
}
return 1;
}
expect_near(
"at the minimum the handle sits one radius in", (
double)pos, (
double)r);
expect_near(
"and at the maximum one radius short of the far end",
(double)pos, 200.0 - (double)r);
expect_near(
"a vertical slider's minimum is at the bottom", (
double)pos,
200.0 - (double)r);
expect_true(
"a slider too small to travel still answers", pos >= 0.0f);
expect_true(
"and puts its handle inside itself", pos <= 6.0f);
} else {
n_log(
LOG_ERR,
"a slider too small to travel refused: FAILED");
}
0.0);
expect_near(
"and the handle lands under it", (
double)pos, (
double)r);
{
}
return 1;
}
return 0;
}
static void expect_true(const char *label, int cond)
static ALLEGRO_EVENT mouse_event(int type, int x, int y, int dz)
Build a left-button mouse event at (x, y).
static void expect_near(const char *label, double got, double want)
Assert two values are equal to within a tolerance.
static void handle_stays_inside(N_GUI_CTX *gui, int id, float along, const char *what)
Check that a slider's handle is drawn whole wherever its value is.
static void type(N_GUI_CTX *gui, const char *s)
Type a whole string into whatever has focus.
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.
#define N_GUI_ALIGN_LEFT
left aligned text
int n_gui_add_slider(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, double min_val, double max_val, double initial, int mode, void(*on_change)(int, double, void *), void *user_data)
Add a slider widget.
int n_gui_add_vslider(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, double min_val, double max_val, double initial, int mode, void(*on_change)(int, double, void *), void *user_data)
Add a vertical slider widget.
#define N_GUI_SLIDER_VALUE
slider uses raw start/end values
int n_gui_slider_handle_pos(N_GUI_CTX *ctx, int widget_id, float *pos, float *radius)
Where a slider's handle is drawn and how big it is.
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
int n_gui_add_label(N_GUI_CTX *ctx, int window_id, const char *text, float x, float y, float w, float h, int align)
Add a static text label.
double n_gui_slider_get_value(N_GUI_CTX *ctx, int widget_id)
get the current value of a slider widget
#define N_GUI_WIN_FRAMELESS
frameless window: no title bar drawn, drag via window body unless N_GUI_WIN_FIXED_POSITION is also se...
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.
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
void n_gui_open_window(N_GUI_CTX *ctx, int window_id)
Open (show) a window.
void n_gui_slider_set_value(N_GUI_CTX *ctx, int widget_id, double value)
set the value of a slider widget
void n_gui_window_set_flags(N_GUI_CTX *ctx, int window_id, int flags)
Set feature flags on a window.
The top-level GUI context that holds all windows.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
#define LOG_NOTICE
normal but significant condition
#define LOG_INFO
informational
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.