Mouse scrolling, BUFFER_DEBUG, todo list
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation
|
https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation
|
||||||
*/
|
*/
|
||||||
|
#define BUFFER_DEBUG 0
|
||||||
|
|
||||||
void InitBuffer(Allocator allocator, Buffer *buffer) {
|
void InitBuffer(Allocator allocator, Buffer *buffer) {
|
||||||
buffer->cap = 4096;
|
buffer->cap = 4096;
|
||||||
@@ -125,15 +126,6 @@ Int XYToPosWithoutNL(Buffer &buffer, XY xy) {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidateLineStarts(Buffer *buffer) {
|
|
||||||
Int line = 0;
|
|
||||||
for (Int i = 0; i < buffer->len; i += 1) {
|
|
||||||
Int l = PosToLine(*buffer, i);
|
|
||||||
Assert(l == line);
|
|
||||||
if (buffer->data[i] == L'\n') line += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateLines(Buffer *buffer, Range range, String16 string) {
|
void UpdateLines(Buffer *buffer, Range range, String16 string) {
|
||||||
Array<Int> &ls = buffer->line_starts;
|
Array<Int> &ls = buffer->line_starts;
|
||||||
Int min_line_number = PosToLine(*buffer, range.min);
|
Int min_line_number = PosToLine(*buffer, range.min);
|
||||||
@@ -175,6 +167,15 @@ void UpdateLines(Buffer *buffer, Range range, String16 string) {
|
|||||||
OffsetAllLinesForward(buffer, nl, &line_offset);
|
OffsetAllLinesForward(buffer, nl, &line_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValidateLineStarts(Buffer *buffer) {
|
||||||
|
Int line = 0;
|
||||||
|
for (Int i = 0; i < buffer->len; i += 1) {
|
||||||
|
Int l = PosToLine(*buffer, i);
|
||||||
|
Assert(l == line);
|
||||||
|
if (buffer->data[i] == L'\n') line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ReplaceText(Buffer *buffer, Range range, String16 string) {
|
void ReplaceText(Buffer *buffer, Range range, String16 string) {
|
||||||
Assert(range.max >= range.min);
|
Assert(range.max >= range.min);
|
||||||
Assert(range.max >= 0 && range.max <= buffer->len);
|
Assert(range.max >= 0 && range.max <= buffer->len);
|
||||||
@@ -199,7 +200,9 @@ void ReplaceText(Buffer *buffer, Range range, String16 string) {
|
|||||||
MemoryCopy(begin_add, string.data, string.len * sizeof(U16));
|
MemoryCopy(begin_add, string.data, string.len * sizeof(U16));
|
||||||
buffer->len = buffer->len + change_size;
|
buffer->len = buffer->len + change_size;
|
||||||
|
|
||||||
|
#if BUFFER_DEBUG
|
||||||
ValidateLineStarts(buffer);
|
ValidateLineStarts(buffer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestBuffer() {
|
void TestBuffer() {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
||||||
#if DEBUG_BUILD
|
#if BUFFER_DEBUG
|
||||||
Assert(buffer->line_starts.len);
|
Assert(buffer->line_starts.len);
|
||||||
Assert(edits.len);
|
Assert(edits.len);
|
||||||
For(edits) {
|
For(edits) {
|
||||||
@@ -119,7 +119,7 @@ void ApplyEdits(Buffer *buffer, Array<Edit> edits) {
|
|||||||
edits = edits_copy;
|
edits = edits_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_BUILD
|
#if BUFFER_DEBUG
|
||||||
for (int64_t i = 0; i < edits.len - 1; i += 1) {
|
for (int64_t i = 0; i < edits.len - 1; i += 1) {
|
||||||
Assert(edits[i].range.min <= edits[i + 1].range.min);
|
Assert(edits[i].range.min <= edits[i + 1].range.min);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,27 @@
|
|||||||
#include "view.cpp"
|
#include "view.cpp"
|
||||||
#include "view_draw.cpp"
|
#include "view_draw.cpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
- Ctrl + Z, Ctrl + C - Undo redo history
|
||||||
|
- Ctrl + D - create new cursor at next occurence of word
|
||||||
|
- Ctrl + X, Ctrl + C, Ctrl + V - Copy paste
|
||||||
|
- Ctrl + Alt + Down - duplicate line down
|
||||||
|
- Shify + Alt + Down - make a cursor below
|
||||||
|
- Backspace, Delete, Enter
|
||||||
|
- Mouse anchor point and double click
|
||||||
|
- Mouse cursor changes
|
||||||
|
- Mouse scrolling
|
||||||
|
- Line highlight
|
||||||
|
- Color new lines and end of buffer
|
||||||
|
- Scrollbars
|
||||||
|
- Line numbers
|
||||||
|
- Test big files!!
|
||||||
|
- Colored strings
|
||||||
|
|
||||||
|
- multiple windows
|
||||||
|
- multiple views per window
|
||||||
|
*/
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
InitScratch();
|
InitScratch();
|
||||||
Test();
|
Test();
|
||||||
@@ -51,9 +72,9 @@ int main(void) {
|
|||||||
view.buffer = CreateBuffer(Perm);
|
view.buffer = CreateBuffer(Perm);
|
||||||
{
|
{
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
for (int i = 0; i < 150; i += 1) {
|
for (int i = 0; i < 15000; i += 1) {
|
||||||
// String s = Format(scratch, "line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d\n", i, i, i, i, i, i, i, i, i, i, i, i);
|
String s = Format(scratch, "line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d line1: %d line2: %d line3: %d line4: %d line5: %d line6: %d\n", i, i, i, i, i, i, i, i, i, i, i, i);
|
||||||
String s = Format(scratch, "line %d\n", i);
|
// String s = Format(scratch, "line %d\n", i);
|
||||||
String16 s16 = ToString16(scratch, s);
|
String16 s16 = ToString16(scratch, s);
|
||||||
ReplaceText(view.buffer, GetEndAsRange(*view.buffer), s16);
|
ReplaceText(view.buffer, GetEndAsRange(*view.buffer), s16);
|
||||||
// ReplaceText(view.buffer, GetEndAsRange(*view.buffer), L" \n");
|
// ReplaceText(view.buffer, GetEndAsRange(*view.buffer), L" \n");
|
||||||
|
|||||||
@@ -174,7 +174,12 @@ void HandleKeybindings(View *_view) {
|
|||||||
Int new_front = MoveCaret(buf, front, i, IsKeyDown(KEY_LEFT_CONTROL));
|
Int new_front = MoveCaret(buf, front, i, IsKeyDown(KEY_LEFT_CONTROL));
|
||||||
it = ChangeFront(it, new_front);
|
it = ChangeFront(it, new_front);
|
||||||
} else {
|
} else {
|
||||||
it.range.max = it.range.min = MoveCaret(buf, it.range.max, i, IsKeyDown(KEY_LEFT_CONTROL));
|
Int p = keys[i] == KEY_RIGHT || keys[i] == KEY_DOWN ? it.range.max : it.range.min;
|
||||||
|
if (GetSize(it.range) == 0) {
|
||||||
|
it = MakeCaret(MoveCaret(buf, p, i, IsKeyDown(KEY_LEFT_CONTROL)));
|
||||||
|
} else {
|
||||||
|
it = MakeCaret(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,6 +234,34 @@ void HandleKeybindings(View *_view) {
|
|||||||
AfterEdit(&view, edits);
|
AfterEdit(&view, edits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Vec2 mouse = GetMousePosition();
|
||||||
|
bool mouse_in_view = CheckCollisionPointRec(mouse, ToRectangle(view.rect));
|
||||||
|
|
||||||
|
Vec2 mworld = mouse - view.rect.min + view.scroll;
|
||||||
|
Vec2 pos = mworld / Vec2{view.char_spacing, view.line_spacing};
|
||||||
|
XY xy = {(Int)(pos.x), (Int)(pos.y)};
|
||||||
|
Int p = XYToPosWithoutNL(buf, xy);
|
||||||
|
|
||||||
|
if (mouse_in_view && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
||||||
|
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
||||||
|
if (!IsKeyDown(KEY_LEFT_CONTROL)) {
|
||||||
|
view.carets.len = 0;
|
||||||
|
}
|
||||||
|
Add(&view.carets, MakeCaret(p, p));
|
||||||
|
} else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
||||||
|
view.mouse_selecting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.mouse_selecting) {
|
||||||
|
if (!IsMouseButtonDown(MOUSE_BUTTON_LEFT)) view.mouse_selecting = false;
|
||||||
|
Caret &caret = *GetLast(view.carets);
|
||||||
|
caret = ChangeFront(caret, p);
|
||||||
|
MergeCarets(&view.carets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scrolling with caret
|
// Scrolling with caret
|
||||||
// @refactor: this should happen after we calculate rect for the view
|
// @refactor: this should happen after we calculate rect for the view
|
||||||
// Usually in other text editors apart from view there is also a 'window'
|
// Usually in other text editors apart from view there is also a 'window'
|
||||||
@@ -274,31 +307,4 @@ void HandleKeybindings(View *_view) {
|
|||||||
Int line_chars = GetCharCountOfLongestLine(view.buffer[0]);
|
Int line_chars = GetCharCountOfLongestLine(view.buffer[0]);
|
||||||
view.scroll.x = Clamp(view.scroll.x, 0.f, Max(0.f, (line_chars - 2) * view.char_spacing));
|
view.scroll.x = Clamp(view.scroll.x, 0.f, Max(0.f, (line_chars - 2) * view.char_spacing));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
Vec2 mouse = GetMousePosition();
|
|
||||||
bool mouse_in_view = CheckCollisionPointRec(mouse, ToRectangle(view.rect));
|
|
||||||
if (mouse_in_view && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
|
||||||
Vec2 mworld = mouse - view.rect.min + view.scroll;
|
|
||||||
Vec2 pos = mworld / Vec2{view.char_spacing, view.line_spacing};
|
|
||||||
XY xy = {(Int)(pos.x), (Int)(pos.y)};
|
|
||||||
Int p = XYToPosWithoutNL(buf, xy);
|
|
||||||
|
|
||||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
|
||||||
if (!IsKeyDown(KEY_LEFT_CONTROL)) {
|
|
||||||
view.carets.len = 0;
|
|
||||||
}
|
|
||||||
Add(&view.carets, MakeCaret(p, p));
|
|
||||||
} else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
|
||||||
view.mouse_selecting = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view.mouse_selecting) {
|
|
||||||
if (!IsMouseButtonDown(MOUSE_BUTTON_LEFT)) view.mouse_selecting = false;
|
|
||||||
Caret &caret = *GetLast(view.carets);
|
|
||||||
caret = ChangeFront(caret, p);
|
|
||||||
}
|
|
||||||
MergeCarets(&view.carets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user