button.c (4727B)
1 #include "button.h"
2 #include <tuxanci2/text.h>
3 #include <tuxanci2/display.h>
4 #include <tuxanci2/keyboard.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <stddef.h>
8
9 #define TA_BUTTON_FONT_SIZE 32
10 #define TA_BUTTON_FONT_SIZE_MAX 255
11 #define TA_BUTTON_SPACING 48
12 #define TA_BUTTON_COLOR_IDLE 118
13 #define TA_BUTTON_COLOR_SELECTED 255
14 #define TA_BUTTON_REFERENCE_WIDTH 800
15 #define TA_BUTTON_REFERENCE_HEIGHT 600
16
17 static uint32_t scale_to_display(uint32_t value) {
18 uint32_t display_width = ta_display_width();
19 uint32_t display_height = ta_display_height();
20 uint32_t numerator = display_width;
21 uint32_t denominator = TA_BUTTON_REFERENCE_WIDTH;
22
23 if ((uint32_t)display_width * TA_BUTTON_REFERENCE_HEIGHT >= (uint32_t)display_height * TA_BUTTON_REFERENCE_WIDTH) {
24 numerator = display_height;
25 denominator = TA_BUTTON_REFERENCE_HEIGHT;
26 }
27
28 uint32_t scaled = (value * numerator * 2 + denominator) / (denominator * 2);
29
30 return scaled == 0 ? 1 : scaled;
31 }
32
33 void ta_button_lists_init(ta_button_lists *list) {
34 if (list == NULL) {
35 return;
36 }
37
38 list->buttons = NULL;
39 list->buttons_size = 0;
40 list->size = 0;
41 list->selected = 0;
42 list->up_was_down = false;
43 list->down_was_down = false;
44 list->enter_was_down = false;
45 }
46
47 bool ta_button_lists_add(ta_button_lists *list, const char *label, ta_button_callback callback) {
48 if (list == NULL || label == NULL) {
49 return false;
50 }
51
52 if (list->size >= list->buttons_size) {
53 size_t new_capacity = list->buttons_size + 1;
54
55 ta_button *temp = (ta_button *)realloc(list->buttons, new_capacity * sizeof(ta_button));
56
57 if (temp == NULL) {
58 return false;
59 }
60
61 list->buttons = temp;
62 list->buttons_size = new_capacity;
63 }
64
65 uint32_t font_size = scale_to_display(TA_BUTTON_FONT_SIZE);
66
67 if (font_size > TA_BUTTON_FONT_SIZE_MAX) {
68 font_size = TA_BUTTON_FONT_SIZE_MAX;
69 }
70
71 ta_text text_idle = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE, TA_BUTTON_COLOR_IDLE), 1, TA_DISPLAY_RGB(0, 0, 0));
72 ta_text text_selected = ta_text_create(label, font_size, TA_DISPLAY_RGB(TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED, TA_BUTTON_COLOR_SELECTED), 1, TA_DISPLAY_RGB(0, 0, 0));
73
74 if (text_idle == 0 || text_selected == 0) {
75 ta_text_destroy(text_idle);
76 ta_text_destroy(text_selected);
77 return false;
78 }
79
80 ta_button *button = &list->buttons[list->size];
81
82 button->label = label;
83 button->callback = callback;
84 button->text_idle = text_idle;
85 button->text_selected = text_selected;
86 button->text_width = ta_text_width(text_idle);
87 button->text_height = ta_text_height(text_idle);
88
89 list->size++;
90
91 return true;
92 }
93
94 void ta_button_lists_update(ta_button_lists *list) {
95 if (list == NULL || list->size == 0) {
96 return;
97 }
98
99 bool up_down = ta_keyboard_is_down(KEY_UP);
100 bool down_down = ta_keyboard_is_down(KEY_DOWN);
101 bool enter_down = ta_keyboard_is_down(KEY_ENTER);
102 bool up_pressed = up_down && !list->up_was_down;
103 bool down_pressed = down_down && !list->down_was_down;
104 bool enter_pressed = enter_down && !list->enter_was_down;
105
106 list->up_was_down = up_down;
107 list->down_was_down = down_down;
108 list->enter_was_down = enter_down;
109
110 if (down_pressed || up_pressed) {
111 if (down_pressed) {
112 list->selected = (list->selected + 1) % list->size;
113 } else {
114 list->selected = list->selected == 0 ? list->size - 1 : list->selected - 1;
115 }
116 }
117
118 if (enter_pressed && list->buttons[list->selected].callback != NULL) {
119 list->buttons[list->selected].callback();
120 }
121 }
122
123 void ta_button_lists_draw(const ta_button_lists *list) {
124 if (list == NULL || list->size == 0) {
125 return;
126 }
127
128 uint32_t display_width = ta_display_width();
129 uint32_t display_height = ta_display_height();
130 int32_t spacing = (int32_t)scale_to_display(TA_BUTTON_SPACING);
131 int32_t center_y = (int32_t)(display_height / 2);
132 int32_t total_span = (int32_t)(list->size - 1) * spacing;
133 int32_t start_y = center_y - (total_span / 2);
134
135 for (size_t i = 0; i < list->size; i++) {
136 const ta_button *button = &list->buttons[i];
137 ta_text text = i == list->selected ? button->text_selected : button->text_idle;
138 int32_t y = start_y + (int32_t)i * spacing - (int32_t)(button->text_height / 2);
139
140 if (y < 0 || (size_t)y >= display_height || button->text_width > display_width) {
141 continue;
142 }
143
144 ta_text_draw(text, (display_width - button->text_width) / 2, (uint32_t)y);
145 }
146 }
147
148 void ta_button_lists_destroy(ta_button_lists *list) {
149 if (list == NULL) {
150 return;
151 }
152
153 for (size_t i = 0; i < list->size; i++) {
154 ta_text_destroy(list->buttons[i].text_idle);
155 ta_text_destroy(list->buttons[i].text_selected);
156 }
157
158 if (list->buttons != NULL) {
159 free(list->buttons);
160 }
161
162 ta_button_lists_init(list);
163 }