Toying with event recording to see if it can be used for testing
This commit is contained in:
@@ -227,6 +227,9 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
|
||||
|
||||
void ApplyEdits(Buffer *buffer, Array<Edit> 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<Edit> 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<Edit> 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;
|
||||
}
|
||||
133
src/text_editor/event_recording.cpp
Normal file
133
src/text_editor/event_recording.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
bool EventRecording = false;
|
||||
bool EventPlaying = false;
|
||||
AutomationEventList EventList;
|
||||
Array<AutomationEventList> 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<Edit> 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);
|
||||
}
|
||||
@@ -239,4 +239,54 @@ Array<LayoutColumn> CalculateVisibleColumns(Arena *arena, Window &window) {
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
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<Edit> 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);
|
||||
}
|
||||
|
||||
@@ -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<Edit> 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<Edit> 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();
|
||||
}
|
||||
}
|
||||
12
src/text_editor/utils.cpp
Normal file
12
src/text_editor/utils.cpp
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user