Fix mouse handling on macOS
[full-beans.git] / main.c
blob8b558017e91cc75546d8b61afeda671ae2c5d255
1 #include "renderer.h"
2 #include "microui.h"
4 #include <stdio.h>
5 #include <ctype.h>
6 #include <string.h>
7 #include <stdlib.h>
10 static char logbuf[64000];
11 static int logbuf_updated = 0;
12 static float bg[3] = { 90, 95, 100 };
15 static void write_log(const char *text) {
16 if (logbuf[0]) { strcat(logbuf, "\n"); }
17 strcat(logbuf, text);
18 logbuf_updated = 1;
22 static void test_window(mu_Context *ctx) {
23 /* do window */
24 if (mu_begin_window(ctx, "Demo Window", mu_rect(40, 40, 300, 450))) {
25 mu_Container *win = mu_get_current_container(ctx);
26 win->rect.w = mu_max(win->rect.w, 240);
27 win->rect.h = mu_max(win->rect.h, 300);
29 /* window info */
30 if (mu_header(ctx, "Window Info")) {
31 mu_Container *win = mu_get_current_container(ctx);
32 char buf[64];
33 mu_layout_row(ctx, 2, (int[]) { 54, -1 }, 0);
34 mu_label(ctx,"Position:");
35 sprintf(buf, "%d, %d", win->rect.x, win->rect.y); mu_label(ctx, buf);
36 mu_label(ctx, "Size:");
37 sprintf(buf, "%d, %d", win->rect.w, win->rect.h); mu_label(ctx, buf);
40 /* labels + buttons */
41 if (mu_header_ex(ctx, "Test Buttons", MU_OPT_EXPANDED)) {
42 mu_layout_row(ctx, 3, (int[]) { 86, -110, -1 }, 0);
43 mu_label(ctx, "Test buttons 1:");
44 if (mu_button(ctx, "Button 1")) { write_log("Pressed button 1"); }
45 if (mu_button(ctx, "Button 2")) { write_log("Pressed button 2"); }
46 mu_label(ctx, "Test buttons 2:");
47 if (mu_button(ctx, "Button 3")) { write_log("Pressed button 3"); }
48 if (mu_button(ctx, "Popup")) { mu_open_popup(ctx, "Test Popup"); }
49 if (mu_begin_popup(ctx, "Test Popup")) {
50 mu_button(ctx, "Hello");
51 mu_button(ctx, "World");
52 mu_end_popup(ctx);
56 /* tree */
57 if (mu_header_ex(ctx, "Tree and Text", MU_OPT_EXPANDED)) {
58 mu_layout_row(ctx, 2, (int[]) { 140, -1 }, 0);
59 mu_layout_begin_column(ctx);
60 if (mu_begin_treenode(ctx, "Test 1")) {
61 if (mu_begin_treenode(ctx, "Test 1a")) {
62 mu_label(ctx, "Hello");
63 mu_label(ctx, "world");
64 mu_end_treenode(ctx);
66 if (mu_begin_treenode(ctx, "Test 1b")) {
67 if (mu_button(ctx, "Button 1")) { write_log("Pressed button 1"); }
68 if (mu_button(ctx, "Button 2")) { write_log("Pressed button 2"); }
69 mu_end_treenode(ctx);
71 mu_end_treenode(ctx);
73 if (mu_begin_treenode(ctx, "Test 2")) {
74 mu_layout_row(ctx, 2, (int[]) { 54, 54 }, 0);
75 if (mu_button(ctx, "Button 3")) { write_log("Pressed button 3"); }
76 if (mu_button(ctx, "Button 4")) { write_log("Pressed button 4"); }
77 if (mu_button(ctx, "Button 5")) { write_log("Pressed button 5"); }
78 if (mu_button(ctx, "Button 6")) { write_log("Pressed button 6"); }
79 mu_end_treenode(ctx);
81 if (mu_begin_treenode(ctx, "Test 3")) {
82 static int checks[3] = { 1, 0, 1 };
83 mu_checkbox(ctx, "Checkbox 1", &checks[0]);
84 mu_checkbox(ctx, "Checkbox 2", &checks[1]);
85 mu_checkbox(ctx, "Checkbox 3", &checks[2]);
86 mu_end_treenode(ctx);
88 mu_layout_end_column(ctx);
90 mu_layout_begin_column(ctx);
91 mu_layout_row(ctx, 1, (int[]) { -1 }, 0);
92 mu_text(ctx, "Lorem ipsum dolor sit amet, consectetur adipiscing "
93 "elit. Maecenas lacinia, sem eu lacinia molestie, mi risus faucibus "
94 "ipsum, eu varius magna felis a nulla.");
95 mu_layout_end_column(ctx);
98 /* background color sliders */
99 if (mu_header_ex(ctx, "Background Color", MU_OPT_EXPANDED)) {
100 mu_layout_row(ctx, 2, (int[]) { -78, -1 }, 74);
101 /* sliders */
102 mu_layout_begin_column(ctx);
103 mu_layout_row(ctx, 2, (int[]) { 46, -1 }, 0);
104 mu_label(ctx, "Red:"); mu_slider(ctx, &bg[0], 0, 255);
105 mu_label(ctx, "Green:"); mu_slider(ctx, &bg[1], 0, 255);
106 mu_label(ctx, "Blue:"); mu_slider(ctx, &bg[2], 0, 255);
107 mu_layout_end_column(ctx);
108 /* color preview */
109 mu_Rect r = mu_layout_next(ctx);
110 mu_draw_rect(ctx, r, mu_color(bg[0], bg[1], bg[2], 255));
111 char buf[32];
112 sprintf(buf, "#%02X%02X%02X", (int) bg[0], (int) bg[1], (int) bg[2]);
113 mu_draw_control_text(ctx, buf, r, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER);
116 mu_end_window(ctx);
121 static void log_window(mu_Context *ctx) {
122 if (mu_begin_window(ctx, "Log Window", mu_rect(350, 40, 300, 200))) {
123 /* output text panel */
124 mu_layout_row(ctx, 1, (int[]) { -1 }, -25);
125 mu_begin_panel(ctx, "Log Output");
126 mu_Container *panel = mu_get_current_container(ctx);
127 mu_layout_row(ctx, 1, (int[]) { -1 }, -1);
128 mu_text(ctx, logbuf);
129 mu_end_panel(ctx);
130 if (logbuf_updated) {
131 panel->scroll.y = panel->content_size.y;
132 logbuf_updated = 0;
135 /* input textbox + submit button */
136 static char buf[128];
137 int submitted = 0;
138 mu_layout_row(ctx, 2, (int[]) { -70, -1 }, 0);
139 if (mu_textbox(ctx, buf, sizeof(buf)) & MU_RES_SUBMIT) {
140 mu_set_focus(ctx, ctx->last_id);
141 submitted = 1;
143 if (mu_button(ctx, "Submit")) { submitted = 1; }
144 if (submitted) {
145 write_log(buf);
146 buf[0] = '\0';
149 mu_end_window(ctx);
154 static int uint8_slider(mu_Context *ctx, unsigned char *value, int low, int high) {
155 static float tmp;
156 mu_push_id(ctx, &value, sizeof(value));
157 tmp = *value;
158 int res = mu_slider_ex(ctx, &tmp, low, high, 0, "%.0f", MU_OPT_ALIGNCENTER);
159 *value = tmp;
160 mu_pop_id(ctx);
161 return res;
165 static void style_window(mu_Context *ctx) {
166 static struct { const char *label; int idx; } colors[] = {
167 { "text:", MU_COLOR_TEXT },
168 { "border:", MU_COLOR_BORDER },
169 { "windowbg:", MU_COLOR_WINDOWBG },
170 { "titlebg:", MU_COLOR_TITLEBG },
171 { "titletext:", MU_COLOR_TITLETEXT },
172 { "panelbg:", MU_COLOR_PANELBG },
173 { "button:", MU_COLOR_BUTTON },
174 { "buttonhover:", MU_COLOR_BUTTONHOVER },
175 { "buttonfocus:", MU_COLOR_BUTTONFOCUS },
176 { "base:", MU_COLOR_BASE },
177 { "basehover:", MU_COLOR_BASEHOVER },
178 { "basefocus:", MU_COLOR_BASEFOCUS },
179 { "scrollbase:", MU_COLOR_SCROLLBASE },
180 { "scrollthumb:", MU_COLOR_SCROLLTHUMB },
181 { NULL }
184 if (mu_begin_window(ctx, "Style Editor", mu_rect(350, 250, 300, 240))) {
185 int sw = mu_get_current_container(ctx)->body.w * 0.14;
186 mu_layout_row(ctx, 6, (int[]) { 80, sw, sw, sw, sw, -1 }, 0);
187 for (int i = 0; colors[i].label; i++) {
188 mu_label(ctx, colors[i].label);
189 uint8_slider(ctx, &ctx->style->colors[i].r, 0, 255);
190 uint8_slider(ctx, &ctx->style->colors[i].g, 0, 255);
191 uint8_slider(ctx, &ctx->style->colors[i].b, 0, 255);
192 uint8_slider(ctx, &ctx->style->colors[i].a, 0, 255);
193 mu_draw_rect(ctx, mu_layout_next(ctx), ctx->style->colors[i]);
195 mu_end_window(ctx);
200 static void process_frame(mu_Context *ctx) {
201 mu_begin(ctx);
202 style_window(ctx);
203 log_window(ctx);
204 test_window(ctx);
205 mu_end(ctx);
209 static int text_width(mu_Font font, const char *text, int len) {
210 if (len == -1) { len = strlen(text); }
211 return r_get_text_width(text, len);
214 static int text_height(mu_Font font) {
215 return r_get_text_height();
218 int main(int argc, char **argv) {
219 r_init();
221 /* init microui */
222 mu_Context *ctx = malloc(sizeof(mu_Context));
223 mu_init(ctx);
224 ctx->text_width = text_width;
225 ctx->text_height = text_height;
227 int fps = 60;
228 int mousex = 0, mousey = 0;
230 /* main loop */
231 for (;;) {
232 int64_t before = r_get_time();
233 if (r_mouse_moved(&mousex, &mousey)) {
234 mu_input_mousemove(ctx, mousex, mousey);
236 if (r_mouse_down()) {
237 mu_input_mousedown(ctx, mousex, mousey, MU_MOUSE_LEFT);
238 } else if (r_mouse_up()) {
239 mu_input_mouseup(ctx, mousex, mousey, MU_MOUSE_LEFT);
241 // TODO(max): scroll
242 if (r_key_down(0x1b)) { break; } // esc
243 if (r_key_down('\n')) { mu_input_keydown(ctx, MU_KEY_RETURN); }
244 else if (r_key_up('\n')) { mu_input_keyup(ctx, MU_KEY_RETURN); }
245 if (r_key_down('\b')) { mu_input_keydown(ctx, MU_KEY_BACKSPACE); }
246 else if (r_key_up('\b')) { mu_input_keyup(ctx, MU_KEY_BACKSPACE); }
247 for (int i = 0; i < 256; i++) {
248 if (r_key_down(i)) {
249 if (' ' <= i && i <= '~') {
250 char text[2] = {i, 0};
251 if (isalpha(i)) {
252 if (!r_shift_pressed()) {
253 text[0] = tolower(i);
256 else {
257 // TODO(kartik): depends on keyboard layout
259 mu_input_text(ctx, text);
261 continue;
263 // TODO(max): mod
266 /* process frame */
267 process_frame(ctx);
269 /* render */
270 r_clear(mu_color(bg[0], bg[1], bg[2], 255));
271 mu_Command *cmd = NULL;
272 while (mu_next_command(ctx, &cmd)) {
273 switch (cmd->type) {
274 case MU_COMMAND_TEXT: r_draw_text(cmd->text.str, cmd->text.pos, cmd->text.color); break;
275 case MU_COMMAND_RECT: r_draw_rect(cmd->rect.rect, cmd->rect.color); break;
276 case MU_COMMAND_ICON: r_draw_icon(cmd->icon.id, cmd->icon.rect, cmd->icon.color); break;
277 case MU_COMMAND_CLIP: r_set_clip_rect(cmd->clip.rect); break;
280 r_present();
281 int64_t after = r_get_time();
282 int64_t paint_time_ms = after - before;
283 int64_t frame_budget_ms = 1000 / fps;
284 int64_t sleep_time_ms = frame_budget_ms - paint_time_ms;
285 if (sleep_time_ms > 0) {
286 r_sleep(sleep_time_ms);
290 return 0;