diff options
Diffstat (limited to 'src/ui_elements/TextEditor.c')
| -rw-r--r-- | src/ui_elements/TextEditor.c | 134 |
1 files changed, 117 insertions, 17 deletions
diff --git a/src/ui_elements/TextEditor.c b/src/ui_elements/TextEditor.c index 9f607d1..ebc8671 100644 --- a/src/ui_elements/TextEditor.c +++ b/src/ui_elements/TextEditor.c @@ -2,6 +2,7 @@ #include "UI.h" #include "../resources/resources.h" +#include <ctype.h> #include <raylib.h> #include <stdlib.h> #include <string.h> @@ -13,7 +14,7 @@ void HighlightCharacter(Vector2 lineStartPos, char *line, int index, Font *font, x_position += spacing; } DrawLine(lineStartPos.x + x_position, lineStartPos.y, - lineStartPos.x + x_position, lineStartPos.y + height, COLORSCHEME_ORANGE); + lineStartPos.x + x_position, lineStartPos.y + height, COLORSCHEME_BROWN); } TextNode *CreateNode(TextNode *prev, TextNode *next) { @@ -117,7 +118,7 @@ void PushNodeBefore(TextArea *ta) { void PopCurrent(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL || ta->NodeLenth <= 1) return; TextNode *current = ta->CurrentNode; - if (current->PrevNode != NULL) + if (current->PrevNode != NULL) ((TextNode *)current->PrevNode)->NextNode = current->NextNode; if (current->NextNode != NULL) ((TextNode *)current->NextNode)->PrevNode = current->PrevNode; @@ -134,17 +135,15 @@ void FreeTextArea(TextArea *ta) { free(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 + 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.y += height; - } +/// Returns a char the cursor is at +char GetCurrentChar(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return 0x0; + return ta->CurrentNode->text[(int)ta->CursorPosition.x]; +} + +/// This function is used in the skips through words (<C-arrows>) +bool IsSkippable(char c) { + return isalpha(c) || isdigit(c); } void MoveCursorRight(TextArea *ta) { @@ -155,12 +154,42 @@ void MoveCursorRight(TextArea *ta) { if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; } +void MoveCursorRightWord(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + do { + ta->CursorPosition.x += 1; + } while (IsSkippable(GetCurrentChar(ta))); + + size_t line_len = ta->CurrentNode->len; + if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; +} + +void MoveCursorEnd(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + ta->CursorPosition.x = ta->CurrentNode->len; +} + void MoveCursorLeft(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL) return; ta->CursorPosition.x -= 1; if (ta->CursorPosition.x < 0) ta->CursorPosition.x = 0; } +void MoveCursorLeftWord(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + do { + ta->CursorPosition.x -= 1; + } while (IsSkippable(GetCurrentChar(ta)) && ta->CursorPosition.x > 0); + + size_t line_len = ta->CurrentNode->len; + if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len; +} + +void MoveCursorHome(TextArea *ta) { + if (ta == NULL || ta->CurrentNode == NULL) return; + ta->CursorPosition.x = 0; +} + void MoveCursorDown(TextArea *ta) { if (ta == NULL || ta->CurrentNode == NULL) return; if (ta->CurrentNode->NextNode == NULL) return; @@ -226,10 +255,10 @@ void InsertChar(TextArea *ta, char new_char) { } if (ta->CursorPosition.x < line_len) { - TraceLog(LOG_INFO, "memcpy"); + // 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); + line_len - (int)ta->CursorPosition.x + 1); } else { (ta->CurrentNode->text)[(int)ta->CursorPosition.x+1] = 0x0; } @@ -246,7 +275,7 @@ void DeleteChar(TextArea *ta) { // TODO: Split this function in parts if (ta == NULL || ta->CurrentNode == NULL) return; if (ta->CursorPosition.x == 0) { - if (ta->CursorPosition.y == 0 || ta->CurrentNode->PrevNode == NULL) return; + 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); @@ -254,7 +283,8 @@ void DeleteChar(TextArea *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; + // ta->CurrentNode->len -= 1; + if (ta->CurrentNode->len < 0) ta->CurrentNode->len = 0; return; }; size_t line_len = ta->CurrentNode->len; @@ -267,6 +297,7 @@ void DeleteChar(TextArea *ta) { } ta->CursorPosition.x -= 1; ta->CurrentNode->len -= 1; + if (ta->CurrentNode->len < 0) ta->CurrentNode->len = 0; } bool IsKeyPressedFix(int key) { @@ -274,6 +305,9 @@ bool IsKeyPressedFix(int key) { } void PrintAllLines(TextArea *ta) { + TraceLog(LOG_INFO, "Cursor: %dx%d", + (int)ta->CursorPosition.x, + (int)ta->CursorPosition.y); TextNode *node = ta->StartNode; while (node != NULL) { TraceLog(LOG_INFO, "%d\t| %s", node->len, node->text); @@ -281,7 +315,44 @@ void PrintAllLines(TextArea *ta) { } } +/// Assumes that control is pressed +void HandleControlComands(TextArea *ta) { + if (IsKeyPressedFix(KEY_RIGHT)) MoveCursorRightWord(ta); + if (IsKeyPressedFix(KEY_LEFT)) MoveCursorLeftWord(ta); + + // emacs-like stuff + if (IsKeyPressedFix(KEY_F)) MoveCursorRight(ta); + if (IsKeyPressedFix(KEY_B)) MoveCursorLeft(ta); + if (IsKeyPressedFix(KEY_N)) MoveCursorDown(ta); + if (IsKeyPressedFix(KEY_P)) MoveCursorUp(ta); + if (IsKeyPressedFix(KEY_A)) MoveCursorHome(ta); + if (IsKeyPressedFix(KEY_E)) MoveCursorEnd(ta); + if (IsKeyPressedFix(KEY_O)) { + BreakLine(ta); + MoveCursorUp(ta); + MoveCursorEnd(ta); + }; +} +/// Assumes that control is pressed +void HandleAltComands(TextArea *ta) { + + // emacs-like stuff + if (IsKeyPressedFix(KEY_F)) MoveCursorRightWord(ta); + if (IsKeyPressedFix(KEY_B)) MoveCursorLeftWord(ta); +} + + void HandleKeyboard(TextArea *ta) { + if (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)) { + HandleControlComands(ta); + return; + } + + if (IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT)) { + HandleAltComands(ta); + return; + } + int charKey = GetCharPressed(); while (charKey > 0) { if (charKey >= 32 && charKey <= 125) { @@ -296,5 +367,34 @@ void HandleKeyboard(TextArea *ta) { if (IsKeyPressedFix(KEY_RIGHT)) MoveCursorRight(ta); if (IsKeyPressedFix(KEY_DOWN)) MoveCursorDown(ta); if (IsKeyPressedFix(KEY_UP)) MoveCursorUp(ta); + + if (IsKeyPressedFix(KEY_HOME)) MoveCursorHome(ta); + if (IsKeyPressedFix(KEY_END)) MoveCursorEnd(ta); + if (IsKeyPressedFix(KEY_F3)) PrintAllLines(ta); } + +/// draws a text area on the screen. Main draw entry point +void DrawTextArea(TextArea *ta, Rectangle rec, Font *font, int height, int spacing, int *scroll) { + int vertical_acc = rec.y - *scroll; + int text_height = ta->NodeLenth * height; + int max_scroll = text_height - rec.height; + + if (text_height >= rec.height && IsMouseInRec(rec)) { + *scroll -= GetMouseWheelMove() * SCROLL_SENC; + if (*scroll < 0) *scroll = 0; + if (*scroll > max_scroll) *scroll = max_scroll; + } + + Vector2 pos = { .x = rec.x + spacing, .y = rec.y - *scroll }; + TextNode *node = ta->StartNode; + BeginScissorMode(rec.x, rec.y, rec.width, rec.height); + 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.y += height; + } + EndScissorMode(); +} |
