bugfix and updates to ui
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 7 Jun 2021 05:14:30 +0000 (00:14 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 7 Jun 2021 05:14:30 +0000 (00:14 -0500)
modules/ui/ui.onyx
src/onyxchecker.c
src/onyxparser.c

index 13a72342a76b0f68dc347074d3a400ae25262e4c..285600d0ced61439a211e8ebbae7c2c84794797c 100644 (file)
@@ -12,34 +12,91 @@ package ui
 DEFAULT_TEXT_SIZE :: 32.0f
 
 
+UI_Id :: #type u32
+
+#private hot_item    : UI_Id = 0
+#private active_item : UI_Id = 0
+#private hot_item_was_set := false
+
+MouseState :: struct {
+    left_button_down    := false;
+    left_button_just_up := false;
+
+    right_button_down    := false;
+    right_button_just_up := false;
+
+    x: f32 = 0;
+    y: f32 = 0;
+}
+
+mouse_state: MouseState = MouseState.{};
+
 
 init_ui :: () {
     init_font();
 }
 
-#private init_font :: () {
-    font_data := #file_contents "./resources/font_2.data";
+clear_buttons :: () {
+    mouse_state.left_button_just_up = false;
+    mouse_state.right_button_just_up = false;
 
-    bft := bitmap_font.Bitmap_Font_Texture.{
-        data = font_data,
-        width = 256,
-        height = 256,
-    };
+    if !hot_item_was_set do set_hot_item(0);
+    hot_item_was_set = false;
+}
 
-    font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff:");
+//
+// Telling the UI system about hardware updates
+//
 
-    font_texture = gl.createTexture();
-    gl.bindTexture(gl.TEXTURE_2D, font_texture);
-    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, font_data);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
-    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-    gl.bindTexture(gl.TEXTURE_2D, -1);
+update_mouse_position :: (new_x: f32, new_y: f32) {
+    mouse_state.x = new_x;
+    mouse_state.y = new_y;
 }
 
-get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
-    return font->get_width(text, size);
+#private_file ButtonKind :: enum { Left; Right; Middle; }
+
+button_pressed :: (kind: ButtonKind) {
+    switch kind {
+        case .Left  do mouse_state.left_button_down  = true;
+        case .Right do mouse_state.right_button_down = true;
+    }
+}
+
+button_released :: (kind: ButtonKind) {
+    switch kind {
+        case .Left {
+            mouse_state.left_button_down    = false;
+            mouse_state.left_button_just_up = true;
+        }
+
+        case .Right {
+            mouse_state.right_button_down    = false;
+            mouse_state.right_button_just_up = true;
+        }
+    }
+}
+
+
+set_active_item :: (id: UI_Id) -> bool {
+    active_item = id;
+    return true;
+}
+
+set_hot_item :: (id: UI_Id) -> bool {
+    if active_item != 0 do return false;
+
+    hot_item_was_set = true;
+
+    hot_item = id;
+    return true;
+}
+
+is_active_item :: (id: UI_Id) -> bool {
+    return active_item == id;
+}
+
+is_hot_item :: (id: UI_Id) -> bool {
+    return hot_item == id;
 }
 
 // 'x' and 'y' are the top-left coordinates of the text. 'y' is NOT the baseline.
@@ -90,27 +147,56 @@ draw_rect :: proc {
 }
 
 @Themeing
-draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme) -> bool {
+draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme, site := #callsite) -> bool {
     height := Rectangle.height(r);
     draw_text_raw(text, x0, y0, theme.font_size * height, theme.text_color);
 }
 
 @Themeing
-draw_button :: (use r: Rectangle, text: str, theme := ^default_button_theme) -> bool {
+draw_button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site := #callsite) -> bool {
     gfx.set_texture();
 
+    result := false;
+
+    hash := get_site_hash(site);
+    if is_active_item(hash) {
+        if mouse_state.left_button_just_up {
+            if is_hot_item(hash) && Rectangle.contains(r, mouse_state.x, mouse_state.y) {
+                result = true;
+            }
+
+            set_active_item(0);
+        }
+
+    } elseif is_hot_item(hash) {
+        if mouse_state.left_button_down {
+            set_active_item(hash);
+        }
+    }
+
+    if Rectangle.contains(r, mouse_state.x, mouse_state.y) {
+        set_hot_item(hash);
+    }
+
     border_width  := theme.border_width;
     width, height := Rectangle.dimensions(r);
 
     gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color);
