summaryrefslogtreecommitdiff
path: root/src/ui_elements/TextEditor.c
diff options
context:
space:
mode:
authorphysick <mynameisgennadiy@vk.com>2026-07-15 17:46:13 +0500
committerphysick <mynameisgennadiy@vk.com>2026-07-15 17:46:13 +0500
commit8b79b8149d1e23d90b5871f980aec65d8aa7ae23 (patch)
tree88a8788b75270dba53a15cbc2b6e0916f05301c6 /src/ui_elements/TextEditor.c
parentf314b56da42e1ead200e2373e9b214f77290d03b (diff)
Puzzle infrastructure pt 1.
Diffstat (limited to 'src/ui_elements/TextEditor.c')
-rw-r--r--src/ui_elements/TextEditor.c142
1 files changed, 117 insertions, 25 deletions
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 <ctype.h>
#include <raylib.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -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;