diff --git a/src/text_editor/commands.cpp b/src/text_editor/commands.cpp index 6f74062..d387575 100644 --- a/src/text_editor/commands.cpp +++ b/src/text_editor/commands.cpp @@ -4,7 +4,6 @@ bool WaitForEvents = true; enum { MOUSE_NONE, - MOUSE_MOVE, MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, @@ -14,18 +13,37 @@ enum { MOUSE_MIDDLE_UP, }; +enum EventKind { + EVENT_NONE, + EVENT_UPDATE, + EVENT_QUIT, + + EVENT_MOUSE_LEFT, + EVENT_MOUSE_RIGHT, + EVENT_MOUSE_MIDDLE, + EVENT_MOUSE_LEFT_UP, + EVENT_MOUSE_RIGHT_UP, + EVENT_MOUSE_MIDDLE_UP, + EVENT_MOUSE_WHEEL, + + EVENT_KEY_PRESS, + EVENT_TEXT_INPUT, +}; + struct Event { + EventKind kind; SDL_Keycode key; int16_t xmouse; int16_t ymouse; + int16_t xwindow; + int16_t ywindow; struct { uint8_t shift : 1; uint8_t ctrl : 1; uint8_t alt : 1; uint8_t super : 1; + uint8_t mouse_double_click : 1; }; - uint8_t mouse; - uint8_t mouse_double_click; Vec2 wheel; const char *text; }; @@ -41,7 +59,7 @@ struct Event { Vec2 { (float)event.xmouse, (float)event.ymouse } #define MouseVec2I() \ Vec2I { (Int) event.xmouse, (Int)event.ymouse } -#define Mouse(x) (event.mouse == MOUSE_##x) +#define Mouse(x) (event.kind == EVENT_MOUSE_##x) #define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE)) Int MoveOnWhitespaceBoundaryForward(Buffer &buffer, Int pos) { @@ -247,7 +265,7 @@ void ToggleFullscreen() { bool GlobalCommand(Event event) { ProfileFunction(); bool run_window_command = true; - if (Mouse(MOVE)) { + { Vec2I mouse = MouseVec2I(); Window *window = GetActiveWindow(); bool mouse_in_document = CheckCollisionPointRec(mouse, window->document_rect); @@ -382,10 +400,32 @@ bool GlobalCommand(Event event) { return run_window_command; } +View *FindView(BufferID buffer_id) { + For(Views) { + if (it.active_buffer.id == buffer_id.id) { + return ⁢ + } + } + return NULL; +} + void AppendToConsole(String16 string) { Buffer *buffer = GetBuffer("*console*"); + + // @todo: ? + View *view = FindView(buffer->id); + + bool scroll_to_end = false; + if (view) { + Int line = PosToLine(*buffer, GetFront(view->carets[0])); + if (line == buffer->line_starts.len - 1) scroll_to_end = true; + } ReplaceText(buffer, GetEndAsRange(*buffer), string); ReplaceText(buffer, GetEndAsRange(*buffer), L"\n"); + + if (scroll_to_end) { + view->carets[0] = MakeCaret(GetEndAsRange(*buffer).min); + } } void AppendToConsole(String string) { diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 4dd3fa4..71a4384 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -325,7 +325,8 @@ void ApplyTitleBarChangesToWindow(Window *window, View *view, Buffer *buffer) { } void ReplaceTitleBarData(Window *window) { - View *view = GetView(window->active_view); + View *view = GetView(window->active_view); + view->scroll.y = 0; Buffer *buffer = GetBuffer(view->active_buffer); if (IsActive(window)) { if (buffer->change_frame_id == FrameID) { @@ -639,8 +640,7 @@ void WindowCommand(Event event, Window *window, View *view) { } } - if (!Mouse(NONE)) { - ProfileScope(mouse); + { Vec2 mouse_vec2 = MouseVec2(); Vec2I mouse = MouseVec2I(); @@ -716,10 +716,6 @@ void WindowCommand(Event event, Window *window, View *view) { view->scroll.y = (Int)(v * (double)s.line_count * (double)FontLineSpacing); } } - - if (window->mouse_selecting || window->mouse_selecting_scrollbar) { - WaitForEvents = false; - } } } diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index ccfdafb..b7e2aa9 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -40,6 +40,84 @@ int FullScreenPositionX, FullScreenPositionY; #include "generated.cpp" #include "window_draw.cpp" +void FillEventWithBasicData(Event *event) { + SDL_Keymod mod = SDL_GetModState(); + event->shift = (mod & SDL_KMOD_SHIFT) != 0; + event->ctrl = (mod & SDL_KMOD_CTRL) != 0; + event->alt = (mod & SDL_KMOD_ALT) != 0; + event->super = (mod & SDL_KMOD_GUI) != 0; + + float xmouse, ymouse; + SDL_GetMouseState(&xmouse, &ymouse); + event->xmouse = (int16_t)xmouse; + event->ymouse = (int16_t)ymouse; + + int xwindow, ywindow; + SDL_GetWindowSize(SDLWindow, &xwindow, &ywindow); + event->xwindow = xwindow; + event->ywindow = ywindow; +} + +Event TranslateSDLEvent(SDL_Event *input_event) { + ProfileFunction(); + Event event = {}; + FillEventWithBasicData(&event); + + switch (input_event->type) { + case SDL_EVENT_QUIT: { + event.kind = EVENT_QUIT; + } break; + case SDL_EVENT_KEY_DOWN: { + event.kind = EVENT_KEY_PRESS; + SDL_KeyboardEvent &key = input_event->key; + event.key = key.key; + } break; + case SDL_EVENT_TEXT_INPUT: { + event.kind = EVENT_TEXT_INPUT; + SDL_TextInputEvent &b = input_event->text; + event.text = b.text; + } break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: { + SDL_MouseButtonEvent &b = input_event->button; + event.xmouse = (int16_t)b.x; + event.ymouse = (int16_t)b.y; + if (b.button == SDL_BUTTON_LEFT) { + event.kind = EVENT_MOUSE_LEFT; + if (b.clicks == 2) { + event.mouse_double_click = 1; + } + } else if (b.button == SDL_BUTTON_RIGHT) { + event.kind = EVENT_MOUSE_RIGHT; + } else if (b.button == SDL_BUTTON_MIDDLE) { + event.kind = EVENT_MOUSE_MIDDLE; + } + } break; + case SDL_EVENT_MOUSE_BUTTON_UP: { + SDL_MouseButtonEvent &b = input_event->button; + event.xmouse = (int16_t)b.x; + event.ymouse = (int16_t)b.y; + if (b.button == SDL_BUTTON_LEFT) { + event.kind = EVENT_MOUSE_LEFT_UP; + } else if (b.button == SDL_BUTTON_RIGHT) { + event.kind = EVENT_MOUSE_RIGHT_UP; + } else if (b.button == SDL_BUTTON_MIDDLE) { + event.kind = EVENT_MOUSE_MIDDLE_UP; + } + } break; + case SDL_EVENT_MOUSE_WHEEL: { + event.kind = EVENT_MOUSE_WHEEL; + SDL_MouseWheelEvent &b = input_event->wheel; + event.xmouse = (int16_t)b.mouse_x; + event.ymouse = (int16_t)b.mouse_y; + event.wheel = {b.x, b.y}; + } break; + default: { + }; + } + + return event; +} + void HandleEvent(Event event) { bool run_window_command = GlobalCommand(event); if (run_window_command) { @@ -50,62 +128,84 @@ void HandleEvent(Event event) { } } -void ProcessSDLEvent(SDL_Event *input_event) { - ProfileFunction(); - Event event = {}; - SDL_Keymod mod = SDL_GetModState(); - event.shift = (mod & SDL_KMOD_SHIFT) != 0; - event.ctrl = (mod & SDL_KMOD_CTRL) != 0; - event.alt = (mod & SDL_KMOD_ALT) != 0; - event.super = (mod & SDL_KMOD_GUI) != 0; +Buffer *LuaBuffer = NULL; +Int LuaBufferChangeID = 0; +void Update(const Event &event) { + WindowSize = {(float)event.xwindow, (float)event.ywindow}; + LayoutWindows(); - switch (input_event->type) { - case SDL_EVENT_QUIT: AppIsRunning = false; return; - case SDL_EVENT_KEY_DOWN: { - SDL_KeyboardEvent &key = input_event->key; - event.key = key.key; - } break; - case SDL_EVENT_TEXT_INPUT: { - SDL_TextInputEvent &b = input_event->text; - event.text = b.text; - } break; - case SDL_EVENT_MOUSE_BUTTON_DOWN: { - SDL_MouseButtonEvent &b = input_event->button; - event.xmouse = (int16_t)b.x; - event.ymouse = (int16_t)b.y; - if (b.button == SDL_BUTTON_LEFT) { - event.mouse = MOUSE_LEFT; - if (b.clicks == 2) { - event.mouse_double_click = 1; + Scratch scratch; + Array order = GetWindowZOrder(scratch); + For(order) { + Window *window = &Windows[it]; + if (!window->visible) continue; + View *view = GetActiveView(window); + view->main_caret_on_begin_frame = view->carets[0]; + view->update_scroll = true; + window->mouse_in_scrollbar = false; + } + HandleEvent(event); + + For(Windows) if (it.is_title_bar) ReplaceTitleBarData(&it); + ReplaceDebugData(); + + if (LuaBuffer->dirty == false && LuaBuffer->change_id != LuaBufferChangeID) { + Scratch scratch; + String16 string16 = GetString(*LuaBuffer); + String string = ToString(scratch, string16); + if (luaL_dostring(LuaState, string.data) == LUA_OK) { + if (lua_isstring(LuaState, -1)) { + const char *text = lua_tostring(LuaState, -1); + ReportConsolef(text); + lua_pop(LuaState, 1); } - } else if (b.button == SDL_BUTTON_RIGHT) { - event.mouse = MOUSE_RIGHT; - } else if (b.button == SDL_BUTTON_MIDDLE) { - event.mouse = MOUSE_MIDDLE; + ReloadColors(); + } else { + const char *error_message = lua_tostring(LuaState, -1); + ReportWarningf("Failed to load user config! %s", error_message); + lua_pop(LuaState, 1); } - } break; - case SDL_EVENT_MOUSE_BUTTON_UP: { - SDL_MouseButtonEvent &b = input_event->button; - event.xmouse = (int16_t)b.x; - event.ymouse = (int16_t)b.y; - if (b.button == SDL_BUTTON_LEFT) { - event.mouse = MOUSE_LEFT_UP; - } else if (b.button == SDL_BUTTON_RIGHT) { - event.mouse = MOUSE_RIGHT_UP; - } else if (b.button == SDL_BUTTON_MIDDLE) { - event.mouse = MOUSE_MIDDLE_UP; - } - } break; - case SDL_EVENT_MOUSE_WHEEL: { - SDL_MouseWheelEvent &b = input_event->wheel; - event.xmouse = (int16_t)b.mouse_x; - event.ymouse = (int16_t)b.mouse_y; - event.wheel = {b.x, b.y}; - } break; - default: return; + LuaBufferChangeID = LuaBuffer->change_id; } - HandleEvent(event); + For(IterateInReverse(&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 = GetView(window->active_view); + UpdateScroll(window, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll); + } +} + +Array GetEventsForFrame(Allocator allocator) { + Array result = {allocator}; + + SDL_Event event; + if (WaitForEvents) { + SDL_WaitEvent(&event); + Event ev = TranslateSDLEvent(&event); + if (ev.kind != EVENT_NONE) Add(&result, ev); + } + + while (SDL_PollEvent(&event)) { + Event ev = TranslateSDLEvent(&event); + if (ev.kind != EVENT_NONE) Add(&result, ev); + } + + if (result.len == 0) { + Event event = {}; + FillEventWithBasicData(&event); + event.kind = EVENT_UPDATE; + Add(&result, event); + } + + return result; } #if _WIN32 @@ -155,7 +255,7 @@ int main() SDL_GLContext gl_context = SDL_GL_CreateContext(SDLWindow); SDL_GL_MakeCurrent(SDLWindow, gl_context); - SDL_GL_SetSwapInterval(1); // Enable vsync + SDL_GL_SetSwapInterval(0); // Enable vsync SDL_ShowWindow(SDLWindow); // Set icon @@ -186,8 +286,6 @@ int main() Buffer *null_buffer = CreateBuffer(sys_allocator, "*scratch*"); View *null_view = CreateView(null_buffer->id); - Buffer *lua_buffer = NULL; - Int lua_buffer_change_id = 0; { // Init base config, test that it works and initialize the lua stuff if (!luaL_dostring(LuaState, BaseLuaConfig.data) == LUA_OK) { @@ -206,9 +304,9 @@ int main() SDL_RemovePath(lua_config_path.data); #endif - lua_buffer = BufferOpenFile(lua_config_path); - if (lua_buffer->len) { - String16 string16 = GetString(*lua_buffer); + LuaBuffer = BufferOpenFile(lua_config_path); + if (LuaBuffer->len) { + String16 string16 = GetString(*LuaBuffer); String string = ToString(scratch, string16); if (luaL_dostring(LuaState, string.data) == LUA_OK) { ReloadColors(); @@ -218,10 +316,10 @@ int main() lua_pop(LuaState, 1); } } else { - ReplaceText(lua_buffer, {}, ToString16(scratch, BaseLuaConfig)); + ReplaceText(LuaBuffer, {}, ToString16(scratch, BaseLuaConfig)); } - lua_buffer_change_id = lua_buffer->change_id; + LuaBufferChangeID = LuaBuffer->change_id; } InitWindows(null_view); @@ -229,97 +327,48 @@ int main() while (AppIsRunning) { FrameID += 1; - // We are waiting here because we don't want to miss the - // resize event which we don't handle but which we will use - // in the loop to figure out window size and window layout - SDL_Event event = {}; - if (WaitForEvents) SDL_WaitEvent(&event); - WaitForEvents = true; - - int window_x, window_y; - SDL_GetWindowSize(SDLWindow, &window_x, &window_y); - WindowSize = {(float)window_x, (float)window_y}; - BeginFrameRender(); - LayoutWindows(); - - Scratch scratch; - Array order = GetWindowZOrder(scratch); - For(order) { - Window *window = &Windows[it]; - if (!window->visible) continue; - View *view = GetActiveView(window); - view->main_caret_on_begin_frame = view->carets[0]; - view->update_scroll = true; - window->mouse_in_scrollbar = false; - } - - if (event.type != SDL_EVENT_FIRST) { - ProcessSDLEvent(&event); - } - while (SDL_PollEvent(&event)) { - ProcessSDLEvent(&event); - } - { - Event event = {}; - float xmouse, ymouse; - SDL_GetMouseState(&xmouse, &ymouse); - event.xmouse = (int16_t)xmouse; - event.ymouse = (int16_t)ymouse; - event.mouse = MOUSE_MOVE; - HandleEvent(event); + Scratch scratch; + Array frame_events = GetEventsForFrame(scratch); + For(frame_events) { + if (it.kind == EVENT_QUIT) goto end_of_editor_loop; + Update(it); + } + + WaitForEvents = true; + Window *window = GetActiveWindow(); + if (window->mouse_selecting || window->mouse_selecting_scrollbar) { + WaitForEvents = false; + } } + // This shouldn't matter to the state of the program, only appearence for + // the user { + Scratch scratch; Window *window = GetActiveWindow(); View *view = GetView(window->active_view); Buffer *buffer = GetBuffer(view->active_buffer); - const char *dirty = buffer->dirty ? "!" : ""; - Format(scratch, "%.*s%s", buffer->name, dirty); - SDL_SetWindowTitle(SDLWindow, buffer->name.data); + const char *dirty = buffer->dirty ? " !" : ""; + String string = Format(scratch, "%.*s%s", FmtString(buffer->name), dirty); + SDL_SetWindowTitle(SDLWindow, string.data); } - For(Windows) { - if (it.is_title_bar) ReplaceTitleBarData(&it); - } - ReplaceDebugData(); - - if (lua_buffer->dirty == false && lua_buffer->change_id != lua_buffer_change_id) { - Scratch scratch; - String16 string16 = GetString(*lua_buffer); - String string = ToString(scratch, string16); - if (luaL_dostring(LuaState, string.data) == LUA_OK) { - if (lua_isstring(LuaState, -1)) { - const char *text = lua_tostring(LuaState, -1); - ReportConsolef(text); - lua_pop(LuaState, 1); - } - ReloadColors(); - } else { - const char *error_message = lua_tostring(LuaState, -1); - ReportWarningf("Failed to load user config! %s", error_message); - lua_pop(LuaState, 1); - } - lua_buffer_change_id = lua_buffer->change_id; - } + // This is here to render changes in title bar size without a frame of delay + LayoutWindows(); + BeginFrameRender(); + Scratch scratch; + Array order = GetWindowZOrder(scratch); For(IterateInReverse(&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 = GetView(window->active_view); - UpdateScroll(window, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll); + if (!window->visible) continue; DrawWindow(window); } EndFrameRender(ColorBackground); SDL_GL_SwapWindow(SDLWindow); } +end_of_editor_loop:; SDL_DestroyWindow(SDLWindow); SDL_Quit(); diff --git a/src/text_editor/text_editor.h b/src/text_editor/text_editor.h index 266c7f4..d6e47b3 100644 --- a/src/text_editor/text_editor.h +++ b/src/text_editor/text_editor.h @@ -86,6 +86,16 @@ struct Window { }; }; +struct VisualRow { + float value; + WindowID window; +}; + +struct VisualColumn { + float value; + Array rows; +}; + struct Scroller { Rect2 rect; double begin; diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 48ffa98..7b37107 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -1,5 +1,6 @@ - bugs: - scrolling when clicking on scroller is busted + - rewrite the main loop to make sure all of code runs for frame - Windows - Mark windows as absolute or non-automatic layout and then just loop through windows diff --git a/src/text_editor/window.cpp b/src/text_editor/window.cpp index 123465d..a114174 100644 --- a/src/text_editor/window.cpp +++ b/src/text_editor/window.cpp @@ -1,3 +1,5 @@ +Array VisualColumns = {}; + Array GetWindowZOrder(Allocator allocator) { Array order = {allocator}; For(Windows) if (it.z == 2) Add(&order, GetIndex(Windows, it)); @@ -30,6 +32,13 @@ Window *CreateInfobar(Window *parent_window) { return window; } +Int GetTitleBarSize(Window *window) { + View *view = GetView(window->active_view); + Buffer *buffer = GetBuffer(view->active_buffer); + float result = (float)buffer->line_starts.len * FontLineSpacing; + return (Int)result; +} + void InitWindows(View *null_view) { Allocator sys_allocator = GetSystemAllocator(); @@ -38,8 +47,9 @@ void InitWindows(View *null_view) { // window->draw_line_numbers = false; Buffer *buffer = CreateBuffer(sys_allocator, "*load_text_a*"); View *view = CreateView(buffer->id); - LoadTextA(buffer); - LoadUnicode(buffer); + // LoadTextA(buffer); + // LoadUnicode(buffer); + LoadBigTextAndBigLine(buffer, 10000000); window->active_view = view->id; SetActiveView(window, view->id); CreateInfobar(window); @@ -138,7 +148,7 @@ void LayoutWindows() { int i = 0; Windows[i].total_rect = CutLeft(&screen_rect, (Int)((double)sizex * 0.5)); Window *title_bar_window = GetWindow(Windows[i].title_bar_window); - title_bar_window->total_rect = CutBottom(&Windows[i].total_rect, FontLineSpacing); + title_bar_window->total_rect = CutBottom(&Windows[i].total_rect, GetTitleBarSize(title_bar_window)); Windows[i].document_rect = Windows[i].total_rect; title_bar_window->document_rect = title_bar_window->total_rect; if (Windows[i].draw_scrollbar) Windows[i].scrollbar_rect = CutRight(&Windows[i].document_rect, (Int)ScrollBarSize); @@ -148,7 +158,7 @@ void LayoutWindows() { int i = 2; Windows[i].total_rect = CutLeft(&screen_rect, (Int)((double)sizex)); Window *title_bar_window = GetWindow(Windows[i].title_bar_window); - title_bar_window->total_rect = CutBottom(&Windows[i].total_rect, FontLineSpacing); + title_bar_window->total_rect = CutBottom(&Windows[i].total_rect, GetTitleBarSize(title_bar_window)); title_bar_window->document_rect = title_bar_window->total_rect; Windows[i].document_rect = Windows[i].total_rect; if (Windows[i].draw_scrollbar) Windows[i].scrollbar_rect = CutRight(&Windows[i].document_rect, (Int)ScrollBarSize);