summaryrefslogtreecommitdiff
path: root/src/ui_elements/TextEditor.c
blob: ca2d270afa3fcfb17324f61014d5c696967f7ce1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "UI.h"
#include "../resources/resources.h"
#include <raylib.h>
#include <stdlib.h>
#include <string.h>

void HighlightCharacter(Vector2 lineStartPos, char *line, int index, Font *font, int height, int spacing) {
    float x_position = 0;
    for (int i = 0; i < index; i++) {
        x_position += MeasureChar(font, height, line[i]);
        x_position += spacing;
    }
    DrawLine(lineStartPos.x + x_position, lineStartPos.y, 
            lineStartPos.x + x_position, lineStartPos.y + height, COLORSCHEME_ORANGE);
}

TextNode *CreateNode(TextNode *prev, TextNode *next) {
    TextNode *node = malloc(sizeof(TextNode));
    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;
    return node;
}

/// Recursively frees the nodes
void FreeNodeRec(TextNode *node) {
    if (node == NULL) return;
    FreeNodeRec(node->NextNode);
    free(node->text);
    free(node);
}

TextArea *CreateTextArea() {
    TextArea *outp = malloc(sizeof(TextArea));
    if (outp == NULL) return NULL;

    TextNode *start_node = CreateNode(NULL, NULL);
    if (start_node == NULL) { 
        free(outp); 
        return NULL; 
    }

    outp->StartNode = start_node;
    outp->CurrentNode = start_node;
    outp->NodeLenth = 1;
    return outp;
}

void FreeTextArea(TextArea *ta) {
    FreeNodeRec(ta->StartNode);
    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, .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;
    }
}

void MoveCursorRight(TextArea *ta) {
    if (ta == NULL || ta->CurrentNode == NULL) return;
    ta->CursorPosition.x += 1;
}

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 InsertChar(TextArea *ta, char new_char) {
    if (ta == NULL || ta->CurrentNode == NULL) return;
    (ta->CurrentNode->text)[(int)ta->CursorPosition.x] = new_char;
    ta->CursorPosition.x += 1;
    size_t line_len = strlen(ta->CurrentNode->text);
    if (ta->CursorPosition.x > line_len) ta->CursorPosition.x = line_len;
}

void DeleteChar(TextArea *ta) {
    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 == line_len) {
        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);
    }
    ta->CursorPosition.x -= 1;
}

bool IsKeyPressedFix(int key) {
    return IsKeyPressedRepeat(key) || IsKeyPressed(key);
}

void HandleKeyboard(TextArea *ta) {
    int charKey = GetCharPressed();
    while (charKey > 0) {
        if (charKey >= 32 && charKey <= 125) {
            InsertChar(ta, (char)charKey);
        }
        charKey = GetCharPressed();
    }

    if (IsKeyPressedFix(KEY_BACKSPACE)) DeleteChar(ta); 
    if (IsKeyPressedFix(KEY_LEFT)) MoveCursorLeft(ta); 
    if (IsKeyPressedFix(KEY_RIGHT)) MoveCursorRight(ta); 
}