From 8d633758387fa59b81061162b9ffb19b5393e30c Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Sat, 27 Jan 2024 13:26:29 -0600 Subject: [PATCH] fix issue with grep/buffer window not changing position on window resize --- plugin-rs-bindings/src/lib.rs | 8 ++ plugins/buffer_search/plugin.odin | 50 ++++--- plugins/grep/src/lib.rs | 224 +++++++++++++++--------------- src/core/core.odin | 2 + src/main.odin | 47 +++++-- src/plugin/plugin.odin | 3 +- src/ui/imm.odin | 12 +- 7 files changed, 195 insertions(+), 151 deletions(-) diff --git a/plugin-rs-bindings/src/lib.rs b/plugin-rs-bindings/src/lib.rs index 8b919af..c1d0ecb 100644 --- a/plugin-rs-bindings/src/lib.rs +++ b/plugin-rs-bindings/src/lib.rs @@ -222,6 +222,7 @@ type UiRectProc = extern "C" fn( ui_context: UiContext, label: *const i8, border: bool, + border: bool, axis: UiAxis, size: [InternalUiSemanticSize; 2], ) -> UiBox; @@ -235,6 +236,7 @@ pub struct UiVTable { push_parent: UiPushParentProc, pop_parent: UiPopParentProc, + spacer: UiSimpleProc, floating: UiFloatingProc, rect: UiRectProc, @@ -253,9 +255,14 @@ impl UiVTable { (self.pop_parent)(self.ui_context); } + pub fn spacer(&self, label: &CStr) -> UiInteraction { + (self.spacer)(self.ui_context, label.as_ptr()) + } + pub fn push_rect( &self, label: &CStr, + show_background: bool, show_border: bool, axis: UiAxis, horizontal_size: UiSemanticSize, @@ -265,6 +272,7 @@ impl UiVTable { let rect = (self.rect)( self.ui_context, label.as_ptr(), + show_background, show_border, axis, [horizontal_size.into(), vertical_size.into()], diff --git a/plugins/buffer_search/plugin.odin b/plugins/buffer_search/plugin.odin index b0f7f9a..382a13f 100644 --- a/plugins/buffer_search/plugin.odin +++ b/plugins/buffer_search/plugin.odin @@ -109,44 +109,54 @@ draw_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) { screen_height := plugin.get_screen_height(); directory := string(plugin.get_current_directory()); - canvas := plugin.ui.floating(plugin.ui.ui_context, "buffer search canvas", {screen_width/8, screen_height/8}); + 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); - ui_window := plugin.ui.rect(plugin.ui.ui_context, "buffer search window", true, .Horizontal, {{4, 75}, {4, 75}}); - plugin.ui.push_parent(plugin.ui.ui_context, ui_window); + 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); - buffer_list_view := plugin.ui.rect(plugin.ui.ui_context, "buffer list view", false, .Vertical, {{4, 60}, {3, 0}}); - plugin.ui.push_parent(plugin.ui.ui_context, buffer_list_view); + 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_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); + 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); - if index == win.selected_index { - plugin.ui.button(plugin.ui.ui_context, text); - } else { - plugin.ui.label(plugin.ui.ui_context, text); + _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", 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); + 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.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"); } /* diff --git a/plugins/grep/src/lib.rs b/plugins/grep/src/lib.rs index d51859d..6d0c3da 100644 --- a/plugins/grep/src/lib.rs +++ b/plugins/grep/src/lib.rs @@ -281,134 +281,130 @@ extern "C" fn draw_window(plugin: Plugin, window: *const std::ffi::c_void) { let dir = plugin.get_current_directory(); let directory = Path::new(dir.as_ref()); - plugin.ui_table.push_floating( - c"grep canvas", - (screen_width as isize) / 8, - (screen_height as isize) / 8, - |ui_table| { + plugin + .ui_table + .push_floating(c"grep canvas", 0, 0, |ui_table| { + // TODO: make some primitive that centers a Box + ui_table.spacer(c"left spacer"); + ui_table.push_rect( - c"grep window", - true, + c"centered container", + false, + false, UiAxis::Vertical, UiSemanticSize::PercentOfParent(75), - UiSemanticSize::PercentOfParent(75), + UiSemanticSize::Fill, |ui_table| { - if let Ok(sink) = window.rx.try_recv() { - window.sink = Some(sink); - } - - ui_table.push_rect( - c"results list", - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| match &window.sink { - Some(sink) if !sink.matches.is_empty() => { - let num_mats_to_draw = std::cmp::min( - (sink.matches.len() - window.top_index) as i32, - (height - font_height) / (font_height), - ); - - for (i, mat) in sink.matches[window.top_index..].iter().enumerate() - { - let index = i + window.top_index; - if i as i32 >= num_mats_to_draw { - break; - } - - let path = Path::new(&mat.path); - let relative_file_path = path - .strip_prefix(directory) - .unwrap_or(path) - .to_str() - .unwrap_or(""); - - let matched_text = String::from_utf8_lossy(&mat.text); - let text = match mat.line_number { - Some(line_number) => format!( - "{}:{}:{}: {}", - relative_file_path, - line_number, - mat.column, - matched_text - ), - None => format!( - "{}:{}: {}", - relative_file_path, mat.column, matched_text - ), - }; - - if index == window.selected_match { - ui_table.button(&CString::new(text).expect("valid text")); - } else { - ui_table.label(&CString::new(text).expect("valid text")); - } - } - } - Some(_) | None => { - ui_table.push_rect( - c"top spacer", - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| {}, - ); - ui_table.push_rect( - c"centered text container", - false, - UiAxis::Horizontal, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| { - ui_table.push_rect( - c"left spacer", - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| {}, - ); - ui_table.label(c"no results"); - ui_table.push_rect( - c"right spacer", - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| {}, - ); - }, - ); - ui_table.push_rect( - c"bottom spacer", - false, - UiAxis::Vertical, - UiSemanticSize::Fill, - UiSemanticSize::Fill, - |ui_table| {}, - ); - } - }, - ); - + ui_table.spacer(c"top spacer"); ui_table.push_rect( c"grep window", - false, + true, + true, UiAxis::Vertical, UiSemanticSize::Fill, - UiSemanticSize::Exact(font_height as isize), + UiSemanticSize::PercentOfParent(75), |ui_table| { - if let Some(buffer) = window.input_buffer { - ui_table.buffer(buffer, false); + if let Ok(sink) = window.rx.try_recv() { + window.sink = Some(sink); } + + ui_table.push_rect( + c"results list", + false, + false, + UiAxis::Vertical, + UiSemanticSize::Fill, + UiSemanticSize::Fill, + |ui_table| match &window.sink { + Some(sink) if !sink.matches.is_empty() => { + let num_mats_to_draw = std::cmp::min( + (sink.matches.len() - window.top_index) as i32, + (height - font_height) / (font_height), + ); + + for (i, mat) in + sink.matches[window.top_index..].iter().enumerate() + { + let index = i + window.top_index; + if i as i32 >= num_mats_to_draw { + break; + } + + let path = Path::new(&mat.path); + let relative_file_path = path + .strip_prefix(directory) + .unwrap_or(path) + .to_str() + .unwrap_or(""); + + let matched_text = String::from_utf8_lossy(&mat.text); + let text = match mat.line_number { + Some(line_number) => format!( + "{}:{}:{}: {}", + relative_file_path, + line_number, + mat.column, + matched_text + ), + None => format!( + "{}:{}: {}", + relative_file_path, mat.column, matched_text + ), + }; + + if index == window.selected_match { + // TODO: don't use button here, but apply a style + // to `label` + ui_table.button( + &CString::new(text).expect("valid text"), + ); + } else { + ui_table.label( + &CString::new(text).expect("valid text"), + ); + } + } + } + Some(_) | None => { + ui_table.spacer(c"top spacer"); + ui_table.push_rect( + c"centered text container", + false, + false, + UiAxis::Horizontal, + UiSemanticSize::Fill, + UiSemanticSize::Fill, + |ui_table| { + ui_table.spacer(c"left spacer"); + ui_table.label(c"no results"); + ui_table.spacer(c"right spacer"); + }, + ); + ui_table.spacer(c"bottom spacer"); + } + }, + ); + + ui_table.push_rect( + c"grep window", + true, + false, + UiAxis::Vertical, + UiSemanticSize::Fill, + UiSemanticSize::Exact(font_height as isize), + |ui_table| { + if let Some(buffer) = window.input_buffer { + ui_table.buffer(buffer, false); + } + }, + ); }, ); + ui_table.spacer(c"bottom spacer"); }, ); - }, - ); + ui_table.spacer(c"right spacer"); + }); } extern "C" fn on_buffer_input(plugin: Plugin, buffer: Buffer) { diff --git a/src/core/core.odin b/src/core/core.odin index d5156ee..1766493 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -49,6 +49,8 @@ State :: struct { should_close: bool, screen_height: int, screen_width: int, + width_dpi_ratio: f32, + height_dpi_ratio: f32, directory: string, diff --git a/src/main.odin b/src/main.odin index 650ae39..0c9e177 100644 --- a/src/main.odin +++ b/src/main.odin @@ -194,6 +194,7 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) { core.register_key_action(input_map, .A, proc(state: ^State) { core.move_cursor_right(&state.buffers[state.current_buffer], false); state.mode = .Insert; + sdl2.StartTextInput(); }, "enter insert mode after character (append)"); } @@ -341,6 +342,9 @@ expose_event_watcher :: proc "c" (state: rawptr, event: ^sdl2.Event) -> i32 { state.state.screen_width = int(w); state.state.screen_height = int(h); + state.state.width_dpi_ratio = f32(w) / f32(event.window.data1); + state.state.height_dpi_ratio = f32(h) / f32(event.window.data2); + draw(state); } } @@ -870,6 +874,18 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { ui.pop_parent(ui_context); }, + spacer = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction { + context = state.ctx; + ui_context := transmute(^ui.Context)ui_context; + label := strings.clone(string(label), context.temp_allocator); + + interaction := ui.spacer(ui_context, label); + + return plugin.UiInteraction { + hovering = interaction.hovering, + clicked = interaction.clicked, + }; + }, // TODO: allow this to have more flags sent to it floating = proc "c" (ui_context: rawptr, label: cstring, pos: [2]int) -> plugin.UiBox { context = state.ctx; @@ -878,7 +894,7 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { return ui.push_floating(ui_context, label, pos); }, - rect = proc "c" (ui_context: rawptr, label: cstring, border: bool, axis: plugin.UiAxis, size: [2]plugin.UiSemanticSize) -> plugin.UiBox { + rect = proc "c" (ui_context: rawptr, label: cstring, background: bool, border: bool, axis: plugin.UiAxis, size: [2]plugin.UiSemanticSize) -> plugin.UiBox { context = state.ctx; ui_context := transmute(^ui.Context)ui_context; label := strings.clone(string(label), context.temp_allocator); @@ -894,7 +910,7 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { }, }; - return ui.push_rect(ui_context, label, border, ui.Axis(axis), size); + return ui.push_rect(ui_context, label, background, border, ui.Axis(axis), size); }, label = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction { @@ -944,8 +960,10 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin { main :: proc() { state = State { ctx = context, - source_font_width = 8 + 2 * 3, - source_font_height = 16 + 2 * 3, + screen_width = 640, + screen_height = 480, + source_font_width = 8, + source_font_height = 16, input_map = core.new_input_map(), window = nil, directory = os.get_current_directory(), @@ -984,7 +1002,7 @@ main :: proc() { 0, 640, 480, - {.SHOWN, .RESIZABLE, .METAL, .ALLOW_HIGHDPI} + {.SHOWN, .RESIZABLE, .ALLOW_HIGHDPI} ); defer if sdl_window != nil { sdl2.DestroyWindow(sdl_window); @@ -1014,6 +1032,17 @@ main :: proc() { } } + { + w,h: i32; + sdl2.GetRendererOutputSize(state.sdl_renderer, &w, &h); + + state.width_dpi_ratio = f32(w) / f32(state.screen_width); + state.height_dpi_ratio = f32(h) / f32(state.screen_height); + state.screen_width = int(w); + state.screen_height = int(h); + } + + // Done to clear the buffer sdl2.StartTextInput(); sdl2.StopTextInput(); @@ -1031,11 +1060,7 @@ main :: proc() { } } - control_key_pressed: bool; - - state.screen_width = 640; //int(raylib.GetScreenWidth()); - state.screen_height = 480; //int(raylib.GetScreenHeight()); for !state.should_close { { buffer := &state.buffers[state.current_buffer]; @@ -1162,8 +1187,8 @@ main :: proc() { } if sdl_event.type == .MOUSEMOTION { - ui_context.mouse_x = int(sdl_event.motion.x); - ui_context.mouse_y = int(sdl_event.motion.y); + ui_context.mouse_x = int(f32(sdl_event.motion.x) * state.width_dpi_ratio); + ui_context.mouse_y = int(f32(sdl_event.motion.y) * state.height_dpi_ratio); } if sdl_event.type == .MOUSEBUTTONDOWN || sdl_event.type == .MOUSEBUTTONUP { diff --git a/src/plugin/plugin.odin b/src/plugin/plugin.odin index 1053fcc..a9786f1 100644 --- a/src/plugin/plugin.odin +++ b/src/plugin/plugin.odin @@ -105,7 +105,7 @@ UiPushParentProc :: proc "c" (ui_context: rawptr, box: UiBox); UiPopParentProc :: proc "c" (ui_context: rawptr); UiFloatingProc :: proc "c" (ui_context: rawptr, label: cstring, pos: [2]int) -> UiBox; UiCreateBoxProc :: proc "c" (ui_context: rawptr, label: cstring) -> UiBox; -UiRectProc :: proc "c" (ui_context: rawptr, label: cstring, border: bool, axis: UiAxis, size: [2]UiSemanticSize) -> UiBox; +UiRectProc :: proc "c" (ui_context: rawptr, label: cstring, background: bool, border: bool, axis: UiAxis, size: [2]UiSemanticSize) -> UiBox; UiSimpleProc :: proc "c" (ui_context: rawptr, label: cstring) -> UiInteraction; UiBufferProc :: proc "c" (ui_context: rawptr, buffer: rawptr, show_line_numbers: bool); UiBufferIndexProc :: proc "c" (ui_context: rawptr, buffer: int, show_line_numbers: bool); @@ -115,6 +115,7 @@ Ui :: struct { push_parent: UiPushParentProc, pop_parent: UiPopParentProc, + spacer: UiSimpleProc, floating: UiFloatingProc, rect: UiRectProc, diff --git a/src/ui/imm.odin b/src/ui/imm.odin index ffe06b1..57e3a20 100644 --- a/src/ui/imm.odin +++ b/src/ui/imm.odin @@ -672,19 +672,21 @@ debug_print :: proc(ctx: ^Context, box: ^Box, depth: int = 0) { } } -spacer :: proc(ctx: ^Context, label: string, flags: bit_set[Flag] = {}, semantic_size: [2]SemanticSize = {{.Fill, 0}, {.Fill,0}}) -> ^Box { - return push_box(ctx, label, flags, semantic_size = semantic_size); +spacer :: proc(ctx: ^Context, label: string, flags: bit_set[Flag] = {}, semantic_size: [2]SemanticSize = {{.Fill, 0}, {.Fill,0}}) -> Interaction { + box := push_box(ctx, label, flags, semantic_size = semantic_size); + + return test_box(ctx, box); } -push_floating :: proc(ctx: ^Context, label: string, pos: [2]int, flags: bit_set[Flag] = {.Floating}, axis: Axis = .Vertical, semantic_size: [2]SemanticSize = Fill) -> ^Box { +push_floating :: proc(ctx: ^Context, label: string, pos: [2]int, flags: bit_set[Flag] = {.Floating}, axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = Fill) -> ^Box { box := push_box(ctx, label, flags, semantic_size = semantic_size); box.computed_pos = pos; return box; } -push_rect :: proc(ctx: ^Context, label: string, border: bool = true, axis: Axis = .Vertical, semantic_size: [2]SemanticSize = Fill) -> ^Box { - return push_box(ctx, label, {.DrawBackground, .DrawBorder if border else nil}, axis, semantic_size = semantic_size); +push_rect :: proc(ctx: ^Context, label: string, background: bool = true, border: bool = true, axis: Axis = .Vertical, semantic_size: [2]SemanticSize = Fill) -> ^Box { + return push_box(ctx, label, {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, semantic_size = semantic_size); } label :: proc(ctx: ^Context, label: string) -> Interaction {