From 8b79b8149d1e23d90b5871f980aec65d8aa7ae23 Mon Sep 17 00:00:00 2001 From: physick Date: Wed, 15 Jul 2026 17:46:13 +0500 Subject: Puzzle infrastructure pt 1. --- src/ui_elements/TextEditor.c | 142 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 25 deletions(-) (limited to 'src/ui_elements/TextEditor.c') diff --git a/src/ui_elements/TextEditor.c b/src/ui_elements/TextEditor.c index 06cfc41..3cf34ff 100644 --- a/src/ui_elements/TextEditor.c +++ b/src/ui_elements/TextEditor.c @@ -5,6 +5,7 @@ #include "../resources/resources.h" #include #include +#include #include #include @@ -218,18 +219,18 @@ void MoveCursorRight(TextArea *ta) { void MoveCursorRightWord(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL) return; + size_t line_len = ta->CurrentNode->len; + if (ta->CursorPosition.x == line_len) { + MoveCursorRight(ta); + return; + } + bool current_type = IsSkippable(GetCurrentChar(ta)); do { ta->CursorPosition.x += 1; - } while (IsSkippable(GetCurrentChar(ta))); + } while (IsSkippable(GetCurrentChar(ta)) == current_type); - size_t line_len = ta->CurrentNode->len; if (ta->CursorPosition.x > line_len) { - if (ta->CurrentNode->NextNode == NULL) { - ta->CursorPosition.x = line_len; - return; - } - MoveCursorDown(ta); - ta->CursorPosition.x = 0; + ta->CursorPosition.x = line_len; } } @@ -254,9 +255,18 @@ void MoveCursorLeft(TextArea *ta) { void MoveCursorLeftWord(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL) return; + if (ta->CursorPosition.x == 0) { + MoveCursorLeft(ta); + return; + } + char prev_symbol = ta->CurrentNode->text[(int)ta->CursorPosition.x - 1]; + bool current_type = IsSkippable(prev_symbol); + do { ta->CursorPosition.x -= 1; - } while (IsSkippable(GetCurrentChar(ta)) && ta->CursorPosition.x > 0); + } while (IsSkippable(GetCurrentChar(ta)) == current_type && ta->CursorPosition.x >= 0); + + ta->CursorPosition.x += 1; if (ta->CursorPosition.x < 0) { if (ta->CursorPosition.y == 0 || ta->CurrentNode->PrevNode == NULL) { @@ -273,6 +283,15 @@ void MoveCursorHome(TextArea *ta) { ta->CursorPosition.x = 0; } +size_t GetStartingSpaces(char *string) { + if (string == NULL) return 0; + size_t idx = 0, len = strlen(string); + while (string[idx] != 0 && string[idx] == ' ') + idx++; + if (string[idx] == 0) return 0; // no starting spaces + return idx; +} + void BreakLine(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL) return; if (ta->CursorPosition.x == 0) { @@ -287,24 +306,44 @@ void BreakLine(TextArea *ta) { return; } + TextNode *next_node = (TextNode *)ta->CurrentNode->NextNode; size_t current_node_len = strlen(ta->CurrentNode->text); + size_t spaces_len = GetStartingSpaces(ta->CurrentNode->text); + size_t needed_space = spaces_len; + + size_t after_str_len = 0; + char *after_str = NULL; + if (ta->CursorPosition.x < current_node_len) { - char *after_str = (ta->CurrentNode->text + (int)ta->CursorPosition.x); - size_t after_str_len = strlen(after_str); - if (((TextNode *)ta->CurrentNode->NextNode)->cap < after_str_len) { - if (!AddSpaceDetermined(ta->CurrentNode->NextNode, after_str_len)) { - TraceLog(LOG_ERROR, "Failed to push a node: the space reservaton failed"); - } + after_str = (ta->CurrentNode->text + (int)ta->CursorPosition.x); + after_str_len = strlen(after_str); + needed_space += after_str_len; + } + + if (next_node->cap < needed_space + 1) { + if (!AddSpaceDetermined(ta->CurrentNode->NextNode, needed_space + 1)) { + TraceLog(LOG_ERROR, "Failed to push a node: the space reservaton failed"); + return; } - strcpy(((TextNode *)ta->CurrentNode->NextNode)->text, after_str); - ((TextNode *)ta->CurrentNode->NextNode)->len = after_str_len; + } + + for (int i = 0; i < spaces_len; ++i) { + next_node->text[i] = ' '; + } + next_node->text[spaces_len] = 0x0; + + if (after_str != NULL) { + strcpy(next_node->text + spaces_len, after_str); + ((TextNode *)ta->CurrentNode->NextNode)->len = after_str_len + spaces_len; for (int i = ta->CursorPosition.x; i < current_node_len; i++) { ta->CurrentNode->text[i] = 0x0; } ta->CurrentNode->len -= after_str_len; } + + next_node->len = strlen(next_node->text); ta->CursorPosition.y += 1; - ta->CursorPosition.x = 0; + ta->CursorPosition.x = spaces_len; ta->CurrentNode = ta->CurrentNode->NextNode; EnsureCursorIsInFrame(ta); } @@ -358,7 +397,9 @@ void DeleteChar(TextArea *ta) { ta->CurrentNode->text[line_len - 1] = 0x0; } else { char *after_str = (ta->CurrentNode->text + (int)ta->CursorPosition.x); - strcpy(ta->CurrentNode->text + (int)ta->CursorPosition.x - 1, after_str); + // Including a zero terminator here + size_t after_str_len = strlen(after_str) + 1; + memmove(ta->CurrentNode->text + (int)ta->CursorPosition.x - 1, after_str, after_str_len); } ta->CursorPosition.x -= 1; ta->CurrentNode->len -= 1; @@ -366,6 +407,54 @@ void DeleteChar(TextArea *ta) { EnsureCursorIsInFrame(ta); } +TextArea *CreateTextAreaFromText(TextAreaDisplayParams *DisplayParams, char *text) { + if (DisplayParams == NULL || text == NULL) return NULL; + TextArea *outp = CreateTextArea(DisplayParams); + if (outp == NULL) return NULL; + + const char *line_start = text; + const char *next_newline = NULL; + + while (line_start != NULL) { + next_newline = strchr(line_start, '\n'); + + size_t part_len = next_newline - line_start; + if (next_newline == NULL) part_len = strlen(line_start); + + if (!PushNode(outp)) { + TraceLog(LOG_ERROR, "Failed to push a node: the initializator returned NULL"); + break; + } + + TextNode *node = (TextNode *)outp->CurrentNode; + + if (part_len > 0) { + if (node->cap < part_len) { + if (!AddSpaceDetermined(node, part_len)) { + TraceLog(LOG_ERROR, "Failed to reserve space for node text"); + break; + } + } + + strncpy(node->text, line_start, part_len); + node->text[part_len] = 0x0; + node->len = part_len; + } else { + node->len = 0; + if (node->text != NULL && node->cap > 0) { + node->text[0] = '\0'; + } + } + + outp->CurrentNode = outp->CurrentNode->NextNode; + if (next_newline != NULL) line_start = next_newline + 1; + else line_start = NULL; + } + + outp->CurrentNode = outp->StartNode; + return outp; +} + bool IsKeyPressedFix(int key) { return IsKeyPressed(key) || IsKeyPressedRepeat(key); } @@ -474,6 +563,13 @@ void HandleScroll(TextArea *ta, Rectangle rec) { } } +void UpdateTextArea(TextArea *ta, Rectangle rec) { + HandleKeyboard(ta); + if (IsMouseInRec(rec)) { + HandleScroll(ta, rec); + } +} + /// draws a text area on the screen. Main draw entry point void DrawTextArea(TextArea *ta, Rectangle rec) { // those are used to move a cursor in frame when typing @@ -481,11 +577,6 @@ void DrawTextArea(TextArea *ta, Rectangle rec) { ta->DisplayParams->_area_width = rec.width; TextAreaDisplayParams *params = ta->DisplayParams; - // int vertical_acc = rec.y - *scroll; - - if (IsMouseInRec(rec)) { - HandleScroll(ta, rec); - } Vector2 pos = { .x = rec.x + params->spacing - params->scroll_h, @@ -500,7 +591,8 @@ void DrawTextArea(TextArea *ta, Rectangle rec) { TextNode *node = ta->StartNode; BeginScissorMode(rec.x, rec.y, rec.width, rec.height); while (node != NULL) { - DrawTextEx(*params->font, node->text, pos, params->font_size, params->spacing, COLORSCHEME_BROWN); + DrawTextEx(*params->font, node->text, pos, + params->font_size, params->spacing, COLORSCHEME_BROWN); if (node == ta->CurrentNode) DrawCursor(ta, pos, cursorPos.x); node = node->NextNode; -- cgit v1.3