]> git.lizzy.rs Git - nothing.git/blob - src/game/level/level_editor/label_layer.c
Merge pull request #970 from TheKnarf/fix/trying-to-get-travis-mac-working
[nothing.git] / src / game / level / level_editor / label_layer.c
1 #include <stdio.h>
2
3 #include <SDL.h>
4
5 #include "system/line_stream.h"
6 #include "system/stacktrace.h"
7 #include "system/nth_alloc.h"
8 #include "system/lt.h"
9 #include "system/str.h"
10 #include "system/log.h"
11 #include "math/point.h"
12 #include "label_layer.h"
13 #include "dynarray.h"
14 #include "color.h"
15 #include "game/camera.h"
16 #include "color_picker.h"
17 #include "ui/edit_field.h"
18
19 #define LABEL_LAYER_SELECTION_THICCNESS 5.0f
20
21 typedef enum {
22     LABEL_LAYER_IDLE = 0,
23     LABEL_LAYER_MOVE,
24     LABEL_LAYER_EDIT_TEXT
25 } LabelLayerState;
26
27 // TODO(#963): LabelLayer cannot add the labels
28 // TODO(#964): LabelLayer cannot modify the labels' id
29 struct LabelLayer {
30     Lt *lt;
31     LabelLayerState state;
32     Dynarray *ids;
33     Dynarray *positions;
34     Dynarray *colors;
35     Dynarray *texts;
36     int selected;
37     ColorPicker color_picker;
38     Point move_anchor;
39     Edit_field *edit_field;
40 };
41
42 LayerPtr label_layer_as_layer(LabelLayer *label_layer)
43 {
44     LayerPtr layer = {
45         .ptr = label_layer,
46         .type = LAYER_LABEL
47     };
48     return layer;
49 }
50
51 LabelLayer *create_label_layer(void)
52 {
53     Lt *lt = create_lt();
54
55     LabelLayer *label_layer = PUSH_LT(
56         lt, nth_calloc(1, sizeof(LabelLayer)), free);
57     if (label_layer == NULL) {
58         RETURN_LT(lt, NULL);
59     }
60     label_layer->lt = lt;
61
62     label_layer->ids = PUSH_LT(
63         lt,
64         create_dynarray(sizeof(char) * LABEL_LAYER_ID_MAX_SIZE),
65         destroy_dynarray);
66     if (label_layer->ids == NULL) {
67         RETURN_LT(lt, NULL);
68     }
69
70     label_layer->positions = PUSH_LT(lt, create_dynarray(sizeof(Point)), destroy_dynarray);
71     if (label_layer->positions == NULL) {
72         RETURN_LT(lt, NULL);
73     }
74
75     label_layer->colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
76     if (label_layer->colors == NULL) {
77         RETURN_LT(lt, NULL);
78     }
79
80     label_layer->texts = PUSH_LT(
81         lt,
82         create_dynarray(sizeof(char) * LABEL_LAYER_TEXT_MAX_SIZE),
83         destroy_dynarray);
84     if (label_layer->texts == NULL) {
85         RETURN_LT(lt, NULL);
86     }
87
88     label_layer->color_picker = create_color_picker_from_rgba(COLOR_RED);
89     label_layer->selected = -1;
90
91     label_layer->edit_field = PUSH_LT(
92         lt,
93         create_edit_field(LABELS_SIZE, COLOR_RED),
94         destroy_edit_field);
95     if (label_layer->edit_field == NULL) {
96         RETURN_LT(lt, NULL);
97     }
98
99     return label_layer;
100 }
101
102 LabelLayer *create_label_layer_from_line_stream(LineStream *line_stream)
103 {
104     trace_assert(line_stream);
105     LabelLayer *label_layer = create_label_layer();
106
107     if (label_layer == NULL) {
108         RETURN_LT(label_layer->lt, NULL);
109     }
110
111     const char *line = line_stream_next(line_stream);
112     if (line == NULL) {
113         log_fail("Could not read amount of labels\n");
114         RETURN_LT(label_layer->lt, NULL);
115     }
116
117     size_t n = 0;
118     if (sscanf(line, "%zu", &n) == EOF) {
119         log_fail("Could not parse amount of labels\n");
120         RETURN_LT(label_layer->lt, NULL);
121     }
122
123     for (size_t i = 0; i < n; ++i) {
124         char hex[7];
125         char id[LABEL_LAYER_ID_MAX_SIZE];
126         Point position;
127
128         line = line_stream_next(line_stream);
129         if (line == NULL) {
130             log_fail("Could not read label meta info\n");
131             RETURN_LT(label_layer->lt, NULL);
132         }
133
134         if (sscanf(
135                 line,
136                 "%"STRINGIFY(LABEL_LAYER_ID_MAX_SIZE)"s%f%f%6s\n",
137                 id, &position.x, &position.y, hex) == EOF) {
138             log_fail("Could not parse label meta info\n");
139             RETURN_LT(label_layer->lt, NULL);
140         }
141
142         Color color = hexstr(hex);
143
144         dynarray_push(label_layer->ids, id);
145         dynarray_push(label_layer->positions, &position);
146         dynarray_push(label_layer->colors, &color);
147
148         line = line_stream_next(line_stream);
149         if (line == NULL) {
150             log_fail("Could not read label text\n");
151         }
152
153         char label_text[LABEL_LAYER_TEXT_MAX_SIZE] = {0};
154         memcpy(label_text, line, LABEL_LAYER_TEXT_MAX_SIZE - 1);
155         trim_endline(label_text);
156         dynarray_push(label_layer->texts, &label_text);
157     }
158
159     return label_layer;
160 }
161
162 void destroy_label_layer(LabelLayer *label_layer)
163 {
164     trace_assert(label_layer);
165     destroy_lt(label_layer->lt);
166 }
167
168 int label_layer_render(const LabelLayer *label_layer,
169                        Camera *camera,
170                        int active)
171 {
172     trace_assert(label_layer);
173     trace_assert(camera);
174
175     if (active && color_picker_render(&label_layer->color_picker, camera) < 0) {
176         return -1;
177     }
178
179     size_t n = dynarray_count(label_layer->ids);
180     Point *positions = dynarray_data(label_layer->positions);
181     Color *colors = dynarray_data(label_layer->colors);
182     char *texts = dynarray_data(label_layer->texts);
183
184     /* TODO(#891): LabelLayer doesn't show the final position of Label after the animation */
185     for (size_t i = 0; i < n; ++i) {
186         if (label_layer->state == LABEL_LAYER_EDIT_TEXT) {
187             if (edit_field_render_world(
188                     label_layer->edit_field,
189                     camera,
190                     positions[i]) < 0) {
191                 return -1;
192             }
193         } else {
194             if (camera_render_text(
195                     camera,
196                     texts + i * LABEL_LAYER_TEXT_MAX_SIZE,
197                     LABELS_SIZE,
198                     color_scale(
199                         colors[i],
200                         rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f)),
201                     positions[i]) < 0) {
202                 return -1;
203             }
204         }
205     }
206
207     if (label_layer->selected >= 0) {
208
209         Rect selection =
210             rect_scale(
211                 camera_rect(
212                     camera,
213                     sprite_font_boundary_box(
214                         camera_font(camera),
215                         positions[label_layer->selected],
216                         LABELS_SIZE,
217                         texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE)),
218                 LABEL_LAYER_SELECTION_THICCNESS * 0.5f);
219
220
221         if (camera_draw_thicc_rect_screen(
222                 camera,
223                 selection,
224                 colors[label_layer->selected],
225                 LABEL_LAYER_SELECTION_THICCNESS) < 0) {
226             return -1;
227         }
228     }
229
230     return 0;
231 }
232
233 static
234 int label_layer_element_at(LabelLayer *label_layer,
235                            const Sprite_font *font,
236                            Point position)
237 {
238     trace_assert(label_layer);
239
240     const size_t n = dynarray_count(label_layer->texts);
241     char *texts = dynarray_data(label_layer->texts);
242     Point *positions = dynarray_data(label_layer->positions);
243
244     for (size_t i = 0; i < n; ++i) {
245         Rect boundary = sprite_font_boundary_box(
246             font,
247             positions[i],
248             LABELS_SIZE,
249             texts + i * LABEL_LAYER_TEXT_MAX_SIZE);
250
251         if (rect_contains_point(boundary, position)) {
252             return (int) i;
253         }
254     }
255
256     return -1;
257 }
258
259 static
260 int label_layer_idle_event(LabelLayer *label_layer,
261                            const SDL_Event *event,
262                            const Camera *camera)
263 {
264     trace_assert(label_layer);
265     trace_assert(event);
266     trace_assert(camera);
267
268     switch (event->type) {
269     case SDL_MOUSEBUTTONDOWN: {
270         switch (event->button.button) {
271         case SDL_BUTTON_LEFT: {
272             const Point position = camera_map_screen(
273                 camera,
274                 event->button.x,
275                 event->button.y);
276
277             const int element = label_layer_element_at(
278                 label_layer,
279                 camera_font(camera),
280                 position);
281
282             if (element >= 0) {
283                 Point *positions = dynarray_data(label_layer->positions);
284                 Color *colors = dynarray_data(label_layer->colors);
285
286                 label_layer->move_anchor = vec_sub(position, positions[element]);
287                 label_layer->selected = element;
288                 label_layer->state = LABEL_LAYER_MOVE;
289
290                 label_layer->color_picker =
291                     create_color_picker_from_rgba(colors[element]);
292             }
293         } break;
294         }
295     } break;
296
297     case SDL_KEYDOWN: {
298         switch (event->key.keysym.sym) {
299         case SDLK_F2: {
300             if (label_layer->selected >= 0) {
301                 char *texts = dynarray_data(label_layer->texts);
302                 label_layer->state = LABEL_LAYER_EDIT_TEXT;
303                 edit_field_replace(
304                     label_layer->edit_field,
305                     texts + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE);
306                 SDL_StartTextInput();
307             }
308         } break;
309         }
310     } break;
311     }
312
313     return 0;
314 }
315
316 static
317 int label_layer_move_event(LabelLayer *label_layer,
318                            const SDL_Event *event,
319                            const Camera *camera)
320 {
321     trace_assert(label_layer);
322     trace_assert(event);
323     trace_assert(camera);
324     trace_assert(label_layer->selected >= 0);
325
326     switch (event->type) {
327     case SDL_MOUSEMOTION: {
328         Point *positions = dynarray_data(label_layer->positions);
329         positions[label_layer->selected] =
330             vec_sub(
331                 camera_map_screen(
332                     camera,
333                     event->motion.x,
334                     event->motion.y),
335                 label_layer->move_anchor);
336     } break;
337
338     case SDL_MOUSEBUTTONUP: {
339         switch (event->button.button) {
340         case SDL_BUTTON_LEFT: {
341             label_layer->state = LABEL_LAYER_IDLE;
342         } break;
343         }
344     } break;
345     }
346
347     return 0;
348 }
349
350 static
351 int label_layer_edit_text_event(LabelLayer *label_layer,
352                                 const SDL_Event *event,
353                                 const Camera *camera)
354 {
355     trace_assert(label_layer);
356     trace_assert(event);
357     trace_assert(camera);
358     trace_assert(label_layer->selected >= 0);
359
360     switch (event->type) {
361     case SDL_KEYDOWN: {
362         if (event->key.keysym.sym == SDLK_RETURN) {
363             char *text =
364                 (char*)dynarray_data(label_layer->texts) + label_layer->selected * LABEL_LAYER_TEXT_MAX_SIZE;
365             memset(text, 0, LABEL_LAYER_TEXT_MAX_SIZE);
366             memcpy(text, edit_field_as_text(label_layer->edit_field), LABEL_LAYER_TEXT_MAX_SIZE - 1);
367             label_layer->state = LABEL_LAYER_IDLE;
368             return 0;
369         }
370     } break;
371     }
372
373     return edit_field_event(label_layer->edit_field, event);
374 }
375
376 int label_layer_event(LabelLayer *label_layer,
377                       const SDL_Event *event,
378                       const Camera *camera)
379 {
380     trace_assert(label_layer);
381     trace_assert(event);
382     trace_assert(camera);
383
384     int changed = 0;
385
386     if (color_picker_event(
387             &label_layer->color_picker,
388             event,
389             &changed) < 0) {
390         return -1;
391     }
392
393     if (changed && label_layer->selected >= 0) {
394         Color *colors = dynarray_data(label_layer->colors);
395         colors[label_layer->selected] =
396             color_picker_rgba(&label_layer->color_picker);
397     }
398
399     switch (label_layer->state) {
400     case LABEL_LAYER_IDLE:
401         return label_layer_idle_event(label_layer, event, camera);
402
403     case LABEL_LAYER_MOVE:
404         return label_layer_move_event(label_layer, event, camera);
405
406     case LABEL_LAYER_EDIT_TEXT:
407         return label_layer_edit_text_event(label_layer, event, camera);
408     }
409
410     return 0;
411 }
412
413 size_t label_layer_count(const LabelLayer *label_layer)
414 {
415     return dynarray_count(label_layer->ids);
416 }
417
418 char *label_layer_ids(const LabelLayer *label_layer)
419 {
420     return dynarray_data(label_layer->ids);
421 }
422
423 Point *label_layer_positions(const LabelLayer *label_layer)
424 {
425     return dynarray_data(label_layer->positions);
426 }
427
428 Color *label_layer_colors(const LabelLayer *label_layer)
429 {
430     return dynarray_data(label_layer->colors);
431 }
432
433 char *labels_layer_texts(const LabelLayer *label_layer)
434 {
435     return dynarray_data(label_layer->texts);
436 }
437
438 int label_layer_dump_stream(const LabelLayer *label_layer, FILE *filedump)
439 {
440     trace_assert(label_layer);
441     trace_assert(filedump);
442
443     size_t n = dynarray_count(label_layer->ids);
444     char *ids = dynarray_data(label_layer->ids);
445     Point *positions = dynarray_data(label_layer->positions);
446     Color *colors = dynarray_data(label_layer->colors);
447     char *texts = dynarray_data(label_layer->texts);
448
449     fprintf(filedump, "%zd\n", n);
450     for (size_t i = 0; i < n; ++i) {
451         fprintf(filedump, "%s %f %f ",
452                 ids + LABEL_LAYER_ID_MAX_SIZE * i,
453                 positions[i].x, positions[i].y);
454         color_hex_to_stream(colors[i], filedump);
455         fprintf(filedump, "\n%s\n", texts + i * LABEL_LAYER_TEXT_MAX_SIZE);
456     }
457
458     return 0;
459 }