27c0645cacf05236c6e3b5ca942a310d5c51ee5f
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
;
43 int click_state
; // 0: released, 1: on down, 2: pressed, 3: on release
47 // ==========================================================
49 static void ui_rect_copy( ui_rect src
, ui_rect dst
)
57 static void ui_rect_pad( ui_ctx
*ctx
, ui_rect rect
)
59 rect
[0] += ctx
->padding
;
60 rect
[1] += ctx
->padding
;
61 rect
[2] -= ctx
->padding
*2;
62 rect
[3] -= ctx
->padding
*2;
65 static void ui_vis_rect( ui_rect rect
, u32 colour
)
72 p1
[0] = rect
[0]+rect
[2];
73 p1
[1] = rect
[1]+rect
[3];
75 vg_line( p0
, (v2f
){p1
[0],p0
[1]}, colour
);
76 vg_line( (v2f
){p1
[0],p0
[1]}, p1
, colour
);
77 vg_line( p1
, (v2f
){p0
[0],p1
[1]}, colour
);
78 vg_line( (v2f
){p0
[0],p1
[1]}, p0
, colour
);
81 static void ui_new_node( ui_ctx
*ctx
)
83 if( ctx
->stack_count
== vg_list_size( ctx
->stack
) )
84 vg_exiterr( "[UI] Stack overflow while creating box!" );
86 struct ui_qnode
*parent
= &ctx
->stack
[ ctx
->stack_count
-1 ];
87 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
++ ];
88 ui_rect_copy( ctx
->cursor
, node
->rect
);
90 if( parent
->mouse_over
)
92 if( ctx
->mouse
[0] >= node
->rect
[0] && ctx
->mouse
[0] <= node
->rect
[0]+node
->rect
[2] &&
93 ctx
->mouse
[1] >= node
->rect
[1] && ctx
->mouse
[1] <= node
->rect
[1]+node
->rect
[3] )
100 static int ui_hasmouse( ui_ctx
*ctx
)
102 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
-1 ];
103 return (node
->mouse_over
&& (node
->capture_id
== ctx
->capture_mouse_id
));
106 static void ui_end( ui_ctx
*ctx
)
108 struct ui_qnode
*node
= &ctx
->stack
[ --ctx
->stack_count
];
110 ui_rect_copy( node
->rect
, ctx
->cursor
);
111 ui_vis_rect( ctx
->cursor
, (node
->mouse_over
&& (node
->capture_id
== ctx
->capture_mouse_id
))? 0xffff0000: 0xff0000ff );
114 static void ui_end_down( ui_ctx
*ctx
)
116 ui_px height
= ctx
->stack
[ ctx
->stack_count
].rect
[3];
118 ctx
->cursor
[1] += height
;
121 static void ui_end_right( ui_ctx
*ctx
)
123 ui_px width
= ctx
->stack
[ ctx
->stack_count
].rect
[2];
125 ctx
->cursor
[0] += width
;
128 static void ui_capture_mouse( ui_ctx
*ctx
, int id
)
130 struct ui_qnode
*node
= &ctx
->stack
[ ctx
->stack_count
-1 ];
131 node
->capture_id
= id
;
133 if( node
->mouse_over
)
135 ctx
->capture_mouse_id
= id
;
140 // ====================================================================
142 static void ui_begin( ui_ctx
*ctx
, ui_px res_x
, ui_px res_y
)
146 ctx
->cursor
[2] = res_x
;
147 ctx
->cursor
[3] = res_y
;
149 ui_rect_copy( ctx
->cursor
, ctx
->stack
[0].rect
);
150 ctx
->stack
[0].mouse_over
= 1;
152 ctx
->stack_count
= 1;
155 static void ui_resolve( ui_ctx
*ctx
)
157 if( ctx
->stack_count
-1 )
158 vg_exiterr( "[UI] Mismatched node create/drestroy!" );
162 // ====================================================================
164 static void ui_set_mouse( ui_ctx
*ctx
, int x
, int y
, int click_state
)
169 ctx
->click_state
= click_state
;
172 static void ui_test(void)
175 +------------------------------------------------------+
176 | Central Market [x]|
177 +------+--------------+-+------------------------------+
178 | Buy | Balance |#| [filters] [favorites] |
179 | <>_ | () 2,356 |#|----------------------------+-+
180 |------|--------------|#| [] potion of madness 4 |#|
181 | Sell | \ Main sword |#|----------------------------|#|
182 | _*^ |--------------|#| [] Balance of time 23 | |
183 |------| * Side arm |#|----------------------------| |
184 | 235 |--------------| | [] Strength 5,300 | |
185 | | () Sheild | |----------------------------| |
186 | |--------------| | [] Bewilder 2,126 | |
187 | [ & Spells ] |----------------------------| |
188 | |--------------| | [] Eternal flames 6 | |
189 +------+--------------+-+----------------------------+-+
192 ui_ctx ctx
= { .padding
= 8 };
194 ui_begin( &ctx
, vg_window_x
, vg_window_y
);
196 // TODO: Find a more elegent form for this
198 if( vg_get_button( "primary" ) ) mouse_state
= 2;
199 if( vg_get_button_down( "primary" ) ) mouse_state
= 1;
200 if( vg_get_button_up( "primary" ) ) mouse_state
= 3;
202 ui_set_mouse( &ctx
, vg_mouse
[0], vg_mouse
[1], mouse_state
);
204 static ui_px window_x
= 20;
205 static ui_px window_y
= 20;
206 static int window_drag
= 0;
207 static ui_px drag_offset
[2];
211 window_x
= ctx
.mouse
[0]+drag_offset
[0];
212 window_y
= ctx
.mouse
[1]+drag_offset
[1];
214 if( ctx
.click_state
== 0 )
220 ctx
.cursor
[0] = window_x
;
221 ctx
.cursor
[1] = window_y
;
232 ui_capture_mouse( &ctx
, 1 );
236 ui_capture_mouse( &ctx
, 2 );
238 if( ui_hasmouse( &ctx
) )
240 if( ctx
.click_state
== 1 ) // start drag
243 drag_offset
[0] = window_x
-ctx
.mouse
[0];
244 drag_offset
[1] = window_y
-ctx
.mouse
[1];
254 m3x3f view
= M3X3_IDENTITY
;
255 m3x3_translate( view
, (v3f
){ -1.0f
, 1.0f
, 0.0f
} );
256 m3x3_scale( view
, (v3f
){ 1.0f
/((float)vg_window_x
*0.5f
), -1.0f
/((float)vg_window_y
*0.5f
), 1.0f
} );
257 vg_lines_drawall( (float*)view
);