]> git.lizzy.rs Git - nothing.git/blob - src/ui/list_selector.c
Merge pull request #725 from tsoding/719
[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     list_selector->items = items;
43     list_selector->count = count;
44     list_selector->cursor = 0;
45     list_selector->selected_item = NULL;
46
47     return list_selector;
48 }
49
50 void destroy_list_selector(ListSelector *list_selector)
51 {
52     trace_assert(list_selector);
53     RETURN_LT0(list_selector->lt);
54 }
55
56 int list_selector_render(const ListSelector *list_selector,
57                          SDL_Renderer *renderer,
58                          Vec position,
59                          Vec font_scale,
60                          float padding_bottom)
61 {
62     trace_assert(list_selector);
63     trace_assert(renderer);
64
65     for (size_t i = 0; i < list_selector->count; ++i) {
66         const Vec current_position = vec_sum(
67             position,
68             vec(0.0f, (float) i * ((float) FONT_CHAR_HEIGHT * font_scale.y + padding_bottom)));
69
70         if (sprite_font_render_text(
71                 list_selector->sprite_font,
72                 renderer,
73                 current_position,
74                 font_scale,
75                 rgba(1.0f, 1.0f, 1.0f, 1.0f),
76                 list_selector->items[i]) < 0) {
77             return -1;
78         }
79
80         if (i == list_selector->cursor) {
81             SDL_Rect boundary_box = rect_for_sdl(
82                 sprite_font_boundary_box(
83                     list_selector->sprite_font,
84                     current_position,
85                     font_scale,
86                     list_selector->items[i]));
87             if (SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255) < 0) {
88                 return -1;
89             }
90
91             if (SDL_RenderDrawRect(renderer, &boundary_box) < 0) {
92                 return -1;
93             }
94         }
95     }
96
97     return 0;
98 }
99
100 Vec list_selector_size(const ListSelector *list_selector,
101                        Vec font_scale,
102                        float padding_bottom)
103 {
104     trace_assert(list_selector);
105
106     Vec result = vec(0.0f, 0.0f);
107
108     for (size_t i = 0; i < list_selector->count; ++i) {
109         Rect boundary_box = sprite_font_boundary_box(
110             list_selector->sprite_font,
111             vec(0.0f, 0.0f),
112             font_scale,
113             list_selector->items[i]);
114
115         result.x = fmaxf(result.x, boundary_box.w);
116         result.y += boundary_box.y + padding_bottom;
117     }
118
119     return result;
120 }
121
122 int list_selector_update(ListSelector *list_selector, float delta_time)
123 {
124     trace_assert(list_selector);
125     (void) delta_time;
126
127     return 0;
128 }
129
130 int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
131 {
132     trace_assert(list_selector);
133     trace_assert(event);
134
135     switch (event->type) {
136     case SDL_KEYDOWN:
137         switch (event->key.keysym.sym) {
138         case SDLK_UP:
139             if (list_selector->cursor > 0) {
140                 list_selector->cursor--;
141             }
142             break;
143         case SDLK_DOWN:
144             if (list_selector->cursor < list_selector->count - 1) {
145                 list_selector->cursor++;
146             }
147             break;
148         case SDLK_RETURN:
149             list_selector->selected_item = list_selector->items[list_selector->cursor];
150             break;
151         }
152         break;
153     }
154
155     return 0;
156 }
157
158 const char *list_selector_selected(const ListSelector *list_selector)
159 {
160     trace_assert(list_selector);
161     return list_selector->selected_item;
162 }
163
164 void list_selector_clean_selection(ListSelector *list_selector)
165 {
166     trace_assert(list_selector);
167     list_selector->selected_item = NULL;
168 }