Replace text_editor and bring back ctrl + f, fix circle rendering pos

This commit is contained in:
Krzosa Karol
2024-07-27 11:38:41 +02:00
parent 03eece4e41
commit 477b485a34
5 changed files with 239 additions and 322 deletions

View File

@@ -128,7 +128,7 @@ int CompileTextEditor() {
AddCommonFlags(&cmd); AddCommonFlags(&cmd);
For2(lib, libs) For(lib.defines) cmd.add(it); For2(lib, libs) For(lib.defines) cmd.add(it);
cmd.add("../src/text_editor/new_text_editor.cpp"); cmd.add("../src/text_editor/text_editor.cpp");
cmd.add("../src/basic/win32.cpp"); cmd.add("../src/basic/win32.cpp");
For2(lib, libs) For(lib.include_paths) cmd.add(Fmt("-I %.*s", S8_Expand(it))); For2(lib, libs) For(lib.include_paths) cmd.add(Fmt("-I %.*s", S8_Expand(it)));

View File

@@ -303,7 +303,7 @@ bool GlobalCommand(Event event) {
run_window_command = false; run_window_command = false;
} }
if (Ctrl(SDLK_P)) { if (Ctrl(SDLK_F)) {
Window *search_window = GetWindow(SearchWindowID); Window *search_window = GetWindow(SearchWindowID);
if (search_window->visible) { if (search_window->visible) {
SetActiveWindow(GetLastActiveWindow()); SetActiveWindow(GetLastActiveWindow());

View File

@@ -1,277 +0,0 @@
#include <math.h>
#define BASIC_IMPL
#include "basic/basic.h"
#include "basic/filesystem.h"
#include "basic/string16.cpp"
#include "basic/math_int.cpp"
#include "basic/math.cpp"
#include "profiler/profiler.cpp"
#include "SDL3/SDL.h"
#include "external/glad/glad.h"
#include "external/stb_truetype.h"
#include "external/stb_truetype.c"
#include "platform/font.cpp"
#include "platform/render_opengl.cpp"
#include "text_editor.h"
#include "buffer_helpers.cpp"
#include "buffer.cpp"
#include "buffer_multi_cursor.cpp"
#include "buffer_history.cpp"
#include "buffer_fuzzy_search.cpp"
#include "buffer_test_load.cpp"
#include "management.cpp"
#include "window.cpp"
#include "commands.cpp"
#include "commands_clipboard.cpp"
#include "commands_window.cpp"
#include "colors.cpp"
#include "window_draw.cpp"
#include "lua.hpp"
#include "lua_api.cpp"
void HandleEvent(Event event) {
bool run_window_command = GlobalCommand(event);
if (run_window_command) {
Window *window = GetActiveWindow();
View *view = GetActiveView(window);
WindowCommand(event, window, view);
MergeCarets(view);
}
}
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;
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;
}
} else if (b.button == SDL_BUTTON_RIGHT) {
event.mouse = MOUSE_RIGHT;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.mouse = 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.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.y;
} break;
default: return;
}
HandleEvent(event);
}
#if _WIN32
int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd)
#else
int main()
#endif
{
BeginProfiler();
InitScratch();
InitArena(&Perm);
WorkingDir = GetWorkingDir(Perm);
if (SDL_Init(SDL_INIT_VIDEO) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return 1;
}
const char *glsl_version = "#version 450";
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY;
SDL_Window *window = SDL_CreateWindow("Text editor", 1280, 720, window_flags);
if (window == NULL) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window!", SDL_GetError(), NULL);
return 1;
}
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync
SDL_ShowWindow(window);
// Set icon
{
uint32_t data = 0xddddddff;
SDL_Surface *surface = SDL_CreateSurfaceFrom(1, 1, SDL_PIXELFORMAT_RGBA8888, &data, sizeof(uint32_t));
SDL_SetWindowIcon(window, surface);
SDL_DestroySurface(surface);
}
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load opengl!", SDL_GetError(), NULL);
return 1;
}
SDL_StartTextInput(window);
SDL_GL_SetSwapInterval(1); // vsync
InitRender();
ReloadFont(16);
InitLua();
InitWindows();
while (AppIsRunning) {
FrameID += 1;
int window_x, window_y;
SDL_GetWindowSize(window, &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->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);
ProcessSDLEvent(&event);
}
WaitForEvents = true;
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);
}
ReplaceInfobarData();
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) continue;
// HandleWindowBindings(&window);
DrawWindow(window);
}
EndFrameRender(ColorBackground);
SDL_GL_SwapWindow(window);
}
SDL_DestroyWindow(window);
SDL_Quit();
EndProfileScope();
EndProfiler();
return 0;
}

View File

