Drawing the cursor and cell setup

This commit is contained in:
Krzosa Karol
2024-06-22 14:48:32 +02:00
parent 443e88b4a9
commit 7b818c5cde
3 changed files with 162 additions and 37 deletions

View File

@@ -1,3 +1,11 @@
/* @todo: I guess I'm overcomplicating a little:
https://github.com/Mango0x45/cbs/
Seems like you only need to compare timestamps of all files with the artifact timestamp,
if one of the files is newer then the artifact then it needs to be recompiled. Do we
even need to store anything then? Just supply artifact file in code and that's it?
*/
#define SRC_CACHE_ENTRY_COUNT 1024 #define SRC_CACHE_ENTRY_COUNT 1024
struct SRC_CacheEntry { struct SRC_CacheEntry {

View File

@@ -4,25 +4,10 @@
#include "raymath.h" #include "raymath.h"
#include "buffer.cpp" #include "buffer.cpp"
#include "rect2.cpp"
Arena FrameArena; Arena FrameArena;
using Vec2 = Vector2;
struct Rect2 {
Vec2 min;
Vec2 max;
};
Vec2 GetSize(Rect2 r) {
Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
Rectangle ToRectangle(Rect2 r) {
Rectangle result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
// Render units - positions ready to draw, y // Render units - positions ready to draw, y
// World units - positions offset by screen movement // World units - positions offset by screen movement
// Window units - positions inside the window (starts in left top of window) // Window units - positions inside the window (starts in left top of window)
@@ -59,8 +44,6 @@ Rect2 GetScreenRectRenderUnits() {
return result; return result;
} }
// Draw text using Font
// NOTE: chars spacing is NOT proportional to fontSize
void DrawString(Font font, String text, Vector2 position, float fontSize, float spacing, Color tint) { void DrawString(Font font, String text, Vector2 position, float fontSize, float spacing, Color tint) {
if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font
@@ -100,13 +83,16 @@ int main() {
Array<Window> windows = {}; Array<Window> windows = {};
windows.add({GetScreenRectRenderUnits()}); windows.add({GetScreenRectRenderUnits()});
{ {
Buffer *buffer = &windows[0].buffer; Window *window = &windows[0];
Buffer *buffer = &window->buffer;
InitBuffer(buffer); InitBuffer(buffer);
for (int i = 0; i < 100; i += 1) { for (int i = 0; i < 100; i += 1) {
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
AddEdit(&edits, GetEnd(*buffer), Format(FrameArena, "line number: %d\n", i)); AddEdit(&edits, GetEnd(*buffer), Format(FrameArena, "line number: %d\n", i));
ApplyEdits(buffer, edits); ApplyEdits(buffer, edits);
} }
window->cursors.add({});
} }
Vec2 camera_offset_world_to_render_units = {}; Vec2 camera_offset_world_to_render_units = {};
@@ -130,15 +116,22 @@ int main() {
} }
Array<Edit> edits = {FrameArena}; Array<Edit> edits = {FrameArena};
AddEdit(&edits, {}, string); For(focused_window->cursors) {
AddEdit(&edits, it, string);
}
ApplyEdits(&focused_window->buffer, edits); ApplyEdits(&focused_window->buffer, edits);
} }
if (IsKeyPressed(KEY_F1)) {
font = LoadFontEx("C:/Windows/Fonts/consola.ttf", (int)font_size, NULL, 250);
}
} }
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
ForItem(window, windows) { ForItem(window, windows) {
// Draw the frame
Rect2 window_rect_in_render_units = { Rect2 window_rect_in_render_units = {
WorldToRenderUnits(window.rect_in_world_units.min, camera_offset_world_to_render_units), WorldToRenderUnits(window.rect_in_world_units.min, camera_offset_world_to_render_units),
WorldToRenderUnits(window.rect_in_world_units.max, camera_offset_world_to_render_units), WorldToRenderUnits(window.rect_in_world_units.max, camera_offset_world_to_render_units),
@@ -146,11 +139,18 @@ int main() {
Rectangle rectangle_in_render_units = ToRectangle(window_rect_in_render_units); Rectangle rectangle_in_render_units = ToRectangle(window_rect_in_render_units);
DrawRectangleRec(rectangle_in_render_units, WHITE); DrawRectangleRec(rectangle_in_render_units, WHITE);
// Rect2 screen_rect_in_render_units = GetScreenRectRenderUnits();
// Line rendering Rect2 window_rect_in_render_units_clamped_to_screen = window_rect_in_render_units;
// window_rect_in_render_units_clamped_to_screen.min.x = Clamp(window_rect_in_render_units_clamped_to_screen.min.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x);
// @todo: how to constrain x? window_rect_in_render_units_clamped_to_screen.max.x = Clamp(window_rect_in_render_units_clamped_to_screen.max.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x);
// @optimize: I could clip to visible on screen window_rectangle but I couldn't get it right window_rect_in_render_units_clamped_to_screen.min.y = Clamp(window_rect_in_render_units_clamped_to_screen.min.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y);
window_rect_in_render_units_clamped_to_screen.max.y = Clamp(window_rect_in_render_units_clamped_to_screen.max.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y);
if (0) {
window_rect_in_render_units_clamped_to_screen = Shrink(window_rect_in_render_units_clamped_to_screen, 10);
DrawRectangleRec(ToRectangle(window_rect_in_render_units_clamped_to_screen), {255, 0, 0, 50});
}
// Figure out which lines to draw
Vec2 s = GetSize(window_rect_in_render_units); Vec2 s = GetSize(window_rect_in_render_units);
float line_offset = font_size; float line_offset = font_size;
float _line_min_y = (window.window_world_to_window_units.y) / line_offset; float _line_min_y = (window.window_world_to_window_units.y) / line_offset;
@@ -158,27 +158,40 @@ int main() {
int64_t line_min_y = (int64_t)floorf(_line_min_y); int64_t line_min_y = (int64_t)floorf(_line_min_y);
int64_t line_max_y = (int64_t)ceilf(_line_max_y); int64_t line_max_y = (int64_t)ceilf(_line_max_y);
Vec2 window_rect_in_render_units_size = GetSize(window_rect_in_render_units); struct Cell {
BeginScissorMode((int)window_rect_in_render_units.min.x, (int)window_rect_in_render_units.min.y, (int)window_rect_in_render_units_size.x, (int)window_rect_in_render_units_size.y); Rect2 rect;
int codepoint;
int64_t pos;
};
struct CellRow {
Array<Cell> cells;
Rect2 rect;
int64_t line;
};
Array<CellRow> rows = {FrameArena};
for (int64_t line = line_min_y; line < line_max_y; line += 1) { for (int64_t line = line_min_y; line < line_max_y; line += 1) {
if (line < 0) break; if (line < 0) break;
if (line >= window.buffer.lines.len) break; if (line >= window.buffer.lines.len) break;
CellRow row = {};
row.line = line;
row.cells.allocator = FrameArena;
Range line_range = window.buffer.lines[line]; Range line_range = window.buffer.lines[line];
Vec2 text_position_in_world_window_units = {0, line_offset * (float)line}; Vec2 text_position_in_world_window_units = {0, line_offset * (float)line};
Vec2 text_position_in_window_units = WindowWorldToWindowUnits(text_position_in_world_window_units, window); Vec2 text_position_in_window_units = WindowWorldToWindowUnits(text_position_in_world_window_units, window);
Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, window); Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, window);
Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units); Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units);
row.rect.min = text_position_in_render_units;
//
// Glyph inside the line rendering
//
String text = GetString(window.buffer, line_range); String text = GetString(window.buffer, line_range);
if (font.texture.id == 0) font = GetFontDefault(); if (font.texture.id == 0) font = GetFontDefault();
float textOffsetX = 0.0f; float textOffsetX = 0.0f;
float scaleFactor = font_size / font.baseSize; // Character quad scaling factor float scaleFactor = font_size / font.baseSize; // Character quad scaling factor
for (int i = 0; i < text.len;) { for (int64_t i = 0; i < text.len;) {
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetCodepointNext(&text.data[i], &codepointByteCount); int codepoint = GetCodepointNext(&text.data[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
@@ -190,16 +203,55 @@ int main() {
Vec2 cell_size = {x_to_offset_by, font_size}; Vec2 cell_size = {x_to_offset_by, font_size};
Rect2 cell_rect = {glyph_position, Vector2Add(glyph_position, cell_size)}; Rect2 cell_rect = {glyph_position, Vector2Add(glyph_position, cell_size)};
Rectangle cell_rectangle = ToRectangle(cell_rect);
DrawRectangleLinesEx(ToRectangle(cell_rect), 1, {255, 0, 0, 120}); if (CheckCollisionRecs(cell_rectangle, ToRectangle(window_rect_in_render_units_clamped_to_screen))) {
if ((codepoint != ' ') && (codepoint != '\t')) { row.cells.add({cell_rect, codepoint, line_range.min + i});
DrawTextCodepoint(font, codepoint, glyph_position, font_size, BLACK); row.rect.max = cell_rect.max;
} }
textOffsetX += x_to_offset_by; textOffsetX += x_to_offset_by;
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
} }
if (row.cells.len) rows.add(row);
} }
// Draw debug markers
if (0) {
ForItem(row, rows) {
For(row.cells) {
DrawRectangleLinesEx(ToRectangle(it.rect), 1, {255, 0, 0, 50});
}
DrawRectangleLinesEx(ToRectangle(row.rect), 1, {0, 190, 50, 255});
}
}
// Draw the glyphs
Vec2 window_rect_in_render_units_size = GetSize(window_rect_in_render_units);
BeginScissorMode((int)window_rect_in_render_units.min.x, (int)window_rect_in_render_units.min.y, (int)window_rect_in_render_units_size.x, (int)window_rect_in_render_units_size.y);
ForItem(row, rows) {
For(row.cells) {
if ((it.codepoint != ' ') && (it.codepoint != '\t')) {
DrawTextCodepoint(font, it.codepoint, it.rect.min, font_size, BLACK);
}
}
}
ForItem(cursor, window.cursors) {
ForItem(row, rows) {
Range line_range = window.buffer.lines[row.line];
if (cursor.min >= line_range.min && cursor.min <= line_range.max) {
ForItem(cell, row.cells) {
if (cursor.min == cell.pos) {
Rect2 rect = cell.rect;
rect = CutLeft(&rect, 4);
DrawRectangleRec(ToRectangle(rect), RED);
}
}
}
}
}
EndScissorMode(); EndScissorMode();
} }

65
src/text_editor/rect2.cpp Normal file
View File

@@ -0,0 +1,65 @@
using Vec2 = Vector2;
struct Rect2 {
Vec2 min;
Vec2 max;
};
Vec2 GetSize(Rect2 r) {
Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
Rectangle ToRectangle(Rect2 r) {
Rectangle result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
Rect2 Shrink(Rect2 result, float v) {
result.min.x += v;
result.max.x -= v;
result.min.y += v;
result.max.y -= v;
return result;
}
Rect2 CutLeft(Rect2 *r, float value) {
float minx = r->min.x;
r->min.x = Min(r->min.x + value, r->max.x);
Rect2 result = {
{ minx, r->min.y},
{r->min.x, r->max.y}
};
return result;
}
Rect2 CutRight(Rect2 *r, float value) {
float maxx = r->max.x;
r->max.x = Max(r->min.x, r->max.x - value);
Rect2 result = {
{r->max.x, r->min.y},
{ maxx, r->max.y},
};
return result;
}
// Y is up
Rect2 CutBottom(Rect2 *r, float value) {
float maxy = r->max.y;
r->max.y = Max(r->min.y, r->max.y - value);
Rect2 result = {
{r->min.x, r->max.y},
{r->max.x, maxy},
};
return result;
}
// Y is up
Rect2 CutTop(Rect2 *r, float value) {
float miny = r->min.y;
r->min.y = Min(r->min.y + value, r->max.y);
Rect2 result = {
{r->min.x, miny},
{r->max.x, r->min.y},
};
return result;
}