From 7266096ba0506c075792524ff7958c33307445ec Mon Sep 17 00:00:00 2001 From: Kenneth Date: Thu, 16 Jan 2025 01:39:27 +0000 Subject: [PATCH] wip: textbox --- src/main.c | 168 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 142 insertions(+), 26 deletions(-) diff --git a/src/main.c b/src/main.c index c747f9c..31819ba 100644 --- a/src/main.c +++ b/src/main.c @@ -8,11 +8,13 @@ #include "sokol_glue.h" #include "sokol_imgui.h" #include "sokol_log.h" +#include #include #include #include #include #include +#include // if mouse movement between mouse down and mouse up is below this threshold (in // px) then it is considered to be a mouse click @@ -147,7 +149,6 @@ void *arena_push(arena_t *arena, size_t size) { arena_page_t *new_page = arena_new_page(arena->capacity); new_page->next = arena->page; arena->page = new_page; - printf("arena realloc\n"); } void *ptr = arena->page->data + arena->page->end_ptr; arena->page->end_ptr += size; @@ -163,6 +164,32 @@ void arena_free(arena_t *arena) { free(arena); } +// =========================== +// struct: string +// =========================== + +typedef struct { + char *data; + size_t length; + size_t capacity; +} growable_string_t; + +growable_string_t growable_string_alloc(size_t capacity) { + char *data = malloc(sizeof(char) * capacity); + return (growable_string_t){ + .data = data, + .length = 0, + .capacity = capacity, + }; +} + +void growable_string_grow(growable_string_t *str, size_t additional_bytes) { + if (str->length + additional_bytes >= str->capacity) { + str->capacity = str->capacity * 2 + additional_bytes; + str->data = realloc(str->data, sizeof(char) * str->capacity); + } +} + // =========================== // struct: point_list // =========================== @@ -209,14 +236,19 @@ void point_list_free(point_list_t *list) { free(list->items); } typedef enum { entity_flag_rect = 1 << 0, entity_flag_path = 1 << 1, - entity_flag_selected = 1 << 2, + entity_flag_editable_text = 1 << 2, + entity_flag_selected = 1 << 3, + entity_flag_active = 1 << 4, } entity_flag_t; typedef struct entity { + int id; entity_flag_t flags; point_list_t points; + ImVec2 dimension; ImColor color; + char content[512]; struct entity *next; struct entity *prev; @@ -242,10 +274,11 @@ typedef struct { // =========================== typedef enum { - toolbox_button_select, - toolbox_button_draw, - toolbox_button_rectangle, -} toolbox_button_kind_t; + tool_select, + tool_draw, + tool_rectangle, + tool_text, +} tool_t; typedef struct { arena_t *arena; @@ -269,7 +302,7 @@ typedef struct { ImVec2 drag_start; ImVec2 last_mouse_pos; - toolbox_button_kind_t selected_toolbox_button; + tool_t current_tool; bool is_color_picker_changing; ImColor picked_color; } state_t; @@ -315,7 +348,8 @@ void remove_selected_entites(state_t *state) { entity_recycle(state, last_removed_entity); last_removed_entity = NULL; } - if (entity->flags & entity_flag_selected) { + if (entity->flags & entity_flag_selected && + (entity->flags & entity_flag_active) == 0) { if (state->entities == entity) { state->entities = entity->next; } @@ -345,13 +379,14 @@ void remove_selected_entites(state_t *state) { void create_entity(state_t *state) { const ImGuiIO *io = igGetIO(); - switch (state->selected_toolbox_button) { + switch (state->current_tool) { default: break; - case toolbox_button_draw: { + case tool_draw: { if (vec2_distance_sqr(&state->drag_start, &io->MousePos) > 100) { entity_t *entity = entity_alloc(state, state->points.capacity); + entity->id = rand(); entity->flags = entity_flag_path; entity->color = state->picked_color; point_list_copy(&entity->points, &state->points); @@ -363,22 +398,50 @@ void create_entity(state_t *state) { break; } - case toolbox_button_rectangle: { + case tool_rectangle: { if (vec2_distance_sqr(&state->drag_start, &io->MousePos) > 625) { entity_t *entity = entity_alloc(state, 2); + entity->id = rand(); entity->flags = entity_flag_rect; entity->color = state->picked_color; + *point_list_push(&entity->points) = state->drag_start; *point_list_push(&entity->points) = (ImVec2){io->MousePos.x, state->drag_start.y}; *point_list_push(&entity->points) = io->MousePos; *point_list_push(&entity->points) = (ImVec2){state->drag_start.x, io->MousePos.y}; + push_entity(state, entity); } break; } + + case tool_text: { + if (vec2_distance_sqr(&state->drag_start, &io->MousePos) > 625) { + entity_t *entity = entity_alloc(state, 4); + entity->id = rand(); + entity->flags = entity_flag_editable_text | entity_flag_selected; + entity->color = state->picked_color; + memcpy(entity->content, "Text", 4); + + ImGuiContext *gui_ctx = GImGui; + + entity->dimension.x = fabs(io->MousePos.x - state->drag_start.x); + entity->dimension.y = fabs(io->MousePos.y - state->drag_start.y); + + *point_list_push(&entity->points) = state->drag_start; + *point_list_push(&entity->points) = + (ImVec2){io->MousePos.x, state->drag_start.y}; + *point_list_push(&entity->points) = io->MousePos; + *point_list_push(&entity->points) = + (ImVec2){state->drag_start.x, io->MousePos.y}; + + push_entity(state, entity); + } + break; + } } } @@ -501,7 +564,7 @@ static void init(void) { state.pass_action.colors[0].load_action = SG_LOADACTION_CLEAR; state.selected_entity = NULL; state.has_selected_entities = false; - state.selected_toolbox_button = toolbox_button_select; + state.current_tool = tool_select; state.picked_color = *ImColor_ImColor_U32(0xFFFFFFFF); state.color_picker_window_size.x = 0; state.color_picker_window_size.y = 0; @@ -509,6 +572,7 @@ static void init(void) { static void toolbox_window(void); static void color_picker_window(void); +static int on_input_text_event(ImGuiInputTextCallbackData *event); static void frame(void) { simgui_new_frame(&(simgui_frame_desc_t){ @@ -547,6 +611,9 @@ static void frame(void) { state.is_mouse_down = false; if (state.is_prev_mouse_down) { create_entity(&state); + if (state.current_tool == tool_text) { + state.current_tool = tool_select; + } } state.is_prev_mouse_down = false; } @@ -556,11 +623,11 @@ static void frame(void) { bool should_clear_prev_selections = false; ImU32 current_picked_color = igGetColorU32_Vec4(state.picked_color.Value); - switch (state.selected_toolbox_button) { + switch (state.current_tool) { default: break; - case toolbox_button_select: { + case tool_select: { if (state.is_mouse_down && !vec2_is_in_area(&io->MousePos, &state.color_picker_window.position_top_left, @@ -611,6 +678,8 @@ static void frame(void) { toolbox_window(); + // ======== calculate color picker window position ======== + if (state.color_picker_window.dimension.x > 0) { ImVec2 *top_left = &state.color_picker_window.position_top_left; ImVec2 *bottom_right = &state.color_picker_window.position_bottom_right; @@ -645,6 +714,9 @@ static void frame(void) { is_selected = entity->flags & entity_flag_selected; } + igPushID_Int(entity->id); + printf("entity id %d\n", entity->id); + if (entity->flags & entity_flag_path) { ImU32 fill_color; if (is_selected && state.is_color_picker_changing) { @@ -699,6 +771,27 @@ static void frame(void) { entity->points.items[2], fill_color, 0.0, ImDrawFlags_None); + if (is_selected) { + ImDrawList_AddRect(draw_list, entity->points.items[0], + entity->points.items[2], + igGetColorU32_Vec4((ImVec4){0.537, 0.706, 1, 1}), + 0.0, ImDrawFlags_None, 2.0); + } + } else if (entity->flags & entity_flag_editable_text) { + ImVec2 cursor_pos; + igGetCursorPos(&cursor_pos); + + igSetCursorPos(entity->points.items[0]); + + igPushStyleColor_U32(ImGuiCol_FrameBg, 0); + + igInputTextMultiline("##text", entity->content, 512, entity->dimension, + ImGuiInputTextFlags_NoHorizontalScroll | + ImGuiInputTextFlags_CallbackEdit, + on_input_text_event, entity); + + igPopStyleColor(1); + if (is_selected) { ImDrawList_AddRect(draw_list, entity->points.items[0], entity->points.items[2], @@ -706,13 +799,15 @@ static void frame(void) { 0.0, ImDrawFlags_None, 2.0); } } + + igPopID(); } - switch (state.selected_toolbox_button) { + switch (state.current_tool) { default: break; - case toolbox_button_select: { + case tool_select: { if (state.is_mouse_down && state.is_prev_mouse_down && !state.is_moving_entities) { ImDrawList_AddRect(draw_list, state.drag_start, io->MousePos, 0xFFFFFFFF, @@ -721,7 +816,7 @@ static void frame(void) { break; } - case toolbox_button_rectangle: + case tool_rectangle: if (state.is_mouse_down) { ImDrawList_AddRectFilled(draw_list, state.drag_start, io->MousePos, igGetColorU32_Vec4(state.picked_color.Value), @@ -729,7 +824,7 @@ static void frame(void) { } break; - case toolbox_button_draw: { + case tool_draw: { if (state.is_mouse_down && (state.last_mouse_pos.x != io->MousePos.x || state.last_mouse_pos.y != io->MousePos.y)) { *point_list_push(&state.points) = io->MousePos; @@ -742,6 +837,12 @@ static void frame(void) { break; } + + case tool_text: + if (state.is_mouse_down && state.is_prev_mouse_down) { + ImDrawList_AddRect(draw_list, state.drag_start, io->MousePos, 0xFFFFFFFF, + 0.0f, ImDrawFlags_None, 1); + } } state.last_mouse_pos = io->MousePos; @@ -769,16 +870,15 @@ static void toolbox_window(void) { igBegin("t", 0, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); if (selectable_button(ICON_FA_MOUSE_POINTER, button_size, - state.selected_toolbox_button == - toolbox_button_select)) { - state.selected_toolbox_button = toolbox_button_select; + state.current_tool == tool_select)) { + state.current_tool = tool_select; }; igSameLine(0, 4); if (selectable_button(ICON_FA_PENCIL, button_size, - state.selected_toolbox_button == toolbox_button_draw)) { - state.selected_toolbox_button = toolbox_button_draw; + state.current_tool == tool_draw)) { + state.current_tool = tool_draw; }; igSameLine(0, 4); @@ -786,11 +886,21 @@ static void toolbox_window(void) { igPushStyleVar_Vec2(ImGuiStyleVar_ButtonTextAlign, (ImVec2){0.8, 1}); if (selectable_button(ICON_FA_SQUARE_O, button_size, - state.selected_toolbox_button == - toolbox_button_rectangle)) { - state.selected_toolbox_button = toolbox_button_rectangle; + state.current_tool == tool_rectangle)) { + state.current_tool = tool_rectangle; }; + igPopStyleVar(1); + + igSameLine(0, 4); + + igPushStyleVar_Vec2(ImGuiStyleVar_ButtonTextAlign, (ImVec2){1, 0.8}); + + if (selectable_button(ICON_FA_FONT, button_size, + state.current_tool == tool_text)) { + state.current_tool = tool_text; + } + igPopStyleVar(3); igPopFont(); @@ -811,6 +921,10 @@ static void color_picker_window(void) { igEnd(); } +static int on_input_text_event(ImGuiInputTextCallbackData *data) { + printf("input text event\n"); +} + static void cleanup(void) { simgui_shutdown(); sg_shutdown(); @@ -819,6 +933,8 @@ static void cleanup(void) { static void event(const sapp_event *event) { simgui_handle_event(event); } sapp_desc sokol_main(int argc, char *argv[]) { + srand(time(NULL)); + return (sapp_desc){ .init_cb = init, .frame_cb = frame,