]> git.lizzy.rs Git - nothing.git/blob - src/game/edit_field.c
(#328) Make scope more typesafe
[nothing.git] / src / game / edit_field.c
1 #include <assert.h>
2
3 #include "edit_field.h"
4 #include "game/sprite_font.h"
5 #include "sdl/renderer.h"
6 #include "system/error.h"
7 #include "system/lt.h"
8
9 #define BUFFER_CAPACITY 256
10
11 struct Edit_field
12 {
13     Lt *lt;
14     char *buffer;
15     size_t buffer_size;
16     size_t cursor;
17     const Sprite_font *font;
18     Vec font_size;
19     Color font_color;
20 };
21
22 static void edit_field_left(Edit_field *edit_field);
23 static void edit_field_right(Edit_field *edit_field);
24 static void edit_field_backspace(Edit_field *edit_field);
25 static void edit_field_delete(Edit_field *edit_field);
26 static void edit_field_insert_char(Edit_field *edit_field, char c);
27
28 Edit_field *create_edit_field(const Sprite_font *font,
29                                 Vec font_size,
30                                 Color font_color)
31 {
32     assert(font);
33
34     Lt *lt = create_lt();
35
36     if (lt == NULL) {
37         return NULL;
38     }
39
40     Edit_field *const edit_field = PUSH_LT(lt, malloc(sizeof(Edit_field)), free);
41     if (edit_field == NULL) {
42         throw_error(ERROR_TYPE_LIBC);
43         RETURN_LT(lt, NULL);
44     }
45     edit_field->lt = lt;
46
47     edit_field->buffer = PUSH_LT(lt, malloc(sizeof(char) * (BUFFER_CAPACITY + 10)), free);
48     if (edit_field->buffer == NULL) {
49         throw_error(ERROR_TYPE_LIBC);
50         RETURN_LT(lt, NULL);
51     }
52
53     edit_field->buffer_size = 0;
54     edit_field->cursor = 0;
55     edit_field->font = font;
56     edit_field->font_size = font_size;
57     edit_field->font_color = font_color;
58
59     edit_field->buffer[edit_field->buffer_size] = 0;
60
61     return edit_field;
62 }
63
64 void destroy_edit_field(Edit_field *edit_field)
65 {
66     assert(edit_field);
67     RETURN_LT0(edit_field->lt);
68 }
69
70 int edit_field_render(const Edit_field *edit_field,
71                       SDL_Renderer *renderer,
72                       Point position)
73 {
74     assert(edit_field);
75     assert(renderer);
76
77     const float cursor_y_overflow = 10.0f;
78     const float cursor_width = 2.0f;
79
80     if (sprite_font_render_text(edit_field->font,
81                                 renderer,
82                                 position,
83                                 edit_field->font_size,
84                                 edit_field->font_color,
85                                 edit_field->buffer) < 0) {
86         return -1;
87     }
88
89     if (fill_rect(
90             renderer,
91             rect(position.x + (float) edit_field->cursor * (float) FONT_CHAR_WIDTH * edit_field->font_size.x,
92                  position.y - cursor_y_overflow,
93                  cursor_width,
94                  FONT_CHAR_HEIGHT * edit_field->font_size.y + cursor_y_overflow * 2.0f),
95             edit_field->font_color) < 0) {
96         return -1;
97     }
98
99     return 0;
100 }
101
102 int edit_field_handle_event(Edit_field *edit_field,
103                             const SDL_Event *event)
104 {
105     assert(edit_field);
106     assert(event);
107
108     switch (event->type) {
109     case SDL_KEYDOWN:
110         switch (event->key.keysym.sym) {
111         case SDLK_LEFT:
112             edit_field_left(edit_field);
113             break;
114
115         case SDLK_RIGHT:
116             edit_field_right(edit_field);
117             break;
118
119         case SDLK_BACKSPACE:
120             edit_field_backspace(edit_field);
121             break;
122
123         case SDLK_DELETE:
124             edit_field_delete(edit_field);
125             break;
126
127         default: {
128             edit_field_insert_char(edit_field, (char) event->key.keysym.sym);
129         }
130         }
131         break;
132
133     default: {}
134     }
135
136     return 0;
137 }
138
139 const char *edit_field_as_text(const Edit_field *edit_field)
140 {
141     assert(edit_field);
142     return edit_field->buffer;
143 }
144
145 static void edit_field_left(Edit_field *edit_field)
146 {
147     if (edit_field->cursor > 0) {
148         edit_field->cursor--;
149     }
150 }
151
152 static void edit_field_right(Edit_field *edit_field)
153 {
154     assert(edit_field);
155     if (edit_field->cursor < edit_field->buffer_size) {
156         edit_field->cursor++;
157     }
158 }
159
160 static void edit_field_backspace(Edit_field *edit_field)
161 {
162     assert(edit_field);
163
164     if (edit_field->cursor == 0) {
165         return;
166     }
167
168     for (size_t i = edit_field->cursor; i < edit_field->buffer_size; ++i) {
169         edit_field->buffer[i - 1] = edit_field->buffer[i];
170     }
171
172     edit_field->cursor--;
173     edit_field->buffer[--edit_field->buffer_size] = 0;
174 }
175
176 static void edit_field_delete(Edit_field *edit_field)
177 {
178     assert(edit_field);
179
180     if (edit_field->cursor >= edit_field->buffer_size) {
181         return;
182     }
183
184     for (size_t i = edit_field->cursor; i < edit_field->buffer_size; ++i) {
185         edit_field->buffer[i] = edit_field->buffer[i + 1];
186     }
187
188     edit_field->buffer[--edit_field->buffer_size] = 0;
189 }
190
191 static void edit_field_insert_char(Edit_field *edit_field, char c)
192 {
193     assert(edit_field);
194
195     if (edit_field->buffer_size >= BUFFER_CAPACITY) {
196         return;
197     }
198
199     for (int64_t i = (int64_t) edit_field->buffer_size - 1; i >= (int64_t) edit_field->cursor; --i) {
200         edit_field->buffer[i + 1] = edit_field->buffer[i];
201     }
202
203     edit_field->buffer[edit_field->cursor++] = c;
204     edit_field->buffer[++edit_field->buffer_size] = 0;
205 }