From 7f7822f1bb74d3a86da5f021b35559d4509f7e08 Mon Sep 17 00:00:00 2001 From: Physick <96335032+DegustatorPonos@users.noreply.github.com> Date: Thu, 9 Jul 2026 01:18:49 +0500 Subject: vertical movement + raygui deletion --- src/main.c | 4 + src/ui_elements/TextEditor.c | 198 +++++++++++++++++++++++++++++++++++++++++-- src/ui_elements/UI.h | 4 +- 3 files changed, 197 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 1131db9..8aa83e5 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,4 @@ + #include #include #include "scenes/scenes.h" @@ -23,12 +24,15 @@ int main(void) { InitWindow(800, 600, "Programming game"); LoadResources(); + SetExitKey(KEY_NULL); SetTargetFPS(60); + while (!WindowShouldClose()) { UpdateScene(); BeginDrawing(); DrawScene(); + DrawFPS(0, 0); EndDrawing(); } diff --git a/src/ui_elements/TextEditor.c b/src/ui_elements/TextEditor.c index ca2d270..9f607d1 100644 --- a/src/ui_elements/TextEditor.c +++ b/src/ui_elements/TextEditor.c @@ -1,3 +1,5 @@ +// TODO: fix j being outside of the box SOME FUCKING HOW + #include "UI.h" #include "../resources/resources.h" #include @@ -19,11 +21,20 @@ TextNode *CreateNode(TextNode *prev, TextNode *next) { if (node == NULL) return NULL; node->NextNode = next; node->PrevNode = prev; - node->text = malloc(DEFAULT_TEXT_NODE_SIZE); - if (node->text != NULL) node->cap = DEFAULT_TEXT_NODE_SIZE; + node->len = 0; + node->text = calloc(DEFAULT_TEXT_NODE_SIZE, sizeof(char)); + if (node->text != NULL) node->cap = DEFAULT_TEXT_NODE_SIZE; + TraceLog(LOG_INFO, "Created a new node"); return node; } +void FreeNode(TextNode *node) { + if (node == NULL) return; + free(node->text); + free(node); + TraceLog(LOG_INFO, "Deleted a node"); +} + /// Recursively frees the nodes void FreeNodeRec(TextNode *node) { if (node == NULL) return; @@ -32,6 +43,37 @@ void FreeNodeRec(TextNode *node) { free(node); } +bool AddSpace(TextNode *base) { + TraceLog(LOG_INFO, "Adding space to a node"); + if (base == NULL) return false; + char *new = realloc(base->text, base->cap + DEFAULT_TEXT_NODE_SIZE); + if (new == NULL) return false; + base->text = new; + memset(new + base->cap, 0, DEFAULT_TEXT_NODE_SIZE); + base->cap += DEFAULT_TEXT_NODE_SIZE; + return true; +} + +bool AddSpaceDetermined(TextNode *base, size_t additional_space) { + TraceLog(LOG_INFO, "Adding space to a node"); + if (base == NULL) return false; + char *new = realloc(base->text, base->cap + additional_space); + if (new == NULL) return false; + base->text = new; + memset(new + base->cap, 0, additional_space); + base->cap += additional_space; + return true; +} +void AppendTextToNode(TextNode *base, char *new_text) { + if (base == NULL || new_text == NULL) return; + size_t len = strlen(base->text); + /// >= and not > because it needs a \0 + if (len + strlen(new_text) >= base->cap) { + if (!AddSpace(base)) return; + } + strcpy(base->text + len, new_text); +} + TextArea *CreateTextArea() { TextArea *outp = malloc(sizeof(TextArea)); if (outp == NULL) return NULL; @@ -48,6 +90,45 @@ TextArea *CreateTextArea() { return outp; } +bool PushNode(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return false; + TextNode *new_node = CreateNode(ta->CurrentNode, ta->CurrentNode->NextNode); + if (new_node == NULL) return false; + if (ta->CurrentNode->NextNode != NULL) + ((TextNode *)ta->CurrentNode->NextNode)->PrevNode = new_node; + + ta->CurrentNode->NextNode = new_node; + ta->NodeLenth += 1; + return true; +} + +void PushNodeBefore(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + TextNode *new_node = CreateNode(ta->CurrentNode->PrevNode, ta->CurrentNode); + if (new_node == NULL) return; + if (ta->CurrentNode->PrevNode != NULL) + ((TextNode *)ta->CurrentNode->PrevNode)->NextNode = new_node; + if (ta->CurrentNode == ta->StartNode) ta->StartNode = new_node; + + ta->CurrentNode->PrevNode = new_node; + ta->NodeLenth += 1; +} + +void PopCurrent(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL || ta->NodeLenth <= 1) return; + TextNode *current = ta->CurrentNode; + if (current->PrevNode != NULL) + ((TextNode *)current->PrevNode)->NextNode = current->NextNode; + if (current->NextNode != NULL) + ((TextNode *)current->NextNode)->PrevNode = current->PrevNode; + + /// One of those is guaranteed not to be null (hopefully) + if (current->PrevNode != NULL) ta->CurrentNode = current->PrevNode; + else ta->CurrentNode = current->NextNode; + ta->NodeLenth -= 1; + FreeNode(current); +} + void FreeTextArea(TextArea *ta) { FreeNodeRec(ta->StartNode); free(ta); @@ -55,20 +136,23 @@ void FreeTextArea(TextArea *ta) { /// draws a text area on the screen. Main draw entry point void DrawTextArea(TextArea *ta, Rectangle rec, Font *font, int height, int spacing) { - Vector2 pos = { .x = rec.x, .y = rec.y }; + Vector2 pos = { .x = rec.x + spacing, .y = rec.y }; TextNode *node = ta->StartNode; while (node != NULL) { DrawTextEx(*font, node->text, pos, height, spacing, COLORSCHEME_BROWN); if (node == ta->CurrentNode) HighlightCharacter(pos, node->text, ta->CursorPosition.x, font, height, spacing); node = node->NextNode; - pos.x += height; + pos.y += height; } } void MoveCursorRight(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL) return; ta->CursorPosition.x += 1; + + size_t line_len = ta->CurrentNode->len; + if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; } void MoveCursorLeft(TextArea *ta) { @@ -77,18 +161,103 @@ void MoveCursorLeft(TextArea *ta) { if (ta->CursorPosition.x < 0) ta->CursorPosition.x = 0; } +void MoveCursorDown(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + if (ta->CurrentNode->NextNode == NULL) return; + ta->CurrentNode = ta->CurrentNode->NextNode; + + ta->CursorPosition.y += 1; + size_t line_len = ta->CurrentNode->len; + if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; +} + +void MoveCursorUp(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + if (ta->CursorPosition.y == 0 || ta->CurrentNode->PrevNode == NULL) return; + ta->CurrentNode = ta->CurrentNode->PrevNode; + ta->CursorPosition.y -= 1; + + size_t line_len = ta->CurrentNode->len; + if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; +} + +void BreakLine(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + if (ta->CursorPosition.x == 0) { + PushNodeBefore(ta); + ta->CursorPosition.y += 1; + return; + } + + if (!PushNode(ta)) { + // Something went wrong, silently undermine + TraceLog(LOG_ERROR, "Failed to push a node: the initializator returned NULL"); + return; + } + + size_t current_node_len = strlen(ta->CurrentNode->text); + 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"); + } + } + strcpy(((TextNode *)ta->CurrentNode->NextNode)->text, after_str); + ((TextNode *)ta->CurrentNode->NextNode)->len = after_str_len; + for (int i = ta->CursorPosition.x; i < current_node_len; i++) { + ta->CurrentNode->text[i] = 0x0; + } + ta->CurrentNode->len -= after_str_len; + } + ta->CursorPosition.y += 1; + ta->CursorPosition.x = 0; + ta->CurrentNode = ta->CurrentNode->NextNode; +} + void InsertChar(TextArea *ta, char new_char) { if (ta == NULL || ta->CurrentNode == NULL) return; + size_t line_len = ta->CurrentNode->len; + + if (line_len + 2 > ta->CurrentNode->cap) { + /// The reallocation fails + if (!AddSpace(ta->CurrentNode)) return; + } + + if (ta->CursorPosition.x < line_len) { + TraceLog(LOG_INFO, "memcpy"); + memmove(ta->CurrentNode->text + (int)ta->CursorPosition.x + 1, + ta->CurrentNode->text + (int)ta->CursorPosition.x, + line_len - ta->CursorPosition.x + 1); + } else { + (ta->CurrentNode->text)[(int)ta->CursorPosition.x+1] = 0x0; + } + (ta->CurrentNode->text)[(int)ta->CursorPosition.x] = new_char; ta->CursorPosition.x += 1; - size_t line_len = strlen(ta->CurrentNode->text); + ta->CurrentNode->len += 1; + line_len += 1; + if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; } void DeleteChar(TextArea *ta) { + // TODO: Split this function in parts if (ta == NULL || ta->CurrentNode == NULL) return; - if (ta->CursorPosition.x == 0) return; - size_t line_len = strlen(ta->CurrentNode->text); + if (ta->CursorPosition.x == 0) { + if (ta->CursorPosition.y == 0 || ta->CurrentNode->PrevNode == NULL) return; + int target_x = strlen(((TextNode *)ta->CurrentNode->PrevNode)->text); + // The cursor should remove prevoius line break + AppendTextToNode(ta->CurrentNode->PrevNode, ta->CurrentNode->text); + PopCurrent(ta); + /// The cursor is guaranteed to go up because the y coordinate is > 0 + ta->CursorPosition.y -= 1; + ta->CursorPosition.x = target_x; + ta->CurrentNode->len -= 1; + return; + }; + size_t line_len = ta->CurrentNode->len; if (ta->CursorPosition.x == line_len) { ta->CurrentNode->text[line_len - 1] = 0x0; @@ -97,10 +266,19 @@ void DeleteChar(TextArea *ta) { strcpy(ta->CurrentNode->text + (int)ta->CursorPosition.x - 1, after_str); } ta->CursorPosition.x -= 1; + ta->CurrentNode->len -= 1; } bool IsKeyPressedFix(int key) { - return IsKeyPressedRepeat(key) || IsKeyPressed(key); + return IsKeyPressed(key) || IsKeyPressedRepeat(key); +} + +void PrintAllLines(TextArea *ta) { + TextNode *node = ta->StartNode; + while (node != NULL) { + TraceLog(LOG_INFO, "%d\t| %s", node->len, node->text); + node = node->NextNode; + } } void HandleKeyboard(TextArea *ta) { @@ -113,6 +291,10 @@ void HandleKeyboard(TextArea *ta) { } if (IsKeyPressedFix(KEY_BACKSPACE)) DeleteChar(ta); + if (IsKeyPressedFix(KEY_ENTER)) BreakLine(ta); if (IsKeyPressedFix(KEY_LEFT)) MoveCursorLeft(ta); if (IsKeyPressedFix(KEY_RIGHT)) MoveCursorRight(ta); + if (IsKeyPressedFix(KEY_DOWN)) MoveCursorDown(ta); + if (IsKeyPressedFix(KEY_UP)) MoveCursorUp(ta); + if (IsKeyPressedFix(KEY_F3)) PrintAllLines(ta); } diff --git a/src/ui_elements/UI.h b/src/ui_elements/UI.h index 4c94bf7..1029289 100644 --- a/src/ui_elements/UI.h +++ b/src/ui_elements/UI.h @@ -10,12 +10,13 @@ float MeasureChar(Font *font, int height, char symbol); // ========== TEXT EDITOR ========== -static const size_t DEFAULT_TEXT_NODE_SIZE = 256; +static const size_t DEFAULT_TEXT_NODE_SIZE = 5; typedef struct { void *PrevNode; void *NextNode; char *text; + size_t len; size_t cap; } TextNode; @@ -37,5 +38,6 @@ void DeleteChar(TextArea *ta); void HandleKeyboard(TextArea *ta); void MoveCursorRight(TextArea *ta); void MoveCursorLeft(TextArea *ta); +void MoveCursorDown(TextArea *ta); #endif // UI_ELEMENTS_H -- cgit v1.3