enums flags with '&' result in bool; working on keyboard events
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 12 Jun 2021 20:00:01 +0000 (15:00 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 12 Jun 2021 20:00:01 +0000 (15:00 -0500)
include/onyxtypes.h
modules/js_events/js_events.js
modules/js_events/js_events.onyx
modules/ui/components/button.onyx
modules/ui/components/checkbox.onyx
modules/ui/components/radio.onyx
modules/ui/components/textbox.onyx
modules/ui/module.onyx
modules/ui/ui.onyx
src/onyxchecker.c
src/onyxtypes.c

index 950434e6021da21ccff3c89548ee7e3cdd8d3f95..97c5f0bd9230a29668e3efb6dd6e08df5a5f5341 100644 (file)
@@ -113,6 +113,7 @@ struct TypeWithOffset {
         u64 unique_id;                                            \
         char* name;                                               \
         Type* backing;                                            \
+        b32   is_flags;                                           \
     })
 
 
index ddc9a95f1f536a657646426e79fe506478b576c8..4ff47d315c9fc0f38cb45a305b9a21848ea5a797 100644 (file)
@@ -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;
         });
 
index f7fbee98fd6a84a16044a458a886522b6467308c..ec441cb8245948e3ea4e0db4feda98013e65ed13 100644 (file)
@@ -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 {
index 835d5915d7cb11591f2ff5500b6572a4e665e99d..c647b2e3a41cb50bba436958c002a2ffd28aeac8 100644 (file)
@@ -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);
index 4acfd98f667a0f6ec97bbc9dd3970f595af906cf..6b84e1ad02258cf27ca3508f5befece88850c6ad 100644 (file)
@@ -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;
 
index 7f9feede352b5cf111449d3171cf706351af2b01..3f27952c3a45f5bac440d51eda50764eb9911305 100644 (file)
@@ -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;
 
index 94ccd9a607e4cbc05951fd27fb9925b4a344c8ef..6d1bf6c07f8b30f3bc90a8d08c6a0558a2e54924 100644 (file)
@@ -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
index 3b28f922133d5d90709b9a77961205e9fa0ea3b2..90a178ebac7e6b040c2fda6830b2ce8bd3a844e4 100644 (file)
@@ -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.
index 74caddc9c7ccc339e98e25db40c1b078f74a4d73..c7922100d8748ab3516f661a4264708e7a8a3118 100644 (file)
@@ -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);
 }
index 17136544052181d9ce567ea7033ee7e62cee06d5..fbc4c6be8c50ca07eecce621209570fc6c9ab24f 100644 (file)
@@ -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);
index 4074c0c8f5d6763f5434177308b447561f9fff7f..c582b081a62ca712d5dab37fc22dfbb07e90538e 100644 (file)
@@ -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;
         }