9758d9840c4add9c0fd524b4b3a056730a0aa36a
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
4 Concurrent UI buffer system
15 #define UI_AUTO_FILL 0
18 // ================================================================
20 typedef u32 ui_colour
;
21 typedef ui_px ui_rect
[4];
22 typedef struct ui_ctx ui_ctx
;
45 int click_state
; // 0: released, 1: on down, 2: pressed, 3: on release
49 // ==========================================================
51 static void ui_rect_copy( ui_rect src
, ui_rect dst
)
59 static void ui_rect_pad( ui_ctx
*ctx
, ui_rect rect
, ui_px pad
)
67 static void ui_vis_rect( ui_rect rect
, u32 colour
)
74 p1
[0] = rect
[0]+rect
[2];
75 p1
[1] = rect
[1]+rect
[3];
77 vg_line( p0
, (v2f
){p1
[0],p0
[1]}, colour
);
78 vg_line( (v2f
){p1
[0],p0
[1]}, p1
, colour
);
79 vg_line( p1
, (v2f
){p0
[0],p1
[1]}, colour
);
80 vg_line( (v2f
){p0
[0],p1
[1]}, p0
, colour
);
83 static void ui_new_node( ui_ctx
*ctx
)
85 if( ctx
->stack_count
== vg_list_size( ctx
->stack
) )
86 vg_exiterr( "[UI] Stack overflow while creating box!" );
88 struct ui_qnode
*parent
= &ctx
->stack
[ ctx
->stack_count
-1 ];
89 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
++ ];
90 ui_rect_copy( ctx
->cursor
, node
->rect
);
92 if( parent
->mouse_over
)
94 if( ctx
->mouse
[0] >= node
->rect
[0] && ctx
->mouse
[0] <= node
->rect
[0]+node
->rect
[2] &&
95 ctx
->mouse
[1] >= node
->rect
[1] && ctx
->mouse
[1] <= node
->rect
[1]+node
->rect
[3] )
102 node
->mouse_over
= 0;
106 static int ui_hasmouse( ui_ctx
*ctx
)
108 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
-1 ];
109 return (node
->mouse_over
&& (node
->capture_id
== ctx
->capture_mouse_id
));
112 static void ui_end( ui_ctx
*ctx
)
114 struct ui_qnode
*node
= &ctx
->stack
[ --ctx
->stack_count
];
116 ui_rect_copy( node
->rect
, ctx
->cursor
);
117 ui_vis_rect( ctx
->cursor
, (node
->mouse_over
&& (node
->capture_id
== ctx
->capture_mouse_id
))? 0xffff0000: 0xff0000ff );
120 static void ui_end_down( ui_ctx
*ctx
)
122 ui_px height
= ctx
->stack
[ ctx
->stack_count
].rect
[3];
124 ctx
->cursor
[1] += height
;
127 static void ui_end_right( ui_ctx
*ctx
)
129 ui_px width
= ctx
->stack
[ ctx
->stack_count
].rect
[2];
131 ctx
->cursor
[0] += width
;
134 static void ui_align_right( ui_ctx
*ctx
)
136 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
-1 ];
137 ctx
->cursor
[0] = node
->rect
[0] + node
->rect
[2] - ctx
->cursor
[2];
140 static void ui_clamp_rect( ui_rect parent
, ui_rect dest
)
142 dest
[0] = vg_min( parent
[0] + parent
[2] - dest
[2], dest
[0] );
143 dest
[1] = vg_min( parent
[1] + parent
[3] - dest
[3], dest
[1] );
144 dest
[0] = vg_max( parent
[0], dest
[0] );
145 dest
[1] = vg_max( parent
[1], dest
[1] );
148 static u32
ui_group_id( ui_ctx
*ctx
, u32 lesser_unique
)
150 return ctx
->id_base
| lesser_unique
;
153 static void ui_capture_mouse( ui_ctx
*ctx
, u32 id
)
155 u32 group_uid
= ui_group_id(ctx
,id
);
157 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
-1 ];
158 node
->capture_id
= group_uid
;
160 if( !ctx
->capture_lock
&& node
->mouse_over
)
162 ctx
->capture_mouse_id
= group_uid
;
167 // ====================================================================
169 static void ui_begin( ui_ctx
*ctx
, ui_px res_x
, ui_px res_y
)
173 ctx
->cursor
[2] = res_x
;
174 ctx
->cursor
[3] = res_y
;
176 ui_rect_copy( ctx
->cursor
, ctx
->stack
[0].rect
);
177 ctx
->stack
[0].mouse_over
= 1;
179 ctx
->stack_count
= 1;
182 static void ui_resolve( ui_ctx
*ctx
)
184 if( ctx
->stack_count
-1 )
185 vg_exiterr( "[UI] Mismatched node create/drestroy!" );
187 if( ctx
->click_state
== 3 || ctx
->click_state
== 0 )
189 ctx
->capture_lock
= 0;
194 // ====================================================================
196 static void ui_set_mouse( ui_ctx
*ctx
, int x
, int y
, int click_state
)
201 ctx
->click_state
= click_state
;
204 // High level controls
205 // ====================================================================
213 ui_px drag_offset
[2];
216 static int ui_button( ui_ctx
*ctx
, u32 id
)
220 ui_capture_mouse( ctx
, id
);
222 if( ui_hasmouse(ctx
) )
224 if( ctx
->click_state
== 1 )
225 ctx
->capture_lock
= 1;
226 else if( ctx
->capture_lock
&& ctx
->click_state
== 3 )
236 static int ui_window( ui_ctx
*ctx
, struct ui_window
*window
, u32 control_group
)
238 ctx
->id_base
= control_group
<< 16;
242 window
->transform
[0] = ctx
->mouse
[0]+window
->drag_offset
[0];
243 window
->transform
[1] = ctx
->mouse
[1]+window
->drag_offset
[1];
245 ui_clamp_rect( ctx
->stack
[0].rect
, window
->transform
);
247 if( ctx
->click_state
== 0 || ctx
->click_state
== 3 )
253 ui_rect_copy( window
->transform
, ctx
->cursor
);
257 ui_capture_mouse( ctx
, __COUNTER__
);
263 ui_capture_mouse( ctx
, __COUNTER__
);
269 ui_align_right( ctx
);
270 ui_rect_pad( ctx
, ctx
->cursor
, 4 );
272 if( ui_button( ctx
, __COUNTER__
) )
274 vg_info( "Click clacked\n" );
278 if( ui_hasmouse( ctx
) )
281 if( ctx
->click_state
== 1 )
284 window
->drag_offset
[0] = window
->transform
[0]-ctx
->mouse
[0];
285 window
->drag_offset
[1] = window
->transform
[1]-ctx
->mouse
[1];
295 static void ui_test(void)
298 +------------------------------------------------------+
299 | Central Market [x]|
300 +------+--------------+-+------------------------------+
301 | Buy | Balance |#| [filters] [favorites] |
302 | <>_ | () 2,356 |#|----------------------------+-+
303 |------|--------------|#| [] potion of madness 4 |#|
304 | Sell | \ Main sword |#|----------------------------|#|
305 | _*^ |--------------|#| [] Balance of time 23 | |
306 |------| * Side arm |#|----------------------------| |
307 | 235 |--------------| | [] Strength 5,300 | |
308 | | () Sheild | |----------------------------| |
309 | |--------------| | [] Bewilder 2,126 | |
310 | [ & Spells ] |----------------------------| |
311 | |--------------| | [] Eternal flames 6 | |
312 +------+--------------+-+----------------------------+-+
315 static ui_ctx ctx
= { .padding
= 8 };
317 ui_begin( &ctx
, vg_window_x
, vg_window_y
);
319 // TODO: Find a more elegent form for this
321 if( vg_get_button( "primary" ) ) mouse_state
= 2;
322 if( vg_get_button_down( "primary" ) ) mouse_state
= 1;
323 if( vg_get_button_up( "primary" ) ) mouse_state
= 3;
325 ui_set_mouse( &ctx
, vg_mouse
[0], vg_mouse
[1], mouse_state
);
327 static struct ui_window window
=
329 .transform
= { 20, 20, 500, 350 },
330 .title
= "Central Market"
333 if( ui_window( &ctx
, &window
, __COUNTER__
) )
341 m3x3f view
= M3X3_IDENTITY
;
342 m3x3_translate( view
, (v3f
){ -1.0f
, 1.0f
, 0.0f
} );
343 m3x3_scale( view
, (v3f
){ 1.0f
/((float)vg_window_x
*0.5f
), -1.0f
/((float)vg_window_y
*0.5f
), 1.0f
} );
344 vg_lines_drawall( (float*)view
);