From 471cbbf2822fa41a4bd470ebf1d837cf8592aa22 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sat, 12 Jun 2021 15:00:01 -0500 Subject: [PATCH] enums flags with '&' result in bool; working on keyboard events --- include/onyxtypes.h | 1 + modules/js_events/js_events.js | 45 +++++++++++++++++++++- modules/js_events/js_events.onyx | 37 +++++++++++++----- modules/ui/components/button.onyx | 4 +- modules/ui/components/checkbox.onyx | 1 - modules/ui/components/radio.onyx | 1 - modules/ui/components/textbox.onyx | 58 ++++++++++++++++++++++++++++- modules/ui/module.onyx | 2 + modules/ui/ui.onyx | 3 +- src/onyxchecker.c | 5 +++ src/onyxtypes.c | 1 + 11 files changed, 137 insertions(+), 21 deletions(-) diff --git a/include/onyxtypes.h b/include/onyxtypes.h index 950434e6..97c5f0bd 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -113,6 +113,7 @@ struct TypeWithOffset { u64 unique_id; \ char* name; \ Type* backing; \ + b32 is_flags; \ }) diff --git a/modules/js_events/js_events.js b/modules/js_events/js_events.js index ddc9a95f..4ff47d31 100644 --- a/modules/js_events/js_events.js +++ b/modules/js_events/js_events.js @@ -30,14 +30,55 @@ window.ONYX_MODULES.push({ document.addEventListener("keydown", function (ev) { if (ev.isComposing || ev.keyCode === 229) return; ev.preventDefault(); - push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode ]); + + // NOTE: These modifiers need to match in js_events.onyx. + var modifiers = 0x0000; + if (ev.ctrlKey) modifiers |= 0x01; + if (ev.altKey) modifiers |= 0x02; + if (ev.metaKey) modifiers |= 0x04; + if (ev.shiftKey) modifiers |= 0x08; + + push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode, modifiers ]); + + var keyname = ev.code; + let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer); + let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2; + + let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer); + + for (var i = 0; i < keyname.length; i++) { + WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i); + } + + WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length; return false; }); document.addEventListener("keyup", function (ev) { if (ev.isComposing || ev.keyCode === 229) return; ev.preventDefault(); - push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode ]); + + // NOTE: These modifiers need to match in js_events.onyx. + var modifiers = 0x0000; + if (ev.ctrlKey) modifiers |= 0x01; + if (ev.altKey) modifiers |= 0x02; + if (ev.metaKey) modifiers |= 0x04; + if (ev.shiftKey) modifiers |= 0x08; + + push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode, modifiers ]); + + var keyname = ev.code; + let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer); + let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2; + + let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer); + + for (var i = 0; i < keyname.length; i++) { + WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i); + } + + WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length; + return false; }); diff --git a/modules/js_events/js_events.onyx b/modules/js_events/js_events.onyx index f7fbee98..ec441cb8 100644 --- a/modules/js_events/js_events.onyx +++ b/modules/js_events/js_events.onyx @@ -30,24 +30,40 @@ DomEvent :: struct { KeyboardEvent :: struct { use event : DomEvent; - keycode : u32; -} - -MouseButton :: enum { - Left :: 0x00; - Middle :: 0x01; - Right :: 0x02; + keycode : u32; // Apparently, keyCode is deprecated on browsers now??? Stupid web standards that aren't "standards" at all. + modifiers : Modifiers; + + // This is assuming that no single keyname is greater than 15 characters in length. + // A quick look at https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values makes + // me think that that isn't possible, but it's the web so anything is possible. 🙄 + keyname : [15] u8; + keyname_count : u8; + + Modifiers :: enum #flags { + CTRL :: 0x01; + ALT :: 0x02; + META :: 0x04; + SHIFT :: 0x08; + } - WheelUp :: 0x03; - WheelDown :: 0x04; + get_name :: (use e: ^KeyboardEvent) -> str do return str.{ ~~keyname, ~~keyname_count }; } MouseEvent :: struct { use event : DomEvent; + Button :: enum { + Left :: 0x00; + Middle :: 0x01; + Right :: 0x02; + + WheelUp :: 0x03; + WheelDown :: 0x04; + } + pos_x : u32; pos_y : u32; - button : MouseButton; + button : Button; } ResizeEvent :: struct { @@ -84,6 +100,7 @@ consume :: () -> Iterator(Event) { use package core.intrinsics.onyx { __zero_value } if event_storage.event_count == 0 do return __zero_value(Event), false; + @CodeGeneration // This instruction (and all instructions involving Event) generate a TON of instructions because Event is a union. event := event_storage.event_buffer[0]; for i: 0 .. Num_Buffered_Events - 2 { diff --git a/modules/ui/components/button.onyx b/modules/ui/components/button.onyx index 835d5915..c647b2e3 100644 --- a/modules/ui/components/button.onyx +++ b/modules/ui/components/button.onyx @@ -14,10 +14,7 @@ Button_Theme :: struct { default_button_theme := Button_Theme.{}; -@Themeing button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site := #callsite, increment := 0) -> bool { - gfx.set_texture(); - result := false; hash := get_site_hash(site, increment); @@ -52,6 +49,7 @@ button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site := border_width := theme.border_width; width, height := Rectangle.dimensions(r); + gfx.set_texture(); gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color); surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color); diff --git a/modules/ui/components/checkbox.onyx b/modules/ui/components/checkbox.onyx index 4acfd98f..6b84e1ad 100644 --- a/modules/ui/components/checkbox.onyx +++ b/modules/ui/components/checkbox.onyx @@ -18,7 +18,6 @@ Checkbox_Theme :: struct { default_checkbox_theme := Checkbox_Theme.{}; -@Themeing checkbox :: (use r: Rectangle, value: ^bool, text: str, theme := ^default_checkbox_theme, site := #callsite, increment := 0) -> bool { result := false; diff --git a/modules/ui/components/radio.onyx b/modules/ui/components/radio.onyx index 7f9feede..3f27952c 100644 --- a/modules/ui/components/radio.onyx +++ b/modules/ui/components/radio.onyx @@ -18,7 +18,6 @@ Radio_Theme :: struct { default_radio_theme := Radio_Theme.{}; -@Themeing radio :: (use r: Rectangle, selected: ^$T, value: T, text: str, theme := ^default_radio_theme, site := #callsite, increment := 0) -> bool { result := false; diff --git a/modules/ui/components/textbox.onyx b/modules/ui/components/textbox.onyx index 94ccd9a6..6d1bf6c0 100644 --- a/modules/ui/components/textbox.onyx +++ b/modules/ui/components/textbox.onyx @@ -1,6 +1,60 @@ package ui +use package core +Textbox_Theme :: struct { + use text_theme := Text_Theme.{ + text_color = .{ 0, 0, 0 } + }; -textbox :: (use r: Rectangle) -> bool { - + background_color := gfx.Color4.{ 0.8, 0.8, 0.8 }; + hover_color := gfx.Color4.{ 1.0, 1.0, 1.0 }; + click_color := gfx.Color4.{ 0.5, 0.5, 0.7 }; + + border_color := gfx.Color4.{ 0.2, 0.2, 0.2 }; + border_width := 6.0f; @InPixels +} + +default_textbox_theme := Textbox_Theme.{}; + +textbox :: (use r: Rectangle, text: str, theme := ^default_textbox_theme, site := #callsite, increment := 0) -> bool { + result := false; + + hash := get_site_hash(site, increment); + animation_state := map.get(^animation_states, hash); + + if Rectangle.contains(r, mouse_state.x, mouse_state.y) { + set_hot_item(hash); + } + + if is_hot_item(hash) { + move_towards(^animation_state.hover_time, 1.0f, 0.1f); @ThemeConfiguration + } else { + move_towards(^animation_state.hover_time, 0.0f, 0.1f); @ThemeConfiguration + } + + border_width := theme.border_width; + width, height := Rectangle.dimensions(r); + + gfx.set_texture(); + gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color); + + surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color); + surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color); + gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, surface_color); + + text_width := bmfont.get_width(^font, text, theme.font_size); + text_height := bmfont.get_height(^font, text, theme.font_size); + + draw_text_raw(text, + x0 + border_width, + y0 + ~~ font.common.baseline * theme.font_size + (height - text_height) / 2, + theme.font_size, theme.text_color); + + move_towards(^animation_state.click_time, 0.0f, 0.08f); @ThemeConfiguration + + if animation_state.click_time > 0 || animation_state.hover_time > 0 { + map.put(^animation_states, hash, animation_state); + } else { + map.delete(^animation_states, hash); + } } \ No newline at end of file diff --git a/modules/ui/module.onyx b/modules/ui/module.onyx index 3b28f922..90a178eb 100644 --- a/modules/ui/module.onyx +++ b/modules/ui/module.onyx @@ -17,6 +17,7 @@ user interfaces in WebGL (and OpenGL when Onyx compiles to C). This module provides several common UI components such as: - Buttons - Checkbox + - Radio buttons - Sliders - Textboxes @@ -39,6 +40,7 @@ package ui #load "./components/checkbox" #load "./components/slider" #load "./components/radio" +#load "./components/textbox" // Package inclusions that are part of all files in the "ui" package. diff --git a/modules/ui/ui.onyx b/modules/ui/ui.onyx index 74caddc9..c7922100 100644 --- a/modules/ui/ui.onyx +++ b/modules/ui/ui.onyx @@ -28,7 +28,7 @@ MouseState :: struct { y: f32 = 0; } -mouse_state: MouseState = MouseState.{}; +mouse_state := MouseState.{}; init_ui :: () { @@ -131,7 +131,6 @@ draw_rect :: proc { } } -@Themeing draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme, site := #callsite) -> bool { draw_text_raw(text, x0, y0 + ~~font.common.baseline * theme.font_size, theme.font_size, theme.text_color); } diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 17136544..fbc4c6be 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -995,6 +995,11 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop, b32 assignment_is_ok) { if ((binop_allowed[binop->operation] & effective_flags) == 0) goto bad_binaryop; + // NOTE: Enum flags with '&' result in a boolean value + if (binop->type->kind == Type_Kind_Enum && binop->type->Enum.is_flags && binop->operation == Binary_Op_And) { + binop->type = &basic_types[Basic_Kind_Bool]; + } + if (binop->flags & Ast_Flag_Comptime) { // NOTE: Not a binary op *pbinop = (AstBinaryOp *) ast_reduce(context.ast_alloc, (AstTyped *) binop); diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 4074c0c8..c582b081 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -425,6 +425,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { enum_type->Enum.unique_id = next_unique_id++; enum_type->Enum.backing = enum_node->backing_type; enum_type->Enum.name = enum_node->name; + enum_type->Enum.is_flags = enum_node->flags & Ast_Flag_Enum_Is_Flags; return enum_type; } -- 2.25.1