-    gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, theme.background_color);
+
+    @Lerp
+    if is_hot_item(hash) {
+        gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, theme.hover_color);
+
+    } else {
+        gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, theme.background_color);
+    }
 
     font_size := height * theme.font_size;
     text_width := font->get_width(text, font_size);
     text_height := font->get_height(text, font_size);
 
     draw_text_raw(text, x0 + (width - text_width) / 2, y0 + (height - text_height) / 2, font_size, theme.text_color);
-    return false;
+    return result;
 }
 
 
@@ -137,6 +223,11 @@ Rectangle :: struct {
 
     top_left     :: (use r: Rectangle) -> (x: f32, y: f32) do return math.min(x0, x1), math.min(y0, y1);
     bottom_right :: (use r: Rectangle) -> (x: f32, y: f32) do return math.max(x0, x1), math.max(y0, y1);
+
+    contains :: (use r: Rectangle, x: f32, y: f32) -> bool {
+        return math.min(x0, x1) <= x && x <= math.max(x0, x1) &&
+               math.min(y0, y1) <= y && y <= math.max(y0, y1);
+    }
 }
 
 
@@ -157,6 +248,7 @@ Button_Theme :: struct {
     use text_theme := Text_Theme.{};
 
     background_color := gfx.Color4.{ 0.1, 0.1, 0.1 };
+    hover_color      := gfx.Color4.{ 0.2, 0.2, 0.2 };
 
     border_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
     border_width := 10.0f; @InPixels
@@ -164,4 +256,46 @@ Button_Theme :: struct {
 
 @Bug // there is a compile-time known bug if either of the 'Button_Theme's below are omitted.
 default_button_theme: Button_Theme = Button_Theme.{};
-default_text_theme:   Text_Theme   = Text_Theme.{};
\ No newline at end of file
+default_text_theme:   Text_Theme   = Text_Theme.{};
+
+
+
+
+
+
+// Utilities
+get_site_hash :: (site: CallSite) -> u32 {
+    hash :: package core.hash
+
+    file_hash   := hash.to_u32(site.file);
+    line_hash   := hash.to_u32(site.line);
+    column_hash := hash.to_u32(site.column);
+
+    return file_hash * 0x472839 + line_hash * 0x6849210 + column_hash * 0x1248382;
+}
+
+get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
+    return font->get_width(text, size);
+}
+
+
+#private init_font :: () {
+    font_data := #file_contents "./resources/font_2.data";
+
+    bft := bitmap_font.Bitmap_Font_Texture.{
+        data = font_data,
+        width = 256,
+        height = 256,
+    };
+
+    font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff:");
+
+    font_texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, font_texture);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, font_data);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+    gl.bindTexture(gl.TEXTURE_2D, -1);
+}
index 305f95afa1bea641370f00d62137f246af6438de..c6afa1cde51a23d9047cf647e8df1543efe40bfc 100644 (file)
@@ -1544,7 +1544,11 @@ CheckStatus check_expression(AstTyped** pexpr) {
             CHECK(compound, (AstCompound *) expr);
             break;
 
-        case Ast_Kind_Call_Site: break;
+        case Ast_Kind_Call_Site:
+            // NOTE: This has to be set here because if it were to be set in the parser,
+            // builtin_callsite_type wouldn't be known when parsing the builtin.onyx file.
+            expr->type_node = builtin_callsite_type;
+            break;
 
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
index 38cec8f809132d494a22aadfc915972a8b32a16b..00e38aafc50f74889eafc7d894dd8eb0f6c77659 100644 (file)
@@ -1873,7 +1873,6 @@ static void parse_function_params(OnyxParser* parser, AstFunction* func) {
             if (parse_possible_directive(parser, "callsite")) {
                 AstCallSite* cs = make_node(AstCallSite, Ast_Kind_Call_Site);
                 cs->token = directive_token;
-                cs->type_node = builtin_callsite_type;
                 curr_param.default_value = (AstTyped *) cs;
 
             } else {