3 #include "game/camera.h"
5 #include "system/stacktrace.h"
6 #include "system/nth_alloc.h"
7 #include "system/log.h"
10 #include "rect_layer.h"
12 #include "system/line_stream.h"
13 #include "color_picker.h"
14 #include "system/str.h"
15 #include "ui/edit_field.h"
16 #include "undo_history.h"
17 #include "game/level/action.h"
18 #include "action_picker.h"
21 #define RECT_LAYER_SELECTION_THICCNESS 15.0f
22 #define RECT_LAYER_ID_LABEL_SIZE vec(3.0f, 3.0f)
23 #define CREATE_AREA_THRESHOLD 10.0
24 #define RECT_LAYER_GRID_ROWS 3
25 #define RECT_LAYER_GRID_COLUMNS 4
27 static int clipboard = 0;
28 static Rect clipboard_rect;
29 static Color clipboard_color;
34 // TODO(#955): Rectangles in Level Editor have only one resize anchor to work with
35 // TODO(#1129): different cursor image in resize mode
50 ColorPicker color_picker;
51 ActionPicker action_picker;
55 Vec2f move_anchor; // The mouse offset from the left-top
56 // corner of the rect during moving it
57 Edit_field *id_edit_field;
61 const char *id_name_prefix;
80 char id[ENTITY_MAX_ID_SIZE];
101 UndoElementContext element;
102 UndoSwapContext swap;
106 UndoContext create_undo_add_context(RectLayer *layer, size_t index)
109 trace_assert(index < dynarray_count(layer->rects));
111 UndoContext undo_context;
112 undo_context.add.type = UNDO_ADD;
113 undo_context.add.layer = layer;
114 undo_context.add.index = index;
119 UndoContext create_undo_element_context(RectLayer *layer)
122 size_t index = (size_t) layer->selection;
123 trace_assert(index < dynarray_count(layer->rects));
125 UndoContext undo_context;
126 undo_context.element.layer = layer;
127 undo_context.element.index = index;
128 dynarray_copy_to(layer->rects, &undo_context.element.rect, index);
129 dynarray_copy_to(layer->colors, &undo_context.element.color, index);
130 dynarray_copy_to(layer->ids, undo_context.element.id, index);
131 dynarray_copy_to(layer->actions, &undo_context.element.action, index);
136 UndoContext create_undo_update_context(RectLayer *rect_layer)
138 UndoContext undo_context = create_undo_element_context(rect_layer);
139 undo_context.type = UNDO_UPDATE;
144 UndoContext create_undo_delete_context(RectLayer *rect_layer)
146 UndoContext undo_context = create_undo_element_context(rect_layer);
147 undo_context.type = UNDO_DELETE;
152 UndoContext create_undo_swap_context(RectLayer *rect_layer, size_t index1, size_t index2)
154 UndoContext undo_context;
155 undo_context.swap.type = UNDO_SWAP;
156 undo_context.swap.layer = rect_layer;
157 undo_context.swap.index1 = index1;
158 undo_context.swap.index2 = index2;
163 void rect_layer_undo(void *context, size_t context_size)
165 trace_assert(context);
166 trace_assert(sizeof(UndoContext) == context_size);
168 UndoContext *undo_context = context;
170 switch (undo_context->type) {
172 RectLayer *layer = undo_context->add.layer;
173 dynarray_delete_at(layer->rects, undo_context->add.index);
174 dynarray_delete_at(layer->colors, undo_context->add.index);
175 dynarray_delete_at(layer->ids, undo_context->add.index);
176 dynarray_delete_at(layer->actions, undo_context->add.index);
177 layer->selection = -1;
181 RectLayer *layer = undo_context->element.layer;
182 dynarray_insert_before(layer->rects, undo_context->element.index, &undo_context->element.rect);
183 dynarray_insert_before(layer->colors, undo_context->element.index, &undo_context->element.color);
184 dynarray_insert_before(layer->ids, undo_context->element.index, &undo_context->element.id);
185 dynarray_insert_before(layer->actions, undo_context->element.index, &undo_context->element.action);
186 layer->selection = -1;
190 RectLayer *layer = undo_context->element.layer;
191 dynarray_replace_at(layer->rects, undo_context->element.index, &undo_context->element.rect);
192 dynarray_replace_at(layer->colors, undo_context->element.index, &undo_context->element.color);
193 dynarray_replace_at(layer->ids, undo_context->element.index, &undo_context->element.id);
194 dynarray_replace_at(layer->actions, undo_context->element.index, &undo_context->element.action);
198 RectLayer *layer = undo_context->element.layer;
199 dynarray_swap(layer->rects, undo_context->swap.index1, undo_context->swap.index2);
200 dynarray_swap(layer->colors, undo_context->swap.index1, undo_context->swap.index2);
201 dynarray_swap(layer->ids, undo_context->swap.index1, undo_context->swap.index2);
202 dynarray_swap(layer->actions, undo_context->swap.index1, undo_context->swap.index2);
207 #define UNDO_PUSH(HISTORY, CONTEXT) \
209 UndoContext context = (CONTEXT); \
217 static int rect_layer_add_rect(RectLayer *layer,
220 UndoHistory *undo_history)
224 if (dynarray_push(layer->rects, &rect) < 0) {
228 if (dynarray_push(layer->colors, &color) < 0) {
232 char id[ENTITY_MAX_ID_SIZE];
233 snprintf(id, ENTITY_MAX_ID_SIZE, "%s_%d",
234 layer->id_name_prefix,
235 layer->id_name_counter++);
236 if (dynarray_push(layer->ids, id)) {
240 dynarray_push_empty(layer->actions);
244 create_undo_add_context(
246 dynarray_count(layer->rects) - 1));
251 static int rect_layer_rect_at(RectLayer *layer, Vec2f position)
255 int n = (int) dynarray_count(layer->rects);
256 Rect *rects = dynarray_data(layer->rects);
258 for (int i = n - 1; i >= 0; --i) {
259 if (rect_contains_point(rects[i], position)) {
267 static void rect_layer_swap_elements(RectLayer *layer, size_t a, size_t b,
268 UndoHistory *undo_history)
271 trace_assert(a < dynarray_count(layer->rects));
272 trace_assert(b < dynarray_count(layer->rects));
274 dynarray_swap(layer->rects, a, b);
275 dynarray_swap(layer->colors, a, b);
276 dynarray_swap(layer->ids, a, b);
277 dynarray_swap(layer->actions, a, b);
279 UNDO_PUSH(undo_history, create_undo_swap_context(layer, a, b));
282 static int rect_layer_delete_rect_at(RectLayer *layer,
284 UndoHistory *undo_history)
288 UNDO_PUSH(undo_history, create_undo_delete_context(layer));
290 dynarray_delete_at(layer->rects, i);
291 dynarray_delete_at(layer->colors, i);
292 dynarray_delete_at(layer->ids, i);
293 dynarray_delete_at(layer->actions, i);
298 static int calc_resize_mask(Vec2f point, Rect rect)
301 for (Rect_side side = 0; side < RECT_SIDE_N; ++side) {
302 if (rect_side_distance(rect, point, side) < RECT_LAYER_SELECTION_THICCNESS) {
303 mask = mask | (1 << side);
309 static int rect_layer_event_idle(RectLayer *layer,
310 const SDL_Event *event,
311 const Camera *camera,
312 UndoHistory *undo_history)
316 trace_assert(camera);
318 int color_changed = 0;
319 if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
324 if (layer->selection >= 0) {
325 dynarray_copy_to(layer->colors, &layer->inter_color, (size_t)layer->selection);
326 layer->state = RECT_LAYER_RECOLOR;
331 switch (event->type) {
332 case SDL_MOUSEBUTTONDOWN: {
333 switch (event->button.button) {
334 case SDL_BUTTON_LEFT: {
335 Vec2f position = camera_map_screen(
339 int rect_at_position =
340 rect_layer_rect_at(layer, position);
342 Rect *rects = dynarray_data(layer->rects);
343 Color *colors = dynarray_data(layer->colors);
345 if (layer->selection >= 0 &&
346 layer->selection == rect_at_position &&
347 (layer->resize_mask = calc_resize_mask(
348 vec((float) event->button.x, (float)event->button.y),
349 camera_rect(camera, rects[layer->selection])))) {
350 layer->state = RECT_LAYER_RESIZE;
351 dynarray_copy_to(layer->rects, &layer->inter_rect, (size_t) layer->selection);
352 } else if (rect_at_position >= 0) {
353 layer->selection = rect_at_position;
354 layer->state = RECT_LAYER_MOVE;
359 rects[layer->selection].x,
360 rects[layer->selection].y));
361 layer->color_picker =
362 create_color_picker_from_rgba(colors[rect_at_position]);
364 dynarray_copy_to(layer->rects, &layer->inter_rect, (size_t) rect_at_position);
366 layer->selection = rect_at_position;
368 if (layer->selection < 0) {
369 layer->state = RECT_LAYER_CREATE;
370 layer->create_begin = position;
371 layer->create_end = position;
379 switch (event->key.keysym.sym) {
381 if ((event->key.keysym.mod & KMOD_SHIFT)
382 && (layer->selection >= 0)
383 && ((size_t)(layer->selection + 1) < dynarray_count(layer->rects))) {
384 rect_layer_swap_elements(
386 (size_t) layer->selection,
387 (size_t) layer->selection + 1,
394 if ((event->key.keysym.mod & KMOD_SHIFT)
395 && (layer->selection > 0)
396 && ((size_t) layer->selection < dynarray_count(layer->rects))) {
397 rect_layer_swap_elements(
399 (size_t) layer->selection,
400 (size_t) layer->selection - 1,
407 if (layer->selection >= 0) {
408 rect_layer_delete_rect_at(layer, (size_t) layer->selection, undo_history);
409 layer->selection = -1;
414 if (layer->selection >= 0) {
415 const char *ids = dynarray_data(layer->ids);
416 Color *colors = dynarray_data(layer->colors);
419 layer->id_edit_field,
420 RECT_LAYER_ID_LABEL_SIZE,
421 color_invert(colors[layer->selection]));
423 layer->state = RECT_LAYER_ID_RENAME;
425 layer->id_edit_field,
426 ids + layer->selection * ENTITY_MAX_ID_SIZE);
427 SDL_StartTextInput();
432 if ((event->key.keysym.mod & KMOD_LCTRL) && layer->selection >= 0) {
434 dynarray_copy_to(layer->rects, &clipboard_rect, (size_t)layer->selection);
435 dynarray_copy_to(layer->colors, &clipboard_color, (size_t)layer->selection);
440 if ((event->key.keysym.mod & KMOD_LCTRL) && clipboard) {
442 SDL_GetMouseState(&x, &y);
443 Vec2f position = camera_map_screen(camera, x, y);
447 rect(position.x, position.y,
448 clipboard_rect.w, clipboard_rect.h),
460 static int rect_layer_event_create(RectLayer *layer,
461 const SDL_Event *event,
462 const Camera *camera,
463 UndoHistory *undo_history)
467 trace_assert(camera);
469 switch (event->type) {
470 case SDL_MOUSEBUTTONUP: {
471 switch (event->button.button) {
472 case SDL_BUTTON_LEFT: {
473 const Rect real_rect =
477 const float area = real_rect.w * real_rect.h;
479 if (area >= CREATE_AREA_THRESHOLD) {
483 color_picker_rgba(&layer->color_picker),
486 log_info("The area is too small %f. Such small box won't be created.\n", area);
488 layer->state = RECT_LAYER_IDLE;
493 case SDL_MOUSEMOTION: {
494 layer->create_end = camera_map_screen(
503 static int rect_layer_event_resize(RectLayer *layer,
504 const SDL_Event *event,
505 const Camera *camera,
506 UndoHistory *undo_history)
510 trace_assert(camera);
511 trace_assert(layer->selection >= 0);
513 Rect *rects = dynarray_data(layer->rects);
515 switch (event->type) {
516 case SDL_MOUSEMOTION: {
517 Vec2f position = camera_map_screen(
522 switch (layer->resize_mask) {
524 layer->inter_rect = rect_from_points(
525 vec(rects[layer->selection].x, position.y),
526 rect_position2(rects[layer->selection]));
530 layer->inter_rect = rect_from_points(
531 vec(position.x, rects[layer->selection].y),
532 rect_position2(rects[layer->selection]));
535 case 3: { // TOP,LEFT
536 layer->inter_rect = rect_from_points(
538 rect_position2(rects[layer->selection]));
542 layer->inter_rect = rect_from_points(
543 rect_position(rects[layer->selection]),
544 vec(rects[layer->selection].x + rects[layer->selection].w,
548 case 6: { // BOTTOM,LEFT
549 layer->inter_rect = rect_from_points(
550 vec(position.x, rects[layer->selection].y),
551 vec(rects[layer->selection].x + rects[layer->selection].w,
556 layer->inter_rect = rect_from_points(
557 rect_position(rects[layer->selection]),
559 rects[layer->selection].y + rects[layer->selection].h));
562 case 9: { // TOP,RIGHT
563 layer->inter_rect = rect_from_points(
564 vec(rects[layer->selection].x, position.y),
566 rects[layer->selection].y + rects[layer->selection].h));
569 case 12: { // BOTTOM,RIGHT
570 layer->inter_rect = rect_from_points(
571 rect_position(rects[layer->selection]),
577 case SDL_MOUSEBUTTONUP: {
578 layer->state = RECT_LAYER_IDLE;
579 UNDO_PUSH(undo_history, create_undo_update_context(layer));
580 dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
587 static int rect_layer_event_move(RectLayer *layer,
588 const SDL_Event *event,
589 const Camera *camera,
590 UndoHistory *undo_history)
594 trace_assert(camera);
595 trace_assert(layer->selection >= 0);
597 Rect *rects = dynarray_data(layer->rects);
599 switch (event->type) {
600 case SDL_MOUSEMOTION: {
601 const Uint8 *state = SDL_GetKeyboardState(NULL);
602 const Vec2f mouse_pos = vec_sub(
609 if (!(state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL])) {
610 layer->inter_rect.x = mouse_pos.x;
611 layer->inter_rect.y = mouse_pos.y;
613 const Vec2f rect_pos = rect_position(rects[layer->selection]);
615 const float dx = fabsf(rect_pos.x - mouse_pos.x);
616 const float dy = fabsf(rect_pos.y - mouse_pos.y);
619 layer->inter_rect.x = mouse_pos.x;
620 layer->inter_rect.y = rect_pos.y;
622 layer->inter_rect.x = rect_pos.x;
623 layer->inter_rect.y = mouse_pos.y;
628 case SDL_MOUSEBUTTONUP: {
629 layer->state = RECT_LAYER_IDLE;
631 float distance = vec_length(
632 vec_sub(rect_position(layer->inter_rect),
633 rect_position(rects[layer->selection])));
635 if (distance > 1e-6) {
636 UNDO_PUSH(undo_history, create_undo_update_context(layer));
637 dynarray_replace_at(layer->rects, (size_t) layer->selection, &layer->inter_rect);
644 static int rect_layer_event_id_rename(RectLayer *layer,
645 const SDL_Event *event,
646 const Camera *camera,
647 UndoHistory *undo_history)
651 trace_assert(camera);
652 trace_assert(layer->selection >= 0);
654 switch (event->type) {
656 switch (event->key.keysym.sym) {
658 UNDO_PUSH(undo_history, create_undo_update_context(layer));
660 char *id = dynarray_pointer_at(layer->ids, (size_t)layer->selection);
661 memset(id, 0, ENTITY_MAX_ID_SIZE);
662 memcpy(id, edit_field_as_text(layer->id_edit_field), ENTITY_MAX_ID_SIZE - 1);
663 layer->state = RECT_LAYER_IDLE;
668 layer->state = RECT_LAYER_IDLE;
675 return edit_field_event(layer->id_edit_field, event);
678 LayerPtr rect_layer_as_layer(RectLayer *rect_layer)
687 RectLayer *create_rect_layer(const char *id_name_prefix)
689 Lt *lt = create_lt();
691 RectLayer *layer = PUSH_LT(lt, nth_calloc(1, sizeof(RectLayer)), free);
697 layer->ids = PUSH_LT(
699 create_dynarray(sizeof(char) * ENTITY_MAX_ID_SIZE),
701 if (layer->ids == NULL) {
705 layer->rects = PUSH_LT(
707 create_dynarray(sizeof(Rect)),
709 if (layer->rects == NULL) {
713 layer->colors = PUSH_LT(
715 create_dynarray(sizeof(Color)),
717 if (layer->colors == NULL) {
721 layer->actions = PUSH_LT(
723 create_dynarray(sizeof(Action)),
725 if (layer->actions == NULL) {
729 layer->id_edit_field = PUSH_LT(
732 RECT_LAYER_ID_LABEL_SIZE,
735 if (layer->id_edit_field == NULL) {
744 sizeof(Grid) + sizeof(Widget*) * RECT_LAYER_GRID_ROWS * RECT_LAYER_GRID_COLUMNS),
746 if (layer->grid == NULL) {
749 layer->grid->rows = RECT_LAYER_GRID_ROWS;
750 layer->grid->columns = RECT_LAYER_GRID_COLUMNS;
751 grid_put_widget(layer->grid, &layer->action_picker.widget, 0, RECT_LAYER_GRID_COLUMNS - 1);
753 layer->color_picker = create_color_picker_from_rgba(rgba(1.0f, 0.0f, 0.0f, 1.0f));
754 layer->selection = -1;
755 layer->id_name_prefix = id_name_prefix;
760 RectLayer *create_rect_layer_from_line_stream(LineStream *line_stream, const char *id_name_prefix)
762 trace_assert(line_stream);
764 RectLayer *layer = create_rect_layer(id_name_prefix);
769 const char *line = line_stream_next(line_stream);
771 RETURN_LT(layer->lt, NULL);
775 if (sscanf(line, "%zu", &count) < 0) {
776 RETURN_LT(layer->lt, NULL);
779 for (size_t i = 0; i < count; ++i) {
780 line = line_stream_next(line_stream);
782 RETURN_LT(layer->lt, NULL);
787 char id[ENTITY_MAX_ID_SIZE];
791 "%"STRINGIFY(ENTITY_MAX_ID_SIZE)"s%f%f%f%f%6s%n",
796 log_fail("%s\n", strerror(errno));
797 RETURN_LT(layer->lt, NULL);
801 Color color = hexstr(hex);
802 dynarray_push(layer->rects, &rect);
803 dynarray_push(layer->ids, id);
804 dynarray_push(layer->colors, &color);
811 if (sscanf(line, "%d%n", (int*)&action.type, &n) > 0) {
813 switch (action.type) {
814 case ACTION_NONE: break;
816 case ACTION_TOGGLE_GOAL:
817 case ACTION_HIDE_LABEL: {
818 if (sscanf(line, "%"STRINGIFY(ENTITY_MAX_ID_SIZE)"s", action.entity_id) <= 0) {
819 log_fail("%s\n", strerror(errno));
820 RETURN_LT(layer->lt, NULL);
824 case ACTION_N: break;
828 dynarray_push(layer->actions, &action);
834 void destroy_rect_layer(RectLayer *layer)
837 RETURN_LT0(layer->lt);
840 int rect_layer_render(const RectLayer *layer, const Camera *camera, int active)
843 trace_assert(camera);
845 const size_t n = dynarray_count(layer->rects);
846 Rect *rects = dynarray_data(layer->rects);
847 Color *colors = dynarray_data(layer->colors);
848 const char *ids = dynarray_data(layer->ids);
851 for (size_t i = 0; i < n; ++i) {
852 Rect rect = rects[i];
853 Color color = colors[i];
855 if (layer->selection == (int) i) {
856 if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
857 rect = layer->inter_rect;
860 if (layer->state == RECT_LAYER_RECOLOR) {
861 color = layer->inter_color;
866 if (camera_fill_rect(
871 rgba(1.0f, 1.0f, 1.0f, active ? 1.0f : 0.5f))) < 0) {
877 if (active && layer->selection >= 0) {
878 Rect rect = rects[layer->selection];
879 Color color = colors[layer->selection];
881 if (layer->state == RECT_LAYER_RESIZE || layer->state == RECT_LAYER_MOVE) {
882 rect = layer->inter_rect;
885 if (layer->state == RECT_LAYER_RECOLOR) {
886 color = layer->inter_color;
889 const Rect overlay_rect =
891 camera_rect(camera, rect),
892 -RECT_LAYER_SELECTION_THICCNESS * 0.5f);
893 const Color overlay_color = color_invert(color);
896 if (camera_draw_thicc_rect_screen(
900 RECT_LAYER_SELECTION_THICCNESS) < 0) {
904 const Vec2f rect_id_pos = vec_sub(
907 RECT_LAYER_ID_LABEL_SIZE,
908 vec(0.0f, FONT_CHAR_HEIGHT)));
911 if (layer->state == RECT_LAYER_ID_RENAME) {
912 // ID renaming Edit Field
913 if (edit_field_render_world(
914 layer->id_edit_field,
921 if (camera_render_text(
923 ids + layer->selection * ENTITY_MAX_ID_SIZE,
924 RECT_LAYER_ID_LABEL_SIZE,
933 const Color color = color_picker_rgba(&layer->color_picker);
934 if (layer->state == RECT_LAYER_CREATE) {
935 if (camera_fill_rect(camera, rect_from_points(layer->create_begin, layer->create_end), color) < 0) {
940 if (active && color_picker_render(&layer->color_picker, camera) < 0) {
948 int rect_layer_event_recolor(RectLayer *layer,
949 const SDL_Event *event,
950 const Camera *camera,
951 UndoHistory *undo_history)
955 trace_assert(camera);
956 trace_assert(undo_history);
957 trace_assert(layer->selection >= 0);
959 int color_changed = 0;
960 if (color_picker_event(&layer->color_picker, event, camera, &color_changed) < 0) {
965 layer->inter_color = color_picker_rgba(&layer->color_picker);
967 if (!color_picker_drag(&layer->color_picker)) {
968 UNDO_PUSH(undo_history, create_undo_update_context(layer));
969 dynarray_replace_at(layer->colors, (size_t) layer->selection, &layer->inter_color);
970 layer->state = RECT_LAYER_IDLE;
977 int rect_layer_event(RectLayer *layer,
978 const SDL_Event *event,
979 const Camera *camera,
980 UndoHistory *undo_history,
985 trace_assert(undo_history);
988 switch (event->type) {
989 case SDL_WINDOWEVENT: {
990 switch (event->window.event) {
991 case SDL_WINDOWEVENT_RESIZED: {
992 grid_relayout(layer->grid, rect(0.0f, 0.0f,
993 (float) event->window.data1,
994 (float) event->window.data2));
1000 switch (layer->state) {
1001 case RECT_LAYER_IDLE:
1002 return rect_layer_event_idle(layer, event, camera, undo_history);
1004 case RECT_LAYER_CREATE:
1005 return rect_layer_event_create(layer, event, camera, undo_history);
1007 case RECT_LAYER_RESIZE:
1008 return rect_layer_event_resize(layer, event, camera, undo_history);
1010 case RECT_LAYER_MOVE:
1011 return rect_layer_event_move(layer, event, camera, undo_history);
1013 case RECT_LAYER_ID_RENAME:
1014 return rect_layer_event_id_rename(layer, event, camera, undo_history);
1016 case RECT_LAYER_RECOLOR:
1017 return rect_layer_event_recolor(layer, event, camera, undo_history);
1024 size_t rect_layer_count(const RectLayer *layer)
1026 return dynarray_count(layer->rects);
1029 const Rect *rect_layer_rects(const RectLayer *layer)
1031 return dynarray_data(layer->rects);
1034 const Color *rect_layer_colors(const RectLayer *layer)
1036 return dynarray_data(layer->colors);
1039 const char *rect_layer_ids(const RectLayer *layer)
1041 return dynarray_data(layer->ids);
1044 int rect_layer_dump_stream(const RectLayer *layer, FILE *filedump)
1046 trace_assert(layer);
1047 trace_assert(filedump);
1049 size_t n = dynarray_count(layer->ids);
1050 char *ids = dynarray_data(layer->ids);
1051 Rect *rects = dynarray_data(layer->rects);
1052 Color *colors = dynarray_data(layer->colors);
1053 Action *actions = dynarray_data(layer->actions);
1055 fprintf(filedump, "%zd\n", n);
1056 for (size_t i = 0; i < n; ++i) {
1057 fprintf(filedump, "%s %f %f %f %f ",
1058 ids + ENTITY_MAX_ID_SIZE * i,
1059 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
1060 color_hex_to_stream(colors[i], filedump);
1062 switch (actions[i].type) {
1063 case ACTION_NONE: {} break;
1065 case ACTION_TOGGLE_GOAL:
1066 case ACTION_HIDE_LABEL: {
1067 fprintf(filedump, " %d %.*s",
1068 (int)actions[i].type,
1069 ENTITY_MAX_ID_SIZE, actions[i].entity_id);
1071 case ACTION_N: break;
1074 fprintf(filedump, "\n");
1080 const Action *rect_layer_actions(const RectLayer *layer)
1082 return dynarray_data(layer->actions);