better textbox support
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 4 Mar 2022 18:26:03 +0000 (12:26 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 4 Mar 2022 18:26:03 +0000 (12:26 -0600)
src/entity/editor.onyx
src/gfx/ui.onyx
src/main.onyx

index 288f0c231cdc691361677c865766ba7a5e11a878..9058033503cdf9be40123eb88e83238c36d3ff59 100644 (file)
@@ -379,7 +379,7 @@ editor_draw :: () {
 #local prepare_field_editor :: (v: any) {
     array.ensure_capacity(^field_buffer, 256);
     field_buffer.count = 256;
-    s := conv.format_va(field_buffer, "{}", .[v]);
+    s := conv.format_va(field_buffer, "{\"d}", .[v]);
     field_buffer.count = s.count;
 }
 
@@ -393,64 +393,47 @@ editor_draw :: () {
     y += 32;
     font_print(editor_font, x, y, field_name);
 
-    switch v.type {
-        type_is(i32) {
-            font_print(editor_font, x, y + 32, "INT: {}\n", value);
-            if draw_textbox(.{ x, y + 64, w, 48 }, ^field_buffer) {
-                conv.parse_any(v.data, v.type, field_buffer);
+    info := type_info.get_type_info(v.type);
+
+    switch info.kind {
+        case .Enum {
+            enum_info := cast(^type_info.Type_Info_Enum) info;
+            value: u64;
+            switch enum_info.backing_type {
+                case i8,  u8  do value = cast(u64) *(cast(^u8) v.data);
+                case i16, u16 do value = cast(u64) *(cast(^u16) v.data);
+                case i32, u32 do value = cast(u64) *(cast(^u32) v.data);
+                case i64, u64 do value = cast(u64) *(cast(^u64) v.data);
+                case #default do assert(false, "Bad enum backing type");
             }
-        }
 
-        type_is(f32) {
-            font_print(editor_font, x, y + 32, "FLOAT: {}\n", value);
-            if draw_textbox(.{ x, y + 64, w, 48 }, ^field_buffer) {
-                conv.parse_any(v.data, v.type, field_buffer);
-            }
-        }
-
-        case #default {
-            info := type_info.get_type_info(v.type);
-
-            if info.kind == .Enum {
-                enum_info := cast(^type_info.Type_Info_Enum) info;
-                value: u64;
-                switch enum_info.backing_type {
-                    case i8,  u8  do value = cast(u64) *(cast(^u8) v.data);
-                    case i16, u16 do value = cast(u64) *(cast(^u16) v.data);
-                    case i32, u32 do value = cast(u64) *(cast(^u32) v.data);
-                    case i64, u64 do value = cast(u64) *(cast(^u64) v.data);
-                    case #default do assert(false, "Bad enum backing type");
-                }
+            if enum_info.is_flags {
+                for^ enum_info.members {
+                    y += 20;
+                    checkbox_value := (value & it.value) != 0;
+                    if draw_checkbox(.{x, y, w, 20}, ^checkbox_value, it.name, increment=~~y) {
+                        switch enum_info.backing_type {
+                            case i8,  u8  do set_value(u8);
+                            case i16, u16 do set_value(u16);
+                            case i32, u32 do set_value(u32);
+                            case i64, u64 do set_value(u64);
+                        }
 
-                if enum_info.is_flags {
-                    for^ enum_info.members {
-                        y += 20;
-                        checkbox_value := (value & it.value) != 0;
-                        if draw_checkbox(.{x, y, w, 20}, ^checkbox_value, it.name, increment=~~y) {
-                            switch enum_info.backing_type {
-                                case i8,  u8  do set_value(u8);
-                                case i16, u16 do set_value(u16);
-                                case i32, u32 do set_value(u32);
-                                case i64, u64 do set_value(u64);
-                            }
-
-                            set_value :: macro (T: type_expr) {
-                                if !checkbox_value do *cast(^T) v.data = ~~(value & ~it.value);
-                                else               do *cast(^T) v.data = ~~(value |  it.value);
-                            }
+                        set_value :: macro (T: type_expr) {
+                            if !checkbox_value do *cast(^T) v.data = ~~(value & ~it.value);
+                            else               do *cast(^T) v.data = ~~(value |  it.value);
                         }
                     }
-                } else {
-                    @TODO // Add radio buttons for enum type.
                 }
+            } else {
+                @TODO // Add radio buttons for enum type.
             }
         }
-    }
 
-    type_is :: macro (T: type_expr, body: Code) {
-        case T {
-            value := *cast(^T) v.data;
-            #insert body;
+        case #default {
+            if draw_textbox(.{ x, y + 64, w, 48 }, ^field_buffer) {
+                conv.parse_any(v.data, v.type, field_buffer);
+            }
         }
     }
 }
index 20f9dc81a9a23c75d7e9cb9922b870075184f857..839b1989fb3c6d3c2ca32d40286eb37ce1f96bab 100644 (file)
@@ -189,12 +189,17 @@ draw_textbox :: (use r: Rect, text_buffer: ^[..] u8, placeholder := null_str, th
 
         if is_button_down(GLFW_MOUSE_BUTTON_LEFT) && contains {
             textbox_editing_state.cursor_animation = 1.0f;
-            // textbox_editing_state.cursor_position = get_cursor_position(text_buffer, text_x, text_y, theme.font_size, ~~mx, ~~my);
+            textbox_editing_state.cursor_position = screen_to_cursor(^font, text_x, text_y, text, ~~mx, ~~my);
         }
 
         keys := input_get_keys_this_frame();
         for key: iter.as_iterator(^keys) {
             switch key.key {
+                case GLFW_KEY_ESCAPE {
+                    set_active_item(0);
+                    input_release_keys();
+                }
+
                 case GLFW_KEY_LEFT  do textbox_editing_state.cursor_position -= 1;
                 case GLFW_KEY_RIGHT do textbox_editing_state.cursor_position += 1;
                 case GLFW_KEY_END   do textbox_editing_state.cursor_position = text_buffer.count;
@@ -258,6 +263,11 @@ draw_textbox :: (use r: Rect, text_buffer: ^[..] u8, placeholder := null_str, th
     // Draw the cursor on textboxes
     if is_active_item(hash) {
         cursor := cursor_to_screen(^font, x + border_width, y + border_width, text, textbox_editing_state.cursor_position);
+        right_edge := x + w - border_width * 2;
+        if cursor.x > right_edge {
+            text_x -= cursor.x - right_edge;
+            cursor.x = right_edge - 2;
+        }
         immediate_set_color(.{0,0,0});
         immediate_rectangle(cursor.x, cursor.y + 2, 2, h - border_width * 2 - 4);
     }
@@ -285,6 +295,28 @@ draw_textbox :: (use r: Rect, text_buffer: ^[..] u8, placeholder := null_str, th
 
         return .{ cx, cy };
     }
+
+    screen_to_cursor :: (font: ^Font, x, y: f32, text: str, mouse_x, mouse_y: f32) -> i32 {
+        mx := mouse_x - x;
+        my := mouse_y - y;
+        
+        cx := 0.0f; 
+        cy := 0.0f;
+        for pos: text.count {
+            if text[pos] == #char "\n" {
+                cx = 0;
+                cy += font.em + 2;
+            } else {
+                cx += font_get_char_width(*font, text[pos]);
+            }
+
+            if cy >= my && cx >= mx {
+                return pos;
+            }
+        }
+
+        return text.count;
+    }
 }
 
 
index c3c6c20d3523e37a686c23cecb9025bbf2d9ecee..882d3a23c2a0348171248014c04b2383511aac62 100644 (file)
@@ -46,7 +46,7 @@ deinit :: () {
 update :: (dt: f32) {
     input_update();
 
-    if is_key_down(GLFW_KEY_ESCAPE) {
+    if is_key_just_up(GLFW_KEY_ESCAPE) {
         glfwSetWindowShouldClose(window, true);
         return;
     }