diff --git a/src/text_editor/buffer.cpp b/src/text_editor/buffer.cpp index c626317..8efd9e6 100644 --- a/src/text_editor/buffer.cpp +++ b/src/text_editor/buffer.cpp @@ -227,6 +227,9 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) { void ApplyEdits(Buffer *buffer, Array edits) { Scratch scratch((Arena *)buffer->allocator.object); + Assert(buffer->data[0]); + Assert(buffer->allocator.proc); + Assert(buffer->lines.len); // Figure out how much we insert and how much we delete so // we can resize buffers properly if necessary @@ -356,13 +359,22 @@ void ApplyEdits(Buffer *buffer, Array edits) { } buffer->lines.add({base_index, base_index + string.len}); } + + Assert(buffer->data[0]); + Assert(buffer->allocator.proc); + Assert(buffer->lines.len); } -void InitBuffer(Buffer *buffer) { - Scratch scratch; - Array edits = {}; - AddEdit(&edits, {}, ""); - ApplyEdits(buffer, edits); +void InitBuffer(Allocator allocator, Buffer *buffer, int64_t _size = 4096) { + int64_t size = AlignUp(_size, 4096); + buffer->allocator = allocator; + for (int i = 0; i < 2; i += 1) { + buffer->data[i] = AllocArray(allocator, char, size); + Assert(buffer->data[i]); + } + buffer->cap = size; + buffer->lines.allocator = allocator; + buffer->lines.add({}); } String CopyNullTerminated(Allocator allocator, Buffer &buffer, Range range) { @@ -569,3 +581,29 @@ int64_t Seek(Buffer &buffer, int64_t pos, int64_t direction = ITERATE_FORWARD) { } return result; } + +int64_t MoveRight(Buffer &buffer, int64_t pos) { + pos = pos + 1; + pos = AdjustUTF8Pos(buffer, pos); + Assert(pos >= 0 && pos <= buffer.len); + return pos; +} + +int64_t MoveLeft(Buffer &buffer, int64_t pos) { + pos = pos - 1; + pos = AdjustUTF8Pos(buffer, pos, -1); + Assert(pos >= 0 && pos <= buffer.len); + return pos; +} + +int64_t MoveDown(Buffer &buffer, int64_t pos) { + LineAndColumn info = FindLineAndColumn(buffer, pos); + int64_t new_pos = FindPos(buffer, info.line.number + 1, info.column); + return new_pos; +} + +int64_t MoveUp(Buffer &buffer, int64_t pos) { + LineAndColumn info = FindLineAndColumn(buffer, pos); + int64_t new_pos = FindPos(buffer, info.line.number - 1, info.column); + return new_pos; +} \ No newline at end of file diff --git a/src/text_editor/event_recording.cpp b/src/text_editor/event_recording.cpp new file mode 100644 index 0000000..9f0cc7b --- /dev/null +++ b/src/text_editor/event_recording.cpp @@ -0,0 +1,133 @@ +bool EventRecording = false; +bool EventPlaying = false; +AutomationEventList EventList; +Array EventsToPlay; +unsigned int frameCounter; +unsigned int playFrameCounter; +unsigned int currentPlayFrame; + +void InitEventRecording() { + EventList = LoadAutomationEventList(0); + SetAutomationEventList(&EventList); +} + +void StartNextEvent() { + Assert(EventPlaying); + if (EventsToPlay.len > 0) { + AutomationEventList event = EventsToPlay.pop(); + EventList = event; + SetAutomationEventList(&EventList); + } else { + EventPlaying = false; + SetTargetFPS(60); + } + currentPlayFrame = 0; + playFrameCounter = -1; +} + +void UpdateEventRecording() { + if (IsKeyPressed(KEY_F5)) { + if (EventRecording) { + Scratch scratch; + EventRecording = false; + + StopAutomationEventRecording(); + int random_value = GetRandomValue(0, INT_MAX); + String path = Format(scratch, "%d.rae", random_value); + + if (!IsKeyDown(KEY_LEFT_CONTROL)) { + ExportAutomationEventList(EventList, path.data); + } + } else { + SetAutomationEventBaseFrame(0); + StartAutomationEventRecording(); + EventRecording = true; + } + } + + if (IsKeyPressed(KEY_F8)) { + if (!EventPlaying) { + FilePathList list = LoadDirectoryFiles("."); + for (unsigned int i = 0; i < list.count; i += 1) { + String path = list.paths[i]; + if (EndsWith(path, "rae")) { + AutomationEventList rae = LoadAutomationEventList(path.data); + EventsToPlay.add(rae); + } + } + UnloadDirectoryFiles(list); + + EventPlaying = true; + SetTargetFPS(3000); + StartNextEvent(); + } + } + + if (EventPlaying) { + // NOTE: Multiple events could be executed in a single frame + while (playFrameCounter == EventList.events[currentPlayFrame].frame) { + TraceLog(LOG_INFO, "PLAYING: PlayFrameCount: %i | currentPlayFrame: %i | Event Frame: %i, param: %i", + playFrameCounter, currentPlayFrame, EventList.events[currentPlayFrame].frame, EventList.events[currentPlayFrame].params[0]); + + PlayAutomationEvent(EventList.events[currentPlayFrame]); + currentPlayFrame++; + + if (currentPlayFrame == EventList.count) { + StartNextEvent(); + break; + } + } + + playFrameCounter++; + } +} + +void EventRecording_SimulateGetCharPressed(Window *focused_window) { + if (!EventPlaying) return; + Scratch scratch; + for (int i = KEY_A; i <= KEY_Z; i += 1) { + bool press = IsKeyPressed(i) || IsKeyPressedRepeat(i); + if (press) { + String string = "?"; + int offset = 32; + if (IsKeyDown(KEY_LEFT_SHIFT)) offset = 0; + UTF8Result utf8 = UTF32ToUTF8((uint32_t)i + offset); + if (utf8.error == 0) { + string = {(char *)utf8.out_str, (int64_t)utf8.len}; + } + + BeforeEdit(focused_window); + Array edits = {scratch}; + For(focused_window->cursors) { + AddEdit(&edits, it.range, string); + } + ApplyEdits(&focused_window->buffer, edits); + AfterEdit(focused_window, edits); + } + } +} + +void EventRecording_Draw() { + if (EventRecording) Assert(EventPlaying == false); + if (EventPlaying) Assert(EventRecording == false); + Rect2 screen = GetScreenRect(); + Color color = {}; + + Rect2 l = CutLeft(&screen, 4); + Rect2 r = CutRight(&screen, 4); + Rect2 t = CutTop(&screen, 4); + Rect2 b = CutBottom(&screen, 4); + + if (EventPlaying) { + color = BLUE; + } + + if (EventRecording) { + color = RED; + } + + DrawRectangleRec(ToRectangle(l), color); + DrawRectangleRec(ToRectangle(r), color); + DrawRectangleRec(ToRectangle(t), color); + DrawRectangleRec(ToRectangle(b), color); +} \ No newline at end of file diff --git a/src/text_editor/layout.cpp b/src/text_editor/layout.cpp index 7d7b392..a54e82e 100644 --- a/src/text_editor/layout.cpp +++ b/src/text_editor/layout.cpp @@ -239,4 +239,54 @@ Array CalculateVisibleColumns(Arena *arena, Window &window) { } } return r; -} \ No newline at end of file +} + +void BeforeEdit(Window *window) { + // 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 < window->cursors.len; cursor_i += 1) { + Cursor &cursor = window->cursors[cursor_i]; + IterRemove(window->cursors) { + IterRemovePrepare(window->cursors); + if (&cursor == &it) continue; + + if (cursor.range.max >= it.range.min && cursor.range.max <= it.range.max) { + remove_item = true; + cursor.range.max = it.range.max; + break; + } + } + } +} + +void AfterEdit(Window *window, Array edits) { + // Offset all cursors by edits + ForItem(edit, edits) { + int64_t remove_size = GetRangeSize(edit.range); + int64_t insert_size = edit.string.len; + int64_t offset = insert_size - remove_size; + + ForItem(cursor, window->cursors) { + if (edit.range.min == cursor.range.min) { + if (GetRangeSize(edit.range)) { + cursor.range.min += edit.string.len; + } else { + cursor.range.min += offset; + } + cursor.range.max = cursor.range.min; + } else if (edit.range.min <= cursor.range.min) { + if (GetRangeSize(edit.range)) { + cursor.range.min += edit.string.len; + } + cursor.range.min += offset; + cursor.range.max = cursor.range.min; + } + } + } + + // Make sure all cursors are in range + For(window->cursors) it.range = Clamp(window->buffer, it.range); + + Clear(&window->layout_arena); + window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing); +} diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index 8b9ab54..89e1ca1 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -8,96 +8,8 @@ #include "rect2.cpp" #include "buffer.cpp" #include "layout.cpp" - -Rect2 GetScreenRect() { - Rect2 result = { - { 0, 0}, - {(float)GetRenderWidth(), (float)GetRenderHeight()} - }; - return result; -} - -int64_t MoveRight(Buffer &buffer, int64_t pos) { - pos = pos + 1; - pos = AdjustUTF8Pos(buffer, pos); - Assert(pos >= 0 && pos <= buffer.len); - return pos; -} - -int64_t MoveLeft(Buffer &buffer, int64_t pos) { - pos = pos - 1; - pos = AdjustUTF8Pos(buffer, pos, -1); - Assert(pos >= 0 && pos <= buffer.len); - return pos; -} - -// @todo: when at the end of line, it resets to first position on next line -int64_t MoveDown(Buffer &buffer, int64_t pos) { - LineAndColumn info = FindLineAndColumn(buffer, pos); - int64_t new_pos = FindPos(buffer, info.line.number + 1, info.column); - return new_pos; -} - -int64_t MoveUp(Buffer &buffer, int64_t pos) { - LineAndColumn info = FindLineAndColumn(buffer, pos); - int64_t new_pos = FindPos(buffer, info.line.number - 1, info.column); - return new_pos; -} - -bool AreEqual(float a, float b, float epsilon = 0.001f) { - bool result = (a - epsilon < b && a + epsilon > b); - return result; -} - -void BeforeEdit(Window *window) { - // 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 < window->cursors.len; cursor_i += 1) { - Cursor &cursor = window->cursors[cursor_i]; - IterRemove(window->cursors) { - IterRemovePrepare(window->cursors); - if (&cursor == &it) continue; - - if (cursor.range.max >= it.range.min && cursor.range.max <= it.range.max) { - remove_item = true; - cursor.range.max = it.range.max; - break; - } - } - } -} - -void AfterEdit(Window *window, Array edits) { - // Offset all cursors by edits - ForItem(edit, edits) { - int64_t remove_size = GetRangeSize(edit.range); - int64_t insert_size = edit.string.len; - int64_t offset = insert_size - remove_size; - - ForItem(cursor, window->cursors) { - if (edit.range.min == cursor.range.min) { - if (GetRangeSize(edit.range)) { - cursor.range.min += edit.string.len; - } else { - cursor.range.min += offset; - } - cursor.range.max = cursor.range.min; - } else if (edit.range.min <= cursor.range.min) { - if (GetRangeSize(edit.range)) { - cursor.range.min += edit.string.len; - } - cursor.range.min += offset; - cursor.range.max = cursor.range.min; - } - } - } - - // Make sure all cursors are in range - For(window->cursors) it.range = Clamp(window->buffer, it.range); - - Clear(&window->layout_arena); - window->layout = CalculateLayout(&window->layout_arena, window->buffer, window->font, window->font_size, window->font_spacing); -} +#include "utils.cpp" +#include "event_recording.cpp" Arena PermArena; Arena FrameArena; @@ -126,68 +38,6 @@ void Dbg_Draw() { } } -bool EventRecording = false; -bool EventPlaying = false; -AutomationEventList EventList; - -void InitEventRecording() { - EventList = LoadAutomationEventList(0); - SetAutomationEventList(&EventList); - EventList = LoadAutomationEventList("automation.rae"); - EventPlaying = true; -} - -int ModifiedGetCharPressed() { - static int i; - int result = GetCharPressed(); - if (EventPlaying && (i % 2) == 0) { - result = 'a'; - } - i += 1; - - return result; -} - -void UpdateEventRecording() { - static unsigned int frameCounter; - static unsigned int playFrameCounter; - static unsigned int currentPlayFrame; - - if (IsKeyPressed(KEY_F5)) { - if (EventRecording) { - StopAutomationEventRecording(); - ExportAutomationEventList(EventList, "automation.rae"); - EventRecording = false; - } else { - SetAutomationEventBaseFrame(0); - StartAutomationEventRecording(); - EventRecording = true; - } - } - - if (EventPlaying) { - // NOTE: Multiple events could be executed in a single frame - while (playFrameCounter == EventList.events[currentPlayFrame].frame) { - TraceLog(LOG_INFO, "PLAYING: PlayFrameCount: %i | currentPlayFrame: %i | Event Frame: %i, param: %i", - playFrameCounter, currentPlayFrame, EventList.events[currentPlayFrame].frame, EventList.events[currentPlayFrame].params[0]); - - PlayAutomationEvent(EventList.events[currentPlayFrame]); - currentPlayFrame++; - - if (currentPlayFrame == EventList.count) { - EventPlaying = false; - currentPlayFrame = 0; - playFrameCounter = 0; - - TraceLog(LOG_INFO, "FINISH PLAYING!"); - break; - } - } - - playFrameCounter++; - } -} - int main() { InitScratch(); InitWindow(800, 600, "Hello"); @@ -210,7 +60,7 @@ int main() { window.font_spacing; InitArena(&window.layout_arena); - InitBuffer(&window.buffer); + InitBuffer(GetSystemAllocator(), &window.buffer); if (1) { // Array edits = {FrameArena}; // AddEdit(&edits, GetEnd(window.buffer), Format(FrameArena, "line number: 1")); @@ -475,7 +325,7 @@ int main() { } } - if (IsKeyPressed(KEY_ENTER)) { + if (IsKeyPressed(KEY_ENTER) || IsKeyPressedRepeat(KEY_ENTER)) { if (IsKeyDown(KEY_LEFT_CONTROL)) { For(focused_window->cursors) { int64_t front = GetFront(it); @@ -493,7 +343,7 @@ int main() { // Handle user input for (;;) { - int c = ModifiedGetCharPressed(); + int c = GetCharPressed(); if (!c) break; String string = "?"; @@ -510,6 +360,7 @@ int main() { ApplyEdits(&focused_window->buffer, edits); AfterEdit(focused_window, edits); } + EventRecording_SimulateGetCharPressed(focused_window); } BeginDrawing(); @@ -654,6 +505,7 @@ int main() { } Dbg_Draw(); + EventRecording_Draw(); EndDrawing(); } } \ No newline at end of file diff --git a/src/text_editor/utils.cpp b/src/text_editor/utils.cpp new file mode 100644 index 0000000..d91e1c1 --- /dev/null +++ b/src/text_editor/utils.cpp @@ -0,0 +1,12 @@ +Rect2 GetScreenRect() { + Rect2 result = { + { 0, 0}, + {(float)GetRenderWidth(), (float)GetRenderHeight()} + }; + return result; +} + +bool AreEqual(float a, float b, float epsilon = 0.001f) { + bool result = (a - epsilon < b && a + epsilon > b); + return result; +}