From 6347b56751d7a0675c832dac086062b64ecf27e3 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sun, 23 Jun 2024 07:22:03 +0200 Subject: [PATCH] Adding scrollbars and titlebars, laying it out --- src/text_editor/main.cpp | 189 +++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 77 deletions(-) diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index 415717b..8193fa6 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -11,18 +11,30 @@ Arena FrameArena; // Render units - positions ready to draw, y // World units - positions offset by screen movement // Window units - positions inside the window (starts in left top of window) -// WindowWorld units - positions offset by a position inside the buffer +// WindowBuffer units +// WindowBufferWorld units + +const uint64_t WindowFlag_DrawTitleBar = 1 << 1; +const uint64_t WindowFlag_DrawLineNumbers = 1 << 2; +const uint64_t WindowFlag_DrawRightScrollBar = 1 << 3; +const uint64_t WindowFlag_DrawBottomScrollBar = 1 << 4; struct Window { - Rect2 rect_in_world_units; - Vec2 window_world_to_window_units; + uint64_t flags; + Rect2 rect_in_world_units; + Vec2 scroll; // window_world_to_window_units Array cursors; Buffer buffer; }; -Vec2 WindowWorldToWindowUnits(Vec2 value, const Window &window) { - Vec2 result = Vector2Subtract(value, window.window_world_to_window_units); +Vec2 WindowBufferWorldToWindowBufferUnits(Vec2 value, const Window &window) { + Vec2 result = Vector2Subtract(value, window.scroll); + return result; +} + +Vec2 WindowBufferToWindowUnits(Vec2 value, Vec2 window_buffer_to_window_units) { + Vec2 result = Vector2Add(value, window_buffer_to_window_units); return result; } @@ -108,21 +120,24 @@ int main() { if (0) font = LoadFontEx("C:/Windows/Fonts/consola.ttf", (int)font_size, NULL, 250); Array windows = {}; - windows.add({GetScreenRectRenderUnits()}); { - Window *window = &windows[0]; - Buffer *buffer = &window->buffer; - InitBuffer(buffer); + Window window = {}; + window.flags = WindowFlag_DrawTitleBar | WindowFlag_DrawLineNumbers; + window.rect_in_world_units = GetScreenRectRenderUnits(); + window.rect_in_world_units.max.x *= 2; + window.rect_in_world_units.max.y *= 2; + InitBuffer(&window.buffer); if (1) { for (int i = 0; i < 5; i += 1) { Array edits = {FrameArena}; - AddEdit(&edits, GetEnd(*buffer), Format(FrameArena, "line number: %d\n", i)); - ApplyEdits(buffer, edits); + AddEdit(&edits, GetEnd(window.buffer), Format(FrameArena, "line number: %d\n", i)); + ApplyEdits(&window.buffer, edits); } } - window->cursors.add({}); - window->cursors.add(GetLine(*buffer, 1).range); + window.cursors.add({}); + window.cursors.add(GetLine(window.buffer, 1).range); + windows.add(window); } Vec2 camera_offset_world_to_render_units = {}; @@ -135,8 +150,8 @@ int main() { } float mouse_wheel = GetMouseWheelMove() * 48; - focused_window->window_world_to_window_units.y -= mouse_wheel; - focused_window->window_world_to_window_units.y = ClampBottom(focused_window->window_world_to_window_units.y, 0.f); + focused_window->scroll.y -= mouse_wheel; + focused_window->scroll.y = ClampBottom(focused_window->scroll.y, 0.f); if (IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT)) { For(focused_window->cursors) { @@ -208,24 +223,33 @@ int main() { Rectangle rectangle_in_render_units = ToRectangle(window_rect_in_render_units); DrawRectangleRec(rectangle_in_render_units, WHITE); - Rect2 screen_rect_in_render_units = GetScreenRectRenderUnits(); - Rect2 window_rect_in_render_units_clamped_to_screen = window_rect_in_render_units; - window_rect_in_render_units_clamped_to_screen.min.x = Clamp(window_rect_in_render_units_clamped_to_screen.min.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x); - window_rect_in_render_units_clamped_to_screen.max.x = Clamp(window_rect_in_render_units_clamped_to_screen.max.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x); - window_rect_in_render_units_clamped_to_screen.min.y = Clamp(window_rect_in_render_units_clamped_to_screen.min.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y); - window_rect_in_render_units_clamped_to_screen.max.y = Clamp(window_rect_in_render_units_clamped_to_screen.max.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y); - if (0) { - window_rect_in_render_units_clamped_to_screen = Shrink(window_rect_in_render_units_clamped_to_screen, 10); - DrawRectangleRec(ToRectangle(window_rect_in_render_units_clamped_to_screen), {255, 0, 0, 50}); - } + Rect2 window_text_rect_in_render_units = window_rect_in_render_units; - // Figure out which lines to draw - Vec2 s = GetSize(window_rect_in_render_units); - float line_offset = font_size; - float _line_min_y = (window.window_world_to_window_units.y) / line_offset; - float _line_max_y = (s.y + window.window_world_to_window_units.y) / line_offset; - int64_t line_min_y = (int64_t)floorf(_line_min_y); - int64_t line_max_y = (int64_t)ceilf(_line_max_y); + Rect2 window_text_rect_in_render_units_clamped_to_screen = window_text_rect_in_render_units; + Rect2 screen_rect_in_render_units = GetScreenRectRenderUnits(); + window_text_rect_in_render_units_clamped_to_screen.min.x = Clamp(window_text_rect_in_render_units_clamped_to_screen.min.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x); + window_text_rect_in_render_units_clamped_to_screen.max.x = Clamp(window_text_rect_in_render_units_clamped_to_screen.max.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x); + window_text_rect_in_render_units_clamped_to_screen.min.y = Clamp(window_text_rect_in_render_units_clamped_to_screen.min.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y); + window_text_rect_in_render_units_clamped_to_screen.max.y = Clamp(window_text_rect_in_render_units_clamped_to_screen.max.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y); + + float title_bar_size = 20; + float line_number_bar_size = 40; + float scroll_bar_size = 30; + Vec2 window_buffer_to_window_units = {line_number_bar_size, title_bar_size}; + Rect2 title_bar_in_render_units = CutTop(&window_text_rect_in_render_units_clamped_to_screen, title_bar_size); + Rect2 line_number_bar_in_render_units = CutLeft(&window_text_rect_in_render_units_clamped_to_screen, line_number_bar_size); + Rect2 bottom_scroll_bar_in_render_units = CutBottom(&window_text_rect_in_render_units_clamped_to_screen, scroll_bar_size); + Rect2 right_scroll_bar_in_render_units = CutRight(&window_text_rect_in_render_units_clamped_to_screen, scroll_bar_size); + + DrawRectangleRec(ToRectangle(title_bar_in_render_units), GRAY); + DrawRectangleRec(ToRectangle(line_number_bar_in_render_units), GRAY); + DrawRectangleRec(ToRectangle(bottom_scroll_bar_in_render_units), GRAY); + DrawRectangleRec(ToRectangle(right_scroll_bar_in_render_units), GRAY); + + if (0) { + window_text_rect_in_render_units_clamped_to_screen = Shrink(window_text_rect_in_render_units_clamped_to_screen, 10); + DrawRectangleRec(ToRectangle(window_text_rect_in_render_units_clamped_to_screen), {255, 0, 0, 50}); + } struct Cell { Rect2 rect; @@ -241,61 +265,72 @@ int main() { // Compute visible rows and cells Array rows = {FrameArena}; - for (int64_t line = line_min_y; line < line_max_y; line += 1) { - if (line < 0) break; - if (line >= window.buffer.lines.len) break; - Range line_range = window.buffer.lines[line]; + { + // Figure out which lines to draw + Vec2 s = GetSize(window_rect_in_render_units); + float line_offset = font_size; + float _line_min_y = (window.scroll.y) / line_offset; + float _line_max_y = (s.y + window.scroll.y) / line_offset; + int64_t line_min_y = (int64_t)floorf(_line_min_y); + int64_t line_max_y = (int64_t)ceilf(_line_max_y); - Vec2 text_position_in_world_window_units = {0, line_offset * (float)line}; - Vec2 text_position_in_window_units = WindowWorldToWindowUnits(text_position_in_world_window_units, window); - Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, window); - Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units); + for (int64_t line = line_min_y; line < line_max_y; line += 1) { + if (line < 0) break; + if (line >= window.buffer.lines.len) break; + Range line_range = window.buffer.lines[line]; - CellRow row = {}; - row.line = line; - row.cells.allocator = FrameArena; - row.rect.min = text_position_in_render_units; + Vec2 text_position_in_window_buffer_world_units = {0, line_offset * (float)line}; + Vec2 text_position_in_window_buffer_units = WindowBufferWorldToWindowBufferUnits(text_position_in_window_buffer_world_units, window); + Vec2 text_position_in_window_units = WindowBufferToWindowUnits(text_position_in_window_buffer_units, window_buffer_to_window_units); + Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, window); + Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units); - // Iterate the string and compute cells for current font - // we are also incorporating - new line and end of buffer glyphs - // into the stream! - String text = GetString(window.buffer, line_range); - if (font.texture.id == 0) font = GetFontDefault(); - float textOffsetX = 0.0f; - float scaleFactor = font_size / font.baseSize; // Character quad scaling factor + CellRow row = {}; + row.line = line; + row.cells.allocator = FrameArena; + row.rect.min = text_position_in_render_units; - for (BufferIter iter = Iterate(window.buffer, line_range);; Advance(&iter)) { - bool end_of_buffer = iter.pos == window.buffer.len; - bool new_line = iter.pos == line_range.max; - bool in_range = IsValid(iter); - bool continue_looping = end_of_buffer || new_line || in_range; - if (!continue_looping) break; + // Iterate the string and compute cells for current font + // we are also incorporating - new line and end of buffer glyphs + // into the stream! + String text = GetString(window.buffer, line_range); + if (font.texture.id == 0) font = GetFontDefault(); + float textOffsetX = 0.0f; + float scaleFactor = font_size / font.baseSize; // Character quad scaling factor - int codepoint = '\n'; - if (in_range) codepoint = iter.item; + for (BufferIter iter = Iterate(window.buffer, line_range);; Advance(&iter)) { + bool end_of_buffer = iter.pos == window.buffer.len; + bool new_line = iter.pos == line_range.max; + bool in_range = IsValid(iter); + bool continue_looping = end_of_buffer || new_line || in_range; + if (!continue_looping) break; - int index = GetGlyphIndex(font, codepoint); - GlyphInfo *glyph = font.glyphs + index; - Vec2 glyph_position = {text_position_in_render_units.x + textOffsetX, text_position_in_render_units.y}; + int codepoint = '\n'; + if (in_range) codepoint = iter.item; - float x_to_offset_by = ((float)glyph->advanceX * scaleFactor + font_spacing); - if (glyph->advanceX == 0) x_to_offset_by = ((float)font.recs[index].width * scaleFactor + font_spacing); + int index = GetGlyphIndex(font, codepoint); + GlyphInfo *glyph = font.glyphs + index; + Vec2 glyph_position = {text_position_in_render_units.x + textOffsetX, text_position_in_render_units.y}; - Vec2 cell_size = {x_to_offset_by, font_size}; - Rect2 cell_rect = {glyph_position, Vector2Add(glyph_position, cell_size)}; - Rectangle cell_rectangle = ToRectangle(cell_rect); + float x_to_offset_by = ((float)glyph->advanceX * scaleFactor + font_spacing); + if (glyph->advanceX == 0) x_to_offset_by = ((float)font.recs[index].width * scaleFactor + font_spacing); - // Clip everything that is outside the window and screen - if (CheckCollisionRecs(cell_rectangle, ToRectangle(window_rect_in_render_units_clamped_to_screen))) { - row.cells.add({cell_rect, codepoint, iter.pos}); - row.rect.max = cell_rect.max; + Vec2 cell_size = {x_to_offset_by, font_size}; + Rect2 cell_rect = {glyph_position, Vector2Add(glyph_position, cell_size)}; + Rectangle cell_rectangle = ToRectangle(cell_rect); + + // Clip everything that is outside the window and screen + if (CheckCollisionRecs(cell_rectangle, ToRectangle(window_text_rect_in_render_units_clamped_to_screen))) { + row.cells.add({cell_rect, codepoint, iter.pos}); + row.rect.max = cell_rect.max; + } + + textOffsetX += x_to_offset_by; + if (end_of_buffer || new_line) break; } - textOffsetX += x_to_offset_by; - if (end_of_buffer || new_line) break; + if (row.cells.len) rows.add(row); } - - if (row.cells.len) rows.add(row); } // Draw debug markers @@ -309,8 +344,8 @@ int main() { } // Draw the glyphs - Vec2 window_rect_in_render_units_size = GetSize(window_rect_in_render_units); - BeginScissorMode((int)window_rect_in_render_units.min.x, (int)window_rect_in_render_units.min.y, (int)window_rect_in_render_units_size.x, (int)window_rect_in_render_units_size.y); + Vec2 window_text_rect_in_render_units_clamped_to_screen_size = GetSize(window_text_rect_in_render_units_clamped_to_screen); + BeginScissorMode((int)window_text_rect_in_render_units_clamped_to_screen.min.x, (int)window_text_rect_in_render_units_clamped_to_screen.min.y, (int)window_text_rect_in_render_units_clamped_to_screen_size.x, (int)window_text_rect_in_render_units_clamped_to_screen_size.y); ForItem(row, rows) { For(row.cells) { if (it.codepoint == '\n') {