From 71494984de9e848d2ec2ff76ec8c620cee9f32be Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sat, 27 Jul 2024 07:41:15 +0200 Subject: [PATCH] Scrolling clip and global commands --- src/text_editor/commands.cpp | 14 +-- src/text_editor/commands_window.cpp | 18 ++- src/text_editor/new_text_editor.cpp | 167 ++++++++++++++++++++++++---- src/text_editor/text_editor.h | 9 +- 4 files changed, 156 insertions(+), 52 deletions(-) diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 19ea902..6798bce 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -184,12 +184,7 @@ Array FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needl // void HandleGlobalCommands() { // if (CtrlPress(KEY_P)) { -// Window *command_window = GetWindow(CommandWindowID); -// if (command_window->visible) { -// SetActiveWindow(GetLastActiveWindow()); -// } else { -// SetActiveWindow(command_window->id); -// } + // } // if (CtrlPress(KEY_F)) { @@ -210,11 +205,4 @@ Array FindAllInBuffer(Allocator allocator, Buffer *buffer, String16 needl // ReloadFont(font_size); // } -// if (CtrlPress(KEY_ONE)) { -// SetActiveWindow({0}); -// } else if (CtrlPress(KEY_TWO)) { -// SetActiveWindow({1}); -// } else if (CtrlPress(KEY_THREE)) { -// SetActiveWindow({2}); -// } // } diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 7df4304..6226ce0 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -181,13 +181,13 @@ void Command_EvalLuaLine(View *view) { Command_EvalLua(view, string); } -void PrintDebugCarets(View *view, const char *msg) { - Buffer *null_buffer = GetBuffer(NullBufferID); - Appendf(null_buffer, "%s id: %d sel_anchor(%d, %d)\n", msg, view->caret_change_id, view->selection_anchor.min, view->selection_anchor.max); - For(view->carets) { - Appendf(null_buffer, " min: %lld max: %lld front: %d\n", (long long)it.range.min, (long long)it.range.max, it.ifront); - } -} +// void PrintDebugCarets(View *view, const char *msg) { +// Buffer *null_buffer = GetBuffer(NullBufferID); +// Appendf(null_buffer, "%s id: %d sel_anchor(%d, %d)\n", msg, view->caret_change_id, view->selection_anchor.min, view->selection_anchor.max); +// For(view->carets) { +// Appendf(null_buffer, " min: %lld max: %lld front: %d\n", (long long)it.range.min, (long long)it.range.max, it.ifront); +// } +// } // Merge carets that overlap, this needs to be handled before any edits to // make sure overlapping edits won't happen. @@ -195,9 +195,7 @@ void PrintDebugCarets(View *view, const char *msg) { // mouse_selection_anchor is special case for mouse handling ! void MergeCarets(View *view, Range *mouse_selection_anchor) { ProfileFunction(); - // PrintDebugCarets(view, "before"); - view->caret_change_id = CaretChangeID++; Buffer *buffer = GetBuffer(view->active_buffer); For(view->carets) it.range = Clamp(*buffer, it.range); Caret first_caret = view->carets.data[0]; @@ -224,8 +222,6 @@ void MergeCarets(View *view, Range *mouse_selection_anchor) { } Swap(&view->carets[first_caret_index], &view->carets[0]); - - // PrintDebugCarets(view, "after"); } void HandleActiveWindowBindings(Window *window, bool *update_scroll) { diff --git a/src/text_editor/new_text_editor.cpp b/src/text_editor/new_text_editor.cpp index 7b42830..d783565 100644 --- a/src/text_editor/new_text_editor.cpp +++ b/src/text_editor/new_text_editor.cpp @@ -36,24 +36,81 @@ #include "lua_api.cpp" bool AppIsRunning = true; -bool WaitForEvents = false; +bool WaitForEvents = true; SDL_Cursor *SDL_MouseCursor = NULL; +struct Key { + SDL_Keycode code; + uint8_t shift; + uint8_t ctrl; + uint8_t alt; + uint8_t super; +}; + +void GlobalCommand(Key key) { + if (key.code == SDLK_F5) { + AppIsRunning = false; + } + + if (key.ctrl && key.code == SDLK_P) { + Window *command_window = GetWindow(CommandWindowID); + if (command_window->visible) { + SetActiveWindow(GetLastActiveWindow()); + } else { + SetActiveWindow(command_window->id); + } + } + + if (key.ctrl && key.code == SDLK_F) { + Window *search_window = GetWindow(SearchWindowID); + if (search_window->visible) { + SetActiveWindow(GetLastActiveWindow()); + } else { + SetActiveWindow(search_window->id); + } + } + + if (key.ctrl && key.code == SDLK_1) { + SetActiveWindow({0}); + } + if (key.ctrl && key.code == SDLK_2) { + SetActiveWindow({1}); + } + if (key.ctrl && key.code == SDLK_3) { + SetActiveWindow({2}); + } +} + +void WindowCommand(Key key, Window *window, View *view) { + Buffer *buffer = GetBuffer(view->active_buffer); + + if (key.code == SDLK_ESCAPE) { + if (window->deactivate_on_escape) { + SetActiveWindow(GetLastActiveWindow()); + } else { + view->carets.len = 1; + } + } +} + void ProcessSDLEvent(SDL_Event *event) { switch (event->type) { case SDL_EVENT_QUIT: AppIsRunning = false; return; case SDL_EVENT_KEY_DOWN: { - SDL_KeyboardEvent &key = event->key; - bool shift = key.mod & SDL_KMOD_SHIFT; - bool ctrl = key.mod & SDL_KMOD_CTRL; - bool alt = key.mod & SDL_KMOD_ALT; - bool super = key.mod & SDL_KMOD_GUI; + SDL_KeyboardEvent &key = event->key; - if (key.key == SDLK_F5) { - AppIsRunning = false; - return; - } + Key k = {key.key}; + k.shift = key.mod & SDL_KMOD_SHIFT; + k.ctrl = key.mod & SDL_KMOD_CTRL; + k.alt = key.mod & SDL_KMOD_ALT; + k.super = key.mod & SDL_KMOD_GUI; + GlobalCommand(k); + + Window *window = GetActiveWindow(); + View *view = GetActiveView(window); + WindowCommand(k, window, view); + MergeCarets(view); } break; case SDL_EVENT_KEY_UP: { SDL_KeyboardEvent &key = event->key; @@ -66,6 +123,15 @@ void ProcessSDLEvent(SDL_Event *event) { case SDL_EVENT_TEXT_INPUT: { SDL_TextInputEvent &b = event->text; + Scratch scratch; + String string = b.text; + String16 string16 = ToString16(scratch, string); + + Window *window = GetActiveWindow(); + View *view = GetActiveView(window); + Command_Replace(view, string16); + + // search = true; } break; case SDL_EVENT_MOUSE_MOTION: { SDL_MouseMotionEvent &b = event->motion; @@ -98,13 +164,6 @@ void ProcessSDLEvent(SDL_Event *event) { For(order) { Window *window = &Windows[it]; if (!window->visible) continue; - // view->main_caret_on_begin_frame = view->carets[0]; - - // if (window->invisible_when_inactive) { - // if (IsActive(window)) window->visible = true; - // else window->visible = false; - // } - bool mouse_in_window = CheckCollisionPointRec(mouse, window->total_rect); if (mouse_in_window) { Window *active_window = GetWindow(ActiveWindow); @@ -183,6 +242,7 @@ int main() return 1; } + SDL_StartTextInput(window); SDL_GL_SetSwapInterval(1); // vsync InitRender(); InitLua(); @@ -214,6 +274,20 @@ int main() BeginFrameRender(); LayoutWindows(); + Scratch scratch; + Array order = GetWindowZOrder(scratch); + For(order) { + Window *window = &Windows[it]; + if (window->invisible_when_inactive) { + if (IsActive(window)) window->visible = true; + else window->visible = false; + } + if (!window->visible) continue; + View *view = GetActiveView(window); + view->main_caret_on_begin_frame = view->carets[0]; + view->update_scroll = true; + } + SDL_Event event; if (WaitForEvents) { SDL_WaitEvent(&event); @@ -224,15 +298,62 @@ int main() } ReplaceInfobarData(); - Scratch scratch; - Array order = GetWindowZOrder(scratch); + For(order) { + Window *window = &Windows[it]; + if (!window->visible) continue; + View *view = GetActiveView(window); + Buffer *buffer = GetBuffer(view->active_buffer); + + // Scrolling with caret + if (!AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll) { + Caret c = view->carets[0]; + Int front = GetFront(c); + XY xy = PosToXY(*buffer, front); + + Rect2I visible = GetVisibleCells(*window); + Vec2I visible_cells = GetSize(visible); + Vec2I visible_size = visible_cells * Vec2I{FontCharSpacing, FontLineSpacing}; + Vec2I rect_size = GetSize(window->document_rect); + + if (xy.line >= visible.max.y - 2) { + Int set_view_at_line = xy.line - (visible_cells.y - 1); + Int cut_off_y = Max((Int)0, visible_size.y - rect_size.y); + view->scroll.y = (set_view_at_line * FontLineSpacing) + cut_off_y; + } + + if (xy.line < visible.min.y + 1) { + view->scroll.y = xy.line * FontLineSpacing; + } + + if (xy.col >= visible.max.x - 1) { + Int set_view_at_line = xy.col - (visible_cells.x - 1); + Int cut_off_x = Max((Int)0, visible_size.x - rect_size.x); + view->scroll.x = (set_view_at_line * FontCharSpacing) + cut_off_x; + } + + if (xy.col <= visible.min.x) { + view->scroll.x = xy.col * FontCharSpacing; + } + } + + // Clip scroll + { + ProfileScope(clip_scroll); + Int last_line = LastLine(*buffer); + view->scroll.y = Clamp(view->scroll.y, (Int)0, Max((Int)0, (last_line)*FontLineSpacing)); + + // @note: + // GetCharCountOfLongestLine is a bottleneck, there is probably an algorithm for + // calculating this value incrementally but do we even need X scrollbar or x clipping? + view->scroll.x = ClampBottom(view->scroll.x, (Int)0); + } + } For(IterateInReverse(&order)) { Window &window = Windows[it]; - if (window.visible) { - // HandleWindowBindings(&window); - DrawWindow(window); - } + if (!window.visible) continue; + // HandleWindowBindings(&window); + DrawWindow(window); } // { // Scratch scratch; diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index bc293c0..2dedc50 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -39,16 +39,15 @@ struct Buffer { }; struct View { - ViewID id; - BufferID active_buffer; - Vec2I scroll; - - Int caret_change_id; // @debug + ViewID id; + BufferID active_buffer; + Vec2I scroll; Array carets; // window | view Range selection_anchor; Caret main_caret_on_begin_frame; + bool update_scroll; }; struct Window {