Text editor: add scroll bar, add mouse selection, cursor move adjustment, load text file
This commit is contained in:
@@ -8,4 +8,4 @@ if not exist build\bld.exe (
|
|||||||
)
|
)
|
||||||
|
|
||||||
rem ubuntu run ./build.sh
|
rem ubuntu run ./build.sh
|
||||||
build\bld.exe --quick
|
build\bld.exe --tests text_editor
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ int main(int argc, char **argv) {
|
|||||||
else IO_Printf("%-50s - ERROR\n", "hello_world");
|
else IO_Printf("%-50s - ERROR\n", "hello_world");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ShouldRun("sandbox")) {
|
if (ShouldRun("sandbox")) {
|
||||||
bool result = sandbox();
|
bool result = sandbox();
|
||||||
if (result) IO_Printf("%-50s - OK\n", "sandbox");
|
if (result) IO_Printf("%-50s - OK\n", "sandbox");
|
||||||
else IO_Printf("%-50s - ERROR\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");
|
else IO_Printf("%-50s - ERROR\n", "add_instrumentation");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (ShouldRun("wasm_playground") && UseClang) {
|
||||||
if (!ShouldRun("wasm_playground") && UseClang) {
|
|
||||||
OS_MakeDir("wasm_playground");
|
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");
|
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");
|
if (result == 0) IO_Printf("%-50s - OK\n", "wasm_playground");
|
||||||
else IO_Printf("%-50s - ERROR\n", "wasm_playground");
|
else IO_Printf("%-50s - ERROR\n", "wasm_playground");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ShouldRun("use_as_data_format_with_typechecking")) {
|
if (ShouldRun("use_as_data_format_with_typechecking")) {
|
||||||
bool result = use_as_data_format_with_typechecking();
|
bool result = use_as_data_format_with_typechecking();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import "std_types";
|
|||||||
import "libc";
|
import "libc";
|
||||||
|
|
||||||
MainCursor: Selection;
|
MainCursor: Selection;
|
||||||
|
MouseScrolling: bool;
|
||||||
|
|
||||||
Selection :: struct {
|
Selection :: struct {
|
||||||
a: int;
|
a: int;
|
||||||
@@ -18,7 +19,7 @@ main :: proc(): int {
|
|||||||
InitWindow(800, 600, "TextEditor");
|
InitWindow(800, 600, "TextEditor");
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
|
|
||||||
font_size: float = 35;
|
font_size: float = 14;
|
||||||
font_spacing: float = 1;
|
font_spacing: float = 1;
|
||||||
font: Font = LoadFontEx("C:/Windows/Fonts/consola.ttf", :int(font_size), nil, 0);
|
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};
|
Monosize = {:float(glyph_info.image.width), size.y};
|
||||||
|
|
||||||
buffer: Buffer;
|
buffer: Buffer;
|
||||||
AddText(&buffer, "1Testing and stuff 1Testing and stuff 1Testing and stuff 1Testing and stuff\n");
|
file_content := LoadFileText("C:/Work/language/examples/text_editor/main.lc");
|
||||||
AddText(&buffer, "2Testing and stuff\n");
|
AddText(&buffer, {file_content, :int(strlen(file_content))});
|
||||||
AddText(&buffer, "3Testing and stuff\n");
|
UnloadFileText(file_content);
|
||||||
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");
|
|
||||||
|
|
||||||
for !WindowShouldClose() {
|
for !WindowShouldClose() {
|
||||||
ScreenSize = {:f32(GetScreenWidth()), :f32(GetScreenHeight())};
|
|
||||||
initial_cursor: Selection = MainCursor;
|
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 IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT) {
|
||||||
if IsKeyDown(KEY_LEFT_SHIFT) {
|
if IsKeyDown(KEY_LEFT_SHIFT) {
|
||||||
if IsKeyDown(KEY_LEFT_CONTROL) {
|
if IsKeyDown(KEY_LEFT_CONTROL) {
|
||||||
@@ -74,12 +50,18 @@ main :: proc(): int {
|
|||||||
if IsKeyDown(KEY_LEFT_CONTROL) {
|
if IsKeyDown(KEY_LEFT_CONTROL) {
|
||||||
MainCursor.a = SeekOnWordBoundary(&buffer, MainCursor.a, GO_BACKWARD);
|
MainCursor.a = SeekOnWordBoundary(&buffer, MainCursor.a, GO_BACKWARD);
|
||||||
MainCursor.b = MainCursor.a;
|
MainCursor.b = MainCursor.a;
|
||||||
|
} else {
|
||||||
|
range := GetRange(MainCursor);
|
||||||
|
if GetRangeSize(range) > 0 {
|
||||||
|
MainCursor.a = MinInt(MainCursor.a, MainCursor.b);
|
||||||
|
MainCursor.b = MinInt(MainCursor.a, MainCursor.b);
|
||||||
} else {
|
} else {
|
||||||
MainCursor.a = MoveLeft(&buffer, MainCursor.a);
|
MainCursor.a = MoveLeft(&buffer, MainCursor.a);
|
||||||
MainCursor.b = MainCursor.a;
|
MainCursor.b = MainCursor.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if IsKeyPressed(KEY_RIGHT) || IsKeyPressedRepeat(KEY_RIGHT) {
|
if IsKeyPressed(KEY_RIGHT) || IsKeyPressedRepeat(KEY_RIGHT) {
|
||||||
if IsKeyDown(KEY_LEFT_SHIFT) {
|
if IsKeyDown(KEY_LEFT_SHIFT) {
|
||||||
@@ -92,12 +74,18 @@ main :: proc(): int {
|
|||||||
if IsKeyDown(KEY_LEFT_CONTROL) {
|
if IsKeyDown(KEY_LEFT_CONTROL) {
|
||||||
MainCursor.a = SeekOnWordBoundary(&buffer, MainCursor.a, GO_FORWARD);
|
MainCursor.a = SeekOnWordBoundary(&buffer, MainCursor.a, GO_FORWARD);
|
||||||
MainCursor.b = MainCursor.a;
|
MainCursor.b = MainCursor.a;
|
||||||
|
} else {
|
||||||
|
range := GetRange(MainCursor);
|
||||||
|
if GetRangeSize(range) > 0 {
|
||||||
|
MainCursor.a = MaxInt(MainCursor.a, MainCursor.b);
|
||||||
|
MainCursor.b = MaxInt(MainCursor.a, MainCursor.b);
|
||||||
} else {
|
} else {
|
||||||
MainCursor.a = MoveRight(&buffer, MainCursor.a);
|
MainCursor.a = MoveRight(&buffer, MainCursor.a);
|
||||||
MainCursor.b = MainCursor.a;
|
MainCursor.b = MainCursor.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) {
|
if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) {
|
||||||
if IsKeyDown(KEY_LEFT_SHIFT) {
|
if IsKeyDown(KEY_LEFT_SHIFT) {
|
||||||
@@ -176,6 +164,18 @@ main :: proc(): int {
|
|||||||
MainCursor.b = MainCursor.a;
|
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) {
|
if IsKeyPressed(KEY_HOME) {
|
||||||
line := FindLineOfPos(&buffer, MainCursor.b);
|
line := FindLineOfPos(&buffer, MainCursor.b);
|
||||||
if IsKeyDown(KEY_LEFT_SHIFT) {
|
if IsKeyDown(KEY_LEFT_SHIFT) {
|
||||||
@@ -197,7 +197,7 @@ main :: proc(): int {
|
|||||||
|
|
||||||
if IsKeyPressed(KEY_PAGE_DOWN) || IsKeyPressedRepeat(KEY_PAGE_DOWN) {
|
if IsKeyPressed(KEY_PAGE_DOWN) || IsKeyPressedRepeat(KEY_PAGE_DOWN) {
|
||||||
vpos := CalculateVisualPos(&buffer, MainCursor.b);
|
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;
|
vpos.y += move_by;
|
||||||
MainCursor.b = CalculatePosFromVisualPos(&buffer, vpos);
|
MainCursor.b = CalculatePosFromVisualPos(&buffer, vpos);
|
||||||
if !IsKeyDown(KEY_LEFT_SHIFT) {
|
if !IsKeyDown(KEY_LEFT_SHIFT) {
|
||||||
@@ -206,7 +206,7 @@ main :: proc(): int {
|
|||||||
}
|
}
|
||||||
if IsKeyPressed(KEY_PAGE_UP) || IsKeyPressedRepeat(KEY_PAGE_UP) {
|
if IsKeyPressed(KEY_PAGE_UP) || IsKeyPressedRepeat(KEY_PAGE_UP) {
|
||||||
vpos := CalculateVisualPos(&buffer, MainCursor.b);
|
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;
|
vpos.y -= move_by;
|
||||||
MainCursor.b = CalculatePosFromVisualPos(&buffer, vpos);
|
MainCursor.b = CalculatePosFromVisualPos(&buffer, vpos);
|
||||||
if !IsKeyDown(KEY_LEFT_SHIFT) {
|
if !IsKeyDown(KEY_LEFT_SHIFT) {
|
||||||
@@ -214,20 +214,39 @@ main :: proc(): int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer_end_vpos := CalculateVisualPos(&buffer, buffer.len - 1);
|
||||||
|
buffer_end_wpos := CalculateWorldPosUnscrolled(buffer_end_vpos);
|
||||||
|
|
||||||
mouse_p := GetMousePosition();
|
mouse_p := GetMousePosition();
|
||||||
if IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
|
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(screen_rect)) && !MouseScrolling {
|
||||||
|
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
||||||
p := Vector2Add(mouse_p, Scroll);
|
p := Vector2Add(mouse_p, Scroll);
|
||||||
p = Vector2Divide(p, Monosize);
|
p = Vector2Divide(p, Monosize);
|
||||||
x := :int(floorf(p.x));
|
x := :int(floorf(p.x));
|
||||||
y := :int(floorf(p.y));
|
y := :int(floorf(p.y));
|
||||||
MainCursor.a = CalculatePosFromVisualPos(&buffer, {x, y});
|
MainCursor.a = CalculatePosFromVisualPos(&buffer, {x, y});
|
||||||
MainCursor.b = MainCursor.a;
|
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});
|
||||||
}
|
}
|
||||||
|
|
||||||
if CheckCollisionPointRec(mouse_p, {0, 0, ScreenSize.x, ScreenSize.y}) {
|
|
||||||
SetMouseCursor(MOUSE_CURSOR_IBEAM);
|
SetMouseCursor(MOUSE_CURSOR_IBEAM);
|
||||||
} else {
|
} else {
|
||||||
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
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() {
|
for key := GetCharPressed(); key; key = GetCharPressed() {
|
||||||
@@ -252,7 +271,7 @@ main :: proc(): int {
|
|||||||
//
|
//
|
||||||
// Scrolling
|
// Scrolling
|
||||||
//
|
//
|
||||||
mouse_wheel := GetMouseWheelMove() * 16;
|
mouse_wheel := GetMouseWheelMove() * 48;
|
||||||
Scroll.y -= mouse_wheel;
|
Scroll.y -= mouse_wheel;
|
||||||
|
|
||||||
if initial_cursor.b != MainCursor.b {
|
if initial_cursor.b != MainCursor.b {
|
||||||
@@ -262,7 +281,7 @@ main :: proc(): int {
|
|||||||
world_pos_cursor_end := Vector2Add(world_pos, Monosize);
|
world_pos_cursor_end := Vector2Add(world_pos, Monosize);
|
||||||
|
|
||||||
scrolled_begin := Scroll;
|
scrolled_begin := Scroll;
|
||||||
scrolled_end := Vector2Add(Scroll, ScreenSize);
|
scrolled_end := Vector2Add(Scroll, GetRectSize(screen_rect));
|
||||||
|
|
||||||
if world_pos_cursor_end.x > scrolled_end.x {
|
if world_pos_cursor_end.x > scrolled_end.x {
|
||||||
Scroll.x += 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.x < 0) Scroll.x = 0;
|
||||||
if (Scroll.y < 0) Scroll.y = 0;
|
if (Scroll.y < 0) Scroll.y = 0;
|
||||||
|
if (Scroll.y > buffer_end_wpos.y) Scroll.y = buffer_end_wpos.y;
|
||||||
|
|
||||||
|
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
|
buffer_pixel_size := GetRectSize(screen_rect);
|
||||||
_miny := Scroll.y / Monosize.y;
|
_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;
|
_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));
|
miny := :int(floorf(_miny));
|
||||||
minx := :int(floorf(_minx));
|
minx := :int(floorf(_minx));
|
||||||
@@ -298,7 +317,7 @@ main :: proc(): int {
|
|||||||
maxx := :int(ceilf(_maxx));
|
maxx := :int(ceilf(_maxx));
|
||||||
|
|
||||||
// Draw grid
|
// Draw grid
|
||||||
{
|
if 0 {
|
||||||
for y := miny; y < maxy; y += 1 {
|
for y := miny; y < maxy; y += 1 {
|
||||||
for x := minx; x < maxx; x += 1 {
|
for x := minx; x < maxx; x += 1 {
|
||||||
p := CalculateWorldPos({x, y});
|
p := CalculateWorldPos({x, y});
|
||||||
@@ -354,6 +373,17 @@ main :: proc(): int {
|
|||||||
DrawRect(rect, RED);
|
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();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ GetRectSize :: proc(rect: Rect2P): Vector2 {
|
|||||||
return result;
|
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 {
|
CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||||
minx := r.min.x;
|
minx := r.min.x;
|
||||||
r.min.x = F32_Min(r.max.x, r.min.x + value);
|
r.min.x = F32_Min(r.max.x, r.min.x + value);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
Monosize: Vector2;
|
Monosize: Vector2;
|
||||||
ScreenSize: Vector2;
|
|
||||||
Scroll: Vector2;
|
Scroll: Vector2;
|
||||||
|
|
||||||
Vec2I :: struct {
|
Vec2I :: struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user