From 4a1554ce2858207bd7a703bec17d425262470a71 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 5 May 2025 08:37:41 +0200 Subject: [PATCH] The new window splits --- src/basic/basic.h | 2 + src/text_editor/commands.cpp | 32 +--- src/text_editor/commands_bindings.cpp | 107 +++++++++++-- src/text_editor/management.cpp | 3 +- src/text_editor/text_editor.cpp | 4 +- src/text_editor/text_editor.h | 28 +++- src/text_editor/todo.txt | 1 + src/text_editor/window.cpp | 210 ++++++++++++-------------- 8 files changed, 224 insertions(+), 163 deletions(-) diff --git a/src/basic/basic.h b/src/basic/basic.h index 6b6344c..4a04dae 100644 --- a/src/basic/basic.h +++ b/src/basic/basic.h @@ -10,6 +10,8 @@ if (!(x)) { \ __debugbreak(); \ } +#define InvalidCodepath() Assert(!"invalid codepath") +#define ElseInvalidCodepath() else {InvalidCodepath()} #if defined(__APPLE__) && defined(__MACH__) #define OS_MAC 1 diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index e0492f2..6747898 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -195,21 +195,7 @@ void ReportErrorf(const char *fmt, ...) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error!", string.data, NULL); View *view = GetView(NullViewID); Command_Appendf(view, "%.*s\n", FmtString(string)); - - // Set console view as active - { - Window *w = GetWindow(NullWindowID); - if (!w) { - BSet bset = GetActiveMainSet(); - w = GetNextLayoutWindow(bset.window); - - Buffer *b = GetBuffer(NullBufferID); - CheckpointBeforeGoto(w); - WindowOpenBufferView(w, b->name); - } - - ActiveWindow = w->id; - } + ActiveWindow = NullWindowID; } void ReportConsolef(const char *fmt, ...) { @@ -224,21 +210,7 @@ void ReportWarningf(const char *fmt, ...) { STRING_FORMAT(scratch, fmt, string); View *null_view = GetView(NullViewID); Command_Appendf(null_view, "%.*s\n", FmtString(string)); - - // Set console view as active - { - Window *w = GetWindow(NullWindowID); - if (!w) { - BSet bset = GetActiveMainSet(); - w = GetNextLayoutWindow(bset.window); - - Buffer *b = GetBuffer(NullBufferID); - CheckpointBeforeGoto(w); - WindowOpenBufferView(w, b->name); - } - - ActiveWindow = w->id; - } + ActiveWindow = NullWindowID; } void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) { diff --git a/src/text_editor/commands_bindings.cpp b/src/text_editor/commands_bindings.cpp index 84b5422..55335eb 100644 --- a/src/text_editor/commands_bindings.cpp +++ b/src/text_editor/commands_bindings.cpp @@ -54,6 +54,83 @@ void Command_GetCFiles(void) { WindowOpenBufferView(main.window, buffer_name); } +Window *GetRightWindow(WindowSplit *split, Window *window, bool *next_is_the_one) { + if (split->kind == WindowSplitKind_Window) { + if (*next_is_the_one) { + return split->window; + } + if (split->window == window) { + *next_is_the_one = true; + } + } else if (split->kind == WindowSplitKind_Vertical || split->kind == WindowSplitKind_Horizontal) { + Window *a = GetRightWindow(split->left, window, next_is_the_one); + if (a != window) return a; + + Window *b = GetRightWindow(split->right, window, next_is_the_one); + if (b != window) return b; + } ElseInvalidCodepath(); + + return window; +} + +Window *GetRightWindow(WindowID id) { + Window *window = GetWindow(id); + WindowSplit *split = window->split_ref; + Assert(split->kind == WindowSplitKind_Window); + bool next_is_the_one = false; + Window *result = GetRightWindow(&WindowSplits, window, &next_is_the_one); + return result; +} + +Window *GetLeftWindow(WindowSplit *split, Window *window, bool *next_is_the_one) { + if (split->kind == WindowSplitKind_Window) { + if (*next_is_the_one) { + return split->window; + } + if (split->window == window) { + *next_is_the_one = true; + } + } else if (split->kind == WindowSplitKind_Vertical || split->kind == WindowSplitKind_Horizontal) { + Window *b = GetLeftWindow(split->right, window, next_is_the_one); + if (b != window) return b; + Window *a = GetLeftWindow(split->left, window, next_is_the_one); + if (a != window) return a; + } ElseInvalidCodepath(); + + return window; +} + +Window *GetLeftWindow(WindowID id) { + Window *window = GetWindow(id); + WindowSplit *split = window->split_ref; + Assert(split->kind == WindowSplitKind_Window); + bool next_is_the_one = false; + Window *result = GetLeftWindow(&WindowSplits, window, &next_is_the_one); + return result; +} + +Window *GetNWindow(WindowSplit *split, Window *null_window, int n, int *counter) { + if (split->kind == WindowSplitKind_Window) { + *counter += 1; + if (n == *counter) { + return split->window; + } + } else if (split->kind == WindowSplitKind_Vertical || split->kind == WindowSplitKind_Horizontal) { + Window *a = GetNWindow(split->left, null_window, n, counter); + if (a) return a; + Window *b = GetNWindow(split->right, null_window, n, counter); + if (b) return b; + } ElseInvalidCodepath(); + + return NULL; +} + +Window *GetNWindow(int n) { + int counter = 0; + Window *result = GetNWindow(&WindowSplits, GetWindow(NullWindowID), n, &counter); + return result; +} + void UpdateScroll(Window *window, bool update_caret_scrolling) { ProfileFunction(); BSet set = GetBSet(window); @@ -333,20 +410,15 @@ void OnCommand(Event event) { } } - if (CtrlPress(SDLK_GRAVE)) { - if (ActiveWindow != NullWindowID) { - ActiveWindow = NullWindowID; - // GetView(NullViewID); - } - } + if (CtrlPress(SDLK_P)) { Command_ListBuffers(); } if (CtrlShiftPress(SDLK_BACKSLASH)) { - AddRowWindow(); + SplitWindow(WindowSplitKind_Horizontal); } else if (CtrlPress(SDLK_BACKSLASH)) { - AddColumnWindow(); + SplitWindow(WindowSplitKind_Vertical); } if (CtrlPress(SDLK_0)) { @@ -361,16 +433,21 @@ void OnCommand(Event event) { ToggleFullscreen(); } + if (CtrlPress(SDLK_GRAVE)) { + if (ActiveWindow != NullWindowID) { + ActiveWindow = NullWindowID; + } + } if (CtrlPress(SDLK_1)) { - Window *window = GetLayoutWindow(0); + Window *window = GetNWindow(2); if (window) ActiveWindow = window->id; } if (CtrlPress(SDLK_2)) { - Window *window = GetLayoutWindow(1); + Window *window = GetNWindow(3); if (window) ActiveWindow = window->id; } if (CtrlPress(SDLK_3)) { - Window *window = GetLayoutWindow(2); + Window *window = GetNWindow(4); if (window) ActiveWindow = window->id; } @@ -589,6 +666,14 @@ void OnCommand(Event event) { ActiveWindow = GetWindow(active.window->title_bar_window)->id; } + if (AltPress(SDLK_RIGHT)) { + ActiveWindow = GetRightWindow(ActiveWindow)->id; + } + if (AltPress(SDLK_LEFT)) { + ActiveWindow = GetLeftWindow(ActiveWindow)->id; + } + + if (CtrlShiftPress(SDLK_G)) { } else if (CtrlPress(SDLK_G)) { diff --git a/src/text_editor/management.cpp b/src/text_editor/management.cpp index 7fc9313..5baacf2 100644 --- a/src/text_editor/management.cpp +++ b/src/text_editor/management.cpp @@ -21,9 +21,8 @@ WindowID NullWindowID; WindowID DebugWindowID; // +debug BufferID DebugBufferID; +WindowSplit WindowSplits; WindowID ActiveWindow; -WindowID ActiveWindowCounterID; -Int ActiveWindowCounter; WindowID ScrollbarSelected = {-1}; WindowID DocumentSelected = {-1}; diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index dc4ee84..fbec506 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -174,7 +174,9 @@ void Update(Event event) { } OnCommand(event); - for (Window *it = FirstWindow; it; it = it->next) if (it->is_title_bar) ReplaceTitleBarData(it); + for (Window *it = FirstWindow; it; it = it->next) { + if (it->is_title_bar) ReplaceTitleBarData(it); + } UpdateProcesses(); UpdateCo(&event); ReloadLuaConfigs(); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 816d0eb..04254b1 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -1,7 +1,8 @@ -struct Window; struct View; +struct Window; struct View; struct WindowSplit; struct ViewID { Int id; View *o; }; struct WindowID { Int id; Window *o; }; // @todo: change name of object to something scary + struct View { ViewID id; BufferID active_buffer; @@ -25,6 +26,7 @@ struct Window { ViewID active_view; Window *next; Window *prev; + WindowSplit *split_ref; WindowID title_bar_window; Int title_bar_last_buffer_change_id; // @todo: bring back the changes to title bar? @@ -52,12 +54,34 @@ struct Window { bool absolute_position : 1; bool is_title_bar : 1; bool is_search_bar : 1; - bool is_column : 1; bool deactivate_on_escape : 1; }; }; +enum WindowSplitKind { + WindowSplitKind_Window, + WindowSplitKind_Vertical, + WindowSplitKind_Horizontal, +}; + +enum ValueKind { + ValueKind_Proportion, + ValueKind_CharSize, + ValueKind_CharSizeOtherWindow, +}; + +struct WindowSplit { + WindowSplitKind kind; + WindowSplit *left; + WindowSplit *right; + WindowSplit *parent; + + Window *window; + ValueKind value_kind; + double value; +}; + struct Scroller { Rect2 rect; double begin; diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 74901dd..e4afd2e 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -3,6 +3,7 @@ - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage - Fix B: not opening - Scroll the console properly +- commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top -------------- buffer = make_buffer() diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index 3f380d9..ae4c250 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -1,48 +1,3 @@ -struct VisualColumn { - Window *window; - Array rows; -}; - -Array GetVisualColumns(Allocator allocator) { - Array columns = {allocator}; - for (Window *it = FirstWindow; it; it = it->next) { - if (!it->visible || it->absolute_position || it->is_title_bar || it->is_search_bar) { - continue; - } - - if (it->is_column) { - Add(&columns, {it, {allocator}}); - VisualColumn *col = GetLast(columns); - Add(&col->rows, it); - } else if (columns.len) { - VisualColumn *col = GetLast(columns); - Add(&col->rows, it); - } - } - return columns; -} - -Window *GetLayoutWindow(int n) { - int i = 0; - for (Window *it = FirstWindow; it; it = it->next) { - if (!it->is_column || !it->visible || it->absolute_position || it->is_title_bar || it->is_search_bar) continue; - - if (n == i) return it; - i += 1; - } - return NULL; -} - -Window *GetNextLayoutWindow(Window *input_window) { - bool found = false; - for (Window *it = FirstWindow; it; it = it->next) { - if (!it->is_column || !it->visible || it->absolute_position || it->is_title_bar || it->is_search_bar) continue; - if (found) return it; - if (it->id == input_window->id) found = true; - } - return input_window; -} - Array GetWindowZOrder(Allocator allocator) { Array order = {allocator}; for (Window *it = FirstWindow; it; it = it->next) if (it->z == 2) Add(&order, it); @@ -105,22 +60,45 @@ Int GetTitleBarSize(Window *window) { return (Int)result; } -void AddColumnWindow() { - Window *window = CreateWindow(); - window->is_column = true; - View *view = OpenBufferView(ScratchBuffer->name); - window->active_view = view->id; - CreateTitlebar(window->id); - CreateSearchBar(window->id); +WindowSplit *CreateSplitForWindow(Window *window) { + WindowSplit *split = AllocType(Perm, WindowSplit); + split->kind = WindowSplitKind_Window; + split->window = window; + window->split_ref = split; + return split; } -void AddRowWindow() { - Window *active_window = GetActiveWindow(); +void SplitWindowEx(WindowSplit **node, WindowSplit *split, Window *target, Window *new_window, WindowSplitKind kind) { + if (split->kind == WindowSplitKind_Horizontal || split->kind == WindowSplitKind_Vertical) { + SplitWindowEx(&split->left, split->left, target, new_window, kind); + SplitWindowEx(&split->right, split->right, target, new_window, kind); + } else { + Assert(split->kind == WindowSplitKind_Window); + if (target != split->window) { + return; + } + + WindowSplit *hori = AllocType(Perm, WindowSplit); + hori->kind = kind; + hori->value_kind = ValueKind_Proportion; + hori->value = 0.5; + hori->left = *node; + hori->right = CreateSplitForWindow(new_window); + *node = hori; + } +} + +void SplitWindow(WindowSplitKind kind) { Window *window = CreateWindow(); View *view = OpenBufferView(ScratchBuffer->name); window->active_view = view->id; CreateTitlebar(window->id); CreateSearchBar(window->id); + + Window *active_window = GetActiveWindow(); + SplitWindowEx(NULL, &WindowSplits, active_window, window, kind); + ActiveWindow = window->id; + } void SetVisibility(WindowID window_id, bool v) { @@ -192,37 +170,37 @@ https://www.lua.org/manual/5.4/ void InitWindows() { Allocator sys_allocator = Perm; + WindowSplit *split = &WindowSplits; + split->kind = WindowSplitKind_Horizontal; + split->value_kind = ValueKind_CharSizeOtherWindow; + split->value = (double)StyleConsoleSizeSmall; + { Window *window = CreateWindow(); window->active_view = NullViewID; - Assert(NullWindowID.id == 0); - // @todo - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage - WindowID id = window->id; + Assert(window->id.id == 0); + CreateTitlebar(window->id); + CreateSearchBar(window->id); - CreateTitlebar(id); - CreateSearchBar(id); + split->left = CreateSplitForWindow(window); } { Window *window = CreateWindow(); - // @todo - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage - WindowID window_id = window->id; - window->is_column = true; Buffer *buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkingDir, "test_buffer")); View *view = CreateView(buffer->id); LoadTestBufferMessage(buffer); window->active_view = view->id; - CreateTitlebar(window_id); + CreateTitlebar(window->id); CreateSearchBar(window->id); + ActiveWindow = window->id; - ActiveWindow = ActiveWindowCounterID = window_id; + split->right = CreateSplitForWindow(window); } { Window *window = CreateWindow(); - // @todo - Windows, Buffers, Views should not be in a dynamic list it risks memory errors. Should be instead in a Double linked list, any freeing should happen at GC stage - WindowID window_id = window->id; DebugWindowID = window->id; window->draw_line_numbers = false; window->absolute_position = true; @@ -237,65 +215,23 @@ void InitWindows() { View *view = CreateView(buffer->id); window->active_view = view->id; - Window *titlebar = CreateTitlebar(window_id); + Window *titlebar = CreateTitlebar(window->id); Window *searchbar = CreateSearchBar(window->id); titlebar->z = 2; searchbar->z = 2; - SetVisibility(window_id, false); + SetVisibility(window->id, false); } } -void LayoutWindows(int16_t wx, int16_t wy) { - float ScrollBarSize = (10.f * DPIScale); - Rect2I screen_rect = RectI0Size(wx, wy); +void LayoutWindowSplit(WindowSplit *split, Rect2I rect) { + float scrollbar_size = (10.f * DPIScale); float line_numbers_size = (float)FontCharSpacing * 10; - float sizex = (float)GetSize(screen_rect).x; - { - Window *window = GetWindow(NullWindowID); - - Int console_panel_size = StyleConsoleSizeSmall; - if (ActiveWindow == window->id) { - console_panel_size = StyleConsoleSizeBig; - } - - Rect2I rect = CutBottom(&screen_rect, FontLineSpacing*console_panel_size); - - Window *title_bar_window = GetWindow(window->title_bar_window); - title_bar_window->total_rect = CutBottom(&window->total_rect, GetTitleBarSize(title_bar_window)); - title_bar_window->document_rect = title_bar_window->total_rect; - - Rect2I save_rect = window->document_rect; - CutLeft(&save_rect, GetSize(save_rect).x/2); - Window *search_bar_window = GetWindow(window->search_bar_window); - search_bar_window->total_rect = CutTop(&save_rect, GetTitleBarSize(search_bar_window)); - search_bar_window->document_rect = search_bar_window->total_rect; - - window->document_rect = window->total_rect; - if (window->draw_scrollbar) window->scrollbar_rect = CutRight(&window->document_rect, (Int)ScrollBarSize); - if (window->draw_line_numbers) window->line_numbers_rect = CutLeft(&window->document_rect, (Int)line_numbers_size); - - window->total_rect = rect; - } - - Scratch scratch; - Array columns = GetVisualColumns(scratch); - float delta_column = 1.0f / (float)columns.len; - ForItem(col, columns) { - Int add = 0; - if (IsLast(columns, col)) add += 2; - - Rect2I rect = CutLeft(&screen_rect, (Int)(delta_column * sizex + add)); - float sizey = (float)GetSize(rect).y; - float delta_row = 1.0f / (float)col.rows.len; - ForItem(row, col.rows) { - row->total_rect = CutTop(&rect, (Int)(delta_row * sizey)); - } - } - - for (Window *it = FirstWindow; it; it = it->next) { - if (!it->visible || it->absolute_position || it->is_title_bar || it->is_search_bar) continue; + if (split->kind == WindowSplitKind_Window) { + Window *it = split->window; + Assert(it->split_ref); + it->total_rect = rect; Window *title_bar_window = GetWindow(it->title_bar_window); title_bar_window->total_rect = CutBottom(&it->total_rect, GetTitleBarSize(title_bar_window)); @@ -308,10 +244,50 @@ void LayoutWindows(int16_t wx, int16_t wy) { search_bar_window->document_rect = search_bar_window->total_rect; it->document_rect = it->total_rect; - if (it->draw_scrollbar) it->scrollbar_rect = CutRight(&it->document_rect, (Int)ScrollBarSize); + if (it->draw_scrollbar) it->scrollbar_rect = CutRight(&it->document_rect, (Int)scrollbar_size); if (it->draw_line_numbers) it->line_numbers_rect = CutLeft(&it->document_rect, (Int)line_numbers_size); + } else if (split->kind == WindowSplitKind_Vertical) { + Rect2I rect2 = {0}; + if (split->value_kind == ValueKind_Proportion) { + rect2 = CutLeft(&rect, (Int)round((double)GetSize(rect).x * split->value)); + } else if (split->value_kind == ValueKind_CharSize) { + rect2 = CutLeft(&rect, (Int)round((double)FontCharSpacing * split->value)); + } else { + Assert(split->value_kind == ValueKind_CharSizeOtherWindow); + rect2 = CutRight(&rect, (Int)round((double)FontCharSpacing * split->value)); + } + + LayoutWindowSplit(split->left, rect2); + LayoutWindowSplit(split->right, rect); + } else if (split->kind == WindowSplitKind_Horizontal) { + Rect2I rect2 = {0}; + if (split->value_kind == ValueKind_Proportion) { + rect2 = CutTop(&rect, (Int)round((double)GetSize(rect).y * split->value)); + } else if (split->value_kind == ValueKind_CharSize) { + rect2 = CutTop(&rect, (Int)round((double)FontLineSpacing * split->value)); + } else { + Assert(split->value_kind == ValueKind_CharSizeOtherWindow); + rect2 = CutBottom(&rect, (Int)round((double)FontLineSpacing * split->value)); + } + + LayoutWindowSplit(split->left, rect2); + LayoutWindowSplit(split->right, rect); + } else { + Assert(!"Invalid codepath"); + } +} + +void LayoutWindows(int16_t wx, int16_t wy) { + if (ActiveWindow == NullWindowID) { + WindowSplits.value = (double)StyleConsoleSizeBig; + } else { + WindowSplits.value = (double)StyleConsoleSizeSmall; } + Rect2I screen_rect = RectI0Size(wx, wy); + LayoutWindowSplit(&WindowSplits, screen_rect); + + // layout debug window { Window *window = GetWindow(DebugWindowID); Rect2 screen_rect = Rect0Size(wx, wy);