]> git.lizzy.rs Git - nothing.git/blob - src/ui/list_selector.c
Merge pull request #716 from tsoding/606
[nothing.git] / src / ui / list_selector.c
1 #include <stdlib.h>
2
3 #include <SDL2/SDL.h>
4
5 #include "system/stacktrace.h"
6 #include "system/lt.h"
7 #include "system/nth_alloc.h"
8 #include "system/str.h"
9 #include "math/point.h"
10 #include "game/sprite_font.h"
11
12 #include "./list_selector.h"
13
14 struct ListSelector
15 {
16     Lt *lt;
17     const Sprite_font *sprite_font;
18     const char **items;
19     size_t count;
20     size_t cursor;
21     const char *selected_item;
22 };
23
24 ListSelector *create_list_selector(const Sprite_font *sprite_font,
25                                    const char *items[],
26                                    size_t count)
27 {
28     trace_assert(items);
29
30     Lt *lt = create_lt();
31     if (lt == NULL) {
32         return NULL;
33     }
34
35     ListSelector *list_selector = PUSH_LT(lt, nth_alloc(sizeof(ListSelector)), free);
36     if (list_selector == NULL) {
37         RETURN_LT(lt, NULL);
38     }
39     list_selector->lt = lt;
40
41     list_selector->sprite_font = sprite_font;
42
43     list_selector->items = PUSH_LT(lt, nth_calloc(count, sizeof(const char*)), free);
44     if (list_selector->items == NULL) {
45         RETURN_LT(lt, NULL);
46     }
47
48     for (size_t i = 0; i < count; ++i) {
49         list_selector->items[i] = PUSH_LT(lt, string_duplicate(items[i], NULL), free);
50         if (list_selector->items[i] == NULL) {
51             RETURN_LT(lt, NULL);
52         }
53     }
54
55     list_selector->count = count;
56     list_selector->cursor = 0;
57     list_selector->selected_item = NULL;
58
59     return list_selector;
60 }
61
62 void destroy_list_selector(ListSelector *list_selector)
63 {
64     trace_assert(list_selector);
65     RETURN_LT0(list_selector->lt);
66 }
67
68 int list_selector_render(const ListSelector *list_selector,
69                          SDL_Renderer *renderer,
70                          Vec position,
71                          Vec font_scale,
72                          float padding_bottom)
73 {
74     trace_assert(list_selector);
75     trace_assert(renderer);
76
77     for (size_t i = 0; i < list_selector->count; ++i) {
78         const Vec current_position = vec_sum(
79             position,
80             vec(0.0f, (float) i * ((float) FONT_CHAR_HEIGHT * font_scale.y + padding_bottom)));
81
82         if (sprite_font_render_text(
83                 list_selector->sprite_font,
84                 renderer,
85                 current_position,
86                 font_scale,
87                 rgba(1.0f, 1.0f, 1.0f, 1.0f),
88                 list_selector->items[i]) < 0) {
89             return -1;
90         }
91
92         if (i == list_selector->cursor) {
93             SDL_Rect boundary_box = rect_for_sdl(
94                 sprite_font_boundary_box(
95                     list_selector->sprite_font,
96                     current_position,
97                     font_scale,
98                     list_selector->items[i]));
99             if (SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255) < 0) {
100                 return -1;
101             }
102
103             if (SDL_RenderDrawRect(renderer, &boundary_box) < 0) {
104                 return -1;
105             }
106         }
107     }
108
109     return 0;
110 }
111
112 Vec list_selector_size(const ListSelector *list_selector,
113                        Vec font_scale,
114                        float padding_bottom)
115 {
116     trace_assert(list_selector);
117
118     Vec result = vec(0.0f, 0.0f);
119
120     for (size_t i = 0; i < list_selector->count; ++i) {
121         Rect boundary_box = sprite_font_boundary_box(
122             list_selector->sprite_font,
123             vec(0.0f, 0.0f),
124             font_scale,
125             list_selector->items[i]);
126
127         result.x = fmaxf(result.x, boundary_box.w);
128         result.y += boundary_box.y + padding_bottom;
129     }
130
131     return result;
132 }
133
134 int list_selector_update(ListSelector *list_selector, float delta_time)
135 {
136     trace_assert(list_selector);
137     (void) delta_time;
138
139     return 0;
140 }
141
142 int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
143 {
144     trace_assert(list_selector);
145     trace_assert(event);
146
147     switch (event->type) {
148     case SDL_KEYDOWN:
149         switch (event->key.keysym.sym) {
150         case SDLK_UP:
151             if (list_selector->cursor > 0) {
152                 list_selector->cursor--;
153             }
154             break;
155         case SDLK_DOWN:
156             if (list_selector->cursor < list_selector->count - 1) {
157                 list_selector->cursor++;
158             }
159             break;
160         case SDLK_RETURN:
161             list_selector->selected_item = list_selector->items[list_selector->cursor];
162             break;
163         }
164         break;
165     }
166
167     return 0;
168 }
169
170 const char *list_selector_selected(const ListSelector *list_selector)
171 {
172     trace_assert(list_selector);
173     return list_selector->selected_item;
174 }