]> git.lizzy.rs Git - nothing.git/blob - src/ui/list_selector.c
`Lt *` -> `Lt `
[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 #include "system/log.h"
12
13 #include "./list_selector.h"
14
15 struct ListSelector
16 {
17     Lt lt;
18     const Sprite_font *sprite_font;
19     const char **items;
20     size_t count;
21     size_t cursor;
22     int selected_item;
23     Vec position;
24     Vec font_scale;
25     float padding_bottom;
26 };
27
28 ListSelector *create_list_selector(const Sprite_font *sprite_font,
29                                    const char *items[],
30                                    size_t count,
31                                    Vec font_scale,
32                                    float padding_bottom)
33 {
34     trace_assert(items);
35
36     Lt lt = create_lt();
37     if (lt == NULL) {
38         return NULL;
39     }
40
41     ListSelector *list_selector = PUSH_LT(lt, nth_calloc(1, sizeof(ListSelector)), free);
42     if (list_selector == NULL) {
43         RETURN_LT(lt, NULL);
44     }
45     list_selector->lt = lt;
46
47     list_selector->sprite_font = sprite_font;
48     list_selector->items = items;
49     list_selector->count = count;
50     list_selector->cursor = 0;
51     list_selector->selected_item = -1;
52     list_selector->position = vec(0.0f, 0.0f);
53     list_selector->font_scale = font_scale;
54     list_selector->padding_bottom = padding_bottom;
55
56     return list_selector;
57 }
58
59 void destroy_list_selector(ListSelector *list_selector)
60 {
61     trace_assert(list_selector);
62     RETURN_LT0(list_selector->lt);
63 }
64
65 int list_selector_render(const ListSelector *list_selector,
66                          SDL_Renderer *renderer)
67 {
68     trace_assert(list_selector);
69     trace_assert(renderer);
70
71     for (size_t i = 0; i < list_selector->count; ++i) {
72         const Vec current_position = vec_sum(
73             list_selector->position,
74             vec(0.0f, (float) i * ((float) FONT_CHAR_HEIGHT * list_selector->font_scale.y + list_selector->padding_bottom)));
75
76         if (sprite_font_render_text(
77                 list_selector->sprite_font,
78                 renderer,
79                 current_position,
80                 list_selector->font_scale,
81                 rgba(1.0f, 1.0f, 1.0f, 1.0f),
82                 list_selector->items[i]) < 0) {
83             return -1;
84         }
85
86         if (i == list_selector->cursor) {
87             SDL_Rect boundary_box = rect_for_sdl(
88                 sprite_font_boundary_box(
89                     list_selector->sprite_font,
90                     current_position,
91                     list_selector->font_scale,
92                     list_selector->items[i]));
93             if (SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255) < 0) {
94                 return -1;
95             }
96
97             if (SDL_RenderDrawRect(renderer, &boundary_box) < 0) {
98                 return -1;
99             }
100         }
101     }
102
103     return 0;
104 }
105
106 Vec list_selector_size(const ListSelector *list_selector,
107                        Vec font_scale,
108                        float padding_bottom)
109 {
110     trace_assert(list_selector);
111
112     Vec result = vec(0.0f, 0.0f);
113
114     for (size_t i = 0; i < list_selector->count; ++i) {
115         Rect boundary_box = sprite_font_boundary_box(
116             list_selector->sprite_font,
117             vec(0.0f, 0.0f),
118             font_scale,
119             list_selector->items[i]);
120
121         result.x = fmaxf(result.x, boundary_box.w);
122         result.y += boundary_box.y + padding_bottom;
123     }
124
125     return result;
126 }
127
128 int list_selector_update(ListSelector *list_selector, float delta_time)
129 {
130     trace_assert(list_selector);
131     (void) delta_time;
132
133     return 0;
134 }
135
136 int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
137 {
138     trace_assert(list_selector);
139     trace_assert(event);
140
141     switch (event->type) {
142     case SDL_KEYDOWN:
143         switch (event->key.keysym.sym) {
144         case SDLK_UP:
145             if (list_selector->cursor > 0) {
146                 list_selector->cursor--;
147             }
148             break;
149         case SDLK_DOWN:
150             if (list_selector->cursor < list_selector->count - 1) {
151                 list_selector->cursor++;
152             }
153             break;
154         case SDLK_RETURN:
155             list_selector->selected_item = (int) list_selector->cursor;
156             break;
157         }
158         break;
159
160     case SDL_MOUSEMOTION: {
161         const Vec mouse_pos = vec((float)event->motion.x, (float)event->motion.y);
162         Vec position = list_selector->position;
163
164         for (size_t i = 0; i < list_selector->count; ++i) {
165             Rect boundary_box = sprite_font_boundary_box(
166                 list_selector->sprite_font,
167                 position,
168                 list_selector->font_scale,
169                 list_selector->items[i]);
170
171             if (rect_contains_point(boundary_box, mouse_pos)) {
172                 list_selector->cursor = i;
173             }
174
175             position.y += boundary_box.h + list_selector->padding_bottom;
176         }
177     } break;
178
179     case SDL_MOUSEBUTTONDOWN: {
180         switch (event->button.button) {
181         case SDL_BUTTON_LEFT: {
182             list_selector->selected_item = (int) list_selector->cursor;
183         } break;
184         }
185     } break;
186     }
187
188     return 0;
189 }
190
191 int list_selector_selected(const ListSelector *list_selector)
192 {
193     trace_assert(list_selector);
194     return list_selector->selected_item;
195 }
196
197 void list_selector_clean_selection(ListSelector *list_selector)
198 {
199     trace_assert(list_selector);
200     list_selector->selected_item = -1;
201 }
202
203 void list_selector_move(ListSelector *list_selector, Vec position)
204 {
205     list_selector->position = position;
206 }