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

examples/ex_gui_frameless_drag.c

Functions

Name
void on_slider(int id, double value, void * data)
Slider callback: counts the changes it is told about.
ALLEGRO_EVENT mouse_event(int type, int x, int y)
Build a mouse event at (x, y).
int main(void )
void expect_true(const char * label, int cond)
Assert a condition, logging which check failed.
void drag_right(N_GUI_CTX * gui, int x, int y, int step)
Press at (x, y), move right in three steps of step with the button held, and release where the pointer ended.

Attributes

Name
int slider_changes
How many times the slider's callback fired.
int failures
Count of failed assertions.

Defines

Name
ALLEGRO_UNSTABLE

Functions Documentation

function on_slider

static void on_slider(
    int id,
    double value,
    void * data
)

Slider callback: counts the changes it is told about.

Parameters:

  • id Widget id, unused.
  • value New value, unused.
  • data Unused.

function mouse_event

static ALLEGRO_EVENT mouse_event(
    int type,
    int x,
    int y
)

Build a mouse event at (x, y).

Parameters:

  • type The ALLEGRO_EVENT_MOUSE_* type.
  • x Cursor x.
  • y Cursor y.

Return: The event.

function main

int main(
    void 
)

function expect_true

static void expect_true(
    const char * label,
    int cond
)

Assert a condition, logging which check failed.

Parameters:

  • label What is being checked.
  • cond Non-zero to pass.

function drag_right

static void drag_right(
    N_GUI_CTX * gui,
    int x,
    int y,
    int step
)

Press at (x, y), move right in three steps of step with the button held, and release where the pointer ended.

Parameters:

  • gui The context.
  • x Press x.
  • y Press y.
  • step Pixels per motion event.

Attributes Documentation

variable slider_changes

static int slider_changes = 0;

How many times the slider's callback fired.

variable failures

static int failures = 0;

Count of failed assertions.

Macros Documentation

define ALLEGRO_UNSTABLE

#define ALLEGRO_UNSTABLE 1

Source code

/*
 * 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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "nilorea/n_common.h"
#include "nilorea/n_gui.h"
#include "nilorea/n_log.h"

static int failures = 0;

static int slider_changes = 0;

static void expect_true(const char* label, int cond) {
    if (!cond) {
        n_log(LOG_ERR, "%s: FAILED", label);
        failures++;
    } else {
        n_log(LOG_INFO, "%s: OK", label);
    }
}

static void on_slider(int id, double value, void* data) {
    (void)id;
    (void)value;
    (void)data;
    slider_changes++;
}

static ALLEGRO_EVENT mouse_event(int type, int x, int y) {
    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;
}

static void drag_right(N_GUI_CTX* gui, int x, int y, int step) {
    int i = 0;

    n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, x, y));
    for (i = 1; i <= 3; i++) {
        n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_AXES, x + i * step, y));
    }
    n_gui_process_event(gui, mouse_event(ALLEGRO_EVENT_MOUSE_BUTTON_UP, x + 3 * step, y));
}

int main(void) {
    ALLEGRO_FONT* font;
    ALLEGRO_BITMAP* pic;
    N_GUI_CTX* gui;
    N_GUI_WINDOW* w;
    int win, slider;
    double before;

    set_log_level(LOG_ERR);
    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;
    }
    /* a memory bitmap, since there is no display to make a video one on */
    al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
    pic = al_create_bitmap(16, 16);
    if (!pic) {
        n_log(LOG_ERR, "al_create_bitmap failed");
        al_destroy_font(font);
        return 1;
    }
    gui = n_gui_new_ctx(font);
    if (!gui) {
        n_log(LOG_ERR, "n_gui_new_ctx failed");
        al_destroy_bitmap(pic);
        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, 300.0f);
    /* frameless and NOT fixed: the body is a drag handle for the window */
    n_gui_window_set_flags(gui, win, N_GUI_WIN_FRAMELESS);
    slider = n_gui_add_slider(gui, win, 0.0f, 0.0f, 200.0f, 24.0f, 0.0, 1.0, 0.0,
                              N_GUI_SLIDER_VALUE, on_slider, NULL);
    n_gui_add_image(gui, win, 0.0f, 100.0f, 50.0f, 50.0f, pic, N_GUI_IMAGE_FIT);
    n_gui_open_window(gui, win);
    w = n_gui_get_window(gui, win);
    if (!w) {
        n_log(LOG_ERR, "n_gui_get_window failed");
        n_gui_destroy_ctx(&gui);
        al_destroy_bitmap(pic);
        al_destroy_font(font);
        return 1;
    }

    /* A drag on the slider moves the slider and leaves the window where it
       is. Before the fix the window moved by exactly the pointer's travel and
       the slider stayed at its first value. */
    n_gui_slider_set_value(gui, slider, 0.0);
    before = n_gui_slider_get_value(gui, slider);
    slider_changes = 0;
    drag_right(gui, 40, 12, 20);
    expect_true("a drag on a slider leaves the window where it was",
                w->x == 0.0f && w->y == 0.0f);
    expect_true("and moves the slider", n_gui_slider_get_value(gui, slider) > before);
    /* one for the press and one per motion event */
    expect_true("and reports every step of it", slider_changes >= 4);

    /* The empty body is still a handle for the window. */
    drag_right(gui, 300, 250, 10);
    expect_true("a drag on the empty body moves the window", w->x == 30.0f && w->y == 0.0f);

    /* So is an image, which does nothing with a press. The window is now 30
       to the right, so the image is too. */
    drag_right(gui, 30 + 20, 120, 10);
    expect_true("a drag on an image moves the window", w->x == 60.0f);

    n_gui_destroy_ctx(&gui);
    al_destroy_bitmap(pic);
    al_destroy_font(font);
    if (failures) {
        n_log(LOG_ERR, "ex_gui_frameless_drag: %d failure(s)", failures);
        return 1;
    }
    n_log(LOG_NOTICE, "ex_gui_frameless_drag: all checks passed");
    return 0;
}