From f602c3a49302237e512ddd46a16e957d0973c916 Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Fri, 9 Feb 2024 16:33:38 -0600 Subject: [PATCH] port UI layout to lua + fun animations + fix memory leaks + add dragging support --- Makefile | 4 +- plugins/buffer_search/plugin.odin | 234 ----------------- plugins/lua/lib.lua | 65 ----- plugins/lua/view.lua | 160 ++++++++++++ src/core/core.odin | 9 +- src/core/file_buffer.odin | 5 - src/main.odin | 414 ++++++++++++++---------------- src/theme/theme.odin | 2 +- src/ui/imm.odin | 198 +++++--------- src/ui/ui.odin | 145 ----------- 10 files changed, 435 insertions(+), 801 deletions(-) delete mode 100644 plugins/buffer_search/plugin.odin delete mode 100644 plugins/lua/lib.lua create mode 100644 plugins/lua/view.lua diff --git a/Makefile b/Makefile index ab9378d..e8079ff 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,8 @@ all: editor -editor: src/*.odin grep odin_highlighter buffer_search +editor: src/*.odin grep odin_highlighter odin build src/ -out:bin/editor -lld -buffer_search: - odin build plugins/buffer_search/ -build-mode:dll -no-entry-point -out:bin/buffer_search odin_highlighter: odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter diff --git a/plugins/buffer_search/plugin.odin b/plugins/buffer_search/plugin.odin deleted file mode 100644 index 382a13f..0000000 --- a/plugins/buffer_search/plugin.odin +++ /dev/null @@ -1,234 +0,0 @@ -// A simple window to view/search open buffers -package buffer_search; - -import "core:runtime" -import "core:fmt" -import "core:path/filepath" - -import p "../../src/plugin" -import "../../src/theme" - -Plugin :: p.Plugin; -Iterator :: p.Iterator; -BufferIter :: p.BufferIter; -BufferIndex :: p.BufferIndex; -Key :: p.Key; - -BufferListWindow :: struct { - selected_index: int, -} - -@export -OnInitialize :: proc "c" (plugin: Plugin) { - context = runtime.default_context(); - fmt.println("builtin buffer search plugin initialized!"); - - plugin.register_input_group(nil, .SPACE, proc "c" (plugin: Plugin, input_map: rawptr) { - plugin.register_input(input_map, .B, open_buffer_window, "show list of open buffers"); - }); -} - -@export -OnExit :: proc "c" (plugin: Plugin) { - context = runtime.default_context(); -} - -open_buffer_window :: proc "c" (plugin: Plugin) { - context = runtime.default_context(); - - window := new(BufferListWindow); - window^ = BufferListWindow {}; - - plugin.create_window(window, proc "c" (plugin: Plugin, input_map: rawptr) { - plugin.register_input(input_map, .K, proc "c" (plugin: Plugin) { - context = runtime.default_context(); - - win := cast(^BufferListWindow)plugin.get_window(); - if win != nil { - if win.selected_index > 0 { - win.selected_index -= 1; - } else { - win.selected_index = plugin.buffer.get_num_buffers()-1; - } - } - }, "move selection up"); - plugin.register_input(input_map, .J, proc "c" (plugin: Plugin) { - context = runtime.default_context(); - - win := cast(^BufferListWindow)plugin.get_window(); - if win != nil { - if win.selected_index < plugin.buffer.get_num_buffers()-1 { - win.selected_index += 1; - } else { - win.selected_index = 0; - } - } - }, "move selection down"); - plugin.register_input(input_map, .ENTER, proc "c" (plugin: Plugin) { - context = runtime.default_context(); - - win := cast(^BufferListWindow)plugin.get_window(); - if win != nil { - plugin.buffer.set_current_buffer(win.selected_index); - } - - plugin.request_window_close(); - }, "switch to buffer") - }, draw_buffer_window, free_buffer_window, nil); -} - -free_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) { - context = runtime.default_context(); - win := cast(^BufferListWindow)plugin.get_window(); - if win == nil { - return; - } - - free(win); -} - -buffer_list_iter :: proc(plugin: Plugin, buffer_index: ^int) -> (int, int, bool) { - if buffer_index^ == -1 { - return 0, 0, false; - } - - index := plugin.iter.get_buffer_list_iter(buffer_index); - return index, 0, true; -} - -draw_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) { - context = runtime.default_context(); - runtime.free_all(context.temp_allocator); - - win := cast(^BufferListWindow)win; - if win == nil { - return; - } - - screen_width := plugin.get_screen_width(); - screen_height := plugin.get_screen_height(); - directory := string(plugin.get_current_directory()); - - canvas := plugin.ui.floating(plugin.ui.ui_context, "buffer search canvas", {0,0}); - - plugin.ui.push_parent(plugin.ui.ui_context, canvas); - { - defer plugin.ui.pop_parent(plugin.ui.ui_context); - - plugin.ui.spacer(plugin.ui.ui_context, "left spacer"); - centered_container := plugin.ui.rect(plugin.ui.ui_context, "centered container", false, false, .Vertical, {{4, 75}, {3, 0}}); - plugin.ui.push_parent(plugin.ui.ui_context, centered_container); - { - defer plugin.ui.pop_parent(plugin.ui.ui_context); - - plugin.ui.spacer(plugin.ui.ui_context, "top spacer"); - ui_window := plugin.ui.rect(plugin.ui.ui_context, "buffer search window", true, true, .Horizontal, {{3, 0}, {4, 75}}); - plugin.ui.push_parent(plugin.ui.ui_context, ui_window); - { - defer plugin.ui.pop_parent(plugin.ui.ui_context); - - buffer_list_view := plugin.ui.rect(plugin.ui.ui_context, "buffer list view", false, false, .Vertical, {{4, 60}, {3, 0}}); - plugin.ui.push_parent(plugin.ui.ui_context, buffer_list_view); - { - defer plugin.ui.pop_parent(plugin.ui.ui_context); - - _buffer_index := 0; - for index in buffer_list_iter(plugin, &_buffer_index) { - buffer := plugin.buffer.get_buffer_info_from_index(index); - relative_file_path, _ := filepath.rel(directory, string(buffer.file_path), context.temp_allocator) - text := fmt.ctprintf("%s:%d", relative_file_path, buffer.cursor.line+1); - - if index == win.selected_index { - plugin.ui.button(plugin.ui.ui_context, text); - } else { - plugin.ui.label(plugin.ui.ui_context, text); - } - } - } - - buffer_preview := plugin.ui.rect(plugin.ui.ui_context, "buffer preview", true, false, .Horizontal, {{3, 0}, {3, 0}}); - plugin.ui.push_parent(plugin.ui.ui_context, buffer_preview); - { - defer plugin.ui.pop_parent(plugin.ui.ui_context); - - plugin.ui.buffer_from_index(plugin.ui.ui_context, win.selected_index, false); - } - } - plugin.ui.spacer(plugin.ui.ui_context, "bottom spacer"); - } - plugin.ui.spacer(plugin.ui.ui_context, "right spacer"); - } - - /* - screen_width := plugin.get_screen_width(); - screen_height := plugin.get_screen_height(); - source_font_width := plugin.get_font_width(); - source_font_height := plugin.get_font_height(); - - win_rec := [4]f32 { - f32(screen_width/8), - f32(screen_height/8), - f32(screen_width - screen_width/4), - f32(screen_height - screen_height/4), - }; - plugin.draw_rect( - i32(win_rec.x), - i32(win_rec.y), - i32(win_rec.z), - i32(win_rec.w), - .Background4 - ); - - win_margin := [2]f32 { f32(source_font_width), f32(source_font_height) }; - - buffer_prev_width := (win_rec.z - win_margin.x*2) / 2; - buffer_prev_height := win_rec.w - win_margin.y*2; - - glyph_buffer_width := int(buffer_prev_width) / source_font_width - 1; - glyph_buffer_height := int(buffer_prev_height) / source_font_height; - - directory := string(plugin.get_current_directory()); - - plugin.draw_rect( - i32(win_rec.x + win_rec.z / 2), - i32(win_rec.y + win_margin.y), - i32(buffer_prev_width), - i32(buffer_prev_height), - .Background2, - ); - - _buffer_index := 0; - for index in buffer_list_iter(plugin, &_buffer_index) { - buffer := plugin.buffer.get_buffer_info_from_index(index); - relative_file_path, _ := filepath.rel(directory, string(buffer.file_path), context.temp_allocator) - text := fmt.ctprintf("%s:%d", relative_file_path, buffer.cursor.line+1); - text_width := len(text) * source_font_width; - - if index == win.selected_index { - plugin.draw_buffer_from_index( - index, - int(win_rec.x + win_margin.x + win_rec.z / 2), - int(win_rec.y + win_margin.y), - glyph_buffer_width, - glyph_buffer_height, - false); - - plugin.draw_rect( - i32(win_rec.x + win_margin.x), - i32(win_rec.y + win_margin.y) + i32(index * source_font_height), - i32(text_width), - i32(source_font_height), - .Background2, - ); - } - - plugin.draw_text( - text, - win_rec.x + win_margin.x, win_rec.y + win_margin.y + f32(index * source_font_height), - .Foreground2 - ); - - runtime.free_all(context.temp_allocator); - } - */ -} diff --git a/plugins/lua/lib.lua b/plugins/lua/lib.lua deleted file mode 100644 index 0f2f54a..0000000 --- a/plugins/lua/lib.lua +++ /dev/null @@ -1,65 +0,0 @@ -local WindowOpen = true - -function buffer_list_iter() - local idx = 0 - return function () - buffer_info = Editor.buffer_info_from_index(idx) - idx = idx + 1 - - return buffer_info, idx-1 - end -end - -function render_ui_window(ctx) - if WindowOpen then - current_buffer_index = Editor.get_current_buffer_index() - - tabs = UI.push_rect(ctx, "tabs", false, true, UI.Vertical, UI.ChildrenSum, UI.Fill) - UI.push_parent(ctx, tabs) - for buffer_info, i in buffer_list_iter() do - button_container = UI.push_rect(ctx, "button container"..i, false, false, UI.Horizontal, UI.ChildrenSum, UI.ChildrenSum) - UI.push_parent(ctx, button_container) - flags = {"Clickable", "Hoverable", "DrawText", "DrawBackground"} - if i ~= current_buffer_index then - table.insert(flags, 1, "DrawBorder") - end - - if UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.PercentOfParent(25), UI.FitText).clicked then - Editor.set_current_buffer_from_index(i) - end - if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then - print("hahah, you can't close buffers yet silly") - end - UI.pop_parent(ctx) - end - UI.pop_parent(ctx) - - -- if Tabs[CurrentTab] ~= nil then - UI.buffer(ctx, current_buffer_index) - -- else - -- UI.push_parent(ctx, UI.push_centered(ctx, "centered no files open", false, false, UI.Vertical, UI.Fill, UI.Fill)) - -- if UI.button(ctx, "Open File").clicked then - -- Tabs[CurrentTab] = {0, "main.odin"} - -- end - -- UI.pop_parent(ctx) - -- end - end -end - -function handle_buffer_input() - print("you inputted into a buffer") -end - -function OnInit() - print("Test lua plugin initialized") - Editor.register_key_group({ - {Editor.Key.T, "Open Test UI", ( - function () - WindowOpen = not WindowOpen - end - )}, - }) - - Editor.register_hook(Editor.Hook.OnDraw, render_ui_window) - Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input) -end diff --git a/plugins/lua/view.lua b/plugins/lua/view.lua new file mode 100644 index 0000000..5b50fc3 --- /dev/null +++ b/plugins/lua/view.lua @@ -0,0 +1,160 @@ +local BufferSearchOpen = false +local BufferSearchOpenElapsed = 0 + +local CurrentPreviewBufferIndex = Editor.get_current_buffer_index() +local BufferSearchIndex = 0 + +local SideBarWidth = 128 + +function buffer_list_iter() + local idx = 0 + return function () + buffer_info = Editor.buffer_info_from_index(idx) + idx = idx + 1 + + return buffer_info, idx-1 + end +end + +function centered(ctx, label, axis, width, height, body) + UI.push_parent(ctx, UI.push_rect(ctx, label, false, false, UI.Horizontal, UI.Fill, UI.Fill)) + UI.spacer(ctx, "left spacer") + UI.push_parent(ctx, UI.push_rect(ctx, "halfway centered", false, false, UI.Vertical, width, UI.Fill)) + UI.spacer(ctx, "top spacer") + UI.push_parent(ctx, UI.push_rect(ctx, "centered container", false, false, axis, UI.Fill, height)) + body() + UI.pop_parent(ctx) + UI.spacer(ctx, "bottom spacer") + UI.pop_parent(ctx) + UI.spacer(ctx, "right spacer") + UI.pop_parent(ctx) +end + +function render_ui_window(ctx) + current_buffer_index = Editor.get_current_buffer_index() + + numFrames = 7 + CurrentPreviewBufferIndex = current_buffer_index + + tabs = UI.push_rect(ctx, "tabs", false, false, UI.Vertical, UI.Exact(SideBarWidth), UI.Fill) + UI.push_parent(ctx, tabs) + UI.push_rect(ctx, "padded top open files", false, false, UI.Horizontal, UI.Fill, UI.Exact(8)) + UI.push_parent(ctx, UI.push_rect(ctx, "padded open files", false, false, UI.Horizontal, UI.Fill, UI.ChildrenSum)) + UI.push_rect(ctx, "padded top open files", false, false, UI.Horizontal, UI.Exact(8), UI.Fill) + UI.label(ctx, "Open Files") + UI.pop_parent(ctx) + UI.push_rect(ctx, "padded bottom open files", false, false, UI.Horizontal, UI.Fill, UI.Exact(8)) + + for buffer_info, i in buffer_list_iter() do + button_container = UI.push_rect(ctx, "button container"..i, false, false, UI.Horizontal, UI.Fill, UI.ChildrenSum) + UI.push_parent(ctx, button_container) + flags = {"Clickable", "Hoverable", "DrawText"} + if i == current_buffer_index then + table.insert(flags, 1, "DrawBackground") + end + + if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then + print("hahah, you can't close buffers yet silly") + end + + tab_button_interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText) + if tab_button_interaction.clicked then + Editor.set_current_buffer_from_index(i) + end + if tab_button_interaction.hovering then + CurrentPreviewBufferIndex = i + end + UI.pop_parent(ctx) + end + UI.spacer(ctx, "below tabs spacer") + + UI.pop_parent(ctx) + if UI.advanced_button(ctx, "side bar grab handle", {"DrawBorder", "Hoverable"}, UI.Exact(16), UI.Fill).dragging then + x,y = UI.get_mouse_pos(ctx) + SideBarWidth = x-8 + + -- TODO: use some math.max function + if SideBarWidth < 128 then + SideBarWidth = 128 + end + end + UI.buffer(ctx, CurrentPreviewBufferIndex) + + render_buffer_search(ctx) +end + +function render_buffer_search(ctx) + if BufferSearchOpen or BufferSearchOpenElapsed > 0 then + if BufferSearchOpen and BufferSearchOpenElapsed < numFrames then + BufferSearchOpenElapsed = BufferSearchOpenElapsed + 1 + elseif not BufferSearchOpen and BufferSearchOpenElapsed > 0 then + BufferSearchOpenElapsed = BufferSearchOpenElapsed - 1 + end + end + + if BufferSearchOpen or BufferSearchOpenElapsed > 0 then + window_percent = 75 + if BufferSearchOpenElapsed > 0 then + window_percent = ((BufferSearchOpenElapsed/numFrames) * 75) + end + + UI.push_parent(ctx, UI.push_floating(ctx, "buffer search canvas", 0, 0)) + centered(ctx, "buffer search window", UI.Horizontal, UI.PercentOfParent(window_percent), UI.PercentOfParent(window_percent), ( + function () + UI.push_parent(ctx, UI.push_rect(ctx, "window", true, true, UI.Horizontal, UI.Fill, UI.Fill)) + UI.push_parent(ctx, UI.push_rect(ctx, "buffer list", false, false, UI.Vertical, UI.Fill, UI.Fill)) + for buffer_info, i in buffer_list_iter() do + flags = {"DrawText"} + + if i == BufferSearchIndex then + table.insert(flags, 1, "DrawBorder") + end + interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText) + end + UI.pop_parent(ctx) + UI.buffer(ctx, BufferSearchIndex) + UI.pop_parent(ctx) + end + )) + UI.pop_parent(ctx) + end +end + +function handle_buffer_input() + -- print("you inputted into a buffer") +end + +function OnInit() + print("Main View plugin initialized") + Editor.register_key_group({ + {Editor.Key.Space, "", { + {Editor.Key.B, "Buffer Search", ( + function () + BufferSearchOpen = true + BufferSearchIndex = 0 + end + ), + { + {Editor.Key.Escape, "Close Window", ( + function () + Editor.request_window_close() + BufferSearchOpen = false + end + )}, + {Editor.Key.Enter, "Switch to Buffer", ( + function () + Editor.set_current_buffer_from_index(BufferSearchIndex) + Editor.request_window_close() + BufferSearchOpen = false + end + )}, + -- TODO: don't scroll past buffers + {Editor.Key.K, "Move Selection Up", (function () BufferSearchIndex = BufferSearchIndex - 1 end)}, + {Editor.Key.J, "Move Selection Down", (function () BufferSearchIndex = BufferSearchIndex + 1 end)}, + }} + }} + }) + + Editor.register_hook(Editor.Hook.OnDraw, render_ui_window) + Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input) +end diff --git a/src/core/core.odin b/src/core/core.odin index e06deb1..7fb8a59 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -37,8 +37,9 @@ close_window_and_free :: proc(state: ^State) { free(state.window); state.window = nil; - state.current_input_map = &state.input_map; } + + state.current_input_map = &state.input_map; } LuaHookRef :: i32; @@ -92,7 +93,11 @@ add_lua_hook :: proc(state: ^State, hook: plugin.Hook, hook_ref: LuaHookRef) { runtime.append(&state.lua_hooks[hook], hook_ref); } -LuaEditorAction :: i32; + +LuaEditorAction :: struct { + fn_ref: i32, + maybe_input_map: InputMap, +}; PluginEditorAction :: proc "c" (plugin: plugin.Plugin); EditorAction :: proc(state: ^State); InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputMap} diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index b7ea8fb..834f656 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -771,10 +771,8 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho // draw cursor if state.mode == .Normal { draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4); - //raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), i32(state.source_font_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Background4)); } else if state.mode == .Insert { draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green); - // raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), i32(state.source_font_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Green)); num_line_break := 0; line_length := 0; @@ -795,7 +793,6 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho } draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Blue); - //raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), i32(state.source_font_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Blue)); } for j in 0.. 0 { if key >= 32 && key <= 125 && len(buffer.input_buffer) < 1024-1 { @@ -75,39 +75,10 @@ do_insert_mode :: proc(state: ^State, buffer: ^FileBuffer) { } } - key = 0; // raylib.GetCharPressed(); + key = 0; } - - // if raylib.IsKeyPressed(.ENTER) { - // append(&buffer.input_buffer, '\n'); - // } - - // if raylib.IsKeyPressed(.ESCAPE) { - // state.mode = .Normal; - - // core.insert_content(buffer, buffer.input_buffer[:]); - // runtime.clear(&buffer.input_buffer); - // return; - // } - - // if raylib.IsKeyPressed(.BACKSPACE) { - // core.delete_content(buffer, 1); - - // for hook_proc in state.hooks[plugin.Hook.BufferInput] { - // hook_proc(state.plugin_vtable, buffer); - // } - // } } -// switch_to_buffer :: proc(state: ^State, item: ^ui.MenuBarItem) { -// for buffer, index in state.buffers { -// if strings.compare(buffer.file_path, item.text) == 0 { -// state.current_buffer = index; -// break; -// } -// } -// } - register_default_leader_actions :: proc(input_map: ^core.InputMap) { core.register_key_action(input_map, .Q, proc(state: ^State) { state.current_input_map = &state.input_map; @@ -163,26 +134,19 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) { // Scale font size { core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State) { - fmt.print("You pressed -MINUS", state.source_font_height, " "); if state.source_font_height > 16 { state.source_font_height -= 2; state.source_font_width = state.source_font_height / 2; state.font_atlas = core.gen_font_atlas(state, "/System/Library/Fonts/Supplemental/Andale Mono.ttf"); - //state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0); - //raylib.SetTextureFilter(state.font.texture, .BILINEAR); } fmt.println(state.source_font_height); }, "increase font size"); core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State) { - fmt.println("You pressed -EQUAL"); - state.source_font_height += 2; state.source_font_width = state.source_font_height / 2; state.font_atlas = core.gen_font_atlas(state, "/System/Library/Fonts/Supplemental/Andale Mono.ttf"); - //state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0); - //raylib.SetTextureFilter(state.font.texture, .BILINEAR); }, "decrease font size"); } @@ -482,21 +446,11 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { context = state.ctx; core.draw_rect(&state, int(x), int(y), int(width), int(height), color); - //raylib.DrawRectangle(x, y, width, height, theme.get_palette_raylib_color(color)); }, draw_text = proc "c" (text: cstring, x: f32, y: f32, color: theme.PaletteColor) { context = state.ctx; core.draw_text(&state, string(text), int(x), int(y), color); - // for codepoint, index in text { - // raylib.DrawTextCodepoint( - // state.font, - // rune(codepoint), - // raylib.Vector2 { x + f32(index * state.source_font_width), y }, - // f32(state.source_font_height), - // theme.get_palette_raylib_color(color) - // ); - // } }, draw_buffer_from_index = proc "c" (buffer_index: int, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool) { context = state.ctx; @@ -1103,24 +1057,6 @@ main :: proc() { return i32(lua.OK); } }, - lua.L_Reg { - "register_key_action", - proc "c" (L: ^lua.State) -> i32 { - context = state.ctx; - - key := lua.L_checkinteger(L, 1); - - lua.L_checktype(L, 2, i32(lua.TFUNCTION)); - lua.pushvalue(L, 2); - fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - desc := strings.clone(string(lua.L_checkstring(L, 3))); - - core.register_key_action_group(&state.input_map, plugin.Key(key), fn_ref, desc); - - return i32(lua.OK); - } - }, lua.L_Reg { "register_key_group", proc "c" (L: ^lua.State) -> i32 { @@ -1167,7 +1103,15 @@ main :: proc() { case i32(lua.TFUNCTION): fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - core.register_key_action_group(input_map, key, fn_ref, desc); + + if lua.rawgeti(L, -1, 4) == i32(lua.TTABLE) { + maybe_input_map := core.new_input_map(); + table_to_action(L, lua.gettop(L), &maybe_input_map); + + core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, maybe_input_map }, desc); + } else { + core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, core.InputMap {} }, desc); + } case: lua.pop(L, 1); @@ -1177,32 +1121,15 @@ main :: proc() { table_to_action(L, 1, state.current_input_map); + return i32(lua.OK); + } + }, + lua.L_Reg { + "request_window_close", + proc "c" (L: ^lua.State) -> i32 { + context = state.ctx; - // key := plugin.Key(lua.L_checkinteger(L, 1)); - - // lua.L_checktype(L, 2, i32(lua.TFUNCTION)); - // lua.pushvalue(L, 2); - // fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); - - // desc := strings.clone(string(lua.L_checkstring(L, 3))); - - // fmt.println("LUA: attempting to register:", key, "ref", fn_ref); - - // if action, exists := state.current_input_map.key_actions[key]; exists { - // switch value in action.action { - // case core.LuaEditorAction: - // fmt.eprintln("Plugin attempted to register input group on existing key action (added from Lua)"); - // case core.PluginEditorAction: - // fmt.eprintln("Plugin attempted to register input group on existing key action (added from Plugin)"); - // case core.EditorAction: - // fmt.eprintln("Plugin attempted to register input group on existing key action"); - // case core.InputMap: - // input_map := &(&state.current_input_map.key_actions[key]).action.(core.InputMap); - // core.register_key_action_group(input_map, key, fn_ref, desc); - // } - // } else { - // core.register_key_action(state.current_input_map, key, core.new_input_map(), desc); - // } + core.request_window_close(&state); return i32(lua.OK); } @@ -1303,13 +1230,43 @@ main :: proc() { } } + push_lua_box_interaction :: proc(L: ^lua.State, interaction: ui.Interaction) { + lua.newtable(L); + { + lua.pushboolean(L, b32(interaction.clicked)); + lua.setfield(L, -2, "clicked"); + + lua.pushboolean(L, b32(interaction.hovering)); + lua.setfield(L, -2, "hovering"); + + lua.pushboolean(L, b32(interaction.dragging)); + lua.setfield(L, -2, "dragging"); + } + } + ui_lib := [?]lua.L_Reg { + lua.L_Reg { + "get_mouse_pos", + proc "c" (L: ^lua.State) -> i32 { + context = state.ctx; + + lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); + lua.pushvalue(L, 1); + ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); + if ui_ctx == nil { return i32(lua.ERRRUN); } + + lua.pushinteger(L, lua.Integer(ui_ctx.mouse_x)); + lua.pushinteger(L, lua.Integer(ui_ctx.mouse_y)); + + return 2; + } + }, lua.L_Reg { "Exact", proc "c" (L: ^lua.State) -> i32 { context = state.ctx; - value := lua.L_checkinteger(L, 1); + value := lua.L_checknumber(L, 1); push_lua_semantic_size_table(L, { ui.SemanticSizeKind.Exact, int(value) }); return 1; @@ -1320,7 +1277,7 @@ main :: proc() { proc "c" (L: ^lua.State) -> i32 { context = state.ctx; - value := lua.L_checkinteger(L, 1); + value := lua.L_checknumber(L, 1); push_lua_semantic_size_table(L, { ui.SemanticSizeKind.PercentOfParent, int(value) }); return 1; @@ -1372,7 +1329,7 @@ main :: proc() { x := int(lua.L_checkinteger(L, 3)); y := int(lua.L_checkinteger(L, 4)); - box := ui.push_floating(ui_ctx, strings.clone(string(label)), {x,y}); + box := ui.push_floating(ui_ctx, strings.clone(string(label), context.temp_allocator), {x,y}); lua.pushlightuserdata(L, box); return 1; } @@ -1397,7 +1354,7 @@ main :: proc() { semantic_width := get_lua_semantic_size(L, 6); semantic_height := get_lua_semantic_size(L, 7); - box := ui.push_rect(ui_ctx, strings.clone(string(label)), background, border, axis, { semantic_width, semantic_height }); + box := ui.push_rect(ui_ctx, strings.clone(string(label), context.temp_allocator), background, border, axis, { semantic_width, semantic_height }); lua.pushlightuserdata(L, box); return 1; } @@ -1423,7 +1380,7 @@ main :: proc() { semantic_width := get_lua_semantic_size(L, 6); semantic_height := get_lua_semantic_size(L, 7); - box := ui.push_centered(ui_ctx, strings.clone(string(label)), {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, { semantic_width, semantic_height }); + box := ui.push_centered(ui_ctx, strings.clone(string(label), context.temp_allocator), {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, { semantic_width, semantic_height }); lua.pushlightuserdata(L, box); return 1; } @@ -1442,13 +1399,29 @@ main :: proc() { if ui_ctx != nil { label := lua.L_checkstring(L, 2); - interaction := ui.spacer(ui_ctx, strings.clone(string(label)), semantic_size = {{.Exact, 8}, {.Fill, 0}}); + interaction := ui.spacer(ui_ctx, strings.clone(string(label), context.temp_allocator), semantic_size = {{.Fill, 0}, {.Fill, 0}}); - lua.newtable(L); - { - lua.pushboolean(L, b32(interaction.clicked)); - lua.setfield(L, -2, "clicked"); - } + push_lua_box_interaction(L, interaction) + + return 1; + } + + return i32(lua.ERRRUN); + } + }, + lua.L_Reg { + "label", + proc "c" (L: ^lua.State) -> i32 { + context = state.ctx; + + lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA)); + lua.pushvalue(L, 1); + ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1); + if ui_ctx != nil { + label := lua.L_checkstring(L, 2); + + interaction := ui.label(ui_ctx, strings.clone(string(label), context.temp_allocator)); + push_lua_box_interaction(L, interaction) return 1; } @@ -1467,13 +1440,8 @@ main :: proc() { if ui_ctx != nil { label := lua.L_checkstring(L, 2); - interaction := ui.button(ui_ctx, strings.clone(string(label))); - - lua.newtable(L); - { - lua.pushboolean(L, b32(interaction.clicked)); - lua.setfield(L, -2, "clicked"); - } + interaction := ui.button(ui_ctx, strings.clone(string(label), context.temp_allocator)); + push_lua_box_interaction(L, interaction) return 1; } @@ -1497,13 +1465,8 @@ main :: proc() { semantic_width := get_lua_semantic_size(L, 4); semantic_height := get_lua_semantic_size(L, 5); - interaction := ui.advanced_button(ui_ctx, strings.clone(string(label)), flags, { semantic_width, semantic_height }); - - lua.newtable(L); - { - lua.pushboolean(L, b32(interaction.clicked)); - lua.setfield(L, -2, "clicked"); - } + interaction := ui.advanced_button(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, { semantic_width, semantic_height }); + push_lua_box_interaction(L, interaction) return 1; } @@ -1540,6 +1503,9 @@ main :: proc() { lua.newtable(L); { lua.newtable(L); + lua.pushinteger(L, lua.Integer(plugin.Key.B)); + lua.setfield(L, -2, "B"); + lua.pushinteger(L, lua.Integer(plugin.Key.T)); lua.setfield(L, -2, "T"); @@ -1552,6 +1518,21 @@ main :: proc() { lua.pushinteger(L, lua.Integer(plugin.Key.M)); lua.setfield(L, -2, "M"); + lua.pushinteger(L, lua.Integer(plugin.Key.K)); + lua.setfield(L, -2, "K"); + + lua.pushinteger(L, lua.Integer(plugin.Key.J)); + lua.setfield(L, -2, "J"); + + lua.pushinteger(L, lua.Integer(plugin.Key.Q)); + lua.setfield(L, -2, "Q"); + + lua.pushinteger(L, lua.Integer(plugin.Key.ESCAPE)); + lua.setfield(L, -2, "Escape"); + + lua.pushinteger(L, lua.Integer(plugin.Key.ENTER)); + lua.setfield(L, -2, "Enter"); + lua.pushinteger(L, lua.Integer(plugin.Key.SPACE)); lua.setfield(L, -2, "Space"); } @@ -1586,7 +1567,7 @@ main :: proc() { lua.setglobal(L, "UI"); } - if lua.L_dofile(L, "plugins/lua/lib.lua") == i32(lua.OK) { + if lua.L_dofile(L, "plugins/lua/view.lua") == i32(lua.OK) { lua.pop(L, lua.gettop(L)); } else { err := lua.tostring(L, lua.gettop(L)); @@ -1611,115 +1592,110 @@ main :: proc() { control_key_pressed: bool; for !state.should_close { - if true { - buffer := &state.buffers[state.current_buffer]; + // if false { + // buffer := &state.buffers[state.current_buffer]; - ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill, 100), ui.make_semantic_size(.Fill, 100)})); - defer ui.pop_parent(&ui_context); + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill, 100), ui.make_semantic_size(.Fill, 100)})); + // defer ui.pop_parent(&ui_context); - { - ui.push_parent(&ui_context, ui.push_box(&ui_context, "top_nav", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)})); - defer ui.pop_parent(&ui_context); + // { + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "top_nav", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)})); + // defer ui.pop_parent(&ui_context); - if ui.label(&ui_context, "Editor").clicked { - fmt.println("you clicked the button"); - } + // if ui.label(&ui_context, "Editor").clicked { + // fmt.println("you clicked the button"); + // } - ui.push_box( - &ui_context, - "nav spacer", - {.DrawBackground}, - semantic_size = { - ui.make_semantic_size(.Exact, 16), - ui.make_semantic_size(.Exact, state.source_font_height) - } - ); + // ui.push_box( + // &ui_context, + // "nav spacer", + // {.DrawBackground}, + // semantic_size = { + // ui.make_semantic_size(.Exact, 16), + // ui.make_semantic_size(.Exact, state.source_font_height) + // } + // ); - if ui.label(&ui_context, "Buffers").clicked { - fmt.println("you clicked the button"); - } - } - { - ui.push_parent(&ui_context, ui.push_box(&ui_context, "deezbuffer", {}, .Horizontal, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Fill, 0)})); - defer ui.pop_parent(&ui_context); + // if ui.label(&ui_context, "Buffers").clicked { + // fmt.println("you clicked the button"); + // } + // } + // { + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "deezbuffer", {}, .Horizontal, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Fill, 0)})); + // defer ui.pop_parent(&ui_context); - { - ui.push_parent(&ui_context, ui.push_box(&ui_context, "left side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)})); - defer ui.pop_parent(&ui_context); + // { + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "left side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)})); + // defer ui.pop_parent(&ui_context); - { - if ui_file_buffer(&ui_context, &state.buffers[0]).clicked { - state.current_buffer = 0; - } - } - { - if ui_file_buffer(&ui_context, &state.buffers[0+1]).clicked { - state.current_buffer = 1; - } - } - { - if ui_file_buffer(&ui_context, &state.buffers[0+2]).clicked { - state.current_buffer = 2; - } - } - } - { - ui.push_parent(&ui_context, ui.push_box(&ui_context, "right side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)})); - defer ui.pop_parent(&ui_context); + // { + // if ui_file_buffer(&ui_context, &state.buffers[0]).clicked { + // state.current_buffer = 0; + // } + // } + // { + // if ui_file_buffer(&ui_context, &state.buffers[0+1]).clicked { + // state.current_buffer = 1; + // } + // } + // { + // if ui_file_buffer(&ui_context, &state.buffers[0+2]).clicked { + // state.current_buffer = 2; + // } + // } + // } + // { + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "right side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)})); + // defer ui.pop_parent(&ui_context); - { - if ui_file_buffer(&ui_context, &state.buffers[state.current_buffer]).clicked { - state.current_buffer = 3; - } - } - } - } - { - ui.push_parent(&ui_context, ui.push_box(&ui_context, "bottom stats", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)})); - defer ui.pop_parent(&ui_context); + // { + // if ui_file_buffer(&ui_context, &state.buffers[state.current_buffer]).clicked { + // state.current_buffer = 3; + // } + // } + // } + // } + // { + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "bottom stats", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)})); + // defer ui.pop_parent(&ui_context); - label := ""; - if state.mode == .Insert { - label = "INSERT"; - } else if state.mode == .Normal { - label = "NORMAL"; - } + // label := ""; + // if state.mode == .Insert { + // label = "INSERT"; + // } else if state.mode == .Normal { + // label = "NORMAL"; + // } - if ui.label(&ui_context, label).clicked { - fmt.println("you clicked the button"); - } - ui.spacer(&ui_context, "mode spacer", semantic_size = {ui.make_semantic_size(.Exact, 16), ui.make_semantic_size(.Fill)}); + // if ui.label(&ui_context, label).clicked { + // fmt.println("you clicked the button"); + // } + // ui.spacer(&ui_context, "mode spacer", semantic_size = {ui.make_semantic_size(.Exact, 16), ui.make_semantic_size(.Fill)}); - relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) - ui.label(&ui_context, relative_file_path); + // relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) + // ui.label(&ui_context, relative_file_path); - ui.spacer(&ui_context, "stats inbetween"); + // ui.spacer(&ui_context, "stats inbetween"); - { - ui.push_parent(&ui_context, ui.push_box(&ui_context, "center info", {}, semantic_size = ui.ChildrenSum)); - defer ui.pop_parent(&ui_context); + // { + // ui.push_parent(&ui_context, ui.push_box(&ui_context, "center info", {}, semantic_size = ui.ChildrenSum)); + // defer ui.pop_parent(&ui_context); - line_info_text := fmt.tprintf( - //"Line: %d, Col: %d, Len: %d --- Slice Index: %d, Content Index: %d", - "Line: %d, Col: %d", - buffer.cursor.line + 1, - buffer.cursor.col + 1, - //core.file_buffer_line_length(buffer, buffer.cursor.index), - // buffer.cursor.index.slice_index, - // buffer.cursor.index.content_index, - ); - ui.label(&ui_context, line_info_text); + // line_info_text := fmt.tprintf( + // //"Line: %d, Col: %d, Len: %d --- Slice Index: %d, Content Index: %d", + // "Line: %d, Col: %d", + // buffer.cursor.line + 1, + // buffer.cursor.col + 1, + // //core.file_buffer_line_length(buffer, buffer.cursor.index), + // // buffer.cursor.index.slice_index, + // // buffer.cursor.index.content_index, + // ); + // ui.label(&ui_context, line_info_text); - mouse_pos_str := fmt.tprintf("x,y: [%d,%d]", ui_context.mouse_x, ui_context.mouse_y); - ui.label(&ui_context, mouse_pos_str); - } - - //ui.spacer(&ui_context, "frame time spacer"); - //frame_time := (60.0/f32(raylib.GetFPS())) * 10; - //frame_time_text := raylib.TextFormat("frame time: %fms", frame_time); - //ui.label(&ui_context, "lol have to figure out how to get the frame time"); - } - } + // mouse_pos_str := fmt.tprintf("x,y: [%d,%d]", ui_context.mouse_x, ui_context.mouse_y); + // ui.label(&ui_context, mouse_pos_str); + // } + // } + // } for hook_ref in state.lua_hooks[plugin.Hook.Draw] { lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(hook_ref)); @@ -1779,8 +1755,7 @@ main :: proc() { if action, exists := state.current_input_map.ctrl_key_actions[key]; exists { switch value in action.action { case core.LuaEditorAction: - fmt.println("trying to call lua registered function:", value); - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value)); + lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value.fn_ref)); if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { err := lua.tostring(L, lua.gettop(L)); lua.pop(L, lua.gettop(L)); @@ -1789,6 +1764,10 @@ main :: proc() { } else { lua.pop(L, lua.gettop(L)); } + + if value.maybe_input_map.ctrl_key_actions != nil { + + } case core.PluginEditorAction: value(state.plugin_vtable); case core.EditorAction: @@ -1801,7 +1780,7 @@ main :: proc() { if action, exists := state.current_input_map.key_actions[key]; exists { switch value in action.action { case core.LuaEditorAction: - lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value)); + lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value.fn_ref)); if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { err := lua.tostring(L, lua.gettop(L)); lua.pop(L, lua.gettop(L)); @@ -1810,6 +1789,11 @@ main :: proc() { } else { lua.pop(L, lua.gettop(L)); } + + if value.maybe_input_map.key_actions != nil { + ptr_action := &(&state.current_input_map.key_actions[key]).action.(core.LuaEditorAction) + state.current_input_map = (&ptr_action.maybe_input_map) + } case core.PluginEditorAction: value(state.plugin_vtable); case core.EditorAction: diff --git a/src/theme/theme.odin b/src/theme/theme.odin index 2dbe393..e83ee5c 100644 --- a/src/theme/theme.odin +++ b/src/theme/theme.odin @@ -98,7 +98,7 @@ light_palette := []u32 { get_palette_color :: proc(palette_color: PaletteColor) -> [4]u8 { color: [4]u8; - c := palette[palette_color]; + c := light_palette[palette_color]; for i in 0..<4 { color[i] = u8((c >> (8*u32(3-i)))&0xff); } diff --git a/src/ui/imm.odin b/src/ui/imm.odin index 55a09be..3d8e790 100644 --- a/src/ui/imm.odin +++ b/src/ui/imm.odin @@ -40,6 +40,7 @@ Key :: struct { Interaction :: struct { hovering: bool, clicked: bool, + dragging: bool, } Flag :: enum { @@ -115,11 +116,11 @@ init :: proc(renderer: ^sdl2.Renderer) -> Context { gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key { key_label := "" if ctx != nil && (ctx.current_parent == nil || len(ctx.current_parent.key.label) < 1) { - key_label = strings.clone(label); + key_label = label; } else if ctx != nil { - key_label = fmt.aprintf("%s:%s", ctx.current_parent.key.label, label); + key_label = fmt.tprintf("%s:%s", ctx.current_parent.key.label, label); } else { - key_label = fmt.aprintf("%s",label); + key_label = fmt.tprintf("%s",label); } return Key { @@ -233,15 +234,22 @@ test_box :: proc(ctx: ^Context, box: ^Box) -> Interaction { hovering = true; } - if hovering { + if hovering || box.active > 0 { box.hot += 1; } else { box.hot = 0; } + if hovering && mouse_is_clicked { + box.active += 1; + } else if !ctx.mouse_left_down { + box.active = 0; + } + return Interaction { - hovering = hovering, + hovering = hovering || box.active > 0, clicked = hovering && mouse_is_clicked, + dragging = box.active > 0 }; } @@ -327,7 +335,7 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font } if .Floating in box.flags { - // box.computed_pos = {0,0}; + box.computed_pos = {0,0}; } else if box.prev != nil { prev := prev_non_floating_sibling(ctx, box); @@ -343,34 +351,18 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font } else { switch box.semantic_size.x.kind { case .FitText: { - // TODO: don't use hardcoded font size box.computed_size.x = len(box.label) * font_width; } case .Exact: { box.computed_size.x = box.semantic_size.x.value; } case .ChildrenSum: { - //compute_children = false; post_compute_size[int(Axis.Horizontal)] = true; - // box.computed_size.x = 0; - - // iter := BoxIter { box.first, 0 }; - // for child in iterate_box(&iter) { - // compute_layout(canvas_size, font_width, font_height, child); - - // switch box.axis { - // case .Horizontal: { - // box.computed_size.x += child.computed_size.x; - // } - // case .Vertical: { - // if child.computed_size.x > box.computed_size.x { - // box.computed_size.x = child.computed_size.x; - // } - // } - // } - // } } case .Fill: { + if .Floating in box.flags { + box.computed_size.x = ancestor_size(ctx, box, .Horizontal); + } } case .PercentOfParent: { box.computed_size.x = int(f32(ancestor_size(ctx, box, .Horizontal))*(f32(box.semantic_size.x.value)/100.0)); @@ -378,52 +370,18 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font } switch box.semantic_size.y.kind { case .FitText: { - // TODO: don't use hardcoded font size box.computed_size.y = font_height; } case .Exact: { box.computed_size.y = box.semantic_size.y.value; } case .ChildrenSum: { - //compute_children = false; post_compute_size[Axis.Vertical] = true; - - // should_post_compute := false; - // number_of_fills := 0; - // box.computed_size.y = 0; - // parent_size := ancestor_size(box, .Vertical); - - // iter := BoxIter { box.first, 0 }; - // for child in iterate_box(&iter) { - // compute_layout(canvas_size, font_width, font_height, child); - - // if child.semantic_size.y.kind == .Fill { - // number_of_fills += 1; - // should_post_compute := true; - // } - - // switch box.axis { - // case .Horizontal: { - // if child.computed_size.y > box.computed_size.y { - // box.computed_size.y = child.computed_size.y; - // } - // } - // case .Vertical: { - // box.computed_size.y += child.computed_size.y; - // } - // } - // } - - // if should_post_compute { - // iter := BoxIter { box.first, 0 }; - // for child in iterate_box(&iter) { - // if compute_layout(canvas_size, font_width, font_height, child) { - // child.computed_size.y = (parent_size - box.computed_size.y) / number_of_fills; - // } - // } - // } } case .Fill: { + if .Floating in box.flags { + box.computed_size.y = ancestor_size(ctx, box, .Vertical); + } } case .PercentOfParent: { box.computed_size.y = int(f32(ancestor_size(ctx, box, .Vertical))*(f32(box.semantic_size.y.value)/100.0)); @@ -433,7 +391,6 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font if compute_children { iter := BoxIter { box.first, 0 }; - should_post_compute := false; child_size: [2]int = {0,0}; // NOTE: the number of fills for the opposite axis of this box needs to be 1 @@ -451,31 +408,22 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font compute_layout(ctx, canvas_size, font_width, font_height, child); if child.semantic_size[box.axis].kind == .Fill { number_of_fills[box.axis] += 1; - should_post_compute = true; } else { child_size[box.axis] += child.computed_size[box.axis]; } } - if true || should_post_compute { - iter := BoxIter { box.first, 0 }; - for child in iterate_box(&iter) { + iter = BoxIter { box.first, 0 }; + for child in iterate_box(&iter) { + if !(.Floating in child.flags) { for axis in 0..<2 { if child.semantic_size[axis].kind == .Fill { - if false && child_size[axis] >= our_size[axis] { - child.computed_size[axis] = our_size[axis] / number_of_fills[axis]; - } else { - child.computed_size[axis] = (our_size[axis] - child_size[axis]) / number_of_fills[axis]; - } + child.computed_size[axis] = (our_size[axis] - child_size[axis]) / number_of_fills[axis]; } } - - compute_layout(ctx, canvas_size, font_width, font_height, child); - - if child.label == "2" { - fmt.println(child.label, child.computed_size, box.label, our_size, child_size, number_of_fills); - } } + + compute_layout(ctx, canvas_size, font_width, font_height, child); } } @@ -546,19 +494,10 @@ push_clip :: proc(ctx: ^Context, pos: [2]int, size: [2]int) { i32(rect.size.y) }); - // raylib.BeginScissorMode( - // i32(rect.pos.x), - // i32(rect.pos.y), - // i32(rect.size.x), - // i32(rect.size.y) - // ); - append(&ctx.clips, rect); } pop_clip :: proc(ctx: ^Context) { - //raylib.EndScissorMode(); - if len(ctx.clips) > 0 { rect := pop(&ctx.clips); @@ -568,12 +507,6 @@ pop_clip :: proc(ctx: ^Context) { i32(rect.size.x), i32(rect.size.y) }); - // raylib.BeginScissorMode( - // i32(rect.pos.x), - // i32(rect.pos.y), - // i32(rect.size.x), - // i32(rect.size.y) - // ); } else { sdl2.RenderSetClipRect(ctx.renderer, nil); } @@ -582,32 +515,47 @@ pop_clip :: proc(ctx: ^Context) { draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: int, box: ^Box) { if box == nil { return; } - // NOTE: for some reason if you place this right before the - // for loop, the clipping only works for the first child. Compiler bug? + push_clip(ctx, box.computed_pos, box.computed_size); + { + defer pop_clip(ctx); + + if .Hoverable in box.flags && box.hot > 0 { + core.draw_rect( + state, + box.computed_pos.x, + box.computed_pos.y, + box.computed_size.x, + box.computed_size.y, + .Background2 + ); + } else if .DrawBackground in box.flags { + core.draw_rect( + state, + box.computed_pos.x, + box.computed_pos.y, + box.computed_size.x, + box.computed_size.y, + .Background1 + ); + } + + if .DrawText in box.flags { + core.draw_text(state, box.label, box.computed_pos.x, box.computed_pos.y); + } + + if .CustomDrawFunc in box.flags && box.custom_draw_func != nil { + box.custom_draw_func(state, box, box.user_data); + } + + iter := BoxIter { box.first, 0 }; + for child in iterate_box(&iter) { + draw(ctx, state, font_width, font_height, child); + } + } + push_clip(ctx, box.computed_pos, box.computed_size); defer pop_clip(ctx); - if .Hoverable in box.flags && box.hot > 0 { - core.draw_rect( - state, - box.computed_pos.x, - box.computed_pos.y, - box.computed_size.x, - box.computed_size.y, - .Background2 - ); - } - else if .DrawBackground in box.flags { - core.draw_rect( - state, - box.computed_pos.x, - box.computed_pos.y, - box.computed_size.x, - box.computed_size.y, - .Background1 - ); - } - if .DrawBorder in box.flags { core.draw_rect_outline( state, @@ -618,18 +566,6 @@ draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: in .Background4 ); } - if .DrawText in box.flags { - core.draw_text(state, box.label, box.computed_pos.x, box.computed_pos.y); - } - - if .CustomDrawFunc in box.flags && box.custom_draw_func != nil { - box.custom_draw_func(state, box, box.user_data); - } - - iter := BoxIter { box.first, 0 }; - for child in iterate_box(&iter) { - draw(ctx, state, font_width, font_height, child); - } } BoxIter :: struct { @@ -693,19 +629,19 @@ push_rect :: proc(ctx: ^Context, label: string, background: bool = true, border: push_centered :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText) -> ^Box { box: ^Box; - push_parent(ctx, push_box(ctx, label, {}, semantic_size = Fill)) + push_parent(ctx, push_box(ctx, label, {}, semantic_size = { {.Fill,0}, semantic_size.y })) { defer pop_parent(ctx); spacer(ctx, "left spacer"); - halfway_centered := push_rect(ctx, "halfway centered", false, false, .Vertical, { semantic_size.x, {.Fill,0} }); + halfway_centered := push_rect(ctx, "halfway centered", false, false, .Vertical, { {.Fill, 0}, {.Fill,0} }); push_parent(ctx, halfway_centered); { defer pop_parent(ctx); spacer(ctx, "top spacer"); - box = push_box(ctx, label, flags, axis, { {.Fill,0}, semantic_size.y }); + box = push_box(ctx, label, flags, axis, FitText); spacer(ctx, "bottom spacer"); } spacer(ctx, "right spacer"); diff --git a/src/ui/ui.odin b/src/ui/ui.odin index b540905..d9f9ecb 100644 --- a/src/ui/ui.odin +++ b/src/ui/ui.odin @@ -4,148 +4,3 @@ import "core:math" import "../core" import "../theme" - -// MenuBarItemOnClick :: proc(state: ^core.State, item: ^MenuBarItem); -// -// text_padding :: 4; -// -// MenuBarItem :: struct { -// text: string, -// selected: bool, -// sub_items: []MenuBarItem, -// on_click: MenuBarItemOnClick, -// } -// -// MenuBarState :: struct { -// items: []MenuBarItem, -// } -// -// draw_menu_bar_item :: proc(state: ^core.State, item: ^MenuBarItem, x, y: i32, parent_width, parent_height: i32, font_height: int, horizontal: bool = false) { -// foreground_color := theme.PaletteColor.Foreground3; -// if horizontal { -// if item.selected { -// foreground_color = theme.PaletteColor.Background4; -// } else { -// foreground_color = theme.PaletteColor.Foreground4; -// } -// } -// -// item_text := raylib.TextFormat("%s", item.text); -// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x; -// -// raylib.DrawRectangle(x, y, parent_width, i32(font_height), theme.get_palette_raylib_color(foreground_color)); -// raylib.DrawTextEx(state.font, item_text, raylib.Vector2 { f32(x + text_padding), f32(y) }, f32(font_height), 0, theme.get_palette_raylib_color(.Background1)); -// -// if item.selected { -// // TODO: change to parent_width -// largest_sub_item: int -// for sub_item in item.sub_items { -// largest_sub_item = math.max(len(sub_item.text), largest_sub_item); -// } -// -// this_width := i32(largest_sub_item * state.source_font_width + text_padding*2); -// sub_list_x := x; -// if horizontal { -// sub_list_x += parent_width; -// } -// for _, index in item.sub_items { -// sub_item := &item.sub_items[index]; -// item_text := raylib.TextFormat("%s", sub_item.text); -// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x; -// -// index_offset := 1; -// if horizontal { -// index_offset = 0; -// } -// item_y := y + i32(font_height * (index+index_offset)); -// draw_menu_bar_item(state, sub_item, sub_list_x, item_y, this_width, 0, font_height, true); -// } -// } -// } -// -// draw_menu_bar :: proc(state: ^core.State, data: ^MenuBarState, x, y: i32, parent_width, parent_height: i32, font_height: int) { -// raylib.DrawRectangle(x, y, parent_width, i32(font_height), theme.get_palette_raylib_color(.Background3)); -// -// raylib.DrawTextEx(state.font, "Editor", raylib.Vector2 { f32(x), f32(y) }, f32(font_height), 0, theme.get_palette_raylib_color(.Foreground1)); -// -// x := x + i32((len("Editor") + 4) * state.source_font_width); -// -// for _, index in data.items { -// item := &data.items[index]; -// item_text := raylib.TextFormat("%s", item.text); -// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x; -// -// item_x := x + (i32(item_width) + text_padding*2) * i32(index); -// draw_menu_bar_item(state, item, item_x, y, i32(item_width + text_padding*2), i32(font_height), font_height); -// } -// } -// -// test_menu_item :: proc(state: ^core.State, item: ^MenuBarItem, rect: raylib.Rectangle, mouse_pos: raylib.Vector2, mouse_has_clicked: bool, font_height: int, horizontal: bool) -> bool { -// if raylib.CheckCollisionPointRec(mouse_pos, rect) { -// item.selected = true; -// -// if item.on_click != nil && mouse_has_clicked { -// item.on_click(state, item); -// } -// } else if item.selected { -// largest_sub_item: int -// for sub_item in item.sub_items { -// largest_sub_item = math.max(len(sub_item.text), largest_sub_item); -// } -// -// this_width := i32(largest_sub_item * state.source_font_width + text_padding*2); -// sub_list_x := rect.x; -// if horizontal { -// sub_list_x += rect.width; -// } -// -// has_sub_item_selected := false; -// for _, index in item.sub_items { -// sub_item := &item.sub_items[index]; -// item_text := raylib.TextFormat("%s", sub_item.text); -// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x; -// -// index_offset := 1; -// if horizontal { -// index_offset = 0; -// } -// item_y := rect.y + f32(font_height * (index+index_offset)); -// -// sub_rec := raylib.Rectangle { -// x = sub_list_x, -// y = item_y, -// width = f32(this_width), -// height = f32(font_height), -// }; -// -// if test_menu_item(state, sub_item, sub_rec, mouse_pos, mouse_has_clicked, font_height, true) { -// has_sub_item_selected = true; -// } -// } -// -// item.selected = has_sub_item_selected; -// } else { -// item.selected = false; -// } -// -// return item.selected; -// } -// -// test_menu_bar :: proc(state: ^core.State, menu_bar: ^MenuBarState, x, y: i32, mouse_pos: raylib.Vector2, mouse_has_clicked: bool, font_height: int) { -// x := x + i32((len("Editor") + 4) * state.source_font_width); -// -// for _, index in menu_bar.items { -// item := &menu_bar.items[index]; -// item_text := raylib.TextFormat("%s", item.text); -// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x; -// -// item_rec := raylib.Rectangle { -// x = f32(x) + (item_width + f32(text_padding*2)) * f32(index), -// y = f32(y), -// width = f32(item_width + text_padding*2), -// height = f32(font_height), -// }; -// -// test_menu_item(state, item, item_rec, mouse_pos, mouse_has_clicked, font_height, false); -// } -// }