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