|
|
-
-
-
- #include <stdio.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <assert.h>
-
-
- #define DEBUG(...) if(ENABLE_DEBUG) {printf(__VA_ARGS__);}
-
- #define ARRAYLENGTH(X) (sizeof(X)/sizeof((X)[0]))
-
-
- bool my_bool = true;
-
-
- int border_thickness = 0;
- float roundedness = 60;
-
- #include "stb_truetype.h"
-
- void print_bakedchar(char c, stbtt_bakedchar *b)
- {
- printf("%c: %d %d %d %d %.2g %.2g %.2g\n",
- c,
- b->x0, b->y0, b->x1, b->y1,
- b->xoff, b->yoff, b->xadvance);
- }
- stbtt_bakedchar g_baked_font[96];
- unsigned char *g_font_bitmap;
- int g_font_bitmap_width = 512;
- int g_font_bitmap_height = 512;
-
-
-
-
- // ---
-
-
- #define arena_allocate_TYPE(arena, TYPE) ((TYPE*)memory_arena_allocate(arena, sizeof(TYPE), _Alignof(TYPE)))
- #define arena_allocate_draw_command(arena) arena_allocate_TYPE(arena, GUI_Draw_Command)
-
- #include "memory_arena.c"
- #include "memory_arena_linux.c"
-
-
- // ---
-
- #define RDIC_IMPLEMENTATION
- #include "../rdic.h"
-
- typedef struct {
- // Top-left corner.
- int x0, y0;
- // Bottom-Right corner.
- int x1, y1;
- } GUI_Rectangle;
-
- // NOTE(Zelaven): I would have loved to do pascal strings here, but I could not
- // find any way to pass those as literals in a reasonable way.
- // I also use int instead of ssize_t or anything else because of the .*s format
- // specifier being an absolute pain.
- typedef struct {
- int length;
- char *cstring;
- } GUI_String;
- #define GUI_STRING(literal) (GUI_String){.length = sizeof(literal)-1, .cstring = literal}
-
- typedef uint32_t GUI_Color;
- typedef struct {
- GUI_Color *pixels;
- int width;
- int height;
- } Pixel_Buffer;
-
- // TODO(Zelaven): Add a generation to this that you can
- // increment so that the nodes that use a style can know
- // when up dirty themselves due to style change?
- typedef struct {
- // TODO(Zelaven): Replace these with GUI_Color.
- unsigned char red;
- unsigned char green;
- unsigned char blue;
-
- GUI_Color border_color;
- int border_thickness;
- unsigned char roundedness;
- } GUI_Style;
-
- static inline int point_in_rect(int x, int y, GUI_Rectangle rect)
- {
- return
- (x >= rect.x0)
- && (y >= rect.y0)
- && (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 {
- GUI_SIZERULE_PIXELS,
- GUI_SIZERULE_TEXTCONTENT,
- GUI_SIZERULE_PERCENTOFPARENT,
- GUI_SIZERULE_SUMOFCHILDREN,
- //GUI_SIZERULE_SHARES,
- } GUI_Size_Rule;
-
- typedef struct GUI_Size
- {
- GUI_Size_Rule size_rule;
- int value;
- int strictness;
- } GUI_Size;
-
- typedef enum GUI_Axis2
- {
- GUI_AXIS2_X,
- GUI_AXIS2_Y,
- GUI_AXIS2_COUNT,
- } GUI_Axis2;
-
- typedef enum {
- GUI_LAYOUT_NONE,
- GUI_LAYOUT_HORIZONTAL,
- GUI_LAYOUT_VERTICAL,
- } GUI_Layout_Direction;
-
- typedef struct GUI_Node {
- RDIC_Node rdic_node;
- GUI_Style *style;
- GUI_String text_string; // Optional.
- int text_width, text_height; // Optional. Initialized by lazy_init and cached.
- Pixel_Buffer *image;
-
- GUI_String debug_string;
-
- // NOTE(Zelaven): Useful for tab-navigation and other non-mouse navigation.
- GUI_Layout_Direction layout_direction;
- GUI_Size semantic_size[GUI_AXIS2_COUNT];
- // TODO(Zelaven): This needs a better name.
- // True iff. it (and its children) should generate draw commands.
- // TODO(Zelaven): Should I make it a flags field, which encodes dirty-reasons?
- // The "dirty test" would be "dirty != 0", and each bit in the field would be
- // a reason that other code can use to figure out why a node was dirtied.
- // Multiple reasons for a decision can all be checked in one go as well.
- bool dirty;
-
- // NOTE(Zelaven): Don't make decisions about visual things based on this.
- // It will be a frame off, and with dirty-redrawing it will result in the
- // error persisting on the screen.
- // All sizing and positioning should be done using semantic sizes and
- // offsets, and should be handled in offline layouting and positioning.
- int computed_size[GUI_AXIS2_COUNT];
- GUI_Rectangle rect; // NOTE(Zelaven): I have no better name for this.
- } GUI_Node;
- #define GUI_NODE_PARENT(node) ((GUI_Node*)(node)->rdic_node.parent)
- #define GUI_NODE_SIBLING(node) ((GUI_Node*)(node)->rdic_node.sibling)
- #define GUI_NODE_FIRST_CHILD(node) ((GUI_Node*)(node)->rdic_node.first_child)
-
- typedef union GUI_Node_Reference {
- RDIC_Node_Reference rdic_ref;
- struct {
- GUI_Node *node;
- unsigned int generation;
- };
- } GUI_Node_Reference;
- #if 0
- #define gui_node_references_equal(n, m) rdic_node_references_equal((n).rdic_ref,(m).rdic_ref)
- #else
- // NOTE(Zelaven): This was just for debugging with better debug messages.
- int gui_node_references_equal(GUI_Node_Reference n, GUI_Node_Reference m)
- {
- return rdic_node_references_equal(n.rdic_ref, m.rdic_ref);
- }
- #endif
-
- typedef struct {
- GUI_Rectangle rectangle;
- GUI_Color color;
- GUI_Color border_color;
- int border_thickness;
- unsigned char roundedness;
- GUI_String text;
- Pixel_Buffer *image;
- } GUI_Draw_Command;
-
- typedef struct GUI_Subtree GUI_Subtree;
- struct GUI_Subtree {
- // NOTE(Zelaven): We are maintaining an immediate interface of subtrees too.
- RDIC_Node rdic_node;
-
- RDIC_Context rdic;
-
- GUI_Node_Reference clipnode;
-
- GUI_Node_Reference relative_to;
- int flat_offset_x;
- int flat_offset_y;
- int offset_relative_node_percentage_x;
- int offset_relative_node_percentage_y;
- int offset_own_size_percentage_x;
- int offset_own_size_percentage_y;
- };
- #define GUI_SUBTREE_PARENT(node) ((GUI_Subtree*)(node)->rdic_node.parent)
- #define GUI_SUBTREE_SIBLING(node) ((GUI_Subtree*)(node)->rdic_node.sibling)
- #define GUI_SUBTREE_FIRST_CHILD(node) ((GUI_Subtree*)(node)->rdic_node.first_child)
- typedef union GUI_Subtree_Reference {
- RDIC_Node_Reference rdic_ref;
- struct {
- GUI_Subtree *node;
- unsigned int generation;
- };
- } GUI_Subtree_Reference;
-
-
- typedef struct {
- RDIC_Context subtree_rdic;
- //GUI_Subtree *first_subtree;
- //GUI_Subtree *last_subtree;
- //GUI_Subtree *current_subtree;
-
- GUI_Subtree_Reference root_subtree;
-
- 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;
-
-
- typedef struct {
- //RDIC_Context rdic;
-
- //GUI_Subtree *first_subtree;
- //GUI_Subtree *last_subtree;
- //GUI_Subtree *current_subtree;
-
- GUI_Layer background_layer;
- GUI_Layer top_layer;
-
- GUI_Layer *current_layer;
-
- GUI_Node_Reference focused_node;
- GUI_Node_Reference hovered_node;
- GUI_Node_Reference top_node_under_cursor;
- int mouse_pressed;
- int mouse_down;
- int mouse_x;
- int mouse_y;
-
- // TODO: An allocator for the nodes.
- RDIC_Freelist *node_freelist;
- RDIC_Freelist *subtree_freelist;
-
- Memory_Arena *draw_command_arena;
- int num_draw_commands;
- } GUI_Context;
-
-
-
-
-
- // ---
-
- #if 1
- void print_node_tree(GUI_Node *node, int level)
- {
- for(int i = 0; i < level; i++) {
- printf("-");
- }
-
- GUI_String text = node->debug_string;
- printf(" %.*s", text.length, text.cstring);
- //printf(" (%p)", node);
- printf(" (Dirty?: %b)", node->dirty);
- printf("\n");
-
- GUI_Node *child = GUI_NODE_FIRST_CHILD(node);
- while(child != NULL) {
- print_node_tree(child, level+1);
- child = GUI_NODE_SIBLING(child);
- }
- }
- #endif
- #if 1
- void print_subtree_tree(GUI_Subtree *node, int level, bool print_nodes)
- {
- for(int i = 0; i < level; i++) {
- printf("=");
- }
-
- printf(" (%p)", node);
- printf("\n");
-
- if(print_nodes) {
- print_node_tree((GUI_Node*)node->rdic.root, level+1);
- }
-
- GUI_Subtree *child = GUI_SUBTREE_FIRST_CHILD(node);
- while(child != NULL) {
- print_subtree_tree(child, level+1, print_nodes);
- child = GUI_SUBTREE_SIBLING(child);
- }
- }
- #endif
-
- // ---
-
-
- // NOTE(Zelaven): This won't be used, but it will stay around as a reference for
- // the technique.
- #if 0
- #define GUIWITH_INNER2(token) defer ## token
- #define GUIWITH_INNER(token) GUIWITH_INNER2(token)
- /*
- * NOTE(Zelaven): This is a "defer loop" macro, fitted as a "with" construct.
- * What it is used for is temporarily overwriting a value, keeping the original
- * value safe in a loop-local variable.
- * The operation functions by declaring the loop variable of an anonymous struct
- * type, which contains the temporary variable as well as the actual loop
- * variable.
- * The temporary is initialized with the contents of the stored value, which is
- * then overwritten with the "with" value, and at the end of the loop the
- * stored value is restored to contain the contents of the temporary.
- * It is important to note that for this to operate correctly, the temporary
- * needs to be filled out before the stored value is overwritten, which is
- * dependent on the ORDER OF THE STRUCT MEMBERS.
- * This is because the overwriting of the stored value is done in the
- * initialization of the loop variable part of the struct, and the members are
- * initialized in member order, not initializer declaration order.
- * I tested this, but both are arranged in the desired order for both reading
- * and in the case that it proves to be compiler-dependent.
- * (Note that it appears to be consistent across optimization flags)
- */
- #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_WITH_REDNESS(context, value) GUIWITH(context->style.red, unsigned char, value)
- #define GUI_WITH_BLUENESS(context, value) GUIWITH(context->style.blue, unsigned char, value)
- #define GUI_WITH_GREENNESS(context, value) GUIWITH(context->style.green, unsigned char, value)
- #define GUI_WITH_STYLE(context, value) GUIWITH(context->style, GUI_Style, value)
-
- #define GUI_WITH_BORDER_COLOR(context, value) GUIWITH((context)->style.border_color, GUI_Color, (value))
- #define GUI_WITH_BORDER_THICKNESS(context, value) GUIWITH((context)->style.border_thickness, int, (value))
- #define GUI_WITH_ROUNDEDNESS(context, value) GUIWITH((context)->style.roundedness, unsigned char, (value))
-
- void fff(GUI_Context *context)
- {
- GUI_WITH_REDNESS(context, 222)
- printf("%d\n", context->style.red);
- GUI_Style style = (GUI_Style){2,2,2,0,0,0};
- GUI_WITH_STYLE(context, style)
- GUI_WITH_STYLE(context, ((GUI_Style){2,2,2,0,0,0}))
- printf("%d\n", context->style.red);
- }
- #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)
-
-
- // ---
-
-
- // TODO(Zelaven): The mouse coordinates are in the context, so no need to pass
- // them as parameters.
- #undef ENABLE_DEBUG
- #define ENABLE_DEBUG 0
- void gui_apply_input(
- GUI_Context *context,
- int mouse_x,
- int mouse_y)
- {
- (void)context;
- (void)mouse_x;
- (void)mouse_y;
- // --- Mouse Input ---
- // NOTE(Zelaven): First hit test against layers.
- GUI_Layer *hit_layer = &context->background_layer;
- GUI_Subtree *hit_root_subtree = (GUI_Subtree*)hit_layer->subtree_rdic.root;
- {
- GUI_Layer *top_layer = &context->top_layer;
- GUI_Subtree *root_subtree = (GUI_Subtree*)top_layer->subtree_rdic.root;
- 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_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;
- }
- }
- }
- (void)hit_layer;
-
- assert(hit_root_subtree != NULL);
-
- GUI_Subtree *top_subtree_under_cursor = hit_root_subtree;
- GUI_Subtree *current_subtree = GUI_SUBTREE_FIRST_CHILD(top_subtree_under_cursor);
- int mouse_over_subtree = 0;
- while(current_subtree != NULL)
- {
- // TODO(Zelaven): Should actually test against the rect-intersect between
- // the clipnode and the subtree root. The clipnode is only a maximal bound.
- mouse_over_subtree = point_in_rect_with_offset(
- mouse_x, mouse_y,
- // TODO(Zelaven): Test clipnode valid.
- current_subtree->clipnode.node->rect,
- hit_layer->offset_x, hit_layer->offset_y);
- if(mouse_over_subtree)
- {
- top_subtree_under_cursor = current_subtree;
- current_subtree = GUI_SUBTREE_FIRST_CHILD(current_subtree);
- }
- else
- {
- current_subtree = GUI_SUBTREE_SIBLING(current_subtree);
- }
- }
- hit_root_subtree = top_subtree_under_cursor;
-
- GUI_Node *top_node_under_cursor = (GUI_Node*)hit_root_subtree->rdic.root;
- GUI_Node *current_node = (GUI_Node*)top_node_under_cursor->rdic_node.first_child;
- int mouse_over_node = 0;
- while(current_node != NULL)
- {
- mouse_over_node = point_in_rect_with_offset(
- mouse_x, mouse_y,
- current_node->rect,
- hit_layer->offset_x, hit_layer->offset_y);
- if(mouse_over_node)
- {
- top_node_under_cursor = current_node;
- current_node = (GUI_Node*)current_node->rdic_node.first_child;
- }
- else
- {
- current_node = (GUI_Node*)current_node->rdic_node.sibling;
- }
- }
-
- context->top_node_under_cursor.node = top_node_under_cursor;
- context->top_node_under_cursor.generation =
- top_node_under_cursor->rdic_node.generation;
- DEBUG("Top node under cursor: %.*s\n",
- top_node_under_cursor->debug_string.length,
- top_node_under_cursor->debug_string.cstring);
-
- return;
- }
- #if 0
- {
- // --- Mouse Input ---
- // NOTE(Zelaven): First hit test against layers.
- GUI_Layer *hit_layer = &context->background_layer;
- {
- GUI_Layer *top_layer = &context->top_layer;
- if(top_layer->first_subtree != NULL)
- {
- GUI_Node *top_layer_root =
- (GUI_Node*)top_layer->first_subtree->rdic.root;
- if(point_in_rect(mouse_x, mouse_y, top_layer_root->rect))
- {
- hit_layer = &context->top_layer;
- }
- }
- }
-
- //GUI_Node *top_node_under_cursor = (GUI_Node*)context->rdic.root;
- //GUI_Node *top_node_under_cursor = (GUI_Node*)context->first_subtree->rdic.root;
- GUI_Node *top_node_under_cursor = (GUI_Node*)hit_layer->first_subtree->rdic.root;
- GUI_Node *current_node = (GUI_Node*)top_node_under_cursor->rdic_node.first_child;
- int mouse_over_node = 0;
- while(current_node != NULL)
- {
- mouse_over_node = point_in_rect(mouse_x, mouse_y, current_node->rect);
- if(mouse_over_node)
- {
- top_node_under_cursor = current_node;
- current_node = (GUI_Node*)current_node->rdic_node.first_child;
- }
- else
- {
- current_node = (GUI_Node*)current_node->rdic_node.sibling;
- }
- }
-
- context->top_node_under_cursor.node = top_node_under_cursor;
- context->top_node_under_cursor.generation =
- top_node_under_cursor->rdic_node.generation;
- DEBUG("Top node under cursor: %.*s\n",
- top_node_under_cursor->debug_string.length,
- top_node_under_cursor->debug_string.cstring);
- }
- #endif
-
-
- GUI_Node_Reference gui_get_node(
- GUI_Context *context,
- GUI_Node_Reference last_reference,
- GUI_Layout_Direction direction,
- GUI_Style *style,
- GUI_Size size[static 2])
- {
- GUI_Layer *current_layer = context->current_layer;
- if(current_layer == NULL) {
- return (GUI_Node_Reference){0};
- }
- GUI_Subtree *current_subtree =
- //(GUI_Subtree*)current_layer->subtree_rdic.frame_current_node;
- // TODO(Zelaven): This has to do with me always pushing the newest subtree
- // as a parent, which honestly doesn't sound ideal to me. I should look
- // into what what my options are.
- (GUI_Subtree*)current_layer->subtree_rdic.current_parent;
- int get_node_flags = 0;
- GUI_Node_Reference new_reference = {
- .rdic_ref = rdic_get_node(
- //&context->current_subtree->rdic, last_reference.rdic, &get_node_flags),
- ¤t_subtree->rdic, last_reference.rdic_ref, &get_node_flags),
- };
- GUI_Node *node = new_reference.node;
- node->layout_direction = direction;
- node->style = style;
- node->semantic_size[GUI_AXIS2_X] = size[GUI_AXIS2_X];
- node->semantic_size[GUI_AXIS2_Y] = size[GUI_AXIS2_Y];
-
- // TODO(Zelaven):
- // get_node_flags & RDIC_GET_NODE__OUT_OF_FREELIST
- // ^ This should result in an attempt to allocate more nodes for the freelist.
- // Then rdic_get_node should be retried.
-
- if(get_node_flags & RDIC_GET_NODE__NODES_COLLECTED)
- {
- GUI_NODE_PARENT(node)->dirty = true;
- }
- if(get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED)
- {
- GUI_NODE_PARENT(node)->dirty = true;
- }
- node->dirty = (get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED) != 0;
-
-
- return new_reference;
- }
- GUI_Subtree_Reference gui_get_subtree(
- GUI_Context *context,
- GUI_Subtree_Reference last_reference)
- {
- GUI_Layer *current_layer = context->current_layer;
- if(current_layer == NULL) {
- return (GUI_Subtree_Reference){0};
- }
- RDIC_Context *subtree_rdic = ¤t_layer->subtree_rdic;
- RDIC_Node *old_subtree_freelist_head = subtree_rdic->freelist->head;
- int get_node_flags = 0;
- GUI_Subtree_Reference new_reference = {
- .rdic_ref = rdic_get_node(
- //&context->current_subtree->rdic, last_reference.rdic, &get_node_flags),
- subtree_rdic, last_reference.rdic_ref, &get_node_flags),
- };
- GUI_Subtree *subtree = new_reference.node;
- subtree->rdic = (RDIC_Context){0};
- subtree->rdic.freelist = context->node_freelist;
- subtree->relative_to = (GUI_Node_Reference){0};
- subtree->flat_offset_x = 0;
- subtree->flat_offset_y = 0;
- subtree->offset_relative_node_percentage_x = 0;
- subtree->offset_relative_node_percentage_y = 0;
- subtree->offset_own_size_percentage_x = 0;
- subtree->offset_own_size_percentage_y = 0;
-
- // TODO(Zelaven):
- // get_node_flags & RDIC_GET_NODE__OUT_OF_FREELIST
- // ^ This should result in an attempt to allocate more nodes for the freelist.
- // Then rdic_get_node should be retried.
-
- if(get_node_flags & RDIC_GET_NODE__NODES_COLLECTED)
- {
- // NOTE(Zelaven): Some subtrees were collected, which means that their RDIC
- // node trees should be collected too.
- for(
- RDIC_Node *i = subtree_rdic->freelist->head;
- i != old_subtree_freelist_head;
- i = i->sibling)
- {
- GUI_Subtree *subtree = (GUI_Subtree*)i;
- // NOTE(Zelaven): This line falsely triggers -Wstringop-overflow and the
- // copy into a temporary variable seemingly fixes it.
- // For this reason I simply opted to use -Wno-stringop-overflow, as I
- // don't want to have a broken flag enabled.
- rdic_cull_subtrees(&subtree->rdic, subtree->rdic.root);
- //RDIC_Context *rdic_context = &subtree->rdic;
- //rdic_cull_subtrees(rdic_context, subtree->rdic.root);
- }
- }
-
- #if 0
- if(get_node_flags & RDIC_GET_NODE__NODES_COLLECTED)
- {
- GUI_NODE_PARENT(node)->dirty = true;
- }
- if(get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED)
- {
- GUI_NODE_PARENT(node)->dirty = true;
- }
- node->dirty = (get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED) != 0;
- #endif
-
-
- return new_reference;
- }
-
-
- 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)
- {
- 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(
- &layer->subtree_rdic, root_subtree.rdic_ref);
- if(root_subtree.node == NULL)
- {
- return (GUI_Node_Reference){0};
- }
- layer->root_subtree = root_subtree;
- root_subtree.node->rdic.freelist = context->node_freelist;
-
- //static GUI_Subtree background_subtree = {0};
- //background_subtree.rdic.freelist = context->node_freelist;
- //context->background_layer.first_subtree = &background_subtree;
- //context->background_layer.last_subtree = &background_subtree;
- //context->current_subtree = &background_subtree;
-
- GUI_Node_Reference new_root_reference = {
- .rdic_ref = rdic_context_start_frame(
- //&background_subtree.rdic, last_root_reference.rdic)
- &root_subtree.node->rdic, last_root_reference.rdic_ref)
- };
- if(new_root_reference.node == NULL)
- {
- return (GUI_Node_Reference){0};
- }
- //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)) {
- root->dirty = true;
- }
- if(layout_direction != root->layout_direction) {
- root->dirty = true;
- }
-
- root->debug_string = GUI_STRING("root");
- root->layout_direction = layout_direction;
- root->semantic_size[GUI_AXIS2_X] = (GUI_Size)
- {.size_rule = GUI_SIZERULE_PIXELS, .value = width, .strictness = 100,};
- root->semantic_size[GUI_AXIS2_Y] = (GUI_Size)
- {.size_rule = GUI_SIZERULE_PIXELS, .value = height, .strictness = 100,};
- root->style = style;
-
- 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)
- {
- //rdic_context_finish_frame(&context->background_layer.first_subtree->rdic);
- rdic_context_finish_frame(&context->background_layer.root_subtree.node->rdic);
- //context->node_freelist =
- // context->background_layer.first_subtree->rdic.node_freelist;
- }
-
- GUI_Node_Reference gui_push_subtree(
- GUI_Context *context,
- GUI_Subtree_Reference subtree,
- GUI_Node_Reference last_root_reference,
- GUI_Layout_Direction layout_direction,
- GUI_Style *style,
- GUI_Size size[static 2],
- GUI_Node_Reference relative_to)
- {
- RDIC_Context *layer_rdic_context = &context->current_layer->subtree_rdic;
- rdic_push_parent(layer_rdic_context, subtree.rdic_ref);
- //context->node_freelist = context->current_subtree->rdic.node_freelist;
- //subtree->rdic.node_freelist = context->node_freelist;
-
- // NOTE(Zelaven): Well, not being able to do this is a problem...
- //context->last_subtree->next = subtree;
- //subtree->prev = context->last_subtree;
- //context->last_subtree = subtree;
-
- //subtree->structural_parent = context->current_subtree;
- //context->current_subtree = subtree;
- subtree.node->relative_to = relative_to;
- subtree.node->clipnode = relative_to;
-
- GUI_Node_Reference new_root_reference = {
- .rdic_ref = rdic_context_start_frame(
- &subtree.node->rdic, last_root_reference.rdic_ref)
- };
- GUI_Node *root = (GUI_Node*)new_root_reference.node;
- root->dirty = false;
- if(!gui_node_references_equal(last_root_reference, new_root_reference)) {
- root->dirty = true;
- }
- if(layout_direction != root->layout_direction) {
- root->dirty = true;
- }
-
- root->debug_string = GUI_STRING("gui_push_subtree");
- root->layout_direction = layout_direction;
- root->semantic_size[GUI_AXIS2_X] = size[GUI_AXIS2_X];
- root->semantic_size[GUI_AXIS2_Y] = size[GUI_AXIS2_Y];
- root->style = style;
-
- return new_root_reference;
- }
-
- void gui_pop_subtree(
- GUI_Context *context)
- {
- //context->node_freelist = context->current_subtree->rdic.node_freelist;
- //context->current_subtree = context->current_subtree->structural_parent;
- //context->current_subtree->rdic.node_freelist = context->node_freelist;
-
- RDIC_Context *layer_rdic_context = &context->current_layer->subtree_rdic;
- rdic_pop_parent(layer_rdic_context);
- }
-
-
- void gui_push_parent(
- GUI_Context *context,
- GUI_Node_Reference parent)
- {
- GUI_Layer *current_layer = context->current_layer;
- GUI_Subtree *current_subtree =
- //(GUI_Subtree*)current_layer->subtree_rdic.frame_current_node;
- (GUI_Subtree*)current_layer->subtree_rdic.current_parent;
- rdic_push_parent(¤t_subtree->rdic, parent.rdic_ref);
- }
-
- void gui_pop_parent(
- GUI_Context *context)
- {
- GUI_Layer *current_layer = context->current_layer;
- GUI_Subtree *current_subtree =
- //(GUI_Subtree*)current_layer->subtree_rdic.frame_current_node;
- (GUI_Subtree*)current_layer->subtree_rdic.current_parent;
- rdic_pop_parent(¤t_subtree->rdic);
- }
-
-
-
- // ---
-
- void gui_layout_calculate_standalone_sizes(
- GUI_Node *node,
- GUI_Axis2 axis)
- {
- switch(node->semantic_size[axis].size_rule)
- {
- case GUI_SIZERULE_PIXELS:
- {
- node->computed_size[axis] = node->semantic_size[axis].value;
- } break;
- case GUI_SIZERULE_TEXTCONTENT:
- {
- // TODO(Zelaven): Calculate text width.
- node->computed_size[axis] = 0;
- } break;
- default:
- {
- //assert(!"Non-standalone size passed to calculate_standalone_sizes.");
- } break;
- }
- if(node->rdic_node.first_child != NULL) {
- gui_layout_calculate_standalone_sizes(GUI_NODE_FIRST_CHILD(node), axis);
- }
- if(node->rdic_node.sibling != NULL) {
- gui_layout_calculate_standalone_sizes(GUI_NODE_SIBLING(node), axis);
- }
- }
- void gui_layout_calculate_parent_percent_sizes(
- GUI_Node *node,
- GUI_Axis2 axis)
- {
- if(node->semantic_size[axis].size_rule == GUI_SIZERULE_PERCENTOFPARENT)
- {
- int percentage = node->semantic_size[axis].value;
- node->computed_size[axis] =
- (GUI_NODE_PARENT(node)->computed_size[axis] * percentage) / 100;
- }
- if(node->rdic_node.first_child != NULL) {
- gui_layout_calculate_parent_percent_sizes(GUI_NODE_FIRST_CHILD(node), axis);
- }
- if(node->rdic_node.sibling != NULL) {
- gui_layout_calculate_parent_percent_sizes(GUI_NODE_SIBLING(node), axis);
- }
- }
-
- void gui_layout_calculate_screen_rects(
- GUI_Node *node,
- int x, int y,
- GUI_Layout_Direction layout_direction)
- {
- int width = node->computed_size[GUI_AXIS2_X];
- int height = node->computed_size[GUI_AXIS2_Y];
- node->rect = (GUI_Rectangle){x, y, x+width, y+height};
- if(node->rdic_node.first_child != NULL) {
- gui_layout_calculate_screen_rects(
- GUI_NODE_FIRST_CHILD(node), x, y, node->layout_direction);
- }
- if(node->rdic_node.sibling != NULL) {
- int sibling_x = x;
- int sibling_y = y;
- if(layout_direction == GUI_LAYOUT_HORIZONTAL)
- {
- sibling_x += width;
- }
- if(layout_direction == GUI_LAYOUT_VERTICAL)
- {
- sibling_y += height;
- }
- gui_layout_calculate_screen_rects(
- GUI_NODE_SIBLING(node), sibling_x, sibling_y, layout_direction);
- }
- }
-
- void gui_layout_nodes(GUI_Subtree *subtree)
- {
- #if 1
- GUI_Node *root = (GUI_Node*)subtree->rdic.root;
- assert(root != NULL);
- for(GUI_Axis2 axis = 0; axis < GUI_AXIS2_COUNT; axis++)
- {
- gui_layout_calculate_standalone_sizes(root, axis);
- gui_layout_calculate_parent_percent_sizes(root, axis);
- }
-
- // TODO(Zelaven): Test reference validity.
- // TODO(Zelaven): This probably can be done once and passed in.
- int x_offset = 0;
- int y_offset = 0;
- GUI_Node *relative_node = (GUI_Node*)subtree->relative_to.node;
- if(relative_node != NULL){
- GUI_Rectangle *relative_rectangle = &relative_node->rect;
- x_offset = relative_rectangle->x0;
- y_offset = relative_rectangle->y0;
- //printf("%.*s: %d, %d\n", relative_node->debug_string.length, relative_node->debug_string.cstring, x_offset, y_offset);
- int relative_width = relative_rectangle->x1 - relative_rectangle->x0;
- int relative_height = relative_rectangle->y1 - relative_rectangle->y0;
- x_offset +=
- (relative_width * subtree->offset_relative_node_percentage_x) / 100;
- y_offset +=
- (relative_height * subtree->offset_relative_node_percentage_y) / 100;
- }
- x_offset += subtree->flat_offset_x;
- y_offset += subtree->flat_offset_y;
-
- x_offset +=
- (root->computed_size[GUI_AXIS2_X] * subtree->offset_own_size_percentage_x) / 100;
- y_offset +=
- (root->computed_size[GUI_AXIS2_Y] * subtree->offset_own_size_percentage_y) / 100;
-
- gui_layout_calculate_screen_rects(root, x_offset, y_offset, GUI_LAYOUT_NONE);
- #else
-
- //GUI_Node *root = (GUI_Node*)context->first_subtree->rdic.root;
- for(GUI_Axis2 axis = 0; axis < GUI_AXIS2_COUNT; axis++)
- {
- gui_layout_calculate_standalone_sizes(root, axis);
- gui_layout_calculate_parent_percent_sizes(root, axis);
- }
- gui_layout_calculate_screen_rects(root, 0, 0, GUI_LAYOUT_NONE);
- #endif
- }
-
-
- // ---
-
-
- #undef ENABLE_DEBUG
- #define ENABLE_DEBUG 0
- void gui_generate_draw_commands_inner(
- //int x_offset,
- //int y_offset,
- GUI_Node *node,
- bool dirty, //TODO(Zelaven): Better name.
- Memory_Arena *draw_command_arena,
- int *out_num_draw_commands)
- {
- DEBUG("%.*s: dirtiness: %b\n",
- node->debug_string.length, node->debug_string.cstring, dirty);
- if(dirty) {
- node->dirty = true;
- GUI_Draw_Command *draw_command =
- arena_allocate_draw_command(draw_command_arena);
- DEBUG("%d, %d, %d, %x, %d, %u\n", node->style->red, node->style->green, node->style->blue, node->style->border_color, node->style->border_thickness, node->style->roundedness);
- *draw_command = (GUI_Draw_Command){
- .rectangle = node->rect,
- .color = node->style->red<<16 | node->style->green<<8 | node->style->blue,
- .border_color = node->style->border_color,
- .border_thickness = node->style->border_thickness,
- .roundedness = node->style->roundedness,
- .text = node->text_string,
- .image = node->image,
- };
- #if 0
- (*draw_command).rectangle.x0 += x_offset;
- (*draw_command).rectangle.x1 += x_offset;
- (*draw_command).rectangle.y0 += y_offset;
- (*draw_command).rectangle.y1 += y_offset;
- #endif
- *out_num_draw_commands += 1;
- }
-
- GUI_Node *sibling = GUI_NODE_SIBLING(node);
- if(sibling != NULL) {
- GUI_Node *parent = GUI_NODE_PARENT(node);
- gui_generate_draw_commands_inner(
- //x_offset, y_offset,
- sibling,
- parent->dirty || sibling->dirty,
- draw_command_arena, out_num_draw_commands);
- }
- GUI_Node *first_child = GUI_NODE_FIRST_CHILD(node);
- if(node->rdic_node.first_child != NULL) {
- gui_generate_draw_commands_inner(
- //x_offset, y_offset,
- first_child,
- dirty || first_child->dirty,
- draw_command_arena, out_num_draw_commands);
- }
- }
-
- void gui_generate_draw_commands(
- //GUI_Node *root,
- GUI_Subtree *subtree,
- Memory_Arena *draw_command_arena,
- int *out_num_draw_commands)
- {
- #if 0
- // TODO(Zelaven): Test reference validity.
- // TODO(Zelaven): This probably can be done once and passed in.
- int x_offset = 0;
- int y_offset = 0;
- GUI_Node *relative_node = (GUI_Node*)subtree->relative_to.node;
- if(relative_node != NULL){
- GUI_Rectangle *relative_rectangle = &relative_node->rect;
- x_offset = relative_rectangle->x0;
- y_offset = relative_rectangle->y0;
- //printf("%.*s: %d, %d\n", relative_node->debug_string.length, relative_node->debug_string.cstring, x_offset, y_offset);
- int relative_width = relative_rectangle->x1 - relative_rectangle->x0;
- int relative_height = relative_rectangle->y1 - relative_rectangle->y0;
- x_offset +=
- (relative_width * subtree->offset_relative_node_percentage_x) / 100;
- y_offset +=
- (relative_height * subtree->offset_relative_node_percentage_y) / 100;
- }
- x_offset += subtree->flat_offset_x;
- y_offset += subtree->flat_offset_y;
-
- GUI_Node *root = (GUI_Node*)subtree->rdic.root;
- assert(root != NULL);
- x_offset +=
- (root->computed_size[GUI_AXIS2_X] * subtree->offset_own_size_percentage_x) / 100;
- y_offset +=
- (root->computed_size[GUI_AXIS2_Y] * subtree->offset_own_size_percentage_y) / 100;
- #else
- GUI_Node *root = (GUI_Node*)subtree->rdic.root;
- assert(root != NULL);
- #endif
-
- assert(draw_command_arena != NULL);
- assert(out_num_draw_commands != NULL);
- *out_num_draw_commands = 0;
- memory_arena_reset(draw_command_arena);
- bool dirtyness = root->dirty;
- GUI_Node_Reference clipnode = subtree->clipnode;
- if(rdic_node_reference_valid(clipnode.rdic_ref)) {
- dirtyness |= clipnode.node->dirty;
- }
- gui_generate_draw_commands_inner(
- //x_offset, y_offset,
- root, dirtyness,
- draw_command_arena, out_num_draw_commands);
- }
-
-
-
- // ---
-
-
-
-
- GUI_Node_Reference gui_layout(
- GUI_Context *context,
- GUI_Node_Reference last_reference,
- GUI_Layout_Direction direction,
- GUI_Style *style,
- GUI_Size size[static 2])
- {
- GUI_Node_Reference new_reference = gui_get_node(
- context, last_reference, direction, style, size);
- GUI_Node *node = new_reference.node;
- node->text_string = (GUI_String){0};
- node->debug_string = GUI_STRING("gui_layout");
- return new_reference;
- }
-
-
- // ---
-
-
- GUI_Node_Reference gui_dumb_block(
- GUI_Context *context,
- GUI_Node_Reference last_reference,
- 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->text_string = (GUI_String){0};
- node->debug_string = GUI_STRING("gui_dumb_block");
- return new_reference;
- }
-
- #undef ENABLE_DEBUG
- #define ENABLE_DEBUG 0
- bool gui_dumb_button(
- 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 = text;
- node->text_string = text;
-
- bool clicked = false;
- if(gui_node_references_equal(
- new_reference, context->top_node_under_cursor))
- {
- DEBUG("%.*s: reference is the top node under cursor.\n",
- text.length, text.cstring);
- if(context->mouse_pressed)
- {
- DEBUG(" Mouse pressed on node\n");
- context->focused_node = new_reference;
- }
- else if(!context->mouse_down)
- {
- DEBUG(" Mouse released on node\n");
- if(gui_node_references_equal(new_reference, context->focused_node))
- {
- DEBUG(" Mouse released over same node as pressed\n");
- context->focused_node.node = NULL;
- clicked = true;
- }
- }
- }
- else if(gui_node_references_equal(new_reference, context->focused_node)
- && !context->mouse_down)
- {
- context->focused_node.node = NULL;
- }
-
- *last_reference = new_reference;
- return clicked;
- }
-
- #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 0
- bool gui_slider(
- GUI_Context *context,
- GUI_Node_Reference *last_reference,
- GUI_Node_Reference *inner_box_reference,
- float *value,
- GUI_Style *background_style,
- GUI_Style *bar_style,
- GUI_Size size[static 2])
- {
- GUI_Node_Reference new_reference = gui_get_node(
- context, *last_reference, GUI_LAYOUT_NONE, background_style, size);
- GUI_Node *node = new_reference.node;
- node->debug_string = GUI_STRING("gui_slider");
- node->text_string = (GUI_String){0};
-
- // NOTE(Zelaven): We need a handle to this node, but we set its values later.
- gui_push_parent(context, new_reference);
- GUI_Node_Reference new_inner_reference = gui_get_node(
- context, *inner_box_reference, GUI_LAYOUT_NONE, bar_style, size);
-
- bool value_changed = false;
- bool new_ref_is_top = gui_node_references_equal(
- 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",
- context->top_node_under_cursor.node,
- last_reference->node, inner_box_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__);
- if(context->mouse_pressed)
- {
- DEBUG(" Mouse pressed on node\n");
- context->focused_node = new_reference;
- }
- else if(!context->mouse_down)
- {
- DEBUG(" Mouse released on node\n");
- if(gui_node_references_equal(new_reference, context->focused_node))
- {
- DEBUG(" Mouse released over same node as pressed\n");
- context->focused_node.node = NULL;
- }
- }
- }
- else if(gui_node_references_equal(new_reference, context->focused_node)
- && !context->mouse_down)
- {
- context->focused_node.node = NULL;
- }
-
- if(gui_node_references_equal(new_reference, context->focused_node))
- {
- int last_frame_width = node->computed_size[GUI_AXIS2_X];
- if(last_frame_width == 0)
- {
- DEBUG(
- " last_frame_width is 0."
- " This shouldn't really happen as the user shouldn't be able to focus"
- " a node that hasn't been displayed on the screen yet."
- " Not going to change the slider value.");
- }
- else
- {
- int offset_x = context->mouse_x - node->rect.x0;
- float before_value = *value;
- float new_value = ((float)offset_x) / ((float)last_frame_width);
- if(new_value < 0.0f)
- {
- new_value = 0.0f;
- }
- else if(new_value >= 1.0f)
- {
- new_value = 1.0f;
- }
- *value = new_value;
- DEBUG(" Value before: %f - Value after: %f\n", before_value, *value);
- value_changed = (before_value != new_value);
- }
- }
-
- // NOTE(Zelaven): Modified by input, so handle input first.
- GUI_Node *inner = new_inner_reference.node;
- inner->debug_string = GUI_STRING("gui_slider - inner node");
- inner->text_string = (GUI_String){0};
- assert(*value <= 1.0f);
- //inner->semantic_size[GUI_AXIS2_X].value = last_frame_width*(*value);
- inner->semantic_size[GUI_AXIS2_Y] =
- (GUI_Size){GUI_SIZERULE_PERCENTOFPARENT, 100, 100};
- inner->semantic_size[GUI_AXIS2_X].size_rule = GUI_SIZERULE_PERCENTOFPARENT;
- inner->semantic_size[GUI_AXIS2_X].value = 100 * (*value);
- gui_pop_parent(context);
-
-
- *last_reference = new_reference;
- *inner_box_reference = new_inner_reference;
- if(value_changed) {node->dirty = true;}
- //node->dirty = true;
- return value_changed;
- }
-
- #undef ENABLE_DEBUG
- #define ENABLE_DEBUG 0
- bool gui_vertical_slider(
- GUI_Context *context,
- GUI_Node_Reference *last_reference,
- GUI_Node_Reference *inner_box_reference,
- float *value,
- GUI_Style *background_style,
- GUI_Style *bar_style,
- GUI_Size size[static 2])
- {
- GUI_Node_Reference new_reference = gui_get_node(
- context, *last_reference, GUI_LAYOUT_NONE, background_style, size);
- GUI_Node *node = new_reference.node;
- node->debug_string = GUI_STRING("gui_slider");
- node->text_string = (GUI_String){0};
-
- // NOTE(Zelaven): We need a handle to this node, but we set its values later.
- gui_push_parent(context, new_reference);
- GUI_Node_Reference new_inner_reference = gui_get_node(
- context, *inner_box_reference, GUI_LAYOUT_NONE, bar_style, size);
-
- bool value_changed = false;
- bool new_ref_is_top = gui_node_references_equal(
- 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",
- context->top_node_under_cursor.node,
- last_reference->node, inner_box_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__);
- if(context->mouse_pressed)
- {
- DEBUG(" Mouse pressed on node\n");
- context->focused_node = new_reference;
- }
- else if(!context->mouse_down)
- {
- DEBUG(" Mouse released on node\n");
- if(gui_node_references_equal(new_reference, context->focused_node))
- {
- DEBUG(" Mouse released over same node as pressed\n");
- context->focused_node.node = NULL;
- }
- }
- }
- else if(gui_node_references_equal(new_reference, context->focused_node)
- && !context->mouse_down)
- {
- context->focused_node.node = NULL;
- }
-
- if(gui_node_references_equal(new_reference, context->focused_node))
- {
- int last_frame_height = node->computed_size[GUI_AXIS2_Y];
- if(last_frame_height == 0)
- {
- DEBUG(
- " last_frame_height is 0."
- " This shouldn't really happen as the user shouldn't be able to focus"
- " a node that hasn't been displayed on the screen yet."
- " Not going to change the slider value.");
- }
- else
- {
- int offset_y = context->mouse_y - node->rect.y0;
- float before_value = *value;
- float new_value = ((float)offset_y) / ((float)last_frame_height);
- if(new_value < 0.0f)
- {
- new_value = 0.0f;
- }
- else if(new_value >= 1.0f)
- {
- new_value = 1.0f;
- }
- *value = new_value;
- DEBUG(" Value before: %f - Value after: %f\n", before_value, *value);
- value_changed = (before_value != new_value);
- }
- }
-
- // NOTE(Zelaven): Modified by input, so handle input first.
- GUI_Node *inner = new_inner_reference.node;
- inner->debug_string = GUI_STRING("gui_slider - inner node");
- inner->text_string = (GUI_String){0};
- assert(*value <= 1.0f);
- inner->semantic_size[GUI_AXIS2_X] =
- (GUI_Size){GUI_SIZERULE_PERCENTOFPARENT, 100, 100};
- inner->semantic_size[GUI_AXIS2_Y].size_rule = GUI_SIZERULE_PERCENTOFPARENT;
- inner->semantic_size[GUI_AXIS2_Y].value = 100 * (*value);
- gui_pop_parent(context);
-
-
- *last_reference = new_reference;
- *inner_box_reference = new_inner_reference;
- if(value_changed) {node->dirty = true;}
- return value_changed;
- }
-
-
-
-
-
- // ---
-
-
-
- void test_gui(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- static float border_thickness = 0;
- float last_border_thickness = border_thickness;
-
-
-
- static GUI_Style root_style = {42, 24, 88, 0,0,0};
- static GUI_Style dumb_button_style = {88, 24, 42, 0,0,0};
- static GUI_Size dumb_button_size[2] = {
- {GUI_SIZERULE_PIXELS, 42, 100},
- {GUI_SIZERULE_PIXELS, 24, 100}};
- static GUI_Style other_dumb_button_style = {24, 42, 88, 0x0000ffff,0,0};
-
- static GUI_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- full_gui_rectangle.x1-full_gui_rectangle.x0,
- full_gui_rectangle.y1-full_gui_rectangle.y0,
- GUI_LAYOUT_HORIZONTAL,
- &root_style);
-
- static GUI_Node_Reference dumb_button = {0};
- if(my_bool)
- if(gui_dumb_button(
- context,
- &dumb_button,
- GUI_STRING("My Dumb Button"),
- &dumb_button_style,
- dumb_button_size))
- {
- printf(
- "**************\n"
- "*** BUTTON ***\n"
- "**************\n");
- border_thickness += 1;
- if(border_thickness > 21) border_thickness = 21;
- printf("border_thickness: %f\n", border_thickness);
- my_bool = false;
- ((GUI_Node*)root.node)->dirty = true;
- }
- static GUI_Node_Reference dumb_button2 = {0};
- if(gui_dumb_button(
- context,
- &dumb_button2,
- GUI_STRING("My Other Dumb Button"),
- &other_dumb_button_style,
- dumb_button_size))
- {
- printf(
- "**************\n"
- "*** OTHER ***\n"
- "**************\n"
- );
- border_thickness -= 1;
- if(border_thickness < 0) border_thickness = 0;
- printf("border_thickness: %f\n", border_thickness);
- my_bool = true;
- }
-
- if(my_bool)
- {
- static GUI_Style layout_style = {100, 0, 100,0,0,0};
- static GUI_Size layout_size[2] = {
- {GUI_SIZERULE_PIXELS, 400, 100},
- {GUI_SIZERULE_PIXELS, 400, 100}};
- static GUI_Node_Reference layout = {0};
- layout = gui_layout(
- context, layout, GUI_LAYOUT_VERTICAL, &layout_style, layout_size);
- gui_push_parent(context, layout);
-
- // static variables can be used for isolated styles that:
- // 1) are only used within the current scope.
- // 2) don't need to be changed at runtime.
- static GUI_Style inner_block_2_style = {200, 253, 235, 0,0,0};
- static GUI_Style inner_block_3_style = {235, 253, 200, 0,0,0};
- static GUI_Style inner_block_4_style = {0 , 0, 0, 0,0,0};
- static GUI_Node_Reference dumb_block2 = {0};
- dumb_block2 = gui_dumb_block(
- context,
- dumb_block2,
- &inner_block_2_style,
- dumb_button_size);
- static GUI_Node_Reference dumb_block3 = {0};
- dumb_block3 = gui_dumb_block(
- context,
- dumb_block3,
- &inner_block_3_style,
- dumb_button_size);
- static GUI_Node_Reference dumb_block4 = {0};
- dumb_block4 = gui_dumb_block(
- context,
- dumb_block4,
- &inner_block_4_style,
- dumb_button_size);
- static GUI_Node_Reference dumb_button3 = {0};
- if(gui_dumb_button(
- context,
- &dumb_button3,
- GUI_STRING("Inner Dumb Button"),
- &dumb_button_style,
- dumb_button_size))
- {
- printf(
- "**************\n"
- "*** INNER ***\n"
- "**************\n"
- );
- }
- static GUI_Size dumb_block5_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 42, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 24, 100}};
- static GUI_Node_Reference dumb_block5 = {0};
- dumb_block5 = gui_dumb_block(
- context,
- dumb_block5,
- &inner_block_4_style,
- dumb_block5_size);
- gui_pop_parent(context);
- }
-
- static GUI_Style slider_background = {0, 0, 0, 0,0,0};
- static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
- static GUI_Size slider_size[2] = {
- {GUI_SIZERULE_PIXELS, 100, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
- static GUI_Node_Reference slider = {0};
- static GUI_Node_Reference slider_inner = {0};
- static float slider_value = 0.25f;
- //slider_bar.blue = 255 * slider_value;
- //slider_value += 0.01f;
- //if(slider_value >= 1.0f) slider_value = 0.5f;
- // NOTE(Zelaven): This line is not good because it causes jankyness when using
- // the slider, and the slider behaves properly without it.
- // NOTE(Zelaven): This line is actually necessary if the value is writable by
- // anything other than the slider. If border_thickness is a float variable,
- // then there is no issue, though.
- slider_value = ((float)border_thickness) / 21.;
- bool slider_value_changed = gui_slider(
- context,
- &slider, &slider_inner,
- &slider_value,
- &slider_background,
- &slider_bar,
- slider_size);
- border_thickness = 21.*slider_value;
- //printf("Slider value changed?: %b\n", slider_value_changed);
- ((GUI_Node*)root.node)->dirty |= slider_value_changed;
-
- static GUI_Style block_after_layout_style = {99, 99, 99, 0,0,0};
- static GUI_Size block_after_layout_size[2] = {
- {GUI_SIZERULE_PIXELS, 50, 100},
- {GUI_SIZERULE_PIXELS, 50, 100}};
- static GUI_Node_Reference dumb_block_after_layout = {0};
- dumb_block_after_layout = gui_dumb_block(
- context,
- dumb_block_after_layout,
- &block_after_layout_style,
- block_after_layout_size);
-
- static GUI_Style my_style = {100, 100, 0, 0, 3, 0};
- static GUI_Size dumb_block_size[2] = {
- {GUI_SIZERULE_PIXELS, 50, 100},
- {GUI_SIZERULE_PIXELS, 100, 100},
- };
- my_style.border_thickness = border_thickness;
- static GUI_Node_Reference new_style_gui_dumb_block = {0};
- new_style_gui_dumb_block = gui_dumb_block(
- context,
- new_style_gui_dumb_block,
- &my_style,
- dumb_block_size);
-
- other_dumb_button_style.border_thickness = border_thickness;
- if(border_thickness != last_border_thickness) {
- ((GUI_Node*)root.node)->dirty = true;
- }
- gui_context_finish_frame(context);
- }
-
-
- // Text field at the top, 4x4 button grid below.
- // See the nuklear example calculator?
- void test_gui__calculator(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- (void)full_gui_rectangle;
-
- static GUI_Style root_style = {0x44,0x44,0x44, 0x00999999,2,0};
- static GUI_Style button_style = {0x33,0x33,0x33, 0x00999999,2,25};
- static GUI_Size button_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 25, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
- static GUI_Style row_style = {0x44,0x44,0x44, 0,0,0};
- static GUI_Size row_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 25, 100}};
-
- static GUI_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- //full_gui_rectangle.x1-full_gui_rectangle.x0,
- //full_gui_rectangle.y1-full_gui_rectangle.y0,
- 300, 400,
- GUI_LAYOUT_VERTICAL,
- &root_style);
-
- #if 1
- static GUI_Node_Reference rows[4] = {0};
- static GUI_Node_Reference buttons[4][4] = {0};
- GUI_String button_labels[4][4] = {
- {GUI_STRING("1"), GUI_STRING("2"), GUI_STRING("3"), GUI_STRING("+")},
- {GUI_STRING("4"), GUI_STRING("5"), GUI_STRING("6"), GUI_STRING("-")},
- {GUI_STRING("7"), GUI_STRING("8"), GUI_STRING("9"), GUI_STRING("*")},
- {GUI_STRING("C"), GUI_STRING("0"), GUI_STRING("="), GUI_STRING("/")},
- };
- for(size_t row = 0; row < ARRAYLENGTH(rows); row++)
- {
- rows[row] = gui_layout(
- context, rows[row], GUI_LAYOUT_HORIZONTAL, &row_style, row_size);
- gui_push_parent(context, rows[row]);
- for(size_t i = 0; i < ARRAYLENGTH(buttons[0]); i++)
- {
- if(gui_dumb_button(
- context, &buttons[row][i],
- button_labels[row][i],
- &button_style, button_size))
- {
- GUI_String button_label = button_labels[row][i];
- printf("%.*s\n", button_label.length, button_label.cstring);
- }
- }
- gui_pop_parent(context);
- }
- #else
- static GUI_Node_Reference row1 = {0};
- row1 = gui_layout2(
- context, row1, GUI_LAYOUT_HORIZONTAL, &row_style, row_size);
- gui_push_parent(context, row1);
- static GUI_Node_Reference row1_buttons[4] = {0};
- char *row1_button_labels[4] = {"1", "2", "3", "+"};
- for(size_t i = 0; i < ARRAYLENGTH(row1_buttons); i++)
- {
- if(gui_dumb_button(
- context, &row1_buttons[i],
- row1_button_labels[i],
- &button_style, button_size))
- {
- printf("%s\n", row1_button_labels[i]);
- }
- }
- gui_pop_parent(context);
- #endif
-
-
- gui_context_finish_frame(context);
- }
-
-
- void test_gui__scrollbars(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- (void)full_gui_rectangle;
-
- static GUI_Style root_style = {0x44,0x44,0x44, 0x00999999,2,0};
- static GUI_Style element_style = {0,0x33,0x33, 0x00009999,2,0};
- static GUI_Size element_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PIXELS, 100, 100}};
- static GUI_Style outer_style = {0x33,0x33,0x33, 0x00999999,2,0};
- static GUI_Size top_bottom_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 25, 100}};
- static GUI_Size middle_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 50, 100}};
- static GUI_Size side_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 25, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
- static GUI_Size center_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 50, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
-
- static GUI_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- full_gui_rectangle.x1-full_gui_rectangle.x0,
- full_gui_rectangle.y1-full_gui_rectangle.y0,
- //300, 400,
- GUI_LAYOUT_VERTICAL,
- &root_style);
-
-
- static GUI_Node_Reference top = {0};
- static GUI_Node_Reference middle = {0};
- static GUI_Node_Reference bottom = {0};
-
- top = gui_dumb_block(context, top, &outer_style, top_bottom_size);
-
- middle = gui_layout(
- context, middle, GUI_LAYOUT_HORIZONTAL, &outer_style, middle_size);
- gui_push_parent(context, middle);
- {
- static GUI_Node_Reference left = {0};
- static GUI_Node_Reference center = {0};
- static GUI_Node_Reference right = {0};
-
- left = gui_dumb_block(context, left, &outer_style, side_size);
- center = gui_dumb_block(context, center, &outer_style, center_size);
- gui_push_parent(context, center);
- {
- static GUI_Node_Reference scrollbox_layout = {0};
- static GUI_Size full_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
- scrollbox_layout = gui_layout(
- context, scrollbox_layout, GUI_LAYOUT_HORIZONTAL, &outer_style, full_size);
-
- gui_push_parent(context, scrollbox_layout);
- {
- static GUI_Node_Reference scrollregion_layout = {0};
- static GUI_Size scrollregion_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 90, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
- static GUI_Size scrollbar_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 10, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
- #if 0
- scrollregion_layout = gui_layout(
- context, scrollregion_layout, GUI_LAYOUT_VERTICAL,
- &outer_style, scrollregion_size);
- gui_push_parent(context, scrollregion_layout);
- {
- static GUI_Node_Reference elements[6] = {0};
- for(size_t i = 0; i < ARRAYLENGTH(elements); i++) {
- elements[i] = gui_dumb_block(
- context, elements[i], &element_style, element_size);
- }
- } gui_pop_parent(context);
- #else
- scrollregion_layout = gui_dumb_block(
- context, scrollregion_layout, &outer_style, scrollregion_size);
- static GUI_Subtree_Reference scrollregion_subtree = {0};
- scrollregion_subtree = gui_get_subtree(context, scrollregion_subtree);
- static GUI_Node_Reference scrollregion_root = {0};
- static GUI_Size scrollregion_inner_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- //{GUI_SIZERULE_PIXELS, 100, 100},
- {GUI_SIZERULE_PIXELS, 880, 100}};
- scrollregion_root = gui_push_subtree(
- context, scrollregion_subtree, scrollregion_root,
- GUI_LAYOUT_VERTICAL, &outer_style, scrollregion_inner_size,
- scrollbox_layout);
- // TODO(Zelaven): Instead of this hack, add to the layout code that it
- // can set the size of the root relative to the size of its relative
- // node.
- scrollregion_root.rdic_ref.node->parent = scrollregion_layout.rdic_ref.node;
- {
- static GUI_Node_Reference elements[6] = {0};
- for(size_t i = 0; i < ARRAYLENGTH(elements); i++) {
- elements[i] = gui_dumb_block(
- context, elements[i], &element_style, element_size);
- }
-
- } gui_pop_subtree(context);
- #endif
- #if 0
- static GUI_Node_Reference scrollbar_layout = {0};
- scrollbar_layout = gui_layout(
- context, scrollbar_layout, GUI_LAYOUT_VERTICAL,
- &outer_style, scrollbar_size);
- float scroll_position = 0.75f;
- int spacer_total = 90;
- int spacer_upper = scroll_position * spacer_total;
- int spacer_lower = spacer_total - spacer_upper;
- gui_push_parent(context, scrollbar_layout);
- {
- static GUI_Size bar_knob_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 10, 100}};
- // NOTE(Zelaven): These sizes are unique to each scrollbar.
- static GUI_Size bar_upper_spacer_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 0, 100}};
- static GUI_Size bar_lower_spacer_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 90, 100}};
- bar_upper_spacer_size[GUI_AXIS2_Y].value = spacer_upper;
- bar_lower_spacer_size[GUI_AXIS2_Y].value = spacer_lower;
-
- static GUI_Node_Reference scrollbar_upper_spacer = {0};
- static GUI_Node_Reference scrollbar_knob = {0};
- static GUI_Node_Reference scrollbar_lower_spacer = {0};
- scrollbar_upper_spacer = gui_dumb_block(
- context, scrollbar_upper_spacer, &outer_style, bar_upper_spacer_size);
- scrollbar_knob = gui_dumb_block(
- context, scrollbar_knob, &outer_style, bar_knob_size);
- scrollbar_lower_spacer = gui_dumb_block(
- context, scrollbar_lower_spacer, &outer_style, bar_lower_spacer_size);
- } gui_pop_parent(context); // scrollbar_layout.
- #else
- static float slider_value = 0.0f;
- static GUI_Style slider_background = {0, 0, 0, 0,0,0};
- static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
- static GUI_Node_Reference slider = {0};
- static GUI_Node_Reference slider_inner = {0};
- gui_vertical_slider(context, &slider, &slider_inner,
- &slider_value, &slider_background, &slider_bar, scrollbar_size);
- scrollregion_subtree.node->offset_relative_node_percentage_y =
- slider_value*100;
- scrollregion_subtree.node->offset_own_size_percentage_y =
- slider_value*-100;
- scrollregion_root.node->dirty = true;
- //((GUI_Node*)slider.node)->dirty;
- //printf("Slider value: %f\n", slider_value);
- #endif
- } gui_pop_parent(context); // scrollbox_layout.
- } gui_pop_parent(context); // center.
- right = gui_dumb_block(context, right, &outer_style, side_size);
- } gui_pop_parent(context); // middle.
-
- bottom = gui_dumb_block(context, bottom, &outer_style, top_bottom_size);
-
-
- gui_context_finish_frame(context);
- }
-
- void test_gui__draw_command_using_sliders(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- //static float border_thickness = 0;
-
- static GUI_Style root_style = {42, 24, 88, 0,0,0};
- static GUI_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- full_gui_rectangle.x1-full_gui_rectangle.x0,
- full_gui_rectangle.y1-full_gui_rectangle.y0,
- GUI_LAYOUT_VERTICAL,
- &root_style);
-
- static GUI_Size layout_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 50, 100}};
- static GUI_Node_Reference layout = {0};
- layout = gui_layout(
- context, layout, GUI_LAYOUT_VERTICAL, &root_style, layout_size);
- gui_push_parent(context, layout);
- {
- static GUI_Style slider_background = {0, 0, 0, 0,0,0};
- static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
- static GUI_Size slider_size[2] = {
- {GUI_SIZERULE_PIXELS, 200, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
- static GUI_Node_Reference slider = {0};
- static GUI_Node_Reference slider_inner = {0};
-
- static GUI_Style button_style = {200, 0, 0, 0,5,0};
- static GUI_Size button_size[2] = {
- {GUI_SIZERULE_PIXELS, 100, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
-
- static GUI_Style slider_spacer_style = {99, 99, 99, 0,0,0};
- static GUI_Size slider_spacer_size[2] = {
- {GUI_SIZERULE_PIXELS, 200, 100},
- {GUI_SIZERULE_PIXELS, 5, 100}};
-
- static GUI_Style button_spacer_style = {99, 99, 99, 0,0,0};
- static GUI_Size button_spacer_size[2] = {
- {GUI_SIZERULE_PIXELS, 5, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
-
- static GUI_Size row_layout_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
-
- static GUI_Node_Reference row1_layout = {0};
- row1_layout = gui_layout(
- context, row1_layout, GUI_LAYOUT_HORIZONTAL, &root_style, row_layout_size);
- #if 1
- gui_push_parent(context, row1_layout);
- {
- static float slider_value = 0.25f;
- // NOTE(Zelaven): This line is not good because it causes jankyness when
- // using the slider, and the slider behaves properly without it.
- // NOTE(Zelaven): This line is actually necessary if the value is writable
- // by anything other than the slider. If border_thickness is a float
- // variable, then there is no issue, though.
- slider_value = ((float)border_thickness) / 51.;
- gui_slider(context, &slider, &slider_inner,
- &slider_value, &slider_background, &slider_bar, slider_size);
- border_thickness = 51.*slider_value;
-
- static GUI_Node_Reference spacer1 = {0};
- spacer1 = gui_dumb_block(
- context, spacer1, &button_spacer_style, button_spacer_size);
-
- static GUI_Node_Reference button_thickness_down = {0};
- if(gui_dumb_button(context, &button_thickness_down,
- GUI_STRING("-"), &button_style, button_size))
- {
- border_thickness -= 1;
- printf("-\n");
- }
-
- static GUI_Node_Reference spacer2 = {0};
- spacer2 = gui_dumb_block(
- context, spacer2, &button_spacer_style, button_spacer_size);
-
- static GUI_Node_Reference button_thickness_up = {0};
- if(gui_dumb_button(context, &button_thickness_up,
- GUI_STRING("+"), &button_style, button_size))
- {
- border_thickness += 1;
- printf("+\n");
- }
- }
- gui_pop_parent(context);
- #endif
-
- static GUI_Node_Reference slider_spacer = {0};
- slider_spacer = gui_dumb_block(
- context, slider_spacer, &slider_spacer_style, slider_spacer_size);
-
- static GUI_Node_Reference slider2 = {0};
- static GUI_Node_Reference slider2_inner = {0};
- static float slider2_value = 0.25f;
- slider2_value = ((float)roundedness) / 100.;
- gui_slider(context, &slider2, &slider2_inner,
- &slider2_value, &slider_background, &slider_bar, slider_size);
- roundedness = 100.*slider2_value;
- }
- gui_pop_parent(context);
-
-
- gui_context_finish_frame(context);
- }
-
-
- #if 1
- void test_gui__subtree(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- static GUI_Style root_style = {0x44,0x33,0x33, 0x00999999,2,0};
- static GUI_Style element_style = {0,0x33,0x33, 0x00009999,2,0};
- static GUI_Size element_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PIXELS, 100, 100}};
- static GUI_Style outer_style = {0x33,0x33,0x33, 0x00999999,2,0};
- static GUI_Size top_bottom_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 25, 100}};
- static GUI_Size middle_size[2] = {
- {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
- {GUI_SIZERULE_PERCENTOFPARENT, 50, 100}};
- static GUI_Size test_size[2] = {
- {GUI_SIZERULE_PIXELS, 200, 100},
- {GUI_SIZERULE_PIXELS, 600, 100}};
-
- static GUI_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- full_gui_rectangle.x1-full_gui_rectangle.x0,
- 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 = 70;
- context->top_layer.offset_y = 20;
-
-
- static GUI_Node_Reference top = {0};
- static GUI_Node_Reference middle = {0};
- static GUI_Node_Reference bottom = {0};
-
- static GUI_Node_Reference slider = {0};
- static float slider_value = 0.25f;
- bool should_dirty = false;
- bool set_pixels = false;
- top = gui_layout(
- context, top, GUI_LAYOUT_HORIZONTAL, &outer_style, top_bottom_size);
- gui_push_parent(context, top);
- {
- static GUI_Style slider_background = {0, 0, 0, 0,0,0};
- static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
- static GUI_Size slider_size[2] = {
- {GUI_SIZERULE_PIXELS, 200, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
- //static GUI_Node_Reference slider = {0};
- static GUI_Node_Reference slider_inner = {0};
- gui_slider(context, &slider, &slider_inner,
- &slider_value, &slider_background, &slider_bar, slider_size);
-
- 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, 170, 100},
- {GUI_SIZERULE_PIXELS, 40, 100}};
- if(gui_dumb_button(
- context, &dirty_button, GUI_STRING("Dirty middle"),
- &button_style, button_size))
- {
- should_dirty = true;
- printf("Dirtying middle.\n");
- }
- static GUI_Node_Reference dirty_button2 = {0};
- if(gui_dumb_button(
- context, &dirty_button2, GUI_STRING("Set Pixels"),
- &button_style, button_size))
- {
- 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("Toggle tooltip"),
- &button_style, button_size))
- {
- tooltip_toggle = !tooltip_toggle;
- printf("Toggling tooltip.\n");
- }
- 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};
- if(gui_dumb_button(
- context, &top_layer_block, GUI_STRING("Hi!"),
- &element_style, full_size))
- {
- printf("Top layer says hi!\n");
- }
- }
- }
- } gui_pop_parent(context); // middle.
-
- middle = gui_dumb_block(context, middle, &outer_style, middle_size);
-
- #if 1
- static GUI_Subtree_Reference middle_subtree = {0};
- middle_subtree = gui_get_subtree(context, middle_subtree);
- static GUI_Node_Reference middle_subtree_root = {0};
- middle_subtree_root = gui_push_subtree(
- context, middle_subtree, middle_subtree_root,
- GUI_LAYOUT_VERTICAL, &element_style, test_size, middle);
- {
- static GUI_Color test_image_pixels[10*12] = {
- 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
- ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
- 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
- ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
- 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
- ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
- 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
- ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
- 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
- ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
- ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
- ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
- };
- static Pixel_Buffer test_image = {
- .pixels = test_image_pixels,
- .width = 10,
- .height = 12,
- };
- static GUI_Node_Reference inner_top = {0};
- inner_top = gui_dumb_block(context, inner_top, &outer_style, element_size);
- ((GUI_Node*)inner_top.node)->image = &test_image;
-
- static GUI_Node_Reference subtree_button = {0};
- if(gui_dumb_button(
- context, &subtree_button, GUI_STRING("In subtree"),
- &element_style, element_size))
- {
- printf("Hi from subtree!\n");
- }
- } gui_pop_subtree(context);
- #endif
- #if 0
- int middle_height =
- ((GUI_Node*)middle.node)->computed_size[GUI_AXIS2_Y];
- int subtree_height =
- ((GUI_Node*)middle_subtree_root.node)->computed_size[GUI_AXIS2_Y];
- int overfill = subtree_height - middle_height;
- printf("\n%d = %d - %d\n", overfill, subtree_height, middle_height);
- if(overfill >= 0)
- {
- printf("?\n");
- middle_subtree.flat_offset_y = -(slider_value * overfill);
- printf("%d\n", middle_subtree.flat_offset_x);
- }
- else
- {
- middle_subtree.flat_offset_y = 0;
- }
- #else
- //printf("slider value: %f\n", slider_value);
- middle_subtree.node->offset_relative_node_percentage_y = slider_value*100;
- middle_subtree.node->offset_own_size_percentage_y = slider_value*-100;
- #endif
- middle_subtree_root.node->dirty = ((GUI_Node*)slider.node)->dirty;
-
- bottom = gui_dumb_block(context, bottom, &element_style, top_bottom_size);
-
- middle.node->dirty |= should_dirty;
-
- if(set_pixels)
- {
- #define SET_PIXEL(pixel_buffer, x, y, color) (pixel_buffer)->pixels[(y)*(pixel_buffer)->width + (x)] = (color)
- Pixel_Buffer *pixbuf = context->background_layer.pixel_buffer;
- SET_PIXEL(pixbuf, 500, 500, 0x00ff0000);
- SET_PIXEL(pixbuf, 500, 501, 0);
- SET_PIXEL(pixbuf, 501, 500, 0);
- SET_PIXEL(pixbuf, 501, 501, 0);
-
- SET_PIXEL(pixbuf, 500, 900, 0x00ff0000);
- SET_PIXEL(pixbuf, 500, 901, 0);
- SET_PIXEL(pixbuf, 501, 900, 0);
- SET_PIXEL(pixbuf, 501, 901, 0);
- #undef SET_PIXEL
- }
-
- gui_context_finish_frame(context);
- }
- #endif
-
-
- void test_gui__tmp(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- static GUI_Style root_style = {0x44,0x33,0x33, 0x00999999,2,0};
- static GUI_Style block_style = {0x33,0x33,0x33, 0x00999999,2,0};
- static GUI_Size block_size[2] = {
- {GUI_SIZERULE_PIXELS, 200, 100},
- {GUI_SIZERULE_PIXELS, 200, 100}};
-
- static GUI_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- full_gui_rectangle.x1-full_gui_rectangle.x0,
- full_gui_rectangle.y1-full_gui_rectangle.y0,
- GUI_LAYOUT_VERTICAL,
- &root_style);
-
-
- static GUI_Node_Reference block1 = {0};
- static GUI_Node_Reference empty_layout = {0};
- static GUI_Node_Reference block2 = {0};
-
- block1 = gui_dumb_block(context, block1, &block_style, block_size);
-
- empty_layout = gui_layout(
- context, empty_layout, GUI_LAYOUT_HORIZONTAL, &block_style, block_size);
- gui_push_parent(context, empty_layout);
- {
- } gui_pop_parent(context);
-
- block2 = gui_dumb_block(context, block2, &block_style, block_size);
-
- gui_context_finish_frame(context);
- }
-
- #if 0
- void test_gui_layout(
- GUI_Context *context,
- GUI_Rectangle full_gui_rectangle)
- {
- static RDIC_Node_Reference root = {0};
- root = gui_context_start_frame(
- context, root,
- full_gui_rectangle.x1-full_gui_rectangle.x0,
- full_gui_rectangle.y1-full_gui_rectangle.y0,
- GUI_LAYOUT_HORIZONTAL);
-
- static RDIC_Node_Reference dumb_block = {0};
- #if 0
- dumb_block = gui_dumb_block(
- context,
- dumb_block,
- (GUI_Style){255, 0, 0,0,0,0},
- 50, 50);
- #else
- if(gui_dumb_button(
- context, &dumb_block, "BEFORE Button", (GUI_Style){255, 0, 0,0,0,0}, 50, 50))
- {printf(
- "**************\n"
- "*** BEFORE ***\n"
- "**************\n");}
- #endif
-
- static RDIC_Node_Reference layout = {0};
- layout = gui_layout(
- context,
- layout,
- GUI_LAYOUT_VERTICAL);
- gui_push_parent(context, layout);
-
- static RDIC_Node_Reference dumb_block2 = {0};
- #if 0
- dumb_block2 = gui_dumb_block(
- context,
- dumb_block2,
- (GUI_Style){0, 255, 0,0,0,0},
- 100, 50);
- #else
- if(gui_dumb_button(
- context, &dumb_block2, "INSIDE Button", (GUI_Style){0, 255, 0,0,0,0}, 100, 50))
- {printf(
- "**************\n"
- "*** INSIDE ***\n"
- "**************\n");}
- #endif
-
- gui_pop_parent(context);
-
- static RDIC_Node_Reference dumb_block3 = {0};
- #if 0
- dumb_block_after_layout = gui_dumb_block(
- context,
- dumb_block3,
- (GUI_Style){0, 0, 255,0,0,0},
- 150, 50);
- #else
- if(gui_dumb_button(
- context, &dumb_block3, "AFTER Button", (GUI_Style){0, 0, 255,0,0,0}, 150, 50))
- {printf(
- "**************\n"
- "*** AFTER ***\n"
- "**************\n");}
- #endif
-
- gui_context_finish_frame(context);
- }
- #endif
-
- // ---
- // ---
- // ---
-
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xatom.h>
-
- #define WINDOW_WIDTH 800
- #define WINDOW_HEIGHT 600
- typedef struct X11_Window {
- Display *display;
- Window root;
- Visual *visual;
- Colormap colormap;
- XWindowAttributes window_attributes;
- XSetWindowAttributes set_window_attributes;
- Window window;
- GC graphics_context;
- int screen;
- unsigned int width;
- unsigned int height;
- XImage *screen_image;
-
- Pixel_Buffer pixel_buffer;
- } X11_Window;
-
-
- #include <stdlib.h>
- #include <stdarg.h>
- #include <stdnoreturn.h>
- #include <stdio.h>
- noreturn void die(const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- exit(EXIT_FAILURE);
- }
-
- void print_binary_long(long value)
- {
- int num_bits = sizeof(long)*8;
- unsigned long mask = ((unsigned long)1) << (num_bits-1);
- while(mask != (unsigned long)0)
- {
- int bit = (value & mask) != 0;
- printf("%d", bit);
- mask >>= 1;
- }
- }
-
-
- void fill_pixel_buffer(
- uint32_t *pixels,
- unsigned int width,
- unsigned int height,
- uint8_t red_offset,
- uint8_t blue_offset)
- {
- for(unsigned int column = 0; column < width; column++)
- {
- for(unsigned int row = 0; row < height; row++)
- {
- uint8_t red = (uint8_t)((column+ red_offset) & 0xFF);
- uint8_t blue = (uint8_t)((row +blue_offset) & 0xFF);
- pixels[column + row*width] = (red<<16) | blue;
- }
- }
- }
- void draw_window(
- X11_Window *xwindow)
- {
- /*
- int XPutImage(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int
- dest_x, int dest_y, unsigned int width, unsigned int height);
- */
-
- int error = XPutImage(
- xwindow->display,
- xwindow->window,
- xwindow->graphics_context,
- xwindow->screen_image,
- 0, 0,
- 0, 0,
- xwindow->width, xwindow->height);
- assert(error == 0);
- }
-
- typedef unsigned int uint;
- void draw_rect(
- uint32_t *pixels,
- unsigned int width,
- unsigned int height,
- uint x0, uint y0, uint x1, uint y1,
- uint32_t color)
- {
- //x0 = x0 < 0 ? 0 : x0;
- //y0 = y0 < 0 ? 0 : y0;
- x1 = x1 > width ? width : x1;
- y1 = y1 > width ? height : y1;
-
- for(unsigned int column = x0; column < x1; column++)
- {
- for(unsigned int row = y0; row < y1; row++)
- {
- pixels[column + row*width] = color;
- }
- }
- }
-
-
-
-
-
- void draw_rect2(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command)
- {
- int width = pixel_buffer->width;
- int height = pixel_buffer->height;
-
- int x0 = draw_command->rectangle.x0;
- int y0 = draw_command->rectangle.y0;
- int x1 = draw_command->rectangle.x1;
- int y1 = draw_command->rectangle.y1;
- x0 = x0 < 0 ? 0 : x0;
- y0 = y0 < 0 ? 0 : y0;
- x1 = x1 > width ? width : x1;
- y1 = y1 > width ? height : y1;
-
- for(int column = x0; column < x1; column++)
- {
- for(int row = y0; row < y1; row++)
- {
- pixel_buffer->pixels[column + row*width] = draw_command->color;
- }
- }
- }
-
- void draw_rect3(
- Pixel_Buffer *pixel_buffer,
- GUI_Rectangle rectangle,
- GUI_Color color)
- {
- int width = pixel_buffer->width;
- int height = pixel_buffer->height;
-
- int x0 = rectangle.x0;
- int y0 = rectangle.y0;
- int x1 = rectangle.x1;
- int y1 = rectangle.y1;
- x0 = x0 < 0 ? 0 : x0;
- y0 = y0 < 0 ? 0 : y0;
- x1 = x1 > width ? width : x1;
- y1 = y1 > height ? height : y1;
-
- for(int column = x0; column < x1; column++)
- {
- for(int row = y0; row < y1; row++)
- {
- pixel_buffer->pixels[column + row*width] = color;
- }
- }
- }
-
-
- #define SET_PIXEL(pixel_buffer, x, y, color) (pixel_buffer)->pixels[(y)*(pixel_buffer)->width + (x)] = (color)
- #define GET_PIXEL(pixel_buffer, x, y) (pixel_buffer)->pixels[(y)*(pixel_buffer)->width + (x)]
-
- void test_draw_horizontal_pixel_line(
- Pixel_Buffer *pixel_buffer,
- int x0, int x1, int y,
- GUI_Color color)
- {
- for(int i = x0; i < x1; i++)
- {
- SET_PIXEL(pixel_buffer, i, y, color);
- }
- }
- void test_draw_vertical_pixel_line(
- Pixel_Buffer *pixel_buffer,
- GUI_Color color,
- int x, int y0, int y1)
- {
- for(int i = y0; i < y1; i++)
- {
- SET_PIXEL(pixel_buffer, x, i, color);
- }
- }
- // NOTE(Zelaven): Based on the technique and code for drawing circles
- // showcased by Casey here:
- // https://www.computerenhance.com/p/efficient-dda-circle-outlines
- void gui_draw_rounded_rect(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command)
- {
- int roundedness = draw_command->roundedness;
- // NOTE(Zelaven): Roundedness is a function of width and height, whichever
- // is smaller.
- int width = draw_command->rectangle.x1 - draw_command->rectangle.x0;
- int height = draw_command->rectangle.y1 - draw_command->rectangle.y0;
- short r = 0;
- {
- int shortest_dimension = width < height ? width : height;
- r = (shortest_dimension * roundedness) / 200;
- }
-
- int Cx = draw_command->rectangle.x0+r;
- int Cy = draw_command->rectangle.y0+r;
- int R = r;
- int R2, X, Y, dY, dX, D;
- // TODO(Zelaven): Remove this static limit.
- assert(R < 500);
- // NOTE(Zelaven): Both of these are used to cache calculations.
- // NOTE(Zelaven): This one is also used to prevent redrawing the same pixels.
- int Y_to_X_map[500];
- int Y_to_X_map2[500];
- #if 0
- for(size_t i = 0; i < ARRAYLENGTH(Y_to_X_map); i++)
- {
- Y_to_X_map[i] = -1;
- Y_to_X_map2[i] = -1;
- }
- #endif
- //printf("\n\n");
- R2 = R+R;
- Y = R; X = 0;
- dX = -2;
- dY = R2+R2 - 4;
- D = R2 - 1;
-
- while(X <= Y)
- {
- //printf("X=%d, Y=%d\n", X, Y);
- //setPixel(Cx - X, Cy - Y);
- Y_to_X_map[Y] = X;
- //setPixel(Cx - X, Cy + Y);
- //setPixel(Cx + X, Cy - Y);
- //setPixel(Cx + X, Cy + Y);
- //setPixel(Cx - Y, Cy - X);
- Y_to_X_map2[X] = Y;
- //setPixel(Cx - Y, Cy + X);
- //setPixel(Cx + Y, Cy - X);
- //setPixel(Cx + Y, Cy + X);
-
- D += dX;
- dX -= 4;
- ++X;
-
- // NOTE(casey): Branchless version
- int Mask = (D >> 31);
- D += dY & Mask;
- dY -= 4 & Mask;
- Y += Mask;
- }
- //SET_PIXEL(pixel_buffer, draw_command->rectangle.x0, draw_command->rectangle.y0, draw_command->border_color);
- //SET_PIXEL(pixel_buffer, draw_command->rectangle.x1-1, draw_command->rectangle.y1-1, draw_command->border_color);
-
- // top.
- int top_y0 = Cy - R;
- int top_y1 = Cy - Y;
- //int top_height = top_y1 - top_y0;
- for(int y = top_y0; y < top_y1; y++)
- {
- int Y_ = Cy - y;
- int X_ = Y_to_X_map[Y_];
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(
- pixel_buffer,
- Cx - X_, draw_command->rectangle.x1 - R + X_, y,
- draw_command->color);
- }
-
- // lower.
- int lower_y0 = Cy - Y;
- int lower_y1 = Cy;
- //int lower_height = lower_y1 - lower_y0;
- //printf("lower: %d to %d\n", lower_y0, lower_y1);
- for(int y = lower_y0; y < lower_y1; y++)
- {
- int Y_ = Cy - y;
- int X_ = Y_to_X_map2[Y_];
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(
- pixel_buffer,
- Cx - X_, draw_command->rectangle.x1 - R + X_, y,
- draw_command->color);
- }
-
- // middle.
- GUI_Rectangle middle = draw_command->rectangle;
- middle.y0 = middle.y0 + r;
- middle.y1 -= r;
- draw_rect3(pixel_buffer, middle, draw_command->color);
- int middle_height = middle.y1-middle.y0;
- int Cy1 = Cy + middle_height - 1;
-
- // lower.
- lower_y0 = Cy1 +1;
- lower_y1 = Cy1 + Y +1;
- //printf("lower: %d = %d = %d - %d\n", lower_height, lower_y1 - lower_y0, lower_y1, lower_y0);
- for(int y = lower_y0; y < lower_y1; y++)
- {
- int Y_ = y - Cy1;
- int X_ = Y_to_X_map2[Y_];
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(
- pixel_buffer,
- Cx - X_, draw_command->rectangle.x1 - R + X_, y,
- draw_command->color);
- }
-
- // top.
- top_y0 = Cy1 + Y +1;
- top_y1 = Cy1 + R +1;
- //printf("top: %d = %d = %d - %d\n", top_height, top_y1 - top_y0, top_y1, top_y0);
- for(int y = top_y0; y < top_y1; y++)
- {
- int Y_ = y - Cy1;
- int X_ = Y_to_X_map[Y_];
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(
- pixel_buffer,
- Cx - X_, draw_command->rectangle.x1 - R + X_, y,
- draw_command->color);
- }
- }
- void gui_draw_rounded_rect_with_border(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command)
- {
- int width = draw_command->rectangle.x1 - draw_command->rectangle.x0;
- int height = draw_command->rectangle.y1 - draw_command->rectangle.y0;
- int roundedness = draw_command->roundedness;
- int border_thickness = draw_command->border_thickness;
- if(border_thickness > (height+1)/2) border_thickness = (height+1)/2;
- //printf("\n\n");
- //printf("border_thickness: %d\n", border_thickness);
- // NOTE(Zelaven): Roundedness is a function of width and height, whichever
- // is smaller.
- short r = 0;
- {
- int shortest_dimension = width < height ? width : height;
- r = (shortest_dimension * roundedness) / 200;
- }
-
- int Cx = draw_command->rectangle.x0+r;
- int Cy = draw_command->rectangle.y0+r;
- int R = r;
- int R2, X, Y, dY, dX, D;
- // TODO(Zelaven): Remove this static limit.
- assert(R < 500);
- // NOTE(Zelaven): Both of these are used to cache calculations.
- // NOTE(Zelaven): This one is also used to prevent redrawing the same pixels.
- int Y_to_X_map[500];
- int Y_to_X_map2[500];
- #if 1
- for(size_t i = 0; i < ARRAYLENGTH(Y_to_X_map); i++)
- {
- Y_to_X_map[i] = -1;
- Y_to_X_map2[i] = -1;
- }
- #endif
- {
- //printf("\n\n");
- R2 = R+R;
- Y = R; X = 0;
- dX = -2;
- dY = R2+R2 - 4;
- D = R2 - 1;
-
- while(X <= Y)
- {
- //printf("X=%d, Y=%d\n", X, Y);
- //setPixel(Cx - X, Cy - Y);
- Y_to_X_map[Y] = X;
- //setPixel(Cx - X, Cy + Y);
- //setPixel(Cx + X, Cy - Y);
- //setPixel(Cx + X, Cy + Y);
- //setPixel(Cx - Y, Cy - X);
- Y_to_X_map2[X] = Y;
- //setPixel(Cx - Y, Cy + X);
- //setPixel(Cx + Y, Cy - X);
- //setPixel(Cx + Y, Cy + X);
- //if((Cx - X) == (Cx - Y) && (Cy - Y)==(Cy - X))
- // printf("SAMENESS: X: %d , Y: %d\n", X, Y);
-
- D += dX;
- dX -= 4;
- ++X;
-
- // NOTE(casey): Branchless version
- int Mask = (D >> 31);
- D += dY & Mask;
- dY -= 4 & Mask;
- Y += Mask;
- }
- }
- //printf("R: %d , X: %d , Y: %d\n", R, X, Y);
-
- // inner circle.
- int R_inner = r - border_thickness;
- int R2_inner, X_inner, Y_inner, dY_inner, dX_inner, D_inner;
- assert(R_inner < 500);
- // NOTE(Zelaven): Both of these are used to cache calculations.
- // NOTE(Zelaven): This one is also used to prevent redrawing the same pixels.
- int Y_to_X_map_inner[500];
- int Y_to_X_map2_inner[500];
- #if 1
- for(size_t i = 0; i < ARRAYLENGTH(Y_to_X_map_inner); i++)
- {
- Y_to_X_map_inner[i] = -1;
- Y_to_X_map2_inner[i] = -1;
- }
- #endif
- {
- //printf("\n\n");
- R2_inner = R_inner+R_inner;
- Y_inner = R_inner; X_inner = 0;
- dX_inner = -2;
- dY_inner = R2_inner+R2_inner - 4;
- D_inner = R2_inner - 1;
-
- while(X_inner <= Y_inner)
- {
- //printf("X_inner=%d, Y_inner=%d\n", X_inner, Y_inner);
- Y_to_X_map_inner[Y_inner] = X_inner;
- Y_to_X_map2_inner[X_inner] = Y_inner;
- //if((Cx - X_inner) == (Cx - Y_inner) && (Cy - Y_inner)==(Cy - X_inner))
- // printf("SAMENESS: X: %d , Y: %d\n", X_inner, Y_inner);
-
- D_inner += dX_inner;
- dX_inner -= 4;
- ++X_inner;
-
- // NOTE(casey): Branchless version
- int Mask = (D_inner >> 31);
- D_inner += dY_inner & Mask;
- dY_inner -= 4 & Mask;
- Y_inner += Mask;
- }
- }
- //printf("R_inner: %d , X_inner: %d , Y_inner: %d\n", R_inner, X_inner, Y_inner);
-
- // Drawing.
- int y_ = draw_command->rectangle.y0;
- int rect_x0 = draw_command->rectangle.x0;
- int rect_x1 = draw_command->rectangle.x1;
- int draw_guide_lines = 0;
- int border_y = y_ + border_thickness;
-
- #if 0
- - top1 : upper octant of outer, above inner.
- - top2 : upper octant of outer, upper octant of inner.
- - lower1: lower octant of outer, above inner.
- Happens when border is thicker than height of outer-upper-octant.
- - lower2: lower octant of outer, upper octant of inner.
- - lower3: lower octant of outer, lower octant of inner.
- #endif
-
- // top1.
- int top1_y0 = Cy-R;
- int top1_ycap = Cy-Y;
- //printf("%d %d\n", border_y, top1_ycap);
- int top1_y1 = top1_ycap < border_y ? top1_ycap : border_y;
- for(int top1_y = top1_y0; top1_y < top1_y1; top1_y++)
- {
- int Y_ = Cy - top1_y;
- int X_ = Y_to_X_map[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, top1_y);
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(
- pixel_buffer,
- Cx - X_, rect_x1 - R + X_, top1_y,
- draw_command->border_color);
- }
- if(draw_guide_lines)test_draw_horizontal_pixel_line(
- pixel_buffer,
- rect_x0, rect_x1, Cy - top1_ycap-1,
- 0x00ffffff);
-
- // top2.
- int top2_y0 = Cy-R_inner;
- int top2_y1 = Cy - Y;
- for(int top2_y = top2_y0; top2_y < top2_y1; top2_y++)
- {
- int Y_ = Cy - top2_y;
- int X_ = Y_to_X_map[Y_];
- int X_inn = Y_to_X_map_inner[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, top2_y);
- //printf("X_: %d , X_inn: %d\n", X_, X_inn);
- test_draw_horizontal_pixel_line(pixel_buffer,
- Cx - X_, Cx - X_inn, top2_y,
- draw_command->border_color);
- test_draw_horizontal_pixel_line(pixel_buffer,
- Cx - X_inn, rect_x1 - R + X_inn, top2_y,
- draw_command->color);
- test_draw_horizontal_pixel_line(pixel_buffer,
- rect_x1 - R + X_inn, rect_x1 - R + X_, top2_y,
- draw_command->border_color);
- }
- if(draw_guide_lines)test_draw_horizontal_pixel_line(
- pixel_buffer,
- rect_x0, rect_x1, top2_y1,
- 0x00ffffff);
-
- // lower1.
- int lower1_y0 = Cy - Y;
- int lower1_y1 = border_y;
- if(border_y > Cy) lower1_y1 = Cy;
- for(int lower1_y = lower1_y0; lower1_y < lower1_y1; lower1_y++)
- {
- int Y_ = Cy - lower1_y;
- int X_ = Y_to_X_map2[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, lower1_y);
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(pixel_buffer,
- Cx - X_, rect_x1 - R + X_, lower1_y,
- draw_command->border_color);
- }
- if(draw_guide_lines)test_draw_horizontal_pixel_line(
- pixel_buffer,
- draw_command->rectangle.x0, draw_command->rectangle.x1, lower1_y1,
- 0x00ffffff);
-
- // lower2.
- int lower2_y0 = Cy - Y;
- if(border_y > lower2_y0) lower2_y0 = border_y;
- if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
- int lower2_y1 = Cy - Y_inner;
- for(int lower2_y = lower2_y0; lower2_y < lower2_y1; lower2_y++)
- {
- int Y_ = Cy - lower2_y;
- int X_ = Y_to_X_map2[Y_];
- int X_inn = Y_to_X_map_inner[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, lower2_y);
- //printf("X_: %d , X_inn: %d\n", X_, X_inn);
- int x0 = Cx - X_; int x1 = Cx - X_inn;
- int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
- test_draw_horizontal_pixel_line(
- pixel_buffer, x0, x1, lower2_y,
- draw_command->border_color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x1, x2, lower2_y,
- draw_command->color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x2, x3, lower2_y,
- draw_command->border_color);
- }
- if(draw_guide_lines)test_draw_horizontal_pixel_line(
- pixel_buffer,
- draw_command->rectangle.x0, draw_command->rectangle.x1, lower2_y1,
- 0x00ffffff);
-
- // lower3.
- int lower3_y0 = Cy - Y_inner;
- int lower3_y1 = Cy;
- for(int lower3_y = lower3_y0; lower3_y < lower3_y1; lower3_y++)
- {
- int Y_ = Cy - lower3_y;
- int X_ = Y_to_X_map2[Y_];
- int X_inn = Y_to_X_map2_inner[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, lower3_y);
- //printf("X_: %d , X_inn: %d\n", X_, X_inn);
- int x0 = Cx - X_; int x1 = Cx - X_inn;
- int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
- test_draw_horizontal_pixel_line(
- pixel_buffer, x0, x1, lower3_y,
- draw_command->border_color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x1, x2, lower3_y,
- draw_command->color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x2, x3, lower3_y,
- draw_command->border_color);
- }
- if(draw_guide_lines)test_draw_horizontal_pixel_line(
- pixel_buffer,
- draw_command->rectangle.x0, draw_command->rectangle.x1, lower3_y1,
- 0x00ffffff);
-
-
- // Middle section.
- GUI_Rectangle middle = draw_command->rectangle;
- middle.y0 = middle.y0 + r;
- middle.y1 -= r;
- //printf("%d %d -> %d %d\n", draw_command->rectangle.y0, draw_command->rectangle.y1, middle.y0, middle.y1);
- int y = middle.y0;
- for(; y < middle.y0 + border_thickness-r; y++)
- {
- test_draw_horizontal_pixel_line(
- pixel_buffer, middle.x0, middle.x1, y,
- draw_command->border_color);
- }
- for(; y < middle.y1 - (border_thickness-r) && y < middle.y1; y++)
- {
- int x = middle.x0;
- for(; x < middle.x0+border_thickness && x < middle.x1; x++)
- {SET_PIXEL(pixel_buffer, x, y, draw_command->border_color);}
- for(; x < middle.x1-border_thickness; x++)
- {SET_PIXEL(pixel_buffer, x, y, draw_command->color);}
- for(; x < middle.x1; x++)
- {SET_PIXEL(pixel_buffer, x, y, draw_command->border_color);}
- }
- for(; y < middle.y1; y++)
- {
- test_draw_horizontal_pixel_line(
- pixel_buffer, middle.x0, middle.x1, y,
- draw_command->border_color);
- }
-
- int middle_height = middle.y1-middle.y0;
- int Cy1 = Cy + middle_height -1;
- border_y = draw_command->rectangle.y1 - border_thickness;
-
- //printf("middle_height: %d, Cy1: %d, border_y: %d\n", middle_height, Cy1, border_y);
-
- // top1.
- {
- int border_y = draw_command->rectangle.y1 - border_thickness;
- int top1_y1 = Cy1+R + 1;
- int top1_ycap = Cy1 + Y +1;
- //int top1_y0 = 1 + (border_y > top1_ycap ? border_y : top1_ycap);
- int top1_y0 = 0 + (border_y > top1_ycap ? border_y : top1_ycap);
- for(int top1_y = top1_y0; top1_y < top1_y1; top1_y++)
- {
- int Y_ = top1_y - Cy1;
- //printf("%d = %d + %d\n", Y_, Cy1, top1_y);
- int X_ = Y_to_X_map[Y_];
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(
- pixel_buffer,
- Cx - X_, rect_x1 - R + X_, top1_y,
- draw_command->border_color);
- }
-
- // top2.
- int top2_y0 = Cy1 + Y +1;
- int top2_y1 = Cy1+R_inner +1;
- //printf("top2: %d to %d\n", top2_y0, top2_y1);
- for(int top2_y = top2_y0; top2_y < top2_y1; top2_y++)
- {
- int Y_ = top2_y - Cy1;
- int X_ = Y_to_X_map[Y_];
- int X_inn = Y_to_X_map_inner[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, top2_y);
- //printf("X_: %d , X_inn: %d\n", X_, X_inn);
- test_draw_horizontal_pixel_line(pixel_buffer,
- Cx - X_, Cx - X_inn, top2_y,
- draw_command->border_color);
- test_draw_horizontal_pixel_line(pixel_buffer,
- Cx - X_inn, rect_x1 - R + X_inn, top2_y,
- draw_command->color);
- test_draw_horizontal_pixel_line(pixel_buffer,
- rect_x1 - R + X_inn, rect_x1 - R + X_, top2_y,
- draw_command->border_color);
- }
-
- // lower1.
- int lower1_y0 = border_y;
- int lower1_y1 = Cy1 + Y +1;
- if(border_y < (Cy1+1)) lower1_y0 = Cy1+1;
- for(int lower1_y = lower1_y0; lower1_y < lower1_y1; lower1_y++)
- {
- int Y_ = lower1_y - Cy1;
- int X_ = Y_to_X_map2[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, lower1_y);
- //printf("X_: %d\n", X_);
- test_draw_horizontal_pixel_line(pixel_buffer,
- Cx - X_, rect_x1 - R + X_, lower1_y,
- draw_command->border_color);
- }
-
- // lower2.
- if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
- int lower2_y0 = Cy1 + Y_inner +1;
- int lower2_y1 = Cy1 + Y +1;
- if(border_y < lower2_y1) lower2_y1 = border_y;
- for(int lower2_y = lower2_y0; lower2_y < lower2_y1; lower2_y++)
- {
- int Y_ = lower2_y - Cy1;
- int X_ = Y_to_X_map2[Y_];
- int X_inn = Y_to_X_map_inner[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, lower2_y);
- //printf("X_: %d , X_inn: %d\n", X_, X_inn);
- int x0 = Cx - X_; int x1 = Cx - X_inn;
- int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
- test_draw_horizontal_pixel_line(
- pixel_buffer, x0, x1, lower2_y,
- draw_command->border_color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x1, x2, lower2_y,
- draw_command->color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x2, x3, lower2_y,
- draw_command->border_color);
- }
-
- // lower3.
- int lower3_y0 = Cy1 +1;
- int lower3_y1 = Cy1 + Y_inner+1;
- for(int lower3_y = lower3_y0; lower3_y < lower3_y1; lower3_y++)
- {
- int Y_ = lower3_y - Cy1;
- int X_ = Y_to_X_map2[Y_];
- int X_inn = Y_to_X_map2_inner[Y_];
- //printf("%d = %d - %d\n", Y_, Cy, lower3_y);
- //printf("X_: %d , X_inn: %d\n", X_, X_inn);
- int x0 = Cx - X_; int x1 = Cx - X_inn;
- int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
- test_draw_horizontal_pixel_line(
- pixel_buffer, x0, x1, lower3_y,
- draw_command->border_color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x1, x2, lower3_y,
- draw_command->color);
- test_draw_horizontal_pixel_line(
- pixel_buffer, x2, x3, lower3_y,
- draw_command->border_color);
- }
- }
- if(draw_guide_lines)test_draw_horizontal_pixel_line(
- pixel_buffer,
- rect_x0, rect_x1, Cy - top1_ycap-1,
- 0x00ffffff);
-
- // Debug.
- #if 0
- GUI_Color white = 0x00ffffff;
- {R2 = R+R;Y = R; X = 0;dX = -2;dY = R2+R2 - 4;D = R2 - 1;
- while(X <= Y){
- //setPixel(Cx - X, Cy - Y);
- //setPixel(Cx - X, Cy + Y + middle_height -1);
- SET_PIXEL(pixel_buffer, Cx-X, Cy-Y, white);
- SET_PIXEL(pixel_buffer, Cx-X, Cy+Y + middle_height -1, white);
- //setPixel(Cx + X, Cy - Y);
- //setPixel(Cx + X, Cy + Y);
- //setPixel(Cx - Y, Cy - X);
- //setPixel(Cx - Y, Cy + X + middle_height -1);
- SET_PIXEL(pixel_buffer, Cx-Y, Cy-X, white);
- SET_PIXEL(pixel_buffer, Cx-Y, Cy+X + middle_height -1, white);
- //setPixel(Cx + Y, Cy - X);
- //setPixel(Cx + Y, Cy + X);
- D += dX;dX -= 4;++X;
- int Mask = (D >> 31);D += dY & Mask;dY -= 4 & Mask;Y += Mask;}}
- {R2_inner = R_inner+R_inner;Y_inner = R_inner; X_inner = 0;dX_inner = -2;dY_inner = R2_inner+R2_inner - 4;D_inner = R2_inner - 1;
- while(X_inner <= Y_inner){
- //setPixel(Cx - X_inner, Cy - Y_inner);
- //setPixel(Cx - X_inner, Cy + Y_inner + middle_height-1);
- SET_PIXEL(pixel_buffer, Cx-X_inner, Cy-Y_inner, white);
- SET_PIXEL(pixel_buffer, Cx-X_inner, Cy+Y_inner + middle_height-1, white);
- //setPixel(Cx + X_inner, Cy - Y_inner);
- //setPixel(Cx + X_inner, Cy + Y_inner);
- //setPixel(Cx - Y_inner, Cy - X_inner);
- //setPixel(Cx - Y_inner, Cy + X_inner + middle_height-1);
- SET_PIXEL(pixel_buffer, Cx-Y_inner, Cy-X_inner, white);
- SET_PIXEL(pixel_buffer, Cx-Y_inner, Cy+X_inner + middle_height-1, white);
- //setPixel(Cx + Y_inner, Cy - X_inner);
- //setPixel(Cx + Y_inner, Cy + X_inner);
- D_inner += dX_inner;dX_inner -= 4;++X_inner;
- int Mask = (D_inner >> 31);D_inner += dY_inner & Mask;dY_inner -= 4 & Mask;Y_inner += Mask;}}
-
- {
- printf("%%%%%%%%%%%%%%%%%%%%\n");
- GUI_Color red = 0x00ff4444;
- GUI_Color cyan = 0x0000ffff;
- GUI_Color yellow = 0x00ffff00;
- int x_ = draw_command->rectangle.x0 + R;
- int y_ = draw_command->rectangle.y0;
-
- int Y_ = Y + 1;
-
- printf("rect corner: x: %d, y: %d\n", x_ -R, y_);
- printf("R: %d, R_inner: %d, Cx: %d, Cy: %d\n", R, R_inner, Cx, Cy);
- printf("Y: %d, Y_: %d, Y_inner: %d\n", Y, Y_, Y_inner);
-
- SET_PIXEL(pixel_buffer, Cx, Cy, white);
-
- if(0)test_draw_horizontal_pixel_line(
- pixel_buffer, draw_command->rectangle.x0, draw_command->rectangle.x1,
- Cy-Y,
- 0x00ffffff);
- int top1_height, top2_height, lower1_height, lower2_height, lower3_height;
- {
- // top1.
- int border_y = y_ + border_thickness;
- int top1_y0 = Cy-R;
- int top1_y = Cy-Y;
- //printf("%d %d\n", border_y, top1_y);
- int top1_y1 = top1_y < border_y ? top1_y : border_y;
- top1_height = top1_y1 - top1_y0; //debug.
- test_draw_vertical_pixel_line(pixel_buffer, cyan,
- x_, top1_y0, top1_y1);
-
- // top2.
- int top2_y0 = Cy-R_inner;
- int top2_y1 = Cy - Y;
- top2_height = top2_y1 - top2_y0; // debug.
- test_draw_vertical_pixel_line(pixel_buffer, red,
- x_+1, top2_y0, top2_y1);
-
- // lower1.
- int lower1_y0 = Cy - Y;
- int lower1_y1 = border_y;
- if(border_y > Cy) lower1_y1 = Cy;
- lower1_height = lower1_y1 - lower1_y0; //debug.
- test_draw_vertical_pixel_line(pixel_buffer, yellow,
- x_+2, lower1_y0, lower1_y1);
-
- // lower2.
- int lower2_y0 = Cy - Y;
- if(border_y > lower2_y0) lower2_y0 = border_y;
- if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
- int lower2_y1 = Cy - Y_inner;
- lower2_height = lower2_y1 - lower2_y0; //debug.
- //printf("lower2: %d %d\n", lower2_y0, lower2_y1);
- test_draw_vertical_pixel_line(pixel_buffer, red,
- x_+3, lower2_y0, lower2_y1);
-
- // lower3.
- int lower3_y0 = Cy - Y_inner;
- int lower3_y1 = Cy;
- lower3_height = lower3_y1 - lower3_y0; //debug.
- test_draw_vertical_pixel_line(pixel_buffer, cyan,
- x_+4, lower3_y0, lower3_y1);
- }
-
-
- if(0)test_draw_horizontal_pixel_line(
- pixel_buffer, draw_command->rectangle.x0, draw_command->rectangle.x1,
- Cy1+Y,
- 0x00ffffff);
- {
- int Cy1 = Cy + middle_height -1;
- printf("Cy1: %d\n", Cy1);
- SET_PIXEL(pixel_buffer, Cx, Cy1, white);
- // top1.
- int border_y = draw_command->rectangle.y1 - border_thickness;
- int top1_y1 = Cy1+R+1;
- int top1_ycap = Cy1 + Y +1;
- //int top1_y0 = 1 + (border_y > top1_ycap ? border_y : top1_ycap);
- int top1_y0 = 0 + (border_y > top1_ycap ? border_y : top1_ycap);
- //printf("%d %d\n", border_y, top1_y);
- if((top1_y1 - top1_y0) != top1_height) printf("top1 height error.\n");
- test_draw_vertical_pixel_line(pixel_buffer, cyan,
- x_, top1_y0, top1_y1);
-
- // top2.
- int top2_y0 = Cy1 + Y +1;
- int top2_y1 = Cy1+R_inner+1;
- if((top2_y1 - top2_y0) != top2_height) printf("top2 height error.\n");
- test_draw_vertical_pixel_line(pixel_buffer, red,
- x_+1, top2_y0, top2_y1);
-
- // lower1.
- int lower1_y0 = border_y;
- int lower1_y1 = Cy1 + Y +1;
- if(border_y < (Cy1+1)) lower1_y0 = Cy1+1;
- if((lower1_y1 - lower1_y0) != lower1_height) printf("lower1 height error.\n");
- test_draw_vertical_pixel_line(pixel_buffer, yellow,
- x_+2, lower1_y0, lower1_y1);
-
- // lower2.
- if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
- int lower2_y0 = Cy1 + Y_inner +1;
- int lower2_y1 = Cy1 + Y +1;
- if(border_y < lower2_y1) lower2_y1 = border_y;
- //printf("lower2: %d %d\n", lower2_y0, lower2_y1);
- if((lower2_y1 - lower2_y0) != lower2_height) printf("lower2 height error.\n");
- test_draw_vertical_pixel_line(pixel_buffer, red,
- x_+3, lower2_y0, lower2_y1);
-
- // lower3.
- int lower3_y0 = Cy1 +1;
- int lower3_y1 = Cy1 + Y_inner+1;
- if((lower3_y1 - lower3_y0) != lower3_height) printf("lower3 height error.\n");
- test_draw_vertical_pixel_line(pixel_buffer, cyan,
- x_+4, lower3_y0, lower3_y1);
- }
-
-
- test_draw_vertical_pixel_line(pixel_buffer, cyan,
- draw_command->rectangle.x0+80, y_, y_+border_thickness);
- test_draw_vertical_pixel_line(pixel_buffer, red,
- draw_command->rectangle.x0+90, y_, y_+height);
- }
- #endif
- }
-
- void gui_draw_rect(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command)
- {
- if(draw_command->roundedness == 0)
- {
- // TODO(Zelaven) Don't double-draw on the space covered by the inner
- // rectangle.
- draw_rect3(
- pixel_buffer, draw_command->rectangle, draw_command->border_color);
- GUI_Rectangle inner = draw_command->rectangle;
- inner.x0 += draw_command->border_thickness;
- inner.y0 += draw_command->border_thickness;
- inner.x1 -= draw_command->border_thickness;
- inner.y1 -= draw_command->border_thickness;
- if(inner.x0 < inner.x1 && inner.y0 < inner.y1)
- {
- draw_rect3(pixel_buffer, inner, draw_command->color);
- }
- }
- else
- {
- if(draw_command->border_thickness == 0)
- {
- gui_draw_rounded_rect(pixel_buffer, draw_command);
- }
- else
- {
- gui_draw_rounded_rect_with_border(pixel_buffer, draw_command);
- }
- }
- }
-
-
- int init_x11(
- X11_Window *xwindow)
- {
- xwindow->display = XOpenDisplay(NULL);
- if(xwindow->display == NULL)
- {
- return EXIT_FAILURE;
- }
-
- xwindow->root = DefaultRootWindow(xwindow->display);
- xwindow->screen = XDefaultScreen(xwindow->display);
- xwindow->visual = XDefaultVisual(xwindow->display, xwindow->screen);
- xwindow->colormap = XCreateColormap(
- xwindow->display, xwindow->root, xwindow->visual, AllocNone);
- xwindow->set_window_attributes.colormap = xwindow->colormap;
- xwindow->set_window_attributes.event_mask =
- StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask |
- ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
- Button1MotionMask | Button3MotionMask |
- Button4MotionMask | Button5MotionMask |
- PointerMotionMask | KeymapStateMask | EnterWindowMask | LeaveWindowMask;
- xwindow->window = XCreateWindow(
- xwindow->display, xwindow->root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
- XDefaultDepth(xwindow->display, xwindow->screen), InputOutput,
- xwindow->visual, CWEventMask | CWColormap, &xwindow->set_window_attributes);
-
- #if 0
- XSelectInput(
- xwindow->display,
- xwindow->window,
- StructureNotifyMask | KeyPressMask | KeyReleaseMask |
- ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
- #endif
-
- XStoreName(xwindow->display, xwindow->window, "X11 Test Program");
- XMapWindow(xwindow->display, xwindow->window);
- XGetWindowAttributes(
- xwindow->display, xwindow->window, &xwindow->window_attributes);
- xwindow->width = (unsigned int)xwindow->window_attributes.width;
- xwindow->height = (unsigned int)xwindow->window_attributes.height;
-
- #if 0
- printf("Initial window dimensions: %u x %u\n", xwindow->width, xwindow->height);
- printf("Window depth: %d\n", xwindow->window_attributes.depth);
- printf("ALL Event mask: %lx\n", xwindow->window_attributes.all_event_masks);
- print_binary_long(xwindow->window_attributes.all_event_masks); printf("\n");
- printf("YOUR Event mask: %lx\n", xwindow->window_attributes.your_event_mask);
- print_binary_long(xwindow->window_attributes.your_event_mask); printf("\n");
- #endif
-
- // TODO: This is an experiment.
- #if 0
- {
- int display_width = XDisplayWidth(xwindow->display, xwindow->screen);
- int display_height = XDisplayHeight(xwindow->display, xwindow->screen);
- int display_width_mm = XDisplayWidthMM(xwindow->display, xwindow->screen);
- int display_height_mm = XDisplayHeightMM(xwindow->display, xwindow->screen);
- printf("Display Resolution: %d, %d.\n", display_width, display_height);
- printf("Display Size: %d, %d.\n", display_width_mm, display_height_mm);
- printf("Display DPmm: %d, %d.\n",
- display_width / display_width_mm,
- display_height / display_height_mm);
- printf("Display DPI: %d, %d.\n",
- display_width / ((display_width_mm*10)/254),
- display_height / ((display_height_mm*10)/254));
-
- Screen *screen = XScreenOfDisplay(xwindow->display, xwindow->screen);
- int screen_width = XWidthOfScreen(screen);
- int screen_height = XHeightOfScreen(screen);
- int screen_width_mm = XWidthMMOfScreen(screen);
- int screen_height_mm = XHeightMMOfScreen(screen);
- printf("Screen Resolution: %d, %d.\n", screen_width, screen_height);
- printf("Screen Size: %d, %d.\n", screen_width_mm, screen_height_mm);
- printf("Screen DPmm: %d, %d.\n",
- screen_width / screen_width_mm,
- screen_height / screen_height_mm);
- printf("Screen DPI: %d, %d.\n",
- screen_width / ((screen_width_mm*10)/254),
- screen_height / ((screen_height_mm*10)/254));
- }
- #endif
- // .
-
-
- #if 0
- XSelectInput(
- xwindow->display,
- xwindow->window,
- StructureNotifyMask | KeyPressMask | KeyReleaseMask |
- ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
- #endif
-
-
-
- // Discard everything preceding the MapNotify event that tells us that we
- // have been properly mapped.
- // This requires StructureNotifyMask to be selected.
- // https://tronche.com/gui/x/xlib-tutorial/2nd-program-anatomy.html
- {
- XEvent e;
- e.type = 0;
- assert(MapNotify != 0);
- while(e.type != MapNotify)
- {
- XNextEvent(xwindow->display, &e);
- }
- }
-
- // Re-get in case the window manager decides to instantiate the window with a
- // different size than the one we ask for.
- XGetWindowAttributes(
- xwindow->display, xwindow->window, &xwindow->window_attributes);
- xwindow->width = (unsigned int)xwindow->window_attributes.width;
- xwindow->height = (unsigned int)xwindow->window_attributes.height;
-
- #if 0
- printf("Window dimensions: %u x %u\n", xwindow->width, xwindow->height);
- printf("Window depth: %d\n", xwindow->window_attributes.depth);
- printf("ALL Event mask: %lx\n", xwindow->window_attributes.all_event_masks);
- print_binary_long(xwindow->window_attributes.all_event_masks); printf("\n");
- printf("YOUR Event mask: %lx\n", xwindow->window_attributes.your_event_mask);
- print_binary_long(xwindow->window_attributes.your_event_mask); printf("\n");
- #endif
-
- uint32_t *pixels = malloc(sizeof(*pixels) * xwindow->width * xwindow->height);
- assert(pixels != NULL);
-
-
- xwindow->graphics_context = XDefaultGC(xwindow->display, xwindow->screen);
- XSetForeground(xwindow->display, xwindow->graphics_context, 0x123456);
-
-
-
-
- XImage *screen_image = XCreateImage(
- xwindow->display,
- xwindow->visual,
- XDefaultDepth(xwindow->display, xwindow->screen),
- // NOTE(Zelaven): I can't find an explanation to what this actually is
- // anywhere. All the documentation I can find just assumes that you
- // magically know.
- ZPixmap,
- 0,
- (char*)pixels,
- xwindow->width, xwindow->height,
- 8, // NOTE(Zelaven): No clue
- // NOTE(Zelaven): This is how many bytes there are in a row of pixels.
- xwindow->width * sizeof(uint32_t));
- assert(screen_image != NULL);
- xwindow->pixel_buffer = (Pixel_Buffer){
- .pixels = (GUI_Color*)pixels,
- .width = xwindow->width,
- .height = xwindow->height,
- };
-
- xwindow->screen_image = screen_image;
- return EXIT_SUCCESS;
- }
-
-
-
-
- // ---
- // ---
- // ---
-
-
-
- void init_node_freelist(GUI_Node *nodes, int node_count)
- {
- // NOTE(Zelaven): We special-case the last node.
- for(int i = 0; i < node_count -1; i++)
- {
- nodes[i] = (GUI_Node){0};
- nodes[i].rdic_node = (RDIC_Node){
- .sibling = &((nodes+i+1)->rdic_node),
- };
- }
- nodes[node_count-1].rdic_node = (RDIC_Node){0};
- }
- void init_subtree_freelist(GUI_Subtree *nodes, int subtree_count)
- {
- // NOTE(Zelaven): We special-case the last node.
- for(int i = 0; i < subtree_count -1; i++)
- {
- nodes[i] = (GUI_Subtree){0};
- nodes[i].rdic_node = (RDIC_Node){
- .sibling = &((nodes+i+1)->rdic_node),
- };
- }
- nodes[subtree_count-1].rdic_node = (RDIC_Node){0};
- }
-
- GUI_Node g_gui_node_freelist[128];
- GUI_Subtree g_gui_subtree_freelist[16];
-
-
-
- #include "size_of_file.c"
-
- struct File_Read_Result {
- unsigned char *data;
- size_t size;
- } read_file__cruddy(
- FILE *file)
- {
- struct File_Read_Result retval = {0};
- size_t status = 0;
- long filesize = size_of_file(file);
- if(filesize == -1) {
- status = 1;}
- if(status == 0) {
- size_t memory_size = filesize;
- memory_size = ((memory_size + 4096 - 1) / 4096) * 4096;
- void *file_memory = mmap(
- NULL, memory_size,
- PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if(file_memory == (void*)-1) {
- //perror("mmap");
- status = 2;
- }
- else
- {
- retval.data = file_memory;
- }
- }
- if(status == 0) {
- if(fread(retval.data, filesize, 1, file) != 1) {
- status = 3;}
- }
-
- if(status == 0) {
- retval.size = (size_t)filesize;}
- else {
- if(retval.data != NULL) {
- free(retval.data);
- retval.data = NULL;}
- retval.size = status;
- }
-
- return retval;
- }
-
-
- void copy_from_atlas(
- Pixel_Buffer *pixel_buffer,
- int off_x, int off_y,
- int x, int y, int w, int h)
- {
- draw_rect(
- pixel_buffer->pixels,
- pixel_buffer->width,
- pixel_buffer->height,
- off_x, off_y, off_x+w, off_y+h,
- 0x00ffffff);
- for(int j=0; j < h; ++j) {
- for(int i=0; i < w; ++i)
- {
- int atlas_x = x + i;
- int atlas_y = y + j;
- int atlas_index = atlas_y * g_font_bitmap_width + atlas_x;
- unsigned char atlas_shade = g_font_bitmap[atlas_index];
- int color = (atlas_shade << 16) | (atlas_shade << 8) | atlas_shade;
- //printf("%d ", color);
- SET_PIXEL(pixel_buffer, x+off_x+i, y+off_y+j, color);
- }
- }
- //printf("\n");
- }
-
- void blend_glyph(
- Pixel_Buffer *pixel_buffer,
- stbtt_bakedchar *bakedchar,
- int x,
- int y)
- {
- int glyph_height = bakedchar->y1 - bakedchar->y0;
- int glyph_width = bakedchar->x1 - bakedchar->x0;
- //printf("%d, %d - %d, %d\n", x, y, glyph_width, glyph_height);
-
- if(0)draw_rect(
- pixel_buffer->pixels,
- pixel_buffer->width,
- pixel_buffer->height,
- x, y, x+glyph_width, y+glyph_height,
- 0x00ffffff);
-
- for(int j=0; j < glyph_height; ++j) {
- for(int i=0; i < glyph_width; ++i)
- {
- //unsigned char font_pixel_shade = glyph_bitmap[j*glyph_size.w+i];
- int atlas_x = bakedchar->x0 + i;
- int atlas_y = bakedchar->y0 + j;
- int atlas_index = atlas_y * g_font_bitmap_width + atlas_x;
- GUI_Color atlas_shade = (GUI_Color)g_font_bitmap[atlas_index];
- //GUI_Color color = (atlas_shade << 16) | (atlas_shade << 8) | atlas_shade;
- //GUI_Color color = atlas_shade;
- GUI_Color pixel_color = GET_PIXEL(pixel_buffer, x+i, y+j);
- //GUI_Color pixel_color = 0x00aa764a;
- int red = ((pixel_color & 0x00ff0000) >> 16) * (256-atlas_shade) / 256;
- int green = ((pixel_color & 0x0000ff00) >> 8) * (256-atlas_shade) / 256;
- int blue = ((pixel_color & 0x000000ff)) * (256-atlas_shade) / 256;
- GUI_Color new_color = (red << 16) | (green << 8) | blue;
- //GUI_Color new_color = pixel_color * (255-color) / 255;
- //GUI_Color new_color = (atlas_shade << 16) | (atlas_shade << 8) | atlas_shade;
- //printf("%x %x %x\n", color, pixel_color, new_color);
- SET_PIXEL(pixel_buffer, x+i, y+j, new_color);
- //*pixel_color = *pixel_color * (255-font_pixel_shade) / 255;
- //*pixel_color = font_pixel_shade;
- }
- }
- //printf("\n");
- }
-
- int text_measure_string_width(char *string, size_t str_length)
- {
- int result = 0;
- for(size_t i = 0; i < str_length; i++)
- {
- int glyph_index = string[i] - 32;
- stbtt_bakedchar *glyph = &g_baked_font[glyph_index];
- result += glyph->xadvance;
- }
-
- return result;
- }
-
- #include <limits.h>
- struct Text_Y_Bounds {int upper; int lower;}
- text_measure_string_y_bounds(char *string, size_t str_length)
- {
- struct Text_Y_Bounds result = {.upper = INT_MAX, .lower = INT_MIN};
- for(size_t i = 0; i < str_length; i++)
- {
- int glyph_index = string[i] - 32;
- stbtt_bakedchar *glyph = &g_baked_font[glyph_index];
- int height = glyph->y1 - glyph->y0;
- int offset = glyph->yoff; // This is negative.
- int uppermost_pixel = offset;
- int lowermost_pixel = height + offset;
- //print_bakedchar(string[i], glyph);
- if(uppermost_pixel < result.upper) {
- result.upper = uppermost_pixel;
- }
- if(lowermost_pixel > result.lower) {
- result.lower = lowermost_pixel;
- }
- }
-
- return result;
- }
-
- void blend_string(
- Pixel_Buffer *pixel_buffer,
- GUI_String text,
- int x, int y)
- {
- int next_x = x;
- for(int i = 0; i < text.length; i++)
- {
- int glyph_index = text.cstring[i] - 32;
- stbtt_bakedchar *g = &g_baked_font[glyph_index];
- blend_glyph(
- pixel_buffer,
- g,
- next_x + g->xoff, y + g->yoff);
- next_x += g->xadvance;
- }
- }
-
- void gui_draw_text(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command)
- {
- if(draw_command->text.cstring == NULL) {
- return;
- }
- //printf("%.*s: %d\n", draw_command->text.length, draw_command->text.cstring, draw_command->text.length);
- int text_width = text_measure_string_width(
- draw_command->text.cstring, draw_command->text.length);
- int width = draw_command->rectangle.x1 - draw_command->rectangle.x0;
- int x = draw_command->rectangle.x0 + width/2 - text_width/2;
-
- struct Text_Y_Bounds y_bounds = text_measure_string_y_bounds(
- draw_command->text.cstring, draw_command->text.length);
- int y_bounds_middle = (y_bounds.lower + y_bounds.upper)/2;
- int height = draw_command->rectangle.y1 - draw_command->rectangle.y0;
- int y = draw_command->rectangle.y0 + height/2 - y_bounds_middle;
- #if 0
- printf("%.*s: %d, (%d,%d) %d -> %d, %d\n",
- draw_command->text.length, draw_command->text.cstring,
- text_width, y_bounds.upper, y_bounds.lower, y_bounds_middle,
- x, y);
- #endif
- blend_string(
- pixel_buffer,
- draw_command->text,
- x, y);
- #if 0
- SET_PIXEL(pixel_buffer, x, draw_command->rectangle.y0 + height/2, 0x00ff0000);
- SET_PIXEL(pixel_buffer, draw_command->rectangle.x0 + width/2, draw_command->rectangle.y0 + height/2, 0x00ffff00);
- SET_PIXEL(pixel_buffer, x, y, 0x0000ff00);
- #endif
- }
-
-
- void gui_draw_image_direct(
- Pixel_Buffer *pixel_buffer,
- Pixel_Buffer *image,
- int off_x, int off_y)
- {
- if(image == NULL) {
- return;
- }
-
- int w = image->width;
- int h = image->height;
-
- for(int j=0; j < h; ++j)
- {
- for(int i=0; i < w; ++i)
- {
- int image_x = i;
- int image_y = j;
- int image_index = image_y * w + image_x;
- GUI_Color pixel = image->pixels[image_index];
- SET_PIXEL(pixel_buffer, off_x+i, off_y+j, pixel);
- }
- }
- }
-
- void gui_draw_image(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command)
- {
- if(draw_command->image == NULL) {
- return;
- }
-
- int off_x = draw_command->rectangle.x0;
- int off_y = draw_command->rectangle.y0;
- Pixel_Buffer *image = draw_command->image;
- int w = image->width;
- int h = image->height;
-
- for(int j=0; j < h; ++j)
- {
- for(int i=0; i < w; ++i)
- {
- int image_x = i;
- int image_y = j;
- int image_index = image_y * w + image_x;
- GUI_Color pixel = image->pixels[image_index];
- SET_PIXEL(pixel_buffer, off_x+i, off_y+j, pixel);
- }
- }
- }
-
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
- #define MAX(a,b) ((a) > (b) ? (a) : (b))
-
- void gui_draw_image_clipped(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command,
- GUI_Rectangle *cliprect)
- {
- if(draw_command->image == NULL) {
- return;
- }
-
- //int off_x = cliprect->x0;
- //int off_y = cliprect->y0;
- Pixel_Buffer *image = draw_command->image;
- int w = image->width;
- int clipwidth = cliprect->x1 - cliprect->x0;
- w = MIN(w, clipwidth);
- int h = image->height;
- int clipheight = cliprect->y1 - cliprect->y0;
- h = MIN(h, clipheight);
-
- int startx = cliprect->x0 - draw_command->rectangle.x0;
- startx = MAX(startx, 0);
- int starty = cliprect->y0 - draw_command->rectangle.y0;
- starty = MAX(starty, 0);
- int off_x = cliprect->x0 - startx;
- int off_y = cliprect->y0 - starty;
-
- for(int j=starty; j < h; ++j)
- {
- for(int i=startx; i < w; ++i)
- {
- int image_x = i;
- int image_y = j;
- int image_index = image_y * w + image_x;
- GUI_Color pixel = image->pixels[image_index];
- SET_PIXEL(pixel_buffer, off_x+i, off_y+j, pixel);
- }
- }
- }
-
- GUI_Rectangle gui_intersect_rectangles(
- GUI_Rectangle *r1,
- GUI_Rectangle *r2)
- {
- GUI_Rectangle r = {
- .x0 = MAX(r1->x0, r2->x0),
- .x1 = MIN(r1->x1, r2->x1),
- .y0 = MAX(r1->y0, r2->y0),
- .y1 = MIN(r1->y1, r2->y1),
- };
- return r;
-
- }
-
- void gui_draw_rect_clipped(
- Pixel_Buffer *pixel_buffer,
- GUI_Draw_Command *draw_command,
- GUI_Rectangle *clip)
- {
- if(clip->x0 <= draw_command->rectangle.x0
- && clip->y0 <= draw_command->rectangle.y0
- && clip->x1 <= draw_command->rectangle.x1
- && clip->y1 <= draw_command->rectangle.y1)
- {
- gui_draw_rect(pixel_buffer, draw_command);
- }
- else
- {
- if(draw_command->roundedness == 0)
- {
- GUI_Rectangle clipped_rect = gui_intersect_rectangles(
- clip,
- &draw_command->rectangle);
- // TODO(Zelaven) Don't double-draw on the space covered by the inner
- // rectangle.
- draw_rect3(
- pixel_buffer, clipped_rect, draw_command->border_color);
- GUI_Rectangle inner = clipped_rect;
- inner.x0 += draw_command->border_thickness;
- inner.y0 += draw_command->border_thickness;
- inner.x1 -= draw_command->border_thickness;
- inner.y1 -= draw_command->border_thickness;
- if(inner.x0 < inner.x1 && inner.y0 < inner.y1)
- {
- draw_rect3(pixel_buffer, inner, draw_command->color);
- }
- }
- else
- {
- assert(!"TODO");
- if(draw_command->border_thickness == 0)
- {
- gui_draw_rounded_rect(pixel_buffer, draw_command);
- }
- else
- {
- gui_draw_rounded_rect_with_border(pixel_buffer, draw_command);
- }
- }
- }
- }
-
- void gui_layout_and_draw_subtree(
- GUI_Context *context,
- GUI_Subtree *subtree,
- Pixel_Buffer *pixel_buffer)
- {
- //gui_layout_nodes((GUI_Node*)subtree->rdic.root);
- gui_layout_nodes(subtree);
- gui_generate_draw_commands(
- subtree,
- context->draw_command_arena,
- &context->num_draw_commands);
-
- GUI_Draw_Command *draw_commands =
- (GUI_Draw_Command*)(context->draw_command_arena->memory);
- GUI_Node_Reference clipnode = subtree->clipnode;
- if(rdic_node_reference_valid(clipnode.rdic_ref)) {
- GUI_Rectangle *cliprect = &clipnode.node->rect;
- for(int i = 0; i < context->num_draw_commands; i++)
- {
- GUI_Draw_Command *draw_command = draw_commands+i;
- gui_draw_rect_clipped(pixel_buffer, draw_command, cliprect);
- //gui_draw_image(pixel_buffer, draw_command);//, cliprect);
- gui_draw_image_clipped(pixel_buffer, draw_command, cliprect);
- gui_draw_text (pixel_buffer, draw_command);//, cliprect);
- }
- }
- else {
- for(int i = 0; i < context->num_draw_commands; i++)
- {
- GUI_Draw_Command *draw_command = draw_commands+i;
- gui_draw_rect (pixel_buffer, draw_command);
- gui_draw_image(pixel_buffer, draw_command);
- gui_draw_text (pixel_buffer, draw_command);
- }
- }
-
- // TODO NOTE(Zelaven): There may arise an issue where the subtrees won't
- // generate draw commands even if they are overdrawn by changes in a
- // parent subtree.
- GUI_Subtree *first_child = GUI_SUBTREE_FIRST_CHILD(subtree);
- if(first_child != NULL)
- {
- gui_layout_and_draw_subtree(context, first_child, pixel_buffer);
- }
- GUI_Subtree *sibling = GUI_SUBTREE_SIBLING(subtree);
- if(sibling != NULL)
- {
- gui_layout_and_draw_subtree(context, sibling, pixel_buffer);
- }
- }
-
- void gui_layout_and_draw(GUI_Context *context)
- {
- // 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];
- GUI_Subtree *subtree_root = (GUI_Subtree*)layer->subtree_rdic.root;
- if(subtree_root != NULL) {
- gui_layout_and_draw_subtree(
- context,
- subtree_root,
- layer->pixel_buffer);
- }
- }
- }
-
- 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.
- int main(void)
- {
- void (*gui)(GUI_Context *,GUI_Rectangle);
-
- // Font initialization.
- Memory_Arena font_arena = {0};
- assert(linux_allocate_arena_memory(
- &font_arena,
- g_font_bitmap_width*g_font_bitmap_height) == 0);
- FILE *font_file = fopen("michroma/Michroma-Regular.ttf", "r");
- //FILE *font_file = fopen("/usr/share/fonts/TTF/Roboto-Black.ttf", "r");
- struct File_Read_Result font_data = read_file__cruddy(font_file);
- // TODO(Zelaven): How much data do I have to make sure that I read at minimum?
- assert(font_data.size > 16);
- {
- int font_bitmap_size = g_font_bitmap_width * g_font_bitmap_height;
- g_font_bitmap = memory_arena_allocate(
- &font_arena, font_bitmap_size, _Alignof(char));
- int bake_font_return_value = stbtt_BakeFontBitmap(
- font_data.data, 0,
- 20.0,
- g_font_bitmap, g_font_bitmap_width, g_font_bitmap_height,
- 32, 96, g_baked_font);
-
- //printf("bake_font_return_value: %d\n", bake_font_return_value);
- if(bake_font_return_value < 1)
- {
- return EXIT_FAILURE;
- }
- }
-
-
-
- // GUI initializaiton.
-
- //gui = test_gui;
- //gui = test_gui__calculator;
- //gui = test_gui__scrollbars;
- //gui = test_gui__draw_command_using_sliders;
- gui = test_gui__subtree;
- //gui = test_gui__tmp;
-
- X11_Window xwindow = {0};
- int xinit_status = init_x11(&xwindow);
- if(xinit_status != EXIT_SUCCESS)
- {
- return EXIT_FAILURE;
- }
-
- Memory_Arena draw_command_arena = {0};
- assert(linux_allocate_arena_memory(
- &draw_command_arena,
- 1024*4) == 0);
-
- GUI_Context context = {0};
- #if 0
- init_node_freelist(g_gui_node_freelist, ARRAYLENGTH(g_gui_node_freelist));
- context.rdic.node_freelist = &g_gui_node_freelist[0].rdic_node;
- #else
- init_node_freelist(g_gui_node_freelist, ARRAYLENGTH(g_gui_node_freelist));
- RDIC_Freelist node_freelist = {&g_gui_node_freelist[0].rdic_node};
- context.node_freelist = &node_freelist;
- init_subtree_freelist(g_gui_subtree_freelist, ARRAYLENGTH(g_gui_subtree_freelist));
- 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*400*sizeof(GUI_Color)),
- .width = 300,
- .height = 400,
- };
- 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 = &background_pixel_buffer,
- };
- context.top_layer = (GUI_Layer){
- .subtree_rdic.freelist = &subtree_freelist,
- .pixel_buffer = &top_pixel_buffer,
- };
- #endif
-
- context.draw_command_arena = &draw_command_arena;
- context.num_draw_commands = 0;
-
- fill_pixel_buffer(
- xwindow.pixel_buffer.pixels,
- 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,
- };
-
- bool running = true;
- while(running)
- {
- usleep(2*100000);
- context.mouse_pressed = false;
- while(XPending(xwindow.display))
- {
- XEvent x_event = {0};
- XNextEvent(xwindow.display, &x_event);
- if(XFilterEvent(&x_event, xwindow.window))
- {
- continue;
- }
- switch(x_event.type)
- {
- case ButtonPress:
- {
- //printf("Button pressed: %d\n", x_event.xbutton.button);
- context.mouse_pressed = true;
- context.mouse_down = true;
- } break;
- case ButtonRelease:
- {
- //printf("Button released: %d\n", x_event.xbutton.button);
- context.mouse_down = false;
- } break;
- case MotionNotify:
- {
- //printf("Pointer motion: %d, %d\n", x_event.xmotion.x, x_event.xmotion.y);
- context.mouse_x = x_event.xmotion.x;
- context.mouse_y = x_event.xmotion.y;
- } break;
- case KeyPress:
- {
- KeySym keysym = XLookupKeysym(
- &x_event.xkey,
- 0); // What does 0 mean here?
- (void) keysym;
-
- //printf("Keysym pressed: %s\n", XKeysymToString(keysym));
- //printf("\tkeycode: %d\n", x_event.xkey.keycode);
- //printf("\tkeysym code: %ld\n", keysym);
- switch(x_event.xkey.keycode)
- {
- case 38: break; // a
- case 40: break; // d
- case 25: break; // w
- case 39: break; // s
- //case 24: running = false; break; // q
- case 24: // q
- {
- // Setting the flag here is necessary.
- running = false;
- // Can I just do this after the loop iteration finishes?
- XDestroyWindow(xwindow.display, xwindow.window);
- } break;
- }
-
- } break;
- case KeyRelease:
- {
- KeySym keysym = XLookupKeysym(
- &x_event.xkey,
- 0); // What does 0 mean here?
- (void) keysym;
-
- //printf("Keysym released: %s\n", XKeysymToString(keysym));
- switch(x_event.xkey.keycode)
- {
- case 38: break; // a
- case 40: break; // d
- case 25: break; // w
- case 39: break; // s
- }
-
- } break;
- case DestroyNotify:
- {
- running = false;
- } break;
- default:
- {
- //printf("Unknown event, type: %d\n", x_event.type);
- } break;
- }
- }
-
- static bool meh = true;
- if(running && meh)
- {
- gui(&context, screen_rectangle);
- if(0)print_node_tree(
- (GUI_Node*)((GUI_Subtree*)context.background_layer.subtree_rdic.root)->rdic.root, 1);
- if(0)print_subtree_tree((GUI_Subtree*)context.background_layer.subtree_rdic.root, 1, true);
- //gui_layout_nodes(&context);
- #if 1
- gui_layout_and_draw(&context);
- gui_compose_layers(&context, &xwindow.pixel_buffer);
- //SET_PIXEL(&xwindow.pixel_buffer, 200, 388, 0x00ff0000);
- #else
- for(
- GUI_Subtree *current = (GUI_Subtree*)context.background_layer.subtree_rdic.root;
- current != NULL;
- current = NULL)//current->next)
- {
- gui_layout_nodes((GUI_Node*)current->rdic.root);
- gui_generate_draw_commands(
- //(GUI_Node*)current->rdic.root,
- current,
- &draw_command_arena,
- &context.num_draw_commands);
-
- GUI_Draw_Command *draw_command =
- (GUI_Draw_Command*)(draw_command_arena.memory);
- for(int i = 0; i < context.num_draw_commands; i++)
- {
- #if 0
- if(i > 0)
- (draw_command+i)->roundedness = roundedness;
- #endif
- gui_draw_rect(
- &xwindow.pixel_buffer,
- draw_command+i);
- gui_draw_image(
- &xwindow.pixel_buffer,
- draw_command+i);
- gui_draw_text(
- &xwindow.pixel_buffer,
- draw_command+i);
- }
- }
- #elseif 0
- gui_generate_draw_commands(
- (GUI_Node*)context.first_subtree->rdic.root,
- &draw_command_arena,
- &context.num_draw_commands);
-
- GUI_Draw_Command *draw_command =
- (GUI_Draw_Command*)(draw_command_arena.memory);
- for(int i = 0; i < context.num_draw_commands; i++)
- {
- #if 0
- if(i > 0)
- (draw_command+i)->roundedness = roundedness;
- #endif
- gui_draw_rect(
- &xwindow.pixel_buffer,
- draw_command+i);
- gui_draw_text(
- &xwindow.pixel_buffer,
- draw_command+i);
- }
- #endif
- #if 0
- GUI_Draw_Command test_draw_command = {
- .rectangle = {50, 150, 250, 250},
- .color = 0x00aa8888,
- .border_color = 0x00ffaaff,
- .border_thickness = border_thickness,
- .roundedness = roundedness,
- };
- gui_draw_rounded_rect(&xwindow.pixel_buffer, &test_draw_command);
- GUI_Draw_Command test_draw_command2 = {
- .rectangle = {50, 300, 250, 400},
- .color = 0x00aa8888,
- .border_color = 0x00ffaaff,
- .border_thickness = border_thickness,
- .roundedness = roundedness,
- };
- gui_draw_rounded_rect_with_border(&xwindow.pixel_buffer, &test_draw_command2);
- //meh = false;
- #endif
- #if 0
- //print_bakedchar(32+1, &g_baked_font[1]);
- blend_glyph(
- &xwindow.pixel_buffer,
- &g_baked_font[1],
- 80, 170);
- blend_glyph(
- &xwindow.pixel_buffer,
- &g_baked_font[1],
- 80+g_baked_font[1].xadvance, 170);
- char *text = "This is a text! VA";
- int textlen = sizeof("This is a text! VA")-1;
- int text_width = text_measure_string_width(text, textlen);
- //printf("Text width: %d\n", text_width);
- int next_x = 80;
- test_draw_horizontal_pixel_line(
- &xwindow.pixel_buffer,
- next_x, next_x + text_width, 195,
- 0);
- for(int i = 0; i < textlen; i++)
- {
- int glyph_index = text[i] - 32;
- stbtt_bakedchar *g = &g_baked_font[glyph_index];
- blend_glyph(
- &xwindow.pixel_buffer,
- g,
- next_x + g->xoff, 195 + g->yoff);
- next_x += g->xadvance;
- }
- blend_string(
- &xwindow.pixel_buffer,
- //GUI_STRING("This is a text! VA"),
- GUI_STRING("a = 19 + 23; 1234567890C+-*/="),
- 360, 260);
- test_draw_horizontal_pixel_line(
- &xwindow.pixel_buffer,
- 360, 360+200, 260,
- 0x00ff0000);
- copy_from_atlas(
- &xwindow.pixel_buffer,
- 300, 100,
- 0, 0, 512, 100);
- //SET_PIXEL(&xwindow.pixel_buffer, 100, 100, 0x00ffffff);
- #endif
-
- draw_window(&xwindow);
- XFlush(xwindow.display);
- }
-
- }
-
- XDestroyImage(xwindow.screen_image);
- //XUnmapWindow(xwindow.display, xwindow.window);
- //XDestroyWindow(xwindow.display, xwindow.window);
- XFreeColormap(xwindow.display, xwindow.colormap);
- XCloseDisplay(xwindow.display);
-
-
- //getc(stdin);
- return 0;
- }
-
-
-
|