Very slow work on new style slider
[carveJwlIkooP6JGAAIwe30JlM.git] / menu.c
1 #pragma once
2 #include "skaterift.h"
3 #include "menu.h"
4 #include "model.h"
5 #include "entity.h"
6 #include "input.h"
7 #include "world_map.h"
8 #include "ent_miniworld.h"
9 #include "audio.h"
10 #include "workshop.h"
11 #include "gui.h"
12 #include "shaders/model_menu.h"
13
14 struct global_menu menu = { .skip_starter = 0 };
15
16 void menu_at_begin(void)
17 {
18 if( menu.skip_starter ) return;
19
20 skaterift.activity = k_skaterift_menu;
21 menu.page = k_menu_page_starter;
22 }
23
24 void menu_init(void)
25 {
26 vg_console_reg_var( "skip_starter_menu", &menu.skip_starter,
27 k_var_dtype_i32, VG_VAR_PERSISTENT );
28 }
29
30 void menu_open( enum menu_page page )
31 {
32 skaterift.activity = k_skaterift_menu;
33
34 if( page != k_menu_page_any )
35 {
36 menu.page = page;
37 }
38 }
39
40 bool menu_viewing_map(void)
41 {
42 return (skaterift.activity == k_skaterift_menu) &&
43 (menu.page == k_menu_page_main) &&
44 (menu.main_index == k_menu_main_map);
45 }
46
47 static void menu_decor_select( ui_rect rect )
48 {
49 ui_px b = vg_ui.font->sx, hb = b/2;
50 ui_rect a0 = { rect[0] - 20 - hb, rect[1] + rect[3]/2 - hb, b,b },
51 a1 = { rect[0] + rect[2] + 20 + hb, rect[1] + rect[3]/2 - hb, b,b };
52
53 ui_text( a0, "\x95", 1, k_ui_align_middle_center, 0 );
54 ui_text( a1, "\x93", 1, k_ui_align_middle_center, 0 );
55 }
56
57 static void menu_standard_widget( ui_rect inout_panel, ui_rect rect, ui_px s )
58 {
59 ui_split( inout_panel, k_ui_axis_h, vg_ui.font->sy*s*2,
60 2, rect, inout_panel );
61 }
62
63 static bool menu_slider( ui_rect inout_panel, bool select, const char *label,
64 const f32 min, const f32 max, f32 *value,
65 const char *format )
66 {
67 ui_rect rect, box;
68 menu_standard_widget( inout_panel, rect, 1 );
69 ui_label( rect, label, 1, 8, box );
70
71 f32 t;
72 enum ui_button_state state = ui_slider_base( box, min, max, value, &t ),
73 mask_using =
74 k_ui_button_holding_inside |
75 k_ui_button_holding_outside |
76 k_ui_button_click,
77 mask_brighter = mask_using | k_ui_button_hover;
78
79 if( menu.input_mode == k_menu_input_mode_keys )
80 {
81 if( select )
82 {
83 f32 m = axis_state( k_sraxis_mbrowse_h );
84 if( fabsf(m) > 0.5f )
85 {
86 *value += m * vg.time_frame_delta * ((max-min) / 2.0f);
87 *value = vg_clampf( *value, min, max );
88 }
89
90 menu_decor_select( rect );
91 state |= k_ui_button_hover;
92 }
93 }
94
95 ui_rect line = { box[0], box[1], t * (f32)box[2], box[3] };
96 ui_fill( line, state&mask_brighter? GUI_COL_ACTIVE: GUI_COL_NORM );
97 ui_fill( (ui_rect){ box[0]+line[2], box[1], box[2]-line[2], box[3] },
98 GUI_COL_DARK );
99
100 ui_outline( box, 1, state? GUI_COL_HI: GUI_COL_ACTIVE, 0 );
101 ui_slider_text( box, NULL, *value );
102
103 return (state & mask_using) && 1;
104 }
105
106 static enum ui_button_state menu_button( ui_rect inout_panel, bool select,
107 const char *text )
108 {
109 ui_rect rect;
110 menu_standard_widget( inout_panel, rect, 1 );
111
112 enum ui_button_state state = k_ui_button_none;
113
114 if( menu.input_mode == k_menu_input_mode_keys )
115 {
116 if( select )
117 {
118 menu_decor_select( rect );
119
120 if( button_down( k_srbind_maccept ) )
121 state = k_ui_button_click;
122 }
123 }
124 else
125 {
126 state = ui_button_base( rect );
127 select = 0;
128 }
129
130 if( state == k_ui_button_click )
131 {
132 ui_fill( rect, GUI_COL_DARK );
133 }
134 else if( state == k_ui_button_holding_inside )
135 {
136 ui_fill( rect, GUI_COL_DARK );
137 }
138 else if( state == k_ui_button_holding_outside )
139 {
140 ui_fill( rect, GUI_COL_DARK );
141 ui_outline( rect, 1, GUI_COL_CLICK, 0 );
142 }
143 else if( state == k_ui_button_hover )
144 {
145 ui_fill( rect, GUI_COL_ACTIVE );
146 ui_outline( rect, 1, GUI_COL_CLICK, 0 );
147 }
148 else
149 ui_fill( rect, select? GUI_COL_ACTIVE: GUI_COL_NORM );
150
151 ui_text( rect, text, 1, k_ui_align_middle_center, 0 );
152 return state;
153 }
154
155 void menu_gui(void)
156 {
157 if( button_down( k_srbind_mopen ) )
158 {
159 if( skaterift.activity == k_skaterift_default )
160 {
161 menu_open( k_menu_page_main );
162 return;
163 }
164 }
165
166 if( skaterift.activity != k_skaterift_menu )
167 return;
168
169 /* get buttons inputs
170 * -------------------------------------------------------------------*/
171 int ml = button_down( k_srbind_mleft ),
172 mr = button_down( k_srbind_mright ),
173 mu = button_down( k_srbind_mup ),
174 md = button_down( k_srbind_mdown ),
175 mh = ml-mr,
176 mv = mu-md,
177 enter = button_down( k_srbind_maccept );
178
179 if( mh||mv||enter )
180 {
181 menu.input_mode = k_menu_input_mode_keys;
182 }
183
184 /* get mouse inputs
185 * --------------------------------------------------------------------*/
186 menu.mouse_dist += v2_length( vg.mouse_delta ); /* TODO: Move to UI */
187 if( menu.mouse_dist > 10.0f )
188 {
189 menu.input_mode = k_menu_input_mode_mouse;
190 menu.mouse_dist = 0.0f;
191 }
192
193 if( ui_clicking(UI_MOUSE_LEFT) || ui_clicking(UI_MOUSE_RIGHT) )
194 {
195 menu.input_mode = k_menu_input_mode_mouse;
196 }
197
198 if( menu.input_mode == k_menu_input_mode_mouse )
199 {
200 /*
201 * handle mouse input
202 * ------------------------------------------------------------*/
203 vg_ui.wants_mouse = 1;
204 }
205
206 if( skaterift.activity != k_skaterift_menu ) return;
207
208
209 /* TOP BAR
210 * -------------------------------------------------------------------*/
211
212 ui_font_face( &vgf_default_title );
213 ui_px height = vg_ui.font->ch + 16;
214 ui_rect topbar = { 0, 0, vg.window_x, height };
215
216 const char *opts[] = {
217 [k_menu_main_main] = "Menu",
218 [k_menu_main_map] = "Map",
219 [k_menu_main_settings ] = "Settings"
220 };
221
222 /* TAB CONTROL */
223 u8 lb_down = 0, rb_down = 0;
224 vg_exec_input_program( k_vg_input_type_button_u8,
225 (vg_input_op[]){
226 vg_joy_button, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, vg_end
227 }, &rb_down );
228 vg_exec_input_program( k_vg_input_type_button_u8,
229 (vg_input_op[]){
230 vg_joy_button, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, vg_end
231 }, &lb_down );
232
233 if( menu.repeater > 0.0f )
234 {
235 menu.repeater -= vg_minf( vg.time_frame_delta, 0.5f );
236 }
237 else
238 {
239 if( lb_down != rb_down )
240 {
241 menu.main_index += rb_down;
242 menu.main_index -= lb_down;
243 menu.repeater += 0.2f;
244
245 if( menu.main_index == -1 )
246 menu.main_index ++;
247
248 if( menu.main_index == vg_list_size(opts) )
249 menu.main_index --;
250 }
251 }
252
253 ui_px x = 0, spacer = 8;
254 for( u32 draw=0; draw<2; draw ++ )
255 {
256 if( menu.input_mode == k_menu_input_mode_keys )
257 {
258 if( draw )
259 {
260 ui_rect inf_lb = { x, 0, 32, height };
261 ui_fill( inf_lb, lb_down? GUI_COL_NORM: GUI_COL_NORM );
262 ui_text( inf_lb, "\x91", 1, k_ui_align_middle_center, 0 );
263 }
264 x += 32 + spacer;
265 }
266
267 for( i32 i=0; i<vg_list_size(opts); i ++ )
268 {
269 ui_rect box = { x, 0, ui_text_line_width(opts[i]) + 32, height };
270
271 if( draw )
272 {
273 enum ui_button_state state = ui_button_base( box );
274 if( state == k_ui_button_click )
275 {
276 ui_fill( box, GUI_COL_DARK );
277 menu.main_index = i;
278 }
279 else if( state == k_ui_button_holding_inside )
280 {
281 ui_fill( box, GUI_COL_DARK );
282 }
283 else if( state == k_ui_button_holding_outside )
284 {
285 ui_fill( box, GUI_COL_DARK );
286 ui_outline( box, 1, GUI_COL_CLICK, 0 );
287 }
288 else if( state == k_ui_button_hover )
289 {
290 ui_fill( box, GUI_COL_NORM );
291 ui_outline( box, 1, GUI_COL_ACTIVE, 0 );
292 }
293 else
294 ui_fill( box, i==menu.main_index? GUI_COL_ACTIVE: GUI_COL_NORM );
295
296 ui_text( box, opts[i], 1, k_ui_align_middle_center, 0 );
297 }
298
299 x += box[2] + spacer;
300 }
301
302 if( menu.input_mode == k_menu_input_mode_keys )
303 {
304 if( draw )
305 {
306 ui_rect inf_rb = { x, 0, 32, height };
307 ui_fill( inf_rb, rb_down? GUI_COL_NORM: GUI_COL_NORM );
308 ui_text( inf_rb, "\x92", 1, k_ui_align_middle_center, 0 );
309 }
310 x += 32;
311 }
312
313 if( draw )
314 ui_fill( (ui_rect){ x+8,0, vg.window_x-(x+8),height }, GUI_COL_NORM );
315 else
316 {
317 x = vg.window_x/2 - x/2;
318 ui_fill( (ui_rect){ 0, 0, x-8, height }, GUI_COL_NORM );
319 }
320 }
321
322 if( menu.main_index == k_menu_main_map )
323 {
324 ui_font_face( &vgf_default_large );
325 ui_rect title = { vg.window_x/2 - 512/2, height+8, 512, 64 };
326
327 ui_px x = 8,
328 y = height+8;
329
330 struct ui_vert *vs =
331 ui_fill( (ui_rect){ x,y, 0,height },
332 world_static.active_instance? GUI_COL_DARK: GUI_COL_ACTIVE );
333
334 char buf[64];
335 vg_str str;
336 vg_strnull( &str, buf, sizeof(buf) );
337 vg_strcat( &str, "Hub World" );
338
339 if( world_static.active_instance &&
340 (vg_input.display_input_method == k_input_method_controller) )
341 {
342 vg_strcat( &str, " (" );
343 vg_input_string( &str, input_button_list[k_srbind_mhub], 1 );
344 vg_strcat( &str, ")" );
345 }
346
347 ui_px w = ui_text( (ui_rect){ x+8, y, 1000, height }, buf, 1,
348 k_ui_align_middle_left, 0 );
349 w *= vg_ui.font->sx;
350 x += w + 16;
351
352 vs[1].co[0] = x + 8;
353 vs[2].co[0] = x;
354
355 x += 2;
356
357 world_instance *world = &world_static.instances[1];
358 if( world->status == k_world_status_loaded )
359 {
360 const char *world_name =
361 mdl_pstr( &world->meta, world->info.pstr_name );
362
363 vg_strnull( &str, buf, sizeof(buf) );
364 vg_strcat( &str, world_name );
365
366 if( !world_static.active_instance &&
367 (vg_input.display_input_method == k_input_method_controller) )
368 {
369 vg_strcat( &str, " (" );
370 vg_input_string( &str, input_button_list[k_srbind_mhub], 1 );
371 vg_strcat( &str, ")" );
372 }
373
374 vs = ui_fill( (ui_rect){ x,y, 1000,height },
375 world_static.active_instance? GUI_COL_ACTIVE: GUI_COL_DARK );
376 w = ui_text( (ui_rect){ x+16,y, 1000,height }, buf,
377 1, k_ui_align_middle_left, 0 );
378
379 w = w*vg_ui.font->sx + 8*3;
380 x += w;
381
382 if( button_down( k_srbind_mhub ) ||
383 ui_button_base( (ui_rect){0,y,x,height} ) == k_ui_button_click )
384 {
385 world_switch_instance( world_static.active_instance ^ 0x1 );
386 skaterift.activity = k_skaterift_default;
387 world_map.view_ready = 0;
388 }
389
390 vs[0].co[0] += 8;
391 vs[1].co[0] = x + 8;
392 vs[2].co[0] = x;
393 }
394 }
395 else
396 {
397 if( button_down( k_srbind_mback ) )
398 {
399 skaterift.activity = k_skaterift_default;
400 return;
401 }
402
403 ui_rect list = { vg.window_x/2 - 512/2, height+64,
404 512, vg.window_y-height-128 };
405
406 if( (mv < 0) && (menu.main_row<2) ) menu.main_row ++;
407 if( (mv > 0) && (menu.main_row>0) ) menu.main_row --;
408
409 /* MAIN / MAIN
410 * -------------------------------------------------------------------*/
411
412 if( menu.main_index == k_menu_main_main )
413 {
414 if( menu_button( list, menu.main_row == 0, "Thing 1" ) ==
415 k_ui_button_click )
416 {
417 vg_info( "A\n" );
418 }
419
420 if( menu_button( list, menu.main_row == 1, "Thing 2" ) ==
421 k_ui_button_click )
422 {
423 vg_info( "B\n" );
424 }
425
426 if( menu_button( list, menu.main_row == 2, "Quit Game" ) ==
427 k_ui_button_click )
428 {
429 vg_info( "C\n" );
430 }
431 }
432 else if( menu.main_index == k_menu_main_settings )
433 {
434 ui_font_face( &vgf_default_large );
435 static f32 tester;
436 menu_slider( list, menu.main_row==0, "Yo", 0, 20, &tester, NULL );
437 }
438 }
439
440 vg_ui.frosting = 0.015f;
441 ui_flush( k_ui_shader_colour, vg.window_x, vg.window_y );
442 vg_ui.frosting = 0.0f;
443
444 ui_font_face( &vgf_default_small );
445 }