@ -1,25 +1,72 @@
module ugui;
module ugui;
import grapheme;
import std::io;
import std::io;
import std::math;
import std::math;
// TODO: this could be a bitstruct
bitstruct InputEvents : uint {
bitstruct InputEvents : uint {
bool resize : 0; // window size was changed
bool resize : 0; // window size was changed
bool change_focus : 1; // window focus changed
bool change_focus : 1; // window focus changed
bool mouse_move : 2; // mouse was moved
bool mouse_move : 2; // mouse was moved
bool mouse_btn : 3; // mouse button pressed or released
bool mouse_btn : 3; // mouse button pressed or released
bool mouse_scroll : 4; // mouse scroll wheel. x or y
bool text_input : 5;
bool mod_key : 6;
}
bitstruct MouseButtons : uint {
bool btn_left : 0;
bool btn_middle : 1;
bool btn_right : 2;
bool btn_4 : 3;
bool btn_5 : 4;
}
// FIXME: all of these names were prefixed with key_ idk if this is better,
// if it is remove the prefix on MouseButtons as well
// Modifier Keys, same as SDL
bitstruct ModKeys : uint {
bool lshift : 0;
bool rshift : 1;
bool lctrl : 2;
bool rctrl : 3;
bool lalt : 4;
bool ralt : 5;
bool lgui : 6;
bool rgui : 7;
bool num : 8;
bool caps : 9;
bool mode : 10;
bool scroll : 11;
}
}
const ModKeys KMOD_CTRL = {.lctrl = true, .rctrl = true};
const ModKeys KMOD_SHIFT = {.lshift = true, .rshift = true};
const ModKeys KMOD_ALT = {.lalt = true, .ralt = true};
const ModKeys KMOD_GUI = {.lgui = true, .rgui = true};
const ModKeys KMOD_NONE = ModKeys{};
const ModKeys KMOD_ANY = (ModKeys)(ModKeys.inner.max);
const MouseButtons BTN_NONE = MouseButtons{};
const MouseButtons BTN_ANY = (MouseButtons)(MouseButtons.inner.max);
const MouseButtons BTN_LEFT = {.btn_left = true};
const MouseButtons BTN_MIDDLE = {.btn_middle = true};
const MouseButtons BTN_RIGHT = {.btn_right = true};
const MouseButtons BTN_4 = {.btn_4 = true};
const MouseButtons BTN_5 = {.btn_5 = true};
const ModKeys KEY_ANY = (ModKeys)(ModKeys.inner.max);
// Window size was changed
// Window size was changed
fn void! Ctx.input_window_size(&ctx, short width, short height)
fn void! Ctx.input_window_size(&ctx, short width, short height)
{
{
if (width <= 0 || height <= 0) {
if (width <= 0 || height <= 0) {
return UgError.INVALID_SIZE?;
return UgError.INVALID_SIZE?;
}
}
ctx.input.events.resize = ctx.width != width || ctx.height != height;
ctx.width = width;
ctx.width = width;
ctx.height = height;
ctx.height = height;
ctx.input.events.resize = true;
}
}
// Window gained/lost focus
// Window gained/lost focus
@ -27,44 +74,26 @@ fn void Ctx.input_changefocus(&ctx, bool has_focus)
{
{
// FIXME: raylib only has an API to query the focus status so we have to
// FIXME: raylib only has an API to query the focus status so we have to
// update the input flag only if the focus changed
// update the input flag only if the focus changed
if (ctx.has_focus != has_focus) {
ctx.input.events.change_focus = ctx.has_focus != has_focus;
ctx.input.events.change_focus = true;
}
ctx.has_focus = has_focus;
ctx.has_focus = has_focus;
}
}
bitstruct MouseButtons : uint {
bool btn_left : 0;
bool btn_middle : 1;
bool btn_right : 2;
bool btn_4 : 3;
bool btn_5 : 4;
}
macro Ctx.mouse_pressed(&ctx) => ctx.input.mouse.updated & ctx.input.mouse.down;
macro Ctx.mouse_pressed(&ctx) => ctx.input.mouse.updated & ctx.input.mouse.down;
macro Ctx.mouse_released(&ctx) => ctx.input.mouse.updated & ~ctx.input.mouse.down;
macro Ctx.mouse_released(&ctx) => ctx.input.mouse.updated & ~ctx.input.mouse.down;
macro Ctx.mouse_down(&ctx) => ctx.input.mouse.down;
macro Ctx.mouse_down(&ctx) => ctx.input.mouse.down;
const MouseButtons BTN_NONE = (MouseButtons)0u;
const MouseButtons BTN_ANY = (MouseButtons)(uint.max);
const MouseButtons BTN_LEFT = {.btn_left = true};
const MouseButtons BTN_MIDDLE = {.btn_middle = true};
const MouseButtons BTN_RIGHT = {.btn_right = true};
const MouseButtons BTN_4 = {.btn_4 = true};
const MouseButtons BTN_5 = {.btn_5 = true};
// FIXME: hthis compairson could be done with a cast using MouseButtons.inner
// FIXME: hthis compairson could be done with a cast using MouseButtons.inner
// property but I could not figure out how
// property but I could not figure out how
macro Ctx.is_mouse_pressed(&ctx, MouseButtons btn) => (ctx.mouse_pressed() & btn) != BTN_NONE;
macro Ctx.is_mouse_pressed(&ctx, MouseButtons btn) => (ctx.mouse_pressed() & btn) != BTN_NONE;
macro Ctx.is_mouse_released(&ctx, MouseButtons btn) => (ctx.mouse_released() & btn) != BTN_NONE;
macro Ctx.is_mouse_released(&ctx, MouseButtons btn) => (ctx.mouse_released() & btn) != BTN_NONE;
macro Ctx.is_mouse_down(&ctx, MouseButtons btn) => (ctx.mouse_down() & btn) != BTN_NONE;
macro Ctx.is_mouse_down(&ctx, MouseButtons btn) => (ctx.mouse_down() & btn) != BTN_NONE;
// Mouse Button move d
// Mouse Buttons down
fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons)
fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons)
{
{
ctx.input.mouse.updated = ctx.input.mouse.down ^ buttons;
ctx.input.mouse.updated = ctx.input.mouse.down ^ buttons;
ctx.input.mouse.down = buttons;
ctx.input.mouse.down = buttons;
ctx.input.events.mouse_btn = true ;
ctx.input.events.mouse_btn = (uint)ctx.input.mouse.down != 0 || (uint)ctx.input.mouse.updated != 0 ;
}
}
// Mouse was moved, report absolute position
// Mouse was moved, report absolute position
@ -80,7 +109,7 @@ fn void Ctx.input_mouse_abs(&ctx, short x, short y)
ctx.input.mouse.delta.x = dx;
ctx.input.mouse.delta.x = dx;
ctx.input.mouse.delta.y = dy;
ctx.input.mouse.delta.y = dy;
ctx.input.events.mouse_move = true ;
ctx.input.events.mouse_move = dx != 0 || dy != 0 ;
}
}
// Mouse was moved, report relative motion
// Mouse was moved, report relative motion
@ -96,5 +125,52 @@ fn void Ctx.input_mouse_delta(&ctx, short dx, short dy)
ctx.input.mouse.pos.x = math::clamp(mx, 0u16, ctx.width);
ctx.input.mouse.pos.x = math::clamp(mx, 0u16, ctx.width);
ctx.input.mouse.pos.y = math::clamp(my, 0u16, ctx.height);
ctx.input.mouse.pos.y = math::clamp(my, 0u16, ctx.height);
ctx.input.events.mouse_move = true;
ctx.input.events.mouse_move = dx != 0 || dy != 0;
}
fn void Ctx.input_mouse_wheel(&ctx, short x, short y, float scale = 1.0)
{
ctx.input.mouse.scroll.x = (short)((float)-x*scale);
ctx.input.mouse.scroll.y = (short)((float)-y*scale);
ctx.input.events.mouse_scroll = x !=0 || y != 0;
}
// append utf-8 encoded text to the context text input
fn void Ctx.input_text_utf8(&ctx, char[] text)
{
if (text.len == 0) { return; }
usz remaining = ctx.input.keyboard.text.len - ctx.input.keyboard.text_len;
usz len = text.len > remaining ? remaining : text.len;
char[] s = ctx.input.keyboard.text[ctx.input.keyboard.text_len ..];
s[..len-1] = text[..len-1];
ctx.input.keyboard.text_len += len;
ctx.input.events.text_input = true;
}
fn void Ctx.input_text_unicode(&ctx, int[] text)
{
if (text.len == 0) { return; }
char[32] tmp;
usz remaining = ctx.input.keyboard.text.len - ctx.input.keyboard.text_len;
char[] s = ctx.input.keyboard.text[ctx.input.keyboard.text_len ..];
usz off;
foreach (idx, cp: text) {
if (off >= remaining) { break; }
usz enc = grapheme::encode_utf8(cp, tmp[..], tmp.len);
s[off..off+enc] = tmp[..enc];
off += enc;
}
ctx.input.keyboard.text_len += off;
ctx.input.events.text_input = true;
}
// Mouse Buttons down
fn void Ctx.input_mod_keys(&ctx, ModKeys modkeys)
{
ctx.input.keyboard.down = modkeys;
ctx.input.events.mod_key = (uint)ctx.input.keyboard.down != 0;
}
}