New event loop setup

This commit is contained in:
Krzosa Karol
2024-08-01 16:28:10 +02:00
parent b93cdd8f4c
commit 6ce5fd59a3
6 changed files with 255 additions and 149 deletions

View File

@@ -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) {

View File

@@ -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;
}
}
}

View File

@@ -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<Int> 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<Event> GetEventsForFrame(Allocator allocator) {
Array<Event> 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<Int> 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<Event> 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<Int> 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();

View File

@@ -86,6 +86,16 @@ struct Window {
};
};
struct VisualRow {
float value;
WindowID window;
};
struct VisualColumn {
float value;
Array<VisualRow> rows;
};
struct Scroller {
Rect2 rect;
double begin;

View File

@@ -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

View File

@@ -1,3 +1,5 @@
Array<VisualColumn> VisualColumns = {};
Array<Int> GetWindowZOrder(Allocator allocator) {
Array<Int> 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);