idk look at the changes
This commit is contained in:
parent
1746f7d940
commit
16adfd7cc5
27
TODO
27
TODO
@ -7,18 +7,31 @@
|
||||
[ ] Write a README.md
|
||||
[ ] Use an arena allocator for cache
|
||||
[ ] Do not redraw if there was no update (no layout and no draw)
|
||||
[ ] Do command buffer damage tracking based on a context grid (see rxi writeup)
|
||||
[x] Better handling of the active and focused widgets, try
|
||||
to maintain focus until mouse release (fix scroll bars)
|
||||
[x] Clip element bounds to parent div, specifically text
|
||||
[ ] Keyboard input
|
||||
[ ] Mouse scroll wheel
|
||||
[ ] Touch input
|
||||
[ ] Resizeable divs
|
||||
[ ] Implement a z index
|
||||
[ ] Text reflow
|
||||
[ ] Implement a z index and sort command buffer based on that
|
||||
[ ] Standardize element handling, for example all buttons do almost the same thing, so write a lot of boiler plate and reuse it
|
||||
[ ] The id combination in gen_id() uses an intger division, which is costly, use another combination function that is non-linear and doesn't use division
|
||||
[x] The id combination in gen_id() uses an intger division, which is costly, use another combination function that is non-linear and doesn't use division
|
||||
[ ] Animations, somehow
|
||||
[ ] Maybe cache codepoint converted strings
|
||||
[x] Fix scroll wheel when div is scrolled
|
||||
|
||||
## Layout
|
||||
|
||||
[ ] Text reflow
|
||||
[ ] Flexbox
|
||||
[ ] Center elements to the row/column
|
||||
|
||||
## Input
|
||||
|
||||
[x] Keyboard input
|
||||
[x] Mouse scroll wheel
|
||||
[ ] Touch input
|
||||
[x] Do not set input event to true if the movement was zero (like no mouse movement)
|
||||
[ ] Use input event flags, for example to consume the input event
|
||||
|
||||
## Commands
|
||||
|
||||
@ -49,3 +62,5 @@ _ border radius
|
||||
[x] Button with label
|
||||
[ ] Text Input box
|
||||
[ ] Icon Buttons
|
||||
[ ] Switch
|
||||
|
||||
|
15
src/cache.c3
15
src/cache.c3
@ -62,8 +62,9 @@ fn Value*! Cache.search(&cache, Key id)
|
||||
// get_entry() faults on miss
|
||||
IdTableEntry* entry = cache.table.get_entry(id)!;
|
||||
|
||||
/* MISS */
|
||||
/* MISS, wrong key */
|
||||
if (entry.key != id) {
|
||||
cache.table.remove(id)!;
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
@ -79,6 +80,18 @@ fn Value*! Cache.search(&cache, Key id)
|
||||
return &(cache.pool[entry.value]);
|
||||
}
|
||||
|
||||
fn void Cache.remove(&cache, Key id)
|
||||
{
|
||||
IdTableEntry*! entry = cache.table.get_entry(id);
|
||||
if (catch entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
// found, remove it
|
||||
cache.present[entry.value] = false;
|
||||
(void)cache.table.remove(id);
|
||||
}
|
||||
|
||||
/* Look for a free spot in the present bitmap and return its index */
|
||||
/* If there is no free space left then just return the first position */
|
||||
fn usz Cache.get_free_spot(&cache) @private
|
||||
|
28
src/main.c3
28
src/main.c3
@ -106,6 +106,7 @@ fn int main(String[] args)
|
||||
while (!rl::window_should_close()) {
|
||||
clock.mark();
|
||||
|
||||
/*
|
||||
KeyboardKey k;
|
||||
do {
|
||||
k = rl::get_key_pressed();
|
||||
@ -115,7 +116,12 @@ fn int main(String[] args)
|
||||
if (rl::is_key_released(k)) { io::print("released "); }
|
||||
io::printfn("%s", k);
|
||||
} while (k != 0);
|
||||
|
||||
*/
|
||||
for (int c; (c = rl::get_char_pressed()) != 0;) {
|
||||
int[1] ts;
|
||||
ts[0] = c;
|
||||
ui.input_text_unicode(ts[..]);
|
||||
}
|
||||
|
||||
/* Start Input Handling */
|
||||
if (rl::is_window_resized()) {
|
||||
@ -128,11 +134,14 @@ fn int main(String[] args)
|
||||
|
||||
rl::Vector2 mpos = rl::get_mouse_position();
|
||||
ui.input_mouse_abs((short)mpos.x, (short)mpos.y);
|
||||
rl::Vector2 mwheel = rl::get_mouse_wheel_move_v();
|
||||
ui.input_mouse_wheel((short)mwheel.x, (short)mwheel.y);
|
||||
|
||||
ugui::MouseButtons buttons;
|
||||
buttons.btn_left = rl::is_mouse_button_down(rl::MOUSE_BUTTON_LEFT);
|
||||
buttons.btn_right = rl::is_mouse_button_down(rl::MOUSE_BUTTON_RIGHT);
|
||||
buttons.btn_middle = rl::is_mouse_button_down(rl::MOUSE_BUTTON_MIDDLE);
|
||||
ugui::MouseButtons buttons = {
|
||||
.btn_left = rl::is_mouse_button_down(rl::MOUSE_BUTTON_LEFT),
|
||||
.btn_right = rl::is_mouse_button_down(rl::MOUSE_BUTTON_RIGHT),
|
||||
.btn_middle = rl::is_mouse_button_down(rl::MOUSE_BUTTON_MIDDLE),
|
||||
};
|
||||
ui.input_mouse_button(buttons);
|
||||
/* End Input Handling */
|
||||
|
||||
@ -196,16 +205,17 @@ fn int main(String[] args)
|
||||
ui.slider_hor("hs2", ugui::Rect{0,0,100,30}, &f2)!!;
|
||||
|};
|
||||
ui.div_end()!!;
|
||||
|
||||
|
||||
// Timings counter
|
||||
TimeStats dts = draw_times.get_stats();
|
||||
TimeStats uts = ui_times.get_stats();
|
||||
|
||||
ui.layout_set_floating()!!;
|
||||
ui.div_begin("fps", ugui::Rect{0, ui.height-60, 200, 60})!!;
|
||||
ui.div_begin("fps", ugui::Rect{0, ui.height-100, 200, 100})!!;
|
||||
{|
|
||||
ui.layout_set_row()!!;
|
||||
ui.text_unbounded("ui avg", string::tformat("ui avg: %s\ndraw avg: %s\nTOT: %s", uts.avg, dts.avg, uts.avg+dts.avg))!!;
|
||||
ui.layout_set_column()!!;
|
||||
ui.text_unbounded("draw times", string::tformat("ui avg: %s\ndraw avg: %s\nTOT: %s", uts.avg, dts.avg, uts.avg+dts.avg))!!;
|
||||
ui.text_unbounded("ui text input", (String)ui.input.keyboard.text[..])!!;
|
||||
|};
|
||||
ui.div_end()!!;
|
||||
|
||||
|
@ -93,6 +93,7 @@ const uint STACK_STEP = 10;
|
||||
const uint MAX_ELEMS = 128;
|
||||
const uint MAX_CMDS = 256;
|
||||
const uint ROOT_ID = 1;
|
||||
const uint TEXT_MAX = 64;
|
||||
|
||||
// global style, similar to the css box model
|
||||
struct Style { // css box model
|
||||
@ -126,6 +127,13 @@ struct Ctx {
|
||||
// mouse_pressed = mouse_updated & mouse_down
|
||||
MouseButtons down;
|
||||
MouseButtons updated;
|
||||
// scroll wheel
|
||||
Point scroll;
|
||||
}
|
||||
struct keyboard {
|
||||
char[TEXT_MAX] text;
|
||||
usz text_len;
|
||||
ModKeys down;
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,18 +190,26 @@ fn Elem*! Ctx.get_parent(&ctx)
|
||||
return ctx.cache.search(parent_id);
|
||||
}
|
||||
|
||||
macro @bits(#a) => $typeof(#a).sizeof*8;
|
||||
macro Id.rotate_left(id, uint $n) => (id << $n) | (id >> (@bits(id) - $n));
|
||||
const uint GOLDEN_RATIO = 0x9E3779B9;
|
||||
|
||||
// generate an id combining the hashes of the parent id and the label
|
||||
// with the Cantor pairing function
|
||||
macro Id! Ctx.gen_id(&ctx, String label)
|
||||
{
|
||||
Id a = ctx.tree.get(ctx.active_div)!;
|
||||
Id b = label.hash();
|
||||
return (a + b) * (a + b + 1) / 2 + a;
|
||||
Id id1 = ctx.tree.get(ctx.active_div)!;
|
||||
Id id2 = label.hash();
|
||||
// Mix the two IDs non-linearly
|
||||
Id mixed = id1 ^ id2.rotate_left(13);
|
||||
mixed ^= id1.rotate_left(7);
|
||||
mixed += GOLDEN_RATIO;
|
||||
return mixed;
|
||||
}
|
||||
|
||||
// get or push an element from the cache, return a pointer to it
|
||||
// resets all flags except is_new which is set accordingly
|
||||
macro Ctx.get_elem(&ctx, Id id)
|
||||
fn Elem*! Ctx.get_elem(&ctx, Id id)
|
||||
{
|
||||
Elem empty_elem;
|
||||
bool is_new;
|
||||
@ -206,6 +222,18 @@ macro Ctx.get_elem(&ctx, Id id)
|
||||
return elem;
|
||||
}
|
||||
|
||||
// find an element, does not allocate a new one in cache
|
||||
// THIS HAS TO BE A MACRO SINCE IT RETURNS A POINTER TO A TEMPORARY VALUE
|
||||
macro Elem* Ctx.find_elem(&ctx, Id id)
|
||||
{
|
||||
Elem*! elem;
|
||||
elem = ctx.cache.search(id);
|
||||
if (catch elem) {
|
||||
return &&Elem{};
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
// FIXME: Since ids are now keyed with the element's parent id, this function does not work
|
||||
// outside of the element's div block.
|
||||
// this searches an element in the cache by label, it does not create a new element
|
||||
@ -305,6 +333,7 @@ fn void! Ctx.frame_end(&ctx)
|
||||
|
||||
// 2. clear input fields
|
||||
ctx.input.events = (InputEvents)0;
|
||||
ctx.input.keyboard.text_len = 0;
|
||||
|
||||
// send atlas updates
|
||||
if (ctx.font.should_update) {
|
||||
|
@ -99,11 +99,14 @@ fn void! Ctx.div_end(&ctx)
|
||||
|
||||
Id hsid = ctx.gen_id("div_scrollbar_horizontal")!;
|
||||
Id vsid = ctx.gen_id("div_scrollbar_vertical")!;
|
||||
|
||||
short wdim = elem.div.scroll_y.on ? (ctx.focus_id == vsid || ctx.hover_id == vsid ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0;
|
||||
short hdim = elem.div.scroll_x.on ? (ctx.focus_id == hsid || ctx.hover_id == hsid ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0;
|
||||
short wdim = elem.div.scroll_y.on ? (ctx.focus_id == vsid || ctx.is_hovered(ctx.find_elem(vsid)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0;
|
||||
short hdim = elem.div.scroll_x.on ? (ctx.focus_id == hsid || ctx.is_hovered(ctx.find_elem(hsid)) ? SCROLLBAR_DIM*3 : SCROLLBAR_DIM) : 0;
|
||||
|
||||
if (elem.div.scroll_y.on) {
|
||||
if (ctx.input.events.mouse_scroll && ctx.hover_id == elem.id) {
|
||||
elem.div.scroll_y.value += ctx.input.mouse.scroll.y * 0.07f;
|
||||
elem.div.scroll_y.value = math::clamp(elem.div.scroll_y.value, 0.0f, 1.0f);
|
||||
}
|
||||
Rect vslider = {
|
||||
.x = elem.bounds.x + elem.bounds.w - wdim,
|
||||
.y = elem.bounds.y,
|
||||
@ -117,6 +120,10 @@ fn void! Ctx.div_end(&ctx)
|
||||
}
|
||||
|
||||
if (elem.div.scroll_x.on) {
|
||||
if (ctx.input.events.mouse_scroll && ctx.hover_id == elem.id) {
|
||||
elem.div.scroll_x.value += ctx.input.mouse.scroll.x * 0.07f;
|
||||
elem.div.scroll_x.value = math::clamp(elem.div.scroll_x.value, 0.0f, 1.0f);
|
||||
}
|
||||
Rect hslider = {
|
||||
.x = elem.bounds.x,
|
||||
.y = elem.bounds.y + elem.bounds.h - hdim,
|
||||
|
@ -76,6 +76,7 @@ fn void! Font.load(&font, String name, ZString path, uint height, float scale)
|
||||
|
||||
font.sft.font = schrift::loadfile(path);
|
||||
if (font.sft.font == null) {
|
||||
font.table.free();
|
||||
return UgFontError.TTF_LOAD_FAILED?;
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,72 @@
|
||||
module ugui;
|
||||
|
||||
import grapheme;
|
||||
import std::io;
|
||||
import std::math;
|
||||
|
||||
// TODO: this could be a bitstruct
|
||||
|
||||
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 mouse_move : 2; // mouse was moved
|
||||
bool mouse_btn : 3; // mouse button pressed or released
|
||||
bool mouse_move : 2; // mouse was moved
|
||||
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
|
||||
fn void! Ctx.input_window_size(&ctx, short width, short height)
|
||||
{
|
||||
if (width <= 0 || height <= 0) {
|
||||
return UgError.INVALID_SIZE?;
|
||||
}
|
||||
ctx.input.events.resize = ctx.width != width || ctx.height != height;
|
||||
ctx.width = width;
|
||||
ctx.height = height;
|
||||
ctx.input.events.resize = true;
|
||||
}
|
||||
|
||||
// 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
|
||||
// update the input flag only if the focus changed
|
||||
if (ctx.has_focus != has_focus) {
|
||||
ctx.input.events.change_focus = true;
|
||||
}
|
||||
ctx.input.events.change_focus = 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_released(&ctx) => ctx.input.mouse.updated & ~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
|
||||
// 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_released(&ctx, MouseButtons btn) => (ctx.mouse_released() & btn) != BTN_NONE;
|
||||
macro Ctx.is_mouse_down(&ctx, MouseButtons btn) => (ctx.mouse_down() & btn) != BTN_NONE;
|
||||
|
||||
// Mouse Button moved
|
||||
// Mouse Buttons down
|
||||
fn void Ctx.input_mouse_button(&ctx, MouseButtons buttons)
|
||||
{
|
||||
ctx.input.mouse.updated = 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
|
||||
@ -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.y = dy;
|
||||
|
||||
ctx.input.events.mouse_move = true;
|
||||
ctx.input.events.mouse_move = dx != 0 || dy != 0;
|
||||
}
|
||||
|
||||
// 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.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;
|
||||
}
|
||||
|
@ -130,5 +130,6 @@ fn ElemEvents! Ctx.slider_ver(&ctx,
|
||||
return elem.events;
|
||||
}
|
||||
|
||||
macro short calc_slider(ushort off, ushort dim, float value) => (short)off + (short)(dim * value);
|
||||
macro float calc_value(ushort off, ushort mouse, ushort dim, ushort slider) => math::clamp((float)(mouse-off-slider/2)/(float)(dim-slider), 0.0f, 1.0f);
|
||||
macro short calc_slider(short off, short dim, float value) => (short)off + (short)(dim * value);
|
||||
macro float calc_value(short off, short mouse, short dim, short slider)
|
||||
=> math::clamp((float)(mouse-off-slider/2)/(float)(dim-slider), 0.0f, 1.0f);
|
||||
|
72
test/test_error.c3
Normal file
72
test/test_error.c3
Normal file
@ -0,0 +1,72 @@
|
||||
import std::io;
|
||||
|
||||
struct FaultStack {
|
||||
usz elem;
|
||||
anyfault[16] v;
|
||||
}
|
||||
|
||||
fn void FaultStack.push(&fs, anyfault f)
|
||||
{
|
||||
if (fs.elem < fs.v.len) {
|
||||
fs.v[fs.elem++] = f;
|
||||
}
|
||||
}
|
||||
|
||||
fn anyfault FaultStack.pop(&fs)
|
||||
{
|
||||
return fs.elem > 0 ? fs.v[fs.elem-- - 1] : anyfault{};
|
||||
}
|
||||
|
||||
FaultStack fs;
|
||||
|
||||
fn int! err1()
|
||||
{
|
||||
return IoError.OUT_OF_SPACE?;
|
||||
}
|
||||
|
||||
fn void! err2()
|
||||
{
|
||||
return IoError.EOF?;
|
||||
}
|
||||
|
||||
/*
|
||||
macro @unwrap(#f)
|
||||
{
|
||||
$if ($typeof(#f).typeid == void!.typeid) {
|
||||
if (catch err = #f) { fs.push(err); }
|
||||
return;
|
||||
} $else {
|
||||
$typeof(#f) x = #f;
|
||||
if (catch err = x) {
|
||||
fs.push(err);
|
||||
return $typeof(#f!!){};
|
||||
} else {return x;}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
<*
|
||||
@require @typekind(#func) == OPTIONAL : `@unwrap requires an optional value`
|
||||
*>
|
||||
macro @unwrap(#func)
|
||||
{
|
||||
anyfault exc = @catch(#func);
|
||||
if (exc != anyfault{}) {
|
||||
fs.push(exc);
|
||||
$if $typeof(#func!!).typeid != void.typeid:
|
||||
return $typeof(#func!!){};
|
||||
$else
|
||||
return;
|
||||
$endif
|
||||
} else {
|
||||
return #func!!;
|
||||
}
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
@unwrap(err1());
|
||||
@unwrap(err2());
|
||||
|
||||
io::printfn("%s", fs.v);
|
||||
}
|
26
test/test_keyboard.c3
Normal file
26
test/test_keyboard.c3
Normal file
@ -0,0 +1,26 @@
|
||||
import rl;
|
||||
import std::io;
|
||||
|
||||
fn int main(String[] args)
|
||||
{
|
||||
short width = 800;
|
||||
short height = 450;
|
||||
rl::set_config_flags(rl::FLAG_WINDOW_RESIZABLE);
|
||||
rl::init_window(width, height, "Ugui Test");
|
||||
rl::set_target_fps(60);
|
||||
rl::enable_event_waiting();
|
||||
|
||||
// Main loop
|
||||
KeyboardKey k;
|
||||
while (!rl::window_should_close()) {
|
||||
do {
|
||||
k = rl::get_char_pressed();
|
||||
io::printfn("%s", k);
|
||||
} while (k != 0);
|
||||
}
|
||||
|
||||
rl::close_window();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user