diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index d3887d2..6002dc9 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -76,6 +76,13 @@ Range GetEnd(const Buffer &buffer) { return range; } +Range MakeRange(int64_t a, int64_t b) { + Range result = {}; + result.min = Min(a, b); + result.max = Max(a, b); + return result; +} + void AddEdit(Array *edits, Range range, String string) { edits->add({range, string}); } diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index fe8a8a5..50f7e49 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -6,14 +6,57 @@ #include "buffer.cpp" #include "rect2.cpp" -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) // WindowBuffer units // WindowBufferWorld units +struct Cursor { + union { + Range range; + int64_t pos[2]; + }; + int64_t ifront; +}; + +int64_t GetFront(Cursor cursor) { + int64_t result = cursor.pos[cursor.ifront]; + return result; +} + +int64_t GetBack(Cursor cursor) { + int64_t index = (cursor.ifront + 1) % 2; + int64_t result = cursor.pos[index]; + return result; +} + +Cursor MakeCursor(int64_t front, int64_t back) { + Cursor result = {}; + if (front >= back) { + result.range.min = back; + result.range.max = front; + result.ifront = 1; + } else { + result.range.min = front; + result.range.max = back; + result.ifront = 0; + } + return result; +} + +Cursor ChangeBack(Cursor cursor, int64_t back) { + int64_t front = GetFront(cursor); + Cursor result = MakeCursor(front, back); + return result; +} + +Cursor ChangeFront(Cursor cursor, int64_t front) { + int64_t back = GetBack(cursor); + Cursor result = MakeCursor(front, back); + return result; +} + struct Window { uint64_t flags; Rect2 rect_in_world_units; @@ -23,8 +66,8 @@ struct Window { float right_scroll_bar_pixel_size; float bottom_scroll_bar_pixel_size; - Array cursors; - Buffer buffer; + Array cursors; + Buffer buffer; }; Vec2 WindowBufferWorldToWindowBufferUnits(Vec2 value, const Window &window) { @@ -112,15 +155,17 @@ void UpdateCursorsAfterEdit(Window *window, Array edits) { int64_t offset = insert_size - remove_size; ForItem(cursor, window->cursors) { - if (edit.range.min <= cursor.min) { - cursor.min += offset; - cursor.max = cursor.min; + if (edit.range.min <= cursor.range.min) { + cursor.range.min += offset; + cursor.range.max = cursor.range.min; } } } + For(window->cursors) it.range = Clamp(window->buffer, it.range); } -int main() { +Arena FrameArena; +int main() { InitScratch(); RunBufferTests(); @@ -179,12 +224,12 @@ int main() { if (IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT)) { For(focused_window->cursors) { if (IsKeyDown(KEY_LEFT_CONTROL)) { - it.max = it.min = Seek(focused_window->buffer, it.min, ITERATE_BACKWARD); + it.range.max = it.range.min = Seek(focused_window->buffer, it.range.min, ITERATE_BACKWARD); } else { if (IsKeyDown(KEY_LEFT_SHIFT)) { - it.min = MoveLeft(focused_window->buffer, it.min); + it.range.min = MoveLeft(focused_window->buffer, it.range.min); } else { - it.max = it.min = MoveLeft(focused_window->buffer, it.min); + it.range.max = it.range.min = MoveLeft(focused_window->buffer, it.range.min); } } } @@ -192,38 +237,38 @@ int main() { if (IsKeyPressed(KEY_RIGHT) || IsKeyPressedRepeat(KEY_RIGHT)) { For(focused_window->cursors) { if (IsKeyDown(KEY_LEFT_CONTROL)) { - it.max = it.min = Seek(focused_window->buffer, it.min, ITERATE_FORWARD); + it.range.max = it.range.min = Seek(focused_window->buffer, it.range.min, ITERATE_FORWARD); } else { if (IsKeyDown(KEY_LEFT_SHIFT)) { - it.max = MoveRight(focused_window->buffer, it.max); + it.range.max = MoveRight(focused_window->buffer, it.range.max); } else { - it.max = it.min = MoveRight(focused_window->buffer, it.min); + it.range.max = it.range.min = MoveRight(focused_window->buffer, it.range.min); } } } } if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) { For(focused_window->cursors) { - it.max = it.min = MoveDown(focused_window->buffer, it.min); + it.range.max = it.range.min = MoveDown(focused_window->buffer, it.range.min); } } if (IsKeyPressed(KEY_UP) || IsKeyPressedRepeat(KEY_UP)) { For(focused_window->cursors) { - it.max = it.min = MoveUp(focused_window->buffer, it.min); + it.range.max = it.range.min = MoveUp(focused_window->buffer, it.range.min); } } // Merge cursors that overlap, this needs to be handled before any edits to // make sure overlapping edits won't happen. for (int64_t cursor_i = 0; cursor_i < focused_window->cursors.len; cursor_i += 1) { - Range &cursor = focused_window->cursors[cursor_i]; + Cursor &cursor = focused_window->cursors[cursor_i]; IterRemove(focused_window->cursors) { IterRemovePrepare(focused_window->cursors); if (&cursor == &it) continue; - if (cursor.max > it.min && cursor.max <= it.max) { - remove_item = true; - cursor.max = it.max; + if (cursor.range.max > it.range.min && cursor.range.max <= it.range.max) { + remove_item = true; + cursor.range.max = it.range.max; break; } } @@ -233,8 +278,8 @@ int main() { Array edits = {FrameArena}; String string = {}; For(focused_window->cursors) { - int64_t pos = MoveLeft(focused_window->buffer, it.min); - AddEdit(&edits, {pos, it.min}, string); + int64_t pos = MoveLeft(focused_window->buffer, it.range.min); + AddEdit(&edits, {pos, it.range.min}, string); } ApplyEdits(&focused_window->buffer, edits); UpdateCursorsAfterEdit(focused_window, edits); @@ -253,7 +298,7 @@ int main() { Array edits = {FrameArena}; For(focused_window->cursors) { - AddEdit(&edits, it, string); + AddEdit(&edits, it.range, string); } ApplyEdits(&focused_window->buffer, edits); UpdateCursorsAfterEdit(focused_window, edits); @@ -389,6 +434,27 @@ int main() { } } + // Mouse in text area + { + // @todo: test for focus + Vec2 mouse_in_render_units = GetMousePosition(); + if (CheckCollisionPointRec(mouse_in_render_units, ToRectangle(window_text_rect_in_render_units_clamped_to_screen))) { + ForItem(row, rows) { + ForItem(cell, row.cells) { + if (CheckCollisionPointRec(mouse_in_render_units, ToRectangle(cell.rect))) { + DrawRectangleRec(ToRectangle(cell.rect), {0, 0, 255, 40}); + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { + window.cursors.clear(); + window.cursors.add({cell.pos, cell.pos}); + } else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { + window.cursors[0] = ChangeBack(window.cursors[0], cell.pos); + } + } + } + } + } + } + // Draw the glyphs 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); @@ -405,35 +471,32 @@ int main() { // Draw cursor stuff ForItem(cursor, window.cursors) { - Line min_line = FindLine(window.buffer, cursor.min); - Line max_line = FindLine(window.buffer, cursor.max); - bool selecting = cursor.min != cursor.max; + Line min_line = FindLine(window.buffer, cursor.range.min); + Line max_line = FindLine(window.buffer, cursor.range.max); + bool selecting = cursor.range.min != cursor.range.max; ForItem(row, rows) { - // Draw line highlights + // Draw line highlight if (row.line == min_line.number) { DrawRectangleRec(ToRectangle(row.rect), {255, 0, 0, 30}); } - // if (row.line == max_line.number) { - // DrawRectangleRec(ToRectangle(row.rect), {0, 255, 0, 30}); - // } ForItem(cell, row.cells) { // Draw selection if (selecting) { if (row.line >= min_line.number && row.line <= max_line.number) { - if (cell.pos >= cursor.min && cell.pos < cursor.max) { + if (cell.pos >= cursor.range.min && cell.pos < cursor.range.max) { DrawRectangleRec(ToRectangle(cell.rect), BLUE); } } } // Draw cursors - if (cell.pos == cursor.min) { + if (cell.pos == GetFront(cursor)) { Rect2 rect = cell.rect; rect = CutLeft(&rect, 4); DrawRectangleRec(ToRectangle(rect), RED); } - if (cell.pos == cursor.max) { + if (cell.pos == GetBack(cursor)) { Rect2 rect = cell.rect; rect = CutLeft(&rect, 2); DrawRectangleRec(ToRectangle(rect), GREEN);