diff --git a/Makefile b/Makefile index a88b2d8..d9868a2 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ all: editor editor: src/*.odin grep odin_highlighter - odin build src/ -out:bin/editor.o -build-mode:obj -debug - dsymutil bin/editor.o -o bin/editor.dw + odin build src/ -out:bin/editor.o -build-mode:obj -debug -lld + dsymutil bin/editor.o -o bin/editor.dSYM odin build src/ -out:bin/editor -lld odin_highlighter: diff --git a/liblua54.a b/liblua54.a deleted file mode 100755 index b9f953e..0000000 Binary files a/liblua54.a and /dev/null differ diff --git a/plugins/grep/src/lib.rs b/plugins/grep/src/lib.rs index 6d0c3da..fd03b6f 100644 --- a/plugins/grep/src/lib.rs +++ b/plugins/grep/src/lib.rs @@ -271,7 +271,6 @@ pub extern "C" fn OnExit(_plugin: Plugin) { extern "C" fn draw_window(plugin: Plugin, window: *const std::ffi::c_void) { let window = Box::leak(unsafe { Box::::from_raw(window as *mut GrepWindow) }); - let screen_width = (plugin.get_screen_width)() as i32; let screen_height = (plugin.get_screen_height)() as i32; let font_height = (plugin.get_font_height)() as i32; diff --git a/plugins/lua/view.lua b/plugins/lua/view.lua index 439e54b..587b5fa 100644 --- a/plugins/lua/view.lua +++ b/plugins/lua/view.lua @@ -8,6 +8,12 @@ local SideBarSmoothedWidth = 128 local SideBarWidth = 128 local SideBarClosed = false +local ActiveCodeView = nil +local CodeViews = {} + +local MovingTab = nil +local MovingTabDest = nil + function buffer_list_iter() local idx = 0 return function () @@ -36,10 +42,28 @@ function lerp(from, to, rate) return (1 - rate) * from + rate*to end -function ui_sidebar(ctx) - SideBarSmoothedWidth = slerp(SideBarSmoothedWidth, SideBarWidth, 0.3) +function add_buffer_to_code_view(code_view_index, file_path, buffer_index) + if code_view_index == nil then + code_view_index = 1 + ActiveCodeView = 1 + end - tabs = UI.push_rect(ctx, "sidebar", false, false, UI.Vertical, UI.Exact(SideBarSmoothedWidth), UI.Fill) + if CodeViews[code_view_index] == nil then + CodeViews[code_view_index] = {} + CodeViews[code_view_index].tabs = {} + end + + ActiveCodeView = code_view_index + + CodeViews[code_view_index].tabs[file_path] = {} + CodeViews[code_view_index].tabs[file_path].buffer_index = buffer_index + CodeViews[code_view_index].current_tab = file_path +end + +function ui_sidebar(ctx) + SideBarSmoothedWidth = lerp(SideBarSmoothedWidth, SideBarWidth, 0.3) + + tabs = UI.push_rect(ctx, "for some reason it chooses this as the parent", false, false, UI.Vertical, UI.Exact(SideBarSmoothedWidth), 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)) @@ -58,11 +82,13 @@ function ui_sidebar(ctx) if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then print("hahah, you can't close buffers yet silly") + add_buffer_to_code_view(ActiveCodeView+1, buffer_info.file_path, i) 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) + add_buffer_to_code_view(ActiveCodeView, buffer_info.file_path, i) end if tab_button_interaction.hovering then CurrentPreviewBufferIndex = i @@ -74,12 +100,75 @@ function ui_sidebar(ctx) UI.pop_parent(ctx) end -function ui_tabs(ctx) - UI.buffer(ctx, CurrentPreviewBufferIndex) +function ui_code_view(ctx, code_view_index) + local code_view = CodeViews[code_view_index] + local is_tab_dest = MovingTab ~= nil and ActiveCodeView ~= code_view_index + + UI.push_parent(ctx, UI.push_rect(ctx, code_view_index.." code view", ActiveCodeView ~= code_view_index, true, UI.Vertical, UI.Fill, UI.Fill)) + if is_tab_dest then + tab_dest_region = UI.push_box(ctx, "code view tab dest", {"Hoverable"}, UI.Vertical, UI.Fill, UI.Fill) + tab_dest_interaction = UI.box_interaction(ctx, tab_dest_region) + UI.push_parent(ctx, tab_dest_region) + + -- if tab_dest_interaction + end + + UI.push_parent(ctx, UI.push_rect(ctx, "tabs", false, true, UI.Horizontal, UI.Fill, UI.ChildrenSum)) + for k,v in pairs(code_view.tabs) do + show_border = v["buffer_index"] ~= code_view.current_buffer_index + background = not show_border + flags = {"Clickable", "Hoverable", "DrawText"} + + UI.push_parent(ctx, UI.push_rect(ctx, k.." tab container", background, show_border, UI.Horizontal, UI.ChildrenSum, UI.ChildrenSum)) + tab_button = UI.advanced_button(ctx, " "..k.." ", flags, UI.FitText, UI.Exact(32)) + if tab_button.clicked then + ActiveCodeView = code_view_index + code_view.current_tab = k + end + + local bb = "false" + if is_tab_dest then bb = "true" end + -- print("our code view "..code_view_index.." - "..k.." - is tab dest "..bb) + + if tab_button.dragging then + if MovingTab == nil then + MovingTab = {} + MovingTab["code_view_index"] = code_view_index + MovingTab["tab"] = k + end + + UI.push_parent(ctx, UI.push_floating(ctx, "dragging tab", x-(96/2), y-(32/2))) + UI.advanced_button(ctx, " "..k.." ", flags, UI.FitText, UI.Exact(32)) + UI.pop_parent(ctx) + elseif MovingTab ~= nil and MovingTab["code_view_index"] == code_view_index and MovingTab["tab"] == k then + -- Editor.quit() + --print("attempting to move tab "..MovingTab["code_view_index"].." - "..MovingTab["tab"]) + if MovingTabDest ~= nil then + print("attempting to place tab at code view "..MovingTabDest.code_view_index) + + MovingTabDest = nil + end + + MovingTab = nil + end + UI.pop_parent(ctx) + end + UI.pop_parent(ctx) + + current_tab = code_view.current_tab + buffer_index = code_view.tabs[current_tab].buffer_index + + UI.buffer(ctx, buffer_index) + + if is_tab_dest then + UI.pop_parent(ctx) + end + UI.pop_parent(ctx) end function render_ui_window(ctx) current_buffer_index = Editor.get_current_buffer_index() + x,y = UI.get_mouse_pos(ctx) numFrames = 7 CurrentPreviewBufferIndex = current_buffer_index @@ -88,7 +177,6 @@ function render_ui_window(ctx) ui_sidebar(ctx) end 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 if SideBarWidth < 32 then @@ -104,7 +192,10 @@ function render_ui_window(ctx) end end - ui_tabs(ctx) + for k in ipairs(CodeViews) do + ui_code_view(ctx, k) + end + render_buffer_search(ctx) end diff --git a/src/main.odin b/src/main.odin index a3dc286..923eee1 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1030,6 +1030,16 @@ main :: proc() { bbb: [^]lua.L_Reg; editor_lib := [?]lua.L_Reg { + lua.L_Reg { + "quit", + proc "c" (L: ^lua.State) -> i32 { + context = state.ctx; + + + state.should_close = true; + return i32(lua.OK); + } + }, lua.L_Reg { "print", proc "c" (L: ^lua.State) -> i32 { @@ -1337,6 +1347,50 @@ main :: proc() { return i32(lua.ERRRUN); } }, + lua.L_Reg { + "push_box", + 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); + flags, err := lua_ui_flags(L, 3); + axis := ui.Axis(lua.L_checkinteger(L, 4)); + + semantic_width := get_lua_semantic_size(L, 5); + semantic_height := get_lua_semantic_size(L, 6); + + box := ui.push_box(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, axis, { semantic_width, semantic_height }); + lua.pushlightuserdata(L, box); + return 1; + } + + return i32(lua.ERRRUN); + } + }, + lua.L_Reg { + "box_interaction", + 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.L_checktype(L, 2, i32(lua.TLIGHTUSERDATA)); + lua.pushvalue(L, 2); + box := transmute(^ui.Box)lua.touserdata(L, -1); + if box == nil { return i32(lua.ERRRUN); } + + interaction := ui.test_box(ui_ctx, box); + push_lua_box_interaction(L, interaction) + return 1; + } + }, lua.L_Reg { "push_rect", proc "c" (L: ^lua.State) -> i32 { @@ -1888,8 +1942,6 @@ main :: proc() { } } - // ui.debug_print(); - draw(&StateWithUi { &state, &ui_context }); ui.prune(&ui_context); diff --git a/src/ui/imm.odin b/src/ui/imm.odin index 3d8e790..bd0d815 100644 --- a/src/ui/imm.odin +++ b/src/ui/imm.odin @@ -11,7 +11,7 @@ import "../theme" Context :: struct { root: ^Box, current_parent: ^Box, - persistent: map[Key]^Box, + persistent: map[string]^Box, current_interaction_index: int, clips: [dynamic]Rect, @@ -103,24 +103,26 @@ Box :: struct { init :: proc(renderer: ^sdl2.Renderer) -> Context { root := new(Box); root.key = gen_key(nil, "root", 69); + root.label = strings.clone("root") return Context { root = root, current_parent = root, - persistent = make(map[Key]^Box), + persistent = make(map[string]^Box), clips = make([dynamic]Rect), renderer = renderer, }; } gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key { - key_label := "" + key_label: string; + if ctx != nil && (ctx.current_parent == nil || len(ctx.current_parent.key.label) < 1) { - key_label = label; + key_label = strings.clone(label); } else if ctx != nil { - key_label = fmt.tprintf("%s:%s", ctx.current_parent.key.label, label); + key_label = fmt.aprintf("%s:%s", ctx.current_parent.key.label, label); } else { - key_label = fmt.tprintf("%s",label); + key_label = strings.clone(label); } return Key { @@ -133,23 +135,30 @@ gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key { make_box :: proc(ctx: ^Context, key: Key, label: string, flags: bit_set[Flag], axis: Axis, semantic_size: [2]SemanticSize) -> ^Box { box: ^Box = nil; - if cached_box, exists := ctx.persistent[key]; exists { - if cached_box.last_interacted_index < ctx.current_interaction_index { - old_cached_box := ctx.persistent[key]; - free(old_cached_box); - box = new(Box); + if cached_box, exists := ctx.persistent[key.label]; exists { + // NOTE(pcleavelin): its important to note that the _cached_ key _is not_ free'd + // as that would invalid the maps reference to the key causing memory leaks because + // the map would think that an entry doesn't exist (in some cases) + delete(key.label) - ctx.persistent[key] = box; + if cached_box.last_interacted_index < ctx.current_interaction_index-1 { + box = cached_box; + + box.last_interacted_index = ctx.current_interaction_index; + box.hot = 0; + box.active = 0; } else { box = cached_box; } } else { box = new(Box); - ctx.persistent[key] = box; + ctx.persistent[key.label] = box; + + box.key = key; + box.last_interacted_index = ctx.current_interaction_index; } - box.key = key; - box.label = label; + box.label = strings.clone(label, context.temp_allocator); box.first = nil; box.last = nil; @@ -206,8 +215,8 @@ Fill :[2]SemanticSize: { } }; -push_box :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText, value: int = 0) -> ^Box { - key := gen_key(ctx, label, value); +push_box :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText) -> ^Box { + key := gen_key(ctx, label, 0); box := make_box(ctx, key, label, flags, axis, semantic_size); return box; @@ -246,6 +255,9 @@ test_box :: proc(ctx: ^Context, box: ^Box) -> Interaction { box.active = 0; } + if box.hot > 0 || box.active > 0 { + box.last_interacted_index = ctx.current_interaction_index; + } return Interaction { hovering = hovering || box.active > 0, clicked = hovering && mouse_is_clicked, @@ -264,7 +276,11 @@ delete_box_children :: proc(ctx: ^Context, box: ^Box, keep_persistent: bool = tr delete_box :: proc(ctx: ^Context, box: ^Box, keep_persistent: bool = true) { delete_box_children(ctx, box, keep_persistent); - if !(box.key in ctx.persistent) || !keep_persistent { + if box.last_interacted_index < ctx.current_interaction_index-1 { + delete_key(&ctx.persistent, box.key.label) + } + + if !(box.key.label in ctx.persistent) || !keep_persistent { delete(box.key.label); free(box); } @@ -276,21 +292,19 @@ prune :: proc(ctx: ^Context) { for box in iterate_box(&iter) { delete_box_children(ctx, box); - if !(box.key in ctx.persistent) { + if !(box.key.label in ctx.persistent) && box != ctx.root { free(box); } } - computed_pos := ctx.root.computed_pos; - computed_size := ctx.root.computed_size; - root_key := ctx.root.key; - ctx.root.first = nil; ctx.root.last = nil; ctx.root.next = nil; ctx.root.prev = nil; ctx.root.parent = nil; ctx.current_parent = ctx.root; + + ctx.current_interaction_index += 1; } // TODO: consider not using `ctx` here @@ -335,7 +349,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); @@ -432,6 +446,8 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font iter := BoxIter { box.first, 0 }; for child in iterate_box(&iter) { + if .Floating in child.flags { continue; } + switch box.axis { case .Horizontal: { box.computed_size[Axis.Horizontal] += child.computed_size[Axis.Horizontal]; @@ -449,6 +465,8 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font iter := BoxIter { box.first, 0 }; for child in iterate_box(&iter) { + if .Floating in child.flags { continue; } + switch box.axis { case .Horizontal: { if child.computed_size[Axis.Vertical] > box.computed_size[Axis.Vertical] { @@ -463,10 +481,10 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font } } -push_clip :: proc(ctx: ^Context, pos: [2]int, size: [2]int) { +push_clip :: proc(ctx: ^Context, pos: [2]int, size: [2]int, inside_parent: bool = true) { rect := Rect { pos, size }; - if len(ctx.clips) > 0 { + if len(ctx.clips) > 0 && inside_parent { parent_rect := ctx.clips[len(ctx.clips)-1]; if rect.pos.x >= parent_rect.pos.x && @@ -515,7 +533,7 @@ pop_clip :: proc(ctx: ^Context) { draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: int, box: ^Box) { if box == nil { return; } - push_clip(ctx, box.computed_pos, box.computed_size); + push_clip(ctx, box.computed_pos, box.computed_size, !(.Floating in box.flags)); { defer pop_clip(ctx); @@ -597,7 +615,7 @@ debug_print :: proc(ctx: ^Context, box: ^Box, depth: int = 0) { if depth > 0 { fmt.print(">"); } - fmt.println(idx, "Box", box.label, "#", box.key.label, "first", transmute(rawptr)box.first, "parent", transmute(rawptr)box.parent, box.computed_size); + fmt.println(idx, "Box _", box.label, "#", box.key.label, "ptr", transmute(rawptr)box); //, "_ first", transmute(rawptr)box.first, "parent", transmute(rawptr)box.parent, box.computed_size); debug_print(ctx, box, depth+1); }