From 50a1ca02b1e4301503465bcec620735240414559 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Thu, 6 Jun 2024 16:11:32 +0200 Subject: [PATCH] Text editor: add scroll bar, add mouse selection, cursor move adjustment, load text file --- build.bat | 2 +- build_file.cpp | 6 +- examples/text_editor/main.lc | 142 +++++++++++++++++------------ examples/text_editor/rect2p.lc | 10 ++ examples/text_editor/visual_pos.lc | 1 - 5 files changed, 99 insertions(+), 62 deletions(-) diff --git a/build.bat b/build.bat index c4f0075..d7b0ada 100644 --- a/build.bat +++ b/build.bat @@ -8,4 +8,4 @@ if not exist build\bld.exe ( ) rem ubuntu run ./build.sh -build\bld.exe --quick +build\bld.exe --tests text_editor diff --git a/build_file.cpp b/build_file.cpp index 1c130bd..5264c03 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -166,7 +166,7 @@ int main(int argc, char **argv) { else IO_Printf("%-50s - ERROR\n", "hello_world"); } - if (!ShouldRun("sandbox")) { + if (ShouldRun("sandbox")) { bool result = sandbox(); if (result) IO_Printf("%-50s - OK\n", "sandbox"); else IO_Printf("%-50s - ERROR\n", "sandbox"); @@ -184,8 +184,7 @@ int main(int argc, char **argv) { else IO_Printf("%-50s - ERROR\n", "add_instrumentation"); } -#if 0 - if (!ShouldRun("wasm_playground") && UseClang) { + if (ShouldRun("wasm_playground") && UseClang) { OS_MakeDir("wasm_playground"); int result = Run("clang --target=wasm32 -mbulk-memory -Oz -Wno-writable-strings --no-standard-libraries -Wl,--strip-all -Wl,--import-memory -Wl,--no-entry -o wasm_playground/playground.wasm ../src/wasm_playground/wasm_main.c -DOS_WASM=1"); @@ -213,7 +212,6 @@ int main(int argc, char **argv) { if (result == 0) IO_Printf("%-50s - OK\n", "wasm_playground"); else IO_Printf("%-50s - ERROR\n", "wasm_playground"); } -#endif if (ShouldRun("use_as_data_format_with_typechecking")) { bool result = use_as_data_format_with_typechecking(); diff --git a/examples/text_editor/main.lc b/examples/text_editor/main.lc index 7af6307..2bb9078 100644 --- a/examples/text_editor/main.lc +++ b/examples/text_editor/main.lc @@ -3,6 +3,7 @@ import "std_types"; import "libc"; MainCursor: Selection; +MouseScrolling: bool; Selection :: struct { a: int; @@ -18,7 +19,7 @@ main :: proc(): int { InitWindow(800, 600, "TextEditor"); SetTargetFPS(60); - font_size: float = 35; + font_size: float = 14; font_spacing: float = 1; font: Font = LoadFontEx("C:/Windows/Fonts/consola.ttf", :int(font_size), nil, 0); @@ -27,42 +28,17 @@ main :: proc(): int { Monosize = {:float(glyph_info.image.width), size.y}; buffer: Buffer; - AddText(&buffer, "1Testing and stuff 1Testing and stuff 1Testing and stuff 1Testing and stuff\n"); - AddText(&buffer, "2Testing and stuff\n"); - AddText(&buffer, "3Testing and stuff\n"); - AddText(&buffer, "4Testing and stuff\n"); - AddText(&buffer, "5Testing and stuff\n"); - AddText(&buffer, "6Testing and stuff\n"); - AddText(&buffer, "7Testing and stuff\n"); - AddText(&buffer, "8Testing and stuff\n"); - AddText(&buffer, "9Testing and stuff\n"); - AddText(&buffer, "1Testing and stuff\n"); - AddText(&buffer, "2Testing and stuff\n"); - AddText(&buffer, "3Testing and stuff\n"); - AddText(&buffer, "4Testing and stuff\n"); - AddText(&buffer, "5Testing and stuff\n"); - AddText(&buffer, "6Testing and stuff\n"); - AddText(&buffer, "7Testing and stuff\n"); - AddText(&buffer, "8Testing and stuff\n"); - AddText(&buffer, "9Testing and stuff\n"); - AddText(&buffer, "1Testing and stuff\n"); - AddText(&buffer, "22esting and stuff\n"); - AddText(&buffer, "3Testing and stuff\n"); - AddText(&buffer, "4Testing and stuff\n"); - AddText(&buffer, "5Testing and stuff\n"); - AddText(&buffer, "6Testing and stuff\n"); - AddText(&buffer, "7Testing and stuff\n"); - AddText(&buffer, "8Testing and stuff\n"); - AddText(&buffer, "9Testing and stuff\n"); - AddText(&buffer, "1Testing and stuff\n"); - AddText(&buffer, "2Testing and stuff\n"); - AddText(&buffer, "3Testing and stuff\n"); - AddText(&buffer, "4Testing and stuff\n"); + file_content := LoadFileText("C:/Work/language/examples/text_editor/main.lc"); + AddText(&buffer, {file_content, :int(strlen(file_content))}); + UnloadFileText(file_content); for !WindowShouldClose() { - ScreenSize = {:f32(GetScreenWidth()), :f32(GetScreenHeight())}; initial_cursor: Selection = MainCursor; + screen_size: Vector2 = {:f32(GetScreenWidth()), :f32(GetScreenHeight())}; + screen_rect := Rect2PSize(0, 0, screen_size.x, screen_size.y); + bar := CutRight(&screen_rect, 10); + if IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT) { if IsKeyDown(KEY_LEFT_SHIFT) { if IsKeyDown(KEY_LEFT_CONTROL) { @@ -75,8 +51,14 @@ main :: proc(): int { MainCursor.a = SeekOnWordBoundary(&buffer, MainCursor.a, GO_BACKWARD); MainCursor.b = MainCursor.a; } else { - MainCursor.a = MoveLeft(&buffer, MainCursor.a); - MainCursor.b = MainCursor.a; + range := GetRange(MainCursor); + if GetRangeSize(range) > 0 { + MainCursor.a = MinInt(MainCursor.a, MainCursor.b); + MainCursor.b = MinInt(MainCursor.a, MainCursor.b); + } else { + MainCursor.a = MoveLeft(&buffer, MainCursor.a); + MainCursor.b = MainCursor.a; + } } } } @@ -93,8 +75,14 @@ main :: proc(): int { MainCursor.a = SeekOnWordBoundary(&buffer, MainCursor.a, GO_FORWARD); MainCursor.b = MainCursor.a; } else { - MainCursor.a = MoveRight(&buffer, MainCursor.a); - MainCursor.b = MainCursor.a; + range := GetRange(MainCursor); + if GetRangeSize(range) > 0 { + MainCursor.a = MaxInt(MainCursor.a, MainCursor.b); + MainCursor.b = MaxInt(MainCursor.a, MainCursor.b); + } else { + MainCursor.a = MoveRight(&buffer, MainCursor.a); + MainCursor.b = MainCursor.a; + } } } } @@ -176,6 +164,18 @@ main :: proc(): int { MainCursor.b = MainCursor.a; } + if IsKeyPressed(KEY_TAB) || IsKeyPressedRepeat(KEY_TAB) { + selection_range := GetRange(MainCursor); + ReplaceText(&buffer, selection_range, " "); + range_size := GetRangeSize(selection_range); + if range_size != 0 { + MainCursor.a = selection_range.min; + MainCursor.b = selection_range.min; + } + MainCursor.a = MoveRight(&buffer, MainCursor.a + 3); + MainCursor.b = MainCursor.a; + } + if IsKeyPressed(KEY_HOME) { line := FindLineOfPos(&buffer, MainCursor.b); if IsKeyDown(KEY_LEFT_SHIFT) { @@ -197,7 +197,7 @@ main :: proc(): int { if IsKeyPressed(KEY_PAGE_DOWN) || IsKeyPressedRepeat(KEY_PAGE_DOWN) { vpos := CalculateVisualPos(&buffer, MainCursor.b); - move_by := :int(roundf(ScreenSize.y / Monosize.y)); + move_by := :int(roundf(GetRectY(screen_rect) / Monosize.y)); vpos.y += move_by; MainCursor.b = CalculatePosFromVisualPos(&buffer, vpos); if !IsKeyDown(KEY_LEFT_SHIFT) { @@ -206,7 +206,7 @@ main :: proc(): int { } if IsKeyPressed(KEY_PAGE_UP) || IsKeyPressedRepeat(KEY_PAGE_UP) { vpos := CalculateVisualPos(&buffer, MainCursor.b); - move_by := :int(roundf(ScreenSize.y / Monosize.y)); + move_by := :int(roundf(GetRectY(screen_rect) / Monosize.y)); vpos.y -= move_by; MainCursor.b = CalculatePosFromVisualPos(&buffer, vpos); if !IsKeyDown(KEY_LEFT_SHIFT) { @@ -214,20 +214,39 @@ main :: proc(): int { } } - mouse_p := GetMousePosition(); - if IsMouseButtonDown(MOUSE_BUTTON_LEFT) { - p := Vector2Add(mouse_p, Scroll); - p = Vector2Divide(p, Monosize); - x := :int(floorf(p.x)); - y := :int(floorf(p.y)); - MainCursor.a = CalculatePosFromVisualPos(&buffer, {x, y}); - MainCursor.b = MainCursor.a; - } + buffer_end_vpos := CalculateVisualPos(&buffer, buffer.len - 1); + buffer_end_wpos := CalculateWorldPosUnscrolled(buffer_end_vpos); - if CheckCollisionPointRec(mouse_p, {0, 0, ScreenSize.x, ScreenSize.y}) { + mouse_p := GetMousePosition(); + if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(screen_rect)) && !MouseScrolling { + if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) { + p := Vector2Add(mouse_p, Scroll); + p = Vector2Divide(p, Monosize); + x := :int(floorf(p.x)); + y := :int(floorf(p.y)); + MainCursor.a = CalculatePosFromVisualPos(&buffer, {x, y}); + MainCursor.b = MainCursor.a; + } else if IsMouseButtonDown(MOUSE_BUTTON_LEFT) { + p := Vector2Add(mouse_p, Scroll); + p = Vector2Divide(p, Monosize); + x := :int(floorf(p.x)); + y := :int(floorf(p.y)); + MainCursor.b = CalculatePosFromVisualPos(&buffer, {x, y}); + } SetMouseCursor(MOUSE_CURSOR_IBEAM); } else { SetMouseCursor(MOUSE_CURSOR_DEFAULT); + + if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) { + MouseScrolling = true; + } + } + + if MouseScrolling { + mouse_scroll_marker_normalized := mouse_p.y / GetRectY(screen_rect); + Scroll.y = mouse_scroll_marker_normalized * buffer_end_wpos.y; + + if IsMouseButtonReleased(MOUSE_BUTTON_LEFT) MouseScrolling = false; } for key := GetCharPressed(); key; key = GetCharPressed() { @@ -252,7 +271,7 @@ main :: proc(): int { // // Scrolling // - mouse_wheel := GetMouseWheelMove() * 16; + mouse_wheel := GetMouseWheelMove() * 48; Scroll.y -= mouse_wheel; if initial_cursor.b != MainCursor.b { @@ -262,7 +281,7 @@ main :: proc(): int { world_pos_cursor_end := Vector2Add(world_pos, Monosize); scrolled_begin := Scroll; - scrolled_end := Vector2Add(Scroll, ScreenSize); + scrolled_end := Vector2Add(Scroll, GetRectSize(screen_rect)); if world_pos_cursor_end.x > scrolled_end.x { Scroll.x += world_pos_cursor_end.x - scrolled_end.x; @@ -279,17 +298,17 @@ main :: proc(): int { } if (Scroll.x < 0) Scroll.x = 0; if (Scroll.y < 0) Scroll.y = 0; - - + if (Scroll.y > buffer_end_wpos.y) Scroll.y = buffer_end_wpos.y; BeginDrawing(); ClearBackground(RAYWHITE); + buffer_pixel_size := GetRectSize(screen_rect); _miny := Scroll.y / Monosize.y; - _maxy := (Scroll.y + ScreenSize.y) / Monosize.y; + _maxy := (Scroll.y + buffer_pixel_size.y) / Monosize.y; _minx := Scroll.x / Monosize.x; - _maxx := (Scroll.x + ScreenSize.x) / Monosize.x; + _maxx := (Scroll.x + buffer_pixel_size.x) / Monosize.x; miny := :int(floorf(_miny)); minx := :int(floorf(_minx)); @@ -298,7 +317,7 @@ main :: proc(): int { maxx := :int(ceilf(_maxx)); // Draw grid - { + if 0 { for y := miny; y < maxy; y += 1 { for x := minx; x < maxx; x += 1 { p := CalculateWorldPos({x, y}); @@ -354,6 +373,17 @@ main :: proc(): int { DrawRect(rect, RED); } + // Draw bar + { + DrawRect(bar, LIGHTGRAY); + + scroll_start_normalized := :f32(Scroll.y) / :f32(buffer_end_wpos.y); + scroll_start := scroll_start_normalized * GetRectSize(bar).y; + CutTop(&bar, scroll_start); + marker := CutTop(&bar, 20); + DrawRect(marker, GRAY); + } + EndDrawing(); } diff --git a/examples/text_editor/rect2p.lc b/examples/text_editor/rect2p.lc index ed3df06..52ba302 100644 --- a/examples/text_editor/rect2p.lc +++ b/examples/text_editor/rect2p.lc @@ -24,6 +24,16 @@ GetRectSize :: proc(rect: Rect2P): Vector2 { return result; } +GetRectY :: proc(rect: Rect2P): f32 { + result := GetRectSize(rect); + return result.y; +} + +GetRectX :: proc(rect: Rect2P): f32 { + result := GetRectSize(rect); + return result.x; +} + CutLeft :: proc(r: *Rect2P, value: f32): Rect2P { minx := r.min.x; r.min.x = F32_Min(r.max.x, r.min.x + value); diff --git a/examples/text_editor/visual_pos.lc b/examples/text_editor/visual_pos.lc index 88bbb9a..b73f33d 100644 --- a/examples/text_editor/visual_pos.lc +++ b/examples/text_editor/visual_pos.lc @@ -1,5 +1,4 @@ Monosize: Vector2; -ScreenSize: Vector2; Scroll: Vector2; Vec2I :: struct {