fix memory leaks and non-cached box interactions
parent
c955a2621b
commit
187f48aa87
4
Makefile
4
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:
|
||||
|
|
BIN
liblua54.a
BIN
liblua54.a
Binary file not shown.
|
@ -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::<GrepWindow>::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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.label = label;
|
||||
box.last_interacted_index = ctx.current_interaction_index;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue