Browse Source

Implemented the top layer

master
Patrick Jakobsen 7 months ago
parent
commit
4cdc17489e
1 changed files with 188 additions and 41 deletions
  1. +188
    -41
      gui/gui.c

+ 188
- 41
gui/gui.c View File

@ -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;

Loading…
Cancel
Save