@@ -6,14 +6,17 @@
#include "basic/string16.cpp" #include "basic/string16.cpp"
#include "basic/math_int.cpp" #include "basic/math_int.cpp"
#include "basic/math.cpp" #include "basic/math.cpp"
#include "raylib.h"
#include "colors.cpp"
#include "raylib_utils.cpp"
#include "profiler/profiler.cpp" #include "profiler/profiler.cpp"
#include "text_editor.h"
#include "SDL3/SDL.h"
#include "external/glad/glad.h"
#include "external/stb_truetype.h"
#include "external/stb_truetype.c"
#include "platform/font.cpp"
#include "platform/render_opengl.cpp"
#include "text_editor.h"
#include "buffer_helpers.cpp" #include "buffer_helpers.cpp"
#include "buffer.cpp" #include "buffer.cpp"
#include "buffer_multi_cursor.cpp" #include "buffer_multi_cursor.cpp"
@@ -22,62 +25,253 @@
#include "buffer_test_load.cpp" #include "buffer_test_load.cpp"
#include "management.cpp" #include "management.cpp"
#include "window.cpp"
#include "commands.cpp" #include "commands.cpp"
#include "commands_clipboard.cpp" #include "commands_clipboard.cpp"
#include "commands_window.cpp" #include "commands_window.cpp"
#include "window.cpp"
#include "colors.cpp"
#include "window_draw.cpp" #include "window_draw.cpp"
#include "lua.hpp" #include "lua.hpp"
#include "lua_api.cpp" #include "lua_api.cpp"
int main(void) { void HandleEvent(Event event) {
InitScratch(); bool run_window_command = GlobalCommand(event);
BeginProfiler(); if (run_window_command) {
BeginProfileScope("main"); Window *window = GetActiveWindow();
View *view = GetActiveView(window);
Arena Perm = {}; WindowCommand(event, window, view);
InitArena(&Perm); MergeCarets(view);
}
WorkingDir = GetWorkingDir(Perm);
SetWindowState(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT);
InitWindow(1280, 720, "hello :)");
SetExitKey(KEY_F5);
SetTargetFPS(60);
{
uint32_t data = 0xffdddddd;
Image window_icon_image = {(void *)&data, 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8};
SetWindowIcon(window_icon_image);
} }
MenuFontSize = 19; void ProcessSDLEvent(SDL_Event *input_event) {
MenuFont = LoadFontEx("c:\\Windows\\Fonts\\Segoeui.ttf", (int)MenuFontSize, NULL, 500); ProfileFunction();
ReloadFont(16); 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;
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;
}
} else if (b.button == SDL_BUTTON_RIGHT) {
event.mouse = MOUSE_RIGHT;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.mouse = 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.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.y;
} break;
default: return;
}
HandleEvent(event);
}
#if _WIN32
int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nShowCmd)
#else
int main()
#endif
{
BeginProfiler();
InitScratch();
InitArena(&Perm);
WorkingDir = GetWorkingDir(Perm);
if (SDL_Init(SDL_INIT_VIDEO) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
return 1;
}
const char *glsl_version = "#version 450";
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY;
SDL_Window *window = SDL_CreateWindow("Text editor", 1280, 720, window_flags);
if (window == NULL) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window!", SDL_GetError(), NULL);
return 1;
}
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync
SDL_ShowWindow(window);
// Set icon
{
uint32_t data = 0xddddddff;
SDL_Surface *surface = SDL_CreateSurfaceFrom(1, 1, SDL_PIXELFORMAT_RGBA8888, &data, sizeof(uint32_t));
SDL_SetWindowIcon(window, surface);
SDL_DestroySurface(surface);
}
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load opengl!", SDL_GetError(), NULL);
return 1;
}
SDL_StartTextInput(window);
SDL_GL_SetSwapInterval(1); // vsync
InitRender();
ReloadFont(16);
InitLua(); InitLua();
while (!WindowShouldClose()) { InitWindows();
while (AppIsRunning) {
BeginDrawing(); FrameID += 1;
ClearBackground(ColorBackground); int window_x, window_y;
SDL_GetWindowSize(window, &window_x, &window_y);
WindowSize = {(float)window_x, (float)window_y};
BeginFrameRender();
LayoutWindows();
Scratch scratch; Scratch scratch;
Array<Int> order = GetWindowZOrder(scratch); Array<Int> order = GetWindowZOrder(scratch);
HandleGlobalCommands(); For(order) {
ChangeActiveWindowAndScroll(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);
ProcessSDLEvent(&event);
}
WaitForEvents = true;
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);
}
ReplaceInfobarData(); ReplaceInfobarData();
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)) { For(IterateInReverse(&order)) {
Window &window = Windows[it]; Window &window = Windows[it];
if (window.visible) { if (!window.visible) continue;
HandleWindowBindings(&window); // HandleWindowBindings(&window);
DrawWindow(window); DrawWindow(window);
} }
EndFrameRender(ColorBackground);
SDL_GL_SwapWindow(window);
} }
SetMouseCursor();
EndDrawing(); SDL_DestroyWindow(window);
} SDL_Quit();
CloseWindow();
EndProfileScope(); EndProfileScope();
EndProfiler(); EndProfiler();
return 0; return 0;
} }

View File

@@ -125,11 +125,11 @@ void DrawWindow(Window &window) {
DrawRect(rect, ColorSelection); DrawRect(rect, ColorSelection);
if (line_string[col] == ' ' || line_string[col] == '\t') { if (line_string[col] == ' ' || line_string[col] == '\t') {
DrawCircle({pos.x + (float)FontCharSpacing / 2.f, (float)pos.y + MainFont.descent}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); DrawCircle({pos.x + (float)FontCharSpacing / 2.f, (float)pos.y - MainFont.ascent / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection);
} else if (line_string[col] == '\n') { } else if (line_string[col] == '\n') {
DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y + (float)FontLineSpacing / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y - MainFont.ascent / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection);
} else if (line_string[col] == '\r') { } else if (line_string[col] == '\r') {
DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y + (float)FontLineSpacing / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection); DrawCircle({pos.x + (float)FontCharSpacing / 2.f, pos.y - MainFont.ascent / 2.f}, MainFont.size / 8.f, ColorWhitespaceDuringSelection);
} }
} }
} }