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

N_GUI_TYPE_DROPMENU entry, label, and clear regression test (headless).

N_GUI_TYPE_DROPMENU entry, label, and clear regression test (headless).

Author
Castagnier Mickael
Version
1.0
/*
* 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 <unistd.h>
#include "nilorea/n_log.h"
#include "nilorea/n_gui.h"
static int log_level = LOG_ERR;
static int failures = 0;
static int click_tag = -1;
static int combo_selected = -1;
static void on_combo(int widget_id, int index, void* user_data) {
(void)widget_id;
(void)user_data;
combo_selected = index;
}
static int process_args(int argc, char** argv) {
int opt;
while ((opt = getopt(argc, argv, "V:")) != -1) {
switch (opt) {
case 'V':
if (!strcmp("LOG_NULL", optarg))
else if (!strcmp("LOG_NOTICE", optarg))
else if (!strcmp("LOG_INFO", optarg))
else if (!strcmp("LOG_ERR", optarg))
else if (!strcmp("LOG_DEBUG", optarg))
else
return -1;
break;
default:
return -1;
}
}
return 0;
}
static void expect_true(const char* label, int cond) {
if (!cond) {
n_log(LOG_ERR, "%s: condition false", label);
}
}
static void on_entry(int widget_id, int entry_index, int tag, void* user_data) {
(void)widget_id;
(void)entry_index;
(void)user_data;
click_tag = tag;
}
/* the dropmenu label lives in N_GUI_DROPMENU_DATA (a public struct), so a headless
test can read it back through the widget accessor to check the label setter */
static const char* dropmenu_label(N_GUI_CTX* gui, int id) {
if (!w || w->type != N_GUI_TYPE_DROPMENU || !w->data)
return NULL;
return ((N_GUI_DROPMENU_DATA*)w->data)->label;
}
int main(int argc, char** argv) {
if (process_args(argc, argv) != 0) {
fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
return 2;
}
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) {
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);
int win = n_gui_add_window(gui, "Panel", 0.0f, 0.0f, 800.0f, 600.0f);
expect_true("window created", win >= 0);
/* frameless so widget client coordinates line up with screen coordinates,
which the mouse-event consumption checks below depend on */
int dm = n_gui_add_dropmenu(gui, win, "Capture", 0.0f, 0.0f, 120.0f, 28.0f, NULL, NULL);
expect_true("dropmenu created", dm >= 0);
expect_true("initial label is Capture", dropmenu_label(gui, dm) && strcmp(dropmenu_label(gui, dm), "Capture") == 0);
expect_true("new dropmenu is empty", n_gui_dropmenu_get_count(gui, dm) == 0);
/* entries carry a tag delivered to the click callback */
expect_true("add entry 0", n_gui_dropmenu_add_entry(gui, dm, "Proxy", 11, on_entry, NULL) == 0);
expect_true("add entry 1", n_gui_dropmenu_add_entry(gui, dm, "Browser", 22, on_entry, NULL) == 1);
expect_true("count is 2", n_gui_dropmenu_get_count(gui, dm) == 2);
/* the label setter (used to reuse one widget for different categories) */
n_gui_dropmenu_set_label(gui, dm, "Auth & session");
expect_true("label updated", dropmenu_label(gui, dm) && strcmp(dropmenu_label(gui, dm), "Auth & session") == 0);
expect_true("label cleared", dropmenu_label(gui, dm) && dropmenu_label(gui, dm)[0] == '\0');
/* re-labelling and re-filling does not disturb the entry count */
expect_true("count still 2 after relabel", n_gui_dropmenu_get_count(gui, dm) == 2);
/* set_label on a non-dropmenu widget is a safe no-op */
int btn = n_gui_add_button(gui, win, "Btn", 0.0f, 40.0f, 60.0f, 24.0f, N_GUI_SHAPE_ROUNDED, NULL, NULL);
n_gui_dropmenu_set_label(gui, btn, "ignored");
expect_true("set_label ignores non-dropmenu", dropmenu_label(gui, btn) == NULL);
/* the open panel widens beyond a narrow trigger button so long entries are not
truncated (a category button shows a short label but its entries can be long) */
{
int narrow = n_gui_add_dropmenu(gui, win, "Cap", 0.0f, 80.0f, 40.0f, 24.0f, NULL, NULL);
float long_w;
expect_true("narrow dropmenu created", narrow >= 0);
/* a non-dropmenu widget has no panel width */
expect_true("panel width 0 for non-dropmenu", n_gui_dropmenu_panel_width(gui, btn) == 0.0f);
/* with no entries the panel is exactly the button width */
expect_true("empty panel width equals button width", n_gui_dropmenu_panel_width(gui, narrow) == 40.0f);
n_gui_dropmenu_add_entry(gui, narrow, "DOM Invader proxy", 1, on_entry, NULL);
n_gui_dropmenu_add_entry(gui, narrow, "X", 2, on_entry, NULL);
long_w = (float)al_get_text_width(font, "DOM Invader proxy");
/* the panel grows past the 40px button to fit the longest entry text */
expect_true("panel widens past the narrow button", n_gui_dropmenu_panel_width(gui, narrow) > 40.0f);
expect_true("panel fits the widest entry", n_gui_dropmenu_panel_width(gui, narrow) >= long_w);
}
/* a hover over an OPEN dropmenu panel is consumed and must not leak through to
the widget sitting beneath the floating panel. The dropmenu (0,0,120,28) opens
its panel downward; a button placed under that panel must stay un-hovered when
the mouse is over the open panel, but hover normally when the menu is closed. */
{
int under = n_gui_add_button(gui, win, "Under", 70.0f, 32.0f, 100.0f, 40.0f, N_GUI_SHAPE_ROUNDED, NULL, NULL);
N_GUI_WIDGET* underw = n_gui_get_widget(gui, under);
ALLEGRO_EVENT ev;
int consumed;
expect_true("dropmenu has entries for the panel", n_gui_dropmenu_get_count(gui, dm) == 2);
/* control: menu CLOSED, a hover over the under-button hovers it */
gui->open_dropmenu_id = -1;
((N_GUI_DROPMENU_DATA*)dmw->data)->is_open = 0;
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_AXES;
ev.mouse.x = 100;
ev.mouse.y = 40;
expect_true("button hovers when no menu is open", underw && (underw->state & N_GUI_STATE_HOVER) != 0);
/* menu OPEN: clear the stale hover from the control step, then the same hover
falls over the panel; it must be consumed and leave the button un-hovered */
gui->open_dropmenu_id = dm;
((N_GUI_DROPMENU_DATA*)dmw->data)->is_open = 1;
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_AXES;
ev.mouse.x = 100;
ev.mouse.y = 40;
consumed = n_gui_process_event(gui, ev);
expect_true("hover over the open panel is consumed", consumed == 1);
expect_true("widget beneath the open panel is NOT hovered", underw && (underw->state & N_GUI_STATE_HOVER) == 0);
/* close it again so the remaining checks are unaffected */
gui->open_dropmenu_id = -1;
((N_GUI_DROPMENU_DATA*)dmw->data)->is_open = 0;
}
/* clearing drops every entry */
expect_true("count is 0 after clear", n_gui_dropmenu_get_count(gui, dm) == 0);
/* the entry click callback receives the entry tag */
n_gui_dropmenu_add_entry(gui, dm, "Findings", 42, on_entry, NULL);
on_entry(dm, 0, 42, NULL);
expect_true("callback saw tag 42", click_tag == 42);
/* wheel and keyboard move the open panel's highlight cursor. Rebuild a list long
enough to scroll, open it, and drive the highlight without a real display: the
events are dispatched with the pointer far from the panel so the open-panel wheel
and key handlers (not the geometry-dependent hover path) do the work. */
{
N_GUI_DROPMENU_DATA* dmd = dmw ? (N_GUI_DROPMENU_DATA*)dmw->data : NULL;
ALLEGRO_EVENT ev;
int i;
for (i = 0; i < 5; i++) {
char name[16];
snprintf(name, sizeof(name), "Item %d", i);
n_gui_dropmenu_add_entry(gui, dm, name, 100 + i, on_entry, NULL);
}
expect_true("dropmenu has data", dmd != NULL);
dmd->max_visible = 3; /* force a scrolling list (5 entries, 3 visible) */
dmd->is_open = 1;
dmd->highlight_index = -1;
gui->open_dropmenu_id = dm;
/* wheel down (dz -1) with the cursor away from the panel: first step reveals
entry 0, and the highlight follows the wheel */
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_AXES;
ev.mouse.x = 5000;
ev.mouse.y = 5000;
ev.mouse.dz = -1;
expect_true("wheel over open menu is consumed", n_gui_process_event(gui, ev) == 1);
expect_true("wheel down highlights the first entry", dmd->highlight_index == 0);
expect_true("wheel steps the highlight down", dmd->highlight_index == 2);
expect_true("panel scrolled to keep the highlight visible", dmd->scroll_offset == 0);
n_gui_process_event(gui, ev); /* to 3, now below the 3-item window */
expect_true("highlight advanced to 3", dmd->highlight_index == 3);
expect_true("panel scrolled down to follow", dmd->scroll_offset == 1);
/* Down / Up arrow keys move the same cursor */
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_KEY_CHAR;
ev.keyboard.keycode = ALLEGRO_KEY_DOWN;
expect_true("Down key is consumed", n_gui_process_event(gui, ev) == 1);
expect_true("Down key advances the highlight", dmd->highlight_index == 4);
ev.keyboard.keycode = ALLEGRO_KEY_UP;
expect_true("Up key moves the highlight back", dmd->highlight_index == 3);
ev.keyboard.keycode = ALLEGRO_KEY_HOME;
expect_true("Home jumps to the first entry", dmd->highlight_index == 0);
ev.keyboard.keycode = ALLEGRO_KEY_END;
expect_true("End jumps to the last entry", dmd->highlight_index == 4);
/* Enter activates the highlighted entry (tag 104) and closes the menu */
click_tag = -1;
ev.keyboard.keycode = ALLEGRO_KEY_ENTER;
expect_true("Enter is consumed", n_gui_process_event(gui, ev) == 1);
expect_true("Enter activates the highlighted entry", click_tag == 104);
expect_true("Enter closes the menu", dmd->is_open == 0 && gui->open_dropmenu_id == -1);
/* Escape on a reopened menu closes it without activating anything */
dmd->is_open = 1;
dmd->highlight_index = 2;
gui->open_dropmenu_id = dm;
click_tag = -1;
ev.keyboard.keycode = ALLEGRO_KEY_ESCAPE;
expect_true("Escape is consumed", n_gui_process_event(gui, ev) == 1);
expect_true("Escape closes the menu", dmd->is_open == 0 && gui->open_dropmenu_id == -1);
expect_true("Escape activates nothing", click_tag == -1);
}
/* the same wheel/key highlight drives a combobox dropdown (the parallel path) */
{
int cb = n_gui_add_combobox(gui, win, 0.0f, 40.0f, 160.0f, 28.0f, on_combo, NULL);
N_GUI_COMBOBOX_DATA* cbd = cbw ? (N_GUI_COMBOBOX_DATA*)cbw->data : NULL;
ALLEGRO_EVENT ev;
int i;
expect_true("combobox created", cb >= 0 && cbd != NULL);
for (i = 0; i < 5; i++) {
char name[16];
snprintf(name, sizeof(name), "Opt %d", i);
}
/* open the panel the way the click handler does: highlight starts on the value */
cbd->max_visible = 3;
cbd->is_open = 1;
gui->open_combobox_id = cb;
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_AXES;
ev.mouse.x = 5000;
ev.mouse.y = 5000;
ev.mouse.dz = -1;
expect_true("combobox wheel is consumed", n_gui_process_event(gui, ev) == 1);
expect_true("wheel steps down from the selected value", cbd->highlight_index == 3);
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_KEY_CHAR;
ev.keyboard.keycode = ALLEGRO_KEY_UP;
expect_true("Up moves the combobox highlight", cbd->highlight_index == 2);
ev.keyboard.keycode = ALLEGRO_KEY_HOME;
expect_true("Home moves to the first option", cbd->highlight_index == 0);
/* Enter commits the highlighted option (selects it and fires on_select) */
ev.keyboard.keycode = ALLEGRO_KEY_ENTER;
expect_true("combobox Enter is consumed", n_gui_process_event(gui, ev) == 1);
expect_true("Enter selects the highlighted option", n_gui_combobox_get_selected(gui, cb) == 0);
expect_true("Enter fires on_select", combo_selected == 0);
expect_true("Enter closes the combobox", cbd->is_open == 0 && gui->open_combobox_id == -1);
}
/* Opened without a click, moved to a point, and with its button hidden:
a context menu at the pointer. The panel is positioned from the
button's rectangle and drawn from ctx->open_dropmenu_id rather than
from the button's visibility, which is what makes a hidden button give
a working menu. */
{
N_GUI_DROPMENU_DATA* dd = NULL;
ALLEGRO_EVENT ev;
float px = 300.0f, py = 200.0f;
expect_true("the dropmenu widget is there", w != NULL);
expect_true("add entry 0", n_gui_dropmenu_add_entry(gui, dm, "Open", 7, on_entry, NULL) == 0);
expect_true("add entry 1", n_gui_dropmenu_add_entry(gui, dm, "Delete", 9, on_entry, NULL) == 1);
/* where the pointer is, and out of sight */
n_gui_widget_set_rect(gui, dm, px, py, 120.0f, 28.0f);
expect_true("it is closed to begin with", n_gui_dropmenu_is_open(gui, dm) == 0);
expect_true("set_open opens it", n_gui_dropmenu_set_open(gui, dm, 1) == 1);
expect_true("and it says so", n_gui_dropmenu_is_open(gui, dm) == 1);
expect_true("the context knows which one", gui->open_dropmenu_id == dm);
expect_true("nothing is pre-highlighted", dd->highlight_index == -1);
/* a click on the second entry of the panel, which starts under the
button and is one item height per entry */
{
ALLEGRO_FONT* f = gui->default_font;
float fh = (float)al_get_font_line_height(f);
float ih = dd->item_height > fh ? dd->item_height : fh + gui->style.item_height_pad;
click_tag = -1;
memset(&ev, 0, sizeof(ev));
ev.type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
ev.mouse.button = 1;
ev.mouse.x = (int)(px + 10.0f);
ev.mouse.y = (int)(py + 28.0f + ih * 1.5f);
expect_true("the hidden button's panel takes the click",
expect_true("and fires the entry under the pointer", click_tag == 9);
expect_true("the click closes it", n_gui_dropmenu_is_open(gui, dm) == 0);
expect_true("and the context forgets it", gui->open_dropmenu_id == -1);
}
/* closing one that is not open is not an error */
expect_true("closing a closed menu answers closed",
/* and a widget that is not a dropmenu is refused rather than crashed.
The window itself is not a widget id at all, which is the other way
a caller gets this wrong. */
{
int label = n_gui_add_label(gui, win, "not a menu", 0.0f, 500.0f, 80.0f, 20.0f,
expect_true("a non dropmenu is refused",
n_gui_dropmenu_set_open(gui, label, 1) == 0);
expect_true("and reads as closed", n_gui_dropmenu_is_open(gui, label) == 0);
expect_true("an id nothing owns is refused",
n_gui_dropmenu_set_open(gui, 9999, 1) == 0);
}
}
/* global shape mode: round vs square GUI toggle (setter/getter round-trip) */
expect_true("shape mode set to rect", n_gui_get_shape_mode(gui) == N_GUI_SHAPE_RECT);
expect_true("shape mode set to rounded", n_gui_get_shape_mode(gui) == N_GUI_SHAPE_ROUNDED);
expect_true("get_shape_mode NULL-safe", n_gui_get_shape_mode(NULL) == N_GUI_SHAPE_ROUNDED);
al_destroy_font(font);
if (failures) {
n_log(LOG_ERR, "ex_gui_dropmenu: %d failure(s)", failures);
return 1;
}
n_log(LOG_NOTICE, "ex_gui_dropmenu: all checks passed");
return 0;
}
void process_args(int argc, char **argv)
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 int log_level
static N_GUI_CTX * gui
static void on_entry(int widget_id, int entry_index, int tag, void *user_data)
static int combo_selected
static const char * dropmenu_label(N_GUI_CTX *gui, int id)
static void on_combo(int widget_id, int index, void *user_data)
static int click_tag
FONT * font
the default 8x8 font, valid after allegro_init()
int is_open
is dropdown currently open
Definition n_gui.h:962
int max_visible
max visible items in dropdown
Definition n_gui.h:973
int selected_index
currently selected index (-1 = none)
Definition n_gui.h:960
float item_height
item height
Definition n_gui.h:1074
int type
widget type (N_GUI_TYPE_*)
Definition n_gui.h:1096
int state
current state flags (N_GUI_STATE_*)
Definition n_gui.h:1106
int max_visible
max visible items
Definition n_gui.h:1072
int highlight_index
open-panel navigation cursor for the wheel and Up/Down keys (-1 = none).
Definition n_gui.h:1070
int scroll_offset
scroll offset
Definition n_gui.h:1065
int highlight_index
open-panel navigation cursor for the wheel and Up/Down keys (-1 = none).
Definition n_gui.h:969
void * data
widget-specific data (union via void pointer)
Definition n_gui.h:1122
int is_open
is the menu currently open
Definition n_gui.h:1063
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
void n_gui_dropmenu_clear(N_GUI_CTX *ctx, int widget_id)
Remove all entries from a dropdown menu.
Definition n_gui.c:6452
#define N_GUI_STATE_HOVER
mouse is hovering the widget
Definition n_gui.h:235
#define N_GUI_ALIGN_LEFT
left aligned text
Definition n_gui.h:212
int n_gui_dropmenu_is_open(N_GUI_CTX *ctx, int widget_id)
Is a dropdown menu's panel showing.
Definition n_gui.c:6542
int n_gui_dropmenu_get_count(N_GUI_CTX *ctx, int widget_id)
Get number of entries in a dropdown menu.
Definition n_gui.c:6477
void n_gui_widget_set_rect(N_GUI_CTX *ctx, int widget_id, float x, float y, float w, float h)
Move and resize a widget after creation.
Definition n_gui.c:3854
#define N_GUI_TYPE_DROPMENU
widget type: dropdown menu with static and dynamic entries
Definition n_gui.h:126
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_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.
Definition n_gui.c:3639
int n_gui_dropmenu_set_open(N_GUI_CTX *ctx, int widget_id, int open)
Open or close a dropdown menu without a click on its button.
Definition n_gui.c:6498
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
void n_gui_set_shape_mode(N_GUI_CTX *ctx, int shape_mode)
Set the global widget shape (round or square GUI).
Definition n_gui.c:12361
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
N_GUI_WIDGET * n_gui_get_widget(N_GUI_CTX *ctx, int widget_id)
Get a widget pointer by id.
Definition n_gui.c:3701
int n_gui_dropmenu_add_entry(N_GUI_CTX *ctx, int widget_id, const char *text, int tag, void(*on_click)(int, int, int, void *), void *user_data)
Add a static entry to a dropdown menu.
Definition n_gui.c:6375
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
float n_gui_dropmenu_panel_width(N_GUI_CTX *ctx, int widget_id)
Width the open drop-down panel needs to show its entries.
Definition n_gui.c:6565
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:1209
int n_gui_get_shape_mode(N_GUI_CTX *ctx)
Get the global widget shape.
Definition n_gui.c:12371
void n_gui_dropmenu_set_label(N_GUI_CTX *ctx, int widget_id, const char *label)
Replace the button label shown on a dropmenu.
Definition n_gui.c:6360
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
#define N_GUI_SHAPE_ROUNDED
rounded rectangle shape
Definition n_gui.h:172
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_set_widget_visible(N_GUI_CTX *ctx, int widget_id, int visible)
Show or hide a widget.
Definition n_gui.c:3828
#define N_GUI_SHAPE_RECT
rectangle shape (default)
Definition n_gui.h:170
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
int n_gui_add_dropmenu(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, void(*on_open)(int, void *), void *on_open_user_data)
Add a dropdown menu widget.
Definition n_gui.c:6297
int n_gui_add_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, void(*on_click)(int, void *), void *user_data)
Add a button widget to a window.
Definition n_gui.c:2720
combo box specific data
Definition n_gui.h:952
The top-level GUI context that holds all windows.
Definition n_gui.h:1669
dropdown menu specific data
Definition n_gui.h:1053
A single GUI widget.
Definition n_gui.h:1092
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_DEBUG
debug-level messages
Definition n_log.h:108
#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_NULL
no log output
Definition n_log.h:70
#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.