|
|
@ -96,6 +96,17 @@ static inline int point_in_rect(int x, int y, GUI_Rectangle rect) |
|
|
|
&& (x <= rect.x1) |
|
|
|
&& (y <= rect.y1); |
|
|
|
} |
|
|
|
static inline int point_in_rect_with_offset( |
|
|
|
int x, int y, |
|
|
|
GUI_Rectangle rect, |
|
|
|
int x_offset, int y_offset) |
|
|
|
{ |
|
|
|
return |
|
|
|
(x >= (rect.x0+x_offset)) |
|
|
|
&& (y >= (rect.y0+y_offset)) |
|
|
|
&& (x <= (rect.x1+x_offset)) |
|
|
|
&& (y <= (rect.y1+y_offset)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
typedef enum { |
|
|
@ -225,6 +236,10 @@ typedef struct { |
|
|
|
GUI_Draw_Command *first_draw_command; |
|
|
|
int num_draw_commands; |
|
|
|
Pixel_Buffer *pixel_buffer; |
|
|
|
bool should_draw; |
|
|
|
// TODO(Zelaven): Offsets like for the subtrees.
|
|
|
|
int offset_x; |
|
|
|
int offset_y; |
|
|
|
} GUI_Layer; |
|
|
|
|
|
|
|
|
|
|
@ -355,7 +370,14 @@ void fff(GUI_Context *context) |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
#define GUIWITH_INNER2(token) defer ## token |
|
|
|
#define GUIWITH_INNER(token) GUIWITH_INNER2(token) |
|
|
|
#define GUIWITH(storage_variable, TYPE, value_to_use)\ |
|
|
|
for(struct {TYPE temp; int i;} GUIWITH_INNER(__LINE__) = {.temp=(storage_variable), .i = ((storage_variable) = (value_to_use), 0)}; !GUIWITH_INNER(__LINE__).i; GUIWITH_INNER(__LINE__).i += 1, ((storage_variable) = GUIWITH_INNER(__LINE__).temp)) |
|
|
|
|
|
|
|
#define GUI_ON_LAYER(context, layer) \ |
|
|
|
(layer)->should_draw = true;\ |
|
|
|
GUIWITH(context->current_layer, GUI_Layer*, layer) |
|
|
|
|
|
|
|
|
|
|
|
// ---
|
|
|
@ -364,7 +386,7 @@ void fff(GUI_Context *context) |
|
|
|
// TODO(Zelaven): The mouse coordinates are in the context, so no need to pass
|
|
|
|
// them as parameters.
|
|
|
|
#undef ENABLE_DEBUG |
|
|
|
#define ENABLE_DEBUG 0 |
|
|
|
#define ENABLE_DEBUG 1 |
|
|
|
void gui_apply_input( |
|
|
|
GUI_Context *context, |
|
|
|
int mouse_x, |
|
|
@ -380,12 +402,15 @@ void gui_apply_input( |
|
|
|
{ |
|
|
|
GUI_Layer *top_layer = &context->top_layer; |
|
|
|
GUI_Subtree *root_subtree = (GUI_Subtree*)top_layer->subtree_rdic.root; |
|
|
|
if(root_subtree != NULL) |
|
|
|
if(top_layer->should_draw && root_subtree != NULL) |
|
|
|
{ |
|
|
|
GUI_Node *top_layer_root = |
|
|
|
(GUI_Node*)root_subtree->rdic.root; |
|
|
|
if(top_layer_root != NULL) |
|
|
|
if(point_in_rect(mouse_x, mouse_y, top_layer_root->rect)) |
|
|
|
if(point_in_rect_with_offset( |
|
|
|
mouse_x, mouse_y, |
|
|
|
top_layer_root->rect, |
|
|
|
top_layer->offset_x, top_layer->offset_y)) |
|
|
|
{ |
|
|
|
hit_layer = &context->top_layer; |
|
|
|
hit_root_subtree = root_subtree; |
|
|
@ -579,45 +604,24 @@ GUI_Subtree_Reference gui_get_subtree( |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#undef ENABLE_DEBUG |
|
|
|
#define ENABLE_DEBUG 0 |
|
|
|
// TODO(Zelaven): Make this cause redrawing of root on parameter change.
|
|
|
|
// Maybe an explicit parameter so it can be based on received events?
|
|
|
|
// Such as expose events, resize events, etc.
|
|
|
|
// May also be a good idea because struct-comparing styles each frame wouldn't
|
|
|
|
// be good for performance, so a force-redraw bool sounds like an always-good
|
|
|
|
// option. That way you can force-dirty the root when you make a style change,
|
|
|
|
// but it could also be added at other granularity.
|
|
|
|
// Or should it be something that is done by just setting
|
|
|
|
// ref.node->dirty = true?
|
|
|
|
// That is one option, specifying the dirty flag as a part of the API itself.
|
|
|
|
// I think I like that option.
|
|
|
|
GUI_Node_Reference gui_context_start_frame( |
|
|
|
GUI_Node_Reference gui_context_prepare_layer( |
|
|
|
GUI_Context *context, |
|
|
|
GUI_Layer *layer, |
|
|
|
GUI_Node_Reference last_root_reference, |
|
|
|
int width, int height, |
|
|
|
GUI_Layout_Direction layout_direction, |
|
|
|
GUI_Style *style) |
|
|
|
{ |
|
|
|
//context->frame_current_node = context->root;
|
|
|
|
context->num_draw_commands = 0; |
|
|
|
memory_arena_reset(context->draw_command_arena); |
|
|
|
|
|
|
|
DEBUG("%s: %d %d %d %d\n", __func__, |
|
|
|
context->mouse_x, context->mouse_y, |
|
|
|
context->mouse_pressed, context->mouse_down); |
|
|
|
|
|
|
|
context->current_layer = &context->background_layer; |
|
|
|
|
|
|
|
GUI_Subtree_Reference root_subtree = context->current_layer->root_subtree; |
|
|
|
layer->should_draw = false; |
|
|
|
GUI_Subtree_Reference root_subtree = layer->root_subtree; |
|
|
|
//root_subtree = gui_get_subtree(context, root_subtree);
|
|
|
|
root_subtree.rdic_ref = rdic_context_start_frame( |
|
|
|
&context->current_layer->subtree_rdic, root_subtree.rdic_ref); |
|
|
|
&layer->subtree_rdic, root_subtree.rdic_ref); |
|
|
|
if(root_subtree.node == NULL) |
|
|
|
{ |
|
|
|
return (GUI_Node_Reference){0}; |
|
|
|
} |
|
|
|
context->current_layer->root_subtree = root_subtree; |
|
|
|
layer->root_subtree = root_subtree; |
|
|
|
root_subtree.node->rdic.freelist = context->node_freelist; |
|
|
|
|
|
|
|
//static GUI_Subtree background_subtree = {0};
|
|
|
@ -638,6 +642,7 @@ GUI_Node_Reference gui_context_start_frame( |
|
|
|
//RDIC_Node_Reference new_root_reference = rdic_context_start_frame(
|
|
|
|
// &background_subtree.rdic,
|
|
|
|
// last_root_reference);
|
|
|
|
|
|
|
|
GUI_Node *root = (GUI_Node*)new_root_reference.node; |
|
|
|
root->dirty = false; |
|
|
|
if(!gui_node_references_equal(last_root_reference, new_root_reference)) { |
|
|
@ -647,8 +652,6 @@ GUI_Node_Reference gui_context_start_frame( |
|
|
|
root->dirty = true; |
|
|
|
} |
|
|
|
|
|
|
|
gui_apply_input(context, context->mouse_x, context->mouse_y); |
|
|
|
|
|
|
|
root->debug_string = GUI_STRING("root"); |
|
|
|
root->layout_direction = layout_direction; |
|
|
|
root->semantic_size[GUI_AXIS2_X] = (GUI_Size) |
|
|
@ -659,6 +662,46 @@ GUI_Node_Reference gui_context_start_frame( |
|
|
|
|
|
|
|
return new_root_reference; |
|
|
|
} |
|
|
|
|
|
|
|
#undef ENABLE_DEBUG |
|
|
|
#define ENABLE_DEBUG 0 |
|
|
|
// TODO(Zelaven): Make this cause redrawing of root on parameter change.
|
|
|
|
// Maybe an explicit parameter so it can be based on received events?
|
|
|
|
// Such as expose events, resize events, etc.
|
|
|
|
// May also be a good idea because struct-comparing styles each frame wouldn't
|
|
|
|
// be good for performance, so a force-redraw bool sounds like an always-good
|
|
|
|
// option. That way you can force-dirty the root when you make a style change,
|
|
|
|
// but it could also be added at other granularity.
|
|
|
|
// Or should it be something that is done by just setting
|
|
|
|
// ref.node->dirty = true?
|
|
|
|
// That is one option, specifying the dirty flag as a part of the API itself.
|
|
|
|
// I think I like that option.
|
|
|
|
GUI_Node_Reference gui_context_start_frame( |
|
|
|
GUI_Context *context, |
|
|
|
GUI_Node_Reference last_root_reference, |
|
|
|
int width, int height, |
|
|
|
GUI_Layout_Direction layout_direction, |
|
|
|
GUI_Style *style) |
|
|
|
{ |
|
|
|
//context->frame_current_node = context->root;
|
|
|
|
context->num_draw_commands = 0; |
|
|
|
memory_arena_reset(context->draw_command_arena); |
|
|
|
|
|
|
|
DEBUG("%s: %d %d %d %d\n", __func__, |
|
|
|
context->mouse_x, context->mouse_y, |
|
|
|
context->mouse_pressed, context->mouse_down); |
|
|
|
|
|
|
|
context->current_layer = &context->background_layer; |
|
|
|
GUI_Node_Reference new_root_reference = gui_context_prepare_layer( |
|
|
|
context, context->current_layer, last_root_reference, |
|
|
|
width, height, layout_direction, style); |
|
|
|
|
|
|
|
context->current_layer->should_draw = true; |
|
|
|
|
|
|
|
gui_apply_input(context, context->mouse_x, context->mouse_y); |
|
|
|
|
|
|
|
return new_root_reference; |
|
|
|
} |
|
|
|
void gui_context_finish_frame( |
|
|
|
GUI_Context *context) |
|
|
|
{ |
|
|
@ -1028,6 +1071,32 @@ bool gui_dumb_button( |
|
|
|
|
|
|
|
#undef ENABLE_DEBUG |
|
|
|
#define ENABLE_DEBUG 0 |
|
|
|
bool gui_mouseover_box( |
|
|
|
GUI_Context *context, |
|
|
|
GUI_Node_Reference *last_reference, |
|
|
|
GUI_String text, |
|
|
|
GUI_Style *style, |
|
|
|
GUI_Size size[static 2]) |
|
|
|
{ |
|
|
|
GUI_Node_Reference new_reference = gui_get_node( |
|
|
|
context, *last_reference, GUI_LAYOUT_NONE, style, size); |
|
|
|
GUI_Node *node = new_reference.node; |
|
|
|
node->debug_string = GUI_STRING("gui_mouseover_box"); |
|
|
|
node->text_string = text; |
|
|
|
|
|
|
|
bool new_ref_is_top = gui_node_references_equal( |
|
|
|
new_reference, context->top_node_under_cursor); |
|
|
|
DEBUG(" %p\n | %p\n | %p\n", |
|
|
|
context->top_node_under_cursor.node, |
|
|
|
last_reference->node, new_reference.node); |
|
|
|
bool hovered = new_ref_is_top; |
|
|
|
|
|
|
|
*last_reference = new_reference; |
|
|
|
return hovered; |
|
|
|
} |
|
|
|
|
|
|
|
#undef ENABLE_DEBUG |
|
|
|
#define ENABLE_DEBUG 1 |
|
|
|
bool gui_slider( |
|
|
|
GUI_Context *context, |
|
|
|
GUI_Node_Reference *last_reference, |
|
|
@ -1053,10 +1122,10 @@ bool gui_slider( |
|
|
|
new_reference, context->top_node_under_cursor); |
|
|
|
bool inner_ref_is_top = gui_node_references_equal( |
|
|
|
new_inner_reference, context->top_node_under_cursor); |
|
|
|
DEBUG("%p\n | %p %p\n | %p %p\n", |
|
|
|
/*DEBUG(" %p\n | %p %p\n | %p %p\n",
|
|
|
|
context->top_node_under_cursor.node, |
|
|
|
last_reference->node, inner_box_reference->node, |
|
|
|
new_reference.node, new_inner_reference.node); |
|
|
|
new_reference.node, new_inner_reference.node);*/ |
|
|
|
if(new_ref_is_top || inner_ref_is_top) |
|
|
|
{ |
|
|
|
DEBUG("\n%s: reference is the top node under cursor.\n", __func__); |
|
|
@ -1814,6 +1883,14 @@ void test_gui__subtree( |
|
|
|
full_gui_rectangle.y1-full_gui_rectangle.y0, |
|
|
|
GUI_LAYOUT_VERTICAL, |
|
|
|
&root_style); |
|
|
|
static GUI_Node_Reference top_root = {0}; |
|
|
|
top_root = gui_context_prepare_layer( |
|
|
|
context, &context->top_layer, top_root, |
|
|
|
context->top_layer.pixel_buffer->width, |
|
|
|
context->top_layer.pixel_buffer->height, |
|
|
|
GUI_LAYOUT_HORIZONTAL, &outer_style); |
|
|
|
context->top_layer.offset_x = 50; |
|
|
|
context->top_layer.offset_y = 250; |
|
|
|
|
|
|
|
|
|
|
|
static GUI_Node_Reference top = {0}; |
|
|
@ -1841,7 +1918,7 @@ void test_gui__subtree( |
|
|
|
static GUI_Node_Reference dirty_button = {0}; |
|
|
|
static GUI_Style button_style = {0x99,0x99,0x99, 0x00222222,2,0}; |
|
|
|
static GUI_Size button_size[2] = { |
|
|
|
{GUI_SIZERULE_PIXELS, 200, 100}, |
|
|
|
{GUI_SIZERULE_PIXELS, 170, 100}, |
|
|
|
{GUI_SIZERULE_PIXELS, 40, 100}}; |
|
|
|
if(gui_dumb_button( |
|
|
|
context, &dirty_button, GUI_STRING("Dirty middle"), |
|
|
@ -1857,6 +1934,31 @@ void test_gui__subtree( |
|
|
|
set_pixels = true; |
|
|
|
printf("Setting pixels.\n"); |
|
|
|
} |
|
|
|
static bool tooltip_toggle = false; |
|
|
|
static GUI_Node_Reference dirty_button3 = {0}; |
|
|
|
if(gui_dumb_button( |
|
|
|
context, &dirty_button3, GUI_STRING("Hover for tooltip"), |
|
|
|
&button_style, button_size)) |
|
|
|
{ |
|
|
|
tooltip_toggle = !tooltip_toggle; |
|
|
|
} |
|
|
|
static GUI_Node_Reference dirty_button4 = {0}; |
|
|
|
if( |
|
|
|
gui_mouseover_box( |
|
|
|
context, &dirty_button4, GUI_STRING("Hover for tooltip"), |
|
|
|
&button_style, button_size) |
|
|
|
|| tooltip_toggle) |
|
|
|
{ |
|
|
|
GUI_ON_LAYER(context, &context->top_layer) |
|
|
|
{ |
|
|
|
static GUI_Size full_size[2] = { |
|
|
|
{GUI_SIZERULE_PERCENTOFPARENT, 100, 100}, |
|
|
|
{GUI_SIZERULE_PERCENTOFPARENT, 100, 100}}; |
|
|
|
static GUI_Node_Reference top_layer_block = {0}; |
|
|
|
top_layer_block = gui_dumb_block( |
|
|
|
context, top_layer_block, &element_style, full_size); |
|
|
|
} |
|
|
|
} |
|
|
|
} gui_pop_parent(context); // middle.
|
|
|
|
|
|
|
|
middle = gui_dumb_block(context, middle, &outer_style, middle_size); |
|
|
@ -3611,6 +3713,30 @@ void gui_layout_and_draw(GUI_Context *context) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void gui_compose_layers( |
|
|
|
GUI_Context *context, |
|
|
|
Pixel_Buffer *target_buffer) |
|
|
|
{ |
|
|
|
// TODO(Zelaven): Make the layers in the context iteratable.
|
|
|
|
GUI_Layer *layers[] = { |
|
|
|
&context->background_layer, |
|
|
|
&context->top_layer, |
|
|
|
}; |
|
|
|
for( |
|
|
|
size_t i = 0; |
|
|
|
i < ARRAYLENGTH(layers); |
|
|
|
i++) |
|
|
|
{ |
|
|
|
GUI_Layer *layer = layers[i]; |
|
|
|
if(layer->should_draw) { |
|
|
|
gui_draw_image_direct( |
|
|
|
target_buffer, |
|
|
|
layer->pixel_buffer, |
|
|
|
layer->offset_x, |
|
|
|
layer->offset_y); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#include <unistd.h> // usleep. |
|
|
@ -3678,12 +3804,27 @@ int main(void) |
|
|
|
RDIC_Freelist subtree_freelist = {&g_gui_subtree_freelist[0].rdic_node}; |
|
|
|
context.subtree_freelist = &subtree_freelist; |
|
|
|
|
|
|
|
Pixel_Buffer background_pixel_buffer = (Pixel_Buffer){ |
|
|
|
.pixels = malloc(xwindow.pixel_buffer.width*xwindow.pixel_buffer.height*sizeof(GUI_Color)), |
|
|
|
.width = xwindow.pixel_buffer.width, |
|
|
|
.height = xwindow.pixel_buffer.height, |
|
|
|
}; |
|
|
|
Pixel_Buffer top_pixel_buffer = (Pixel_Buffer){ |
|
|
|
.pixels = malloc(300*200*sizeof(GUI_Color)), |
|
|
|
.width = 300, |
|
|
|
.height = 200, |
|
|
|
}; |
|
|
|
assert(background_pixel_buffer.pixels); |
|
|
|
assert(top_pixel_buffer.pixels); |
|
|
|
|
|
|
|
context.background_layer = (GUI_Layer){ |
|
|
|
.subtree_rdic.freelist = &subtree_freelist, |
|
|
|
.pixel_buffer = &xwindow.pixel_buffer, |
|
|
|
//.pixel_buffer = &xwindow.pixel_buffer,
|
|
|
|
.pixel_buffer = &background_pixel_buffer, |
|
|
|
}; |
|
|
|
context.top_layer = (GUI_Layer){ |
|
|
|
.subtree_rdic.freelist = &subtree_freelist, |
|
|
|
.pixel_buffer = &top_pixel_buffer, |
|
|
|
}; |
|
|
|
#endif |
|
|
|
|
|
|
@ -3692,10 +3833,16 @@ int main(void) |
|
|
|
|
|
|
|
fill_pixel_buffer( |
|
|
|
xwindow.pixel_buffer.pixels, |
|
|
|
xwindow.width, |
|
|
|
xwindow.height, |
|
|
|
0, |
|
|
|
0); |
|
|
|
xwindow.width, xwindow.height, |
|
|
|
0, 0); |
|
|
|
fill_pixel_buffer( |
|
|
|
background_pixel_buffer.pixels, |
|
|
|
background_pixel_buffer.width, background_pixel_buffer.height, |
|
|
|
0, 0); |
|
|
|
fill_pixel_buffer( |
|
|
|
top_pixel_buffer.pixels, |
|
|
|
top_pixel_buffer.width, top_pixel_buffer.height, |
|
|
|
0, 0); |
|
|
|
GUI_Rectangle screen_rectangle = { |
|
|
|
.x0 = 0, .y0 = 0, |
|
|
|
.x1 = xwindow.width, .y1 = xwindow.height, |
|
|
@ -3798,7 +3945,7 @@ int main(void) |
|
|
|
//gui_layout_nodes(&context);
|
|
|
|
#if 1 |
|
|
|
gui_layout_and_draw(&context); |
|
|
|
SET_PIXEL(&xwindow.pixel_buffer, 239, 259, 0x00ff0000); |
|
|
|
gui_compose_layers(&context, &xwindow.pixel_buffer); |
|
|
|
#else |
|
|
|
for( |
|
|
|
GUI_Subtree *current = (GUI_Subtree*)context.background_layer.subtree_rdic.root; |
|
|
|