You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4181 lines
121 KiB

преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 11 месеца
преди 1 година
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 1 година
преди 11 месеца
преди 11 месеца
преди 1 година
преди 1 година
преди 1 година
преди 1 година
преди 11 месеца
преди 1 година
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <stdint.h>
  4. #include <assert.h>
  5. #define DEBUG(...) if(ENABLE_DEBUG) {printf(__VA_ARGS__);}
  6. #define ARRAYLENGTH(X) (sizeof(X)/sizeof((X)[0]))
  7. bool my_bool = true;
  8. int border_thickness = 0;
  9. float roundedness = 60;
  10. #include "stb_truetype.h"
  11. void print_bakedchar(char c, stbtt_bakedchar *b)
  12. {
  13. printf("%c: %d %d %d %d %.2g %.2g %.2g\n",
  14. c,
  15. b->x0, b->y0, b->x1, b->y1,
  16. b->xoff, b->yoff, b->xadvance);
  17. }
  18. stbtt_bakedchar g_baked_font[96];
  19. unsigned char *g_font_bitmap;
  20. int g_font_bitmap_width = 512;
  21. int g_font_bitmap_height = 512;
  22. // ---
  23. #define arena_allocate_TYPE(arena, TYPE) ((TYPE*)memory_arena_allocate(arena, sizeof(TYPE), _Alignof(TYPE)))
  24. #define arena_allocate_draw_command(arena) arena_allocate_TYPE(arena, GUI_Draw_Command)
  25. #include "memory_arena.c"
  26. #include "memory_arena_linux.c"
  27. // ---
  28. #define RDIC_IMPLEMENTATION
  29. #include "../rdic.h"
  30. typedef struct {
  31. // Top-left corner.
  32. int x0, y0;
  33. // Bottom-Right corner.
  34. int x1, y1;
  35. } GUI_Rectangle;
  36. // NOTE(Zelaven): I would have loved to do pascal strings here, but I could not
  37. // find any way to pass those as literals in a reasonable way.
  38. // I also use int instead of ssize_t or anything else because of the .*s format
  39. // specifier being an absolute pain.
  40. typedef struct {
  41. int length;
  42. char *cstring;
  43. } GUI_String;
  44. #define GUI_STRING(literal) (GUI_String){.length = sizeof(literal)-1, .cstring = literal}
  45. typedef uint32_t GUI_Color;
  46. typedef struct {
  47. GUI_Color *pixels;
  48. int width;
  49. int height;
  50. } Pixel_Buffer;
  51. // TODO(Zelaven): Add a generation to this that you can
  52. // increment so that the nodes that use a style can know
  53. // when up dirty themselves due to style change?
  54. typedef struct {
  55. // TODO(Zelaven): Replace these with GUI_Color.
  56. unsigned char red;
  57. unsigned char green;
  58. unsigned char blue;
  59. GUI_Color border_color;
  60. int border_thickness;
  61. unsigned char roundedness;
  62. } GUI_Style;
  63. static inline int point_in_rect(int x, int y, GUI_Rectangle rect)
  64. {
  65. return
  66. (x >= rect.x0)
  67. && (y >= rect.y0)
  68. && (x <= rect.x1)
  69. && (y <= rect.y1);
  70. }
  71. static inline int point_in_rect_with_offset(
  72. int x, int y,
  73. GUI_Rectangle rect,
  74. int x_offset, int y_offset)
  75. {
  76. return
  77. (x >= (rect.x0+x_offset))
  78. && (y >= (rect.y0+y_offset))
  79. && (x <= (rect.x1+x_offset))
  80. && (y <= (rect.y1+y_offset));
  81. }
  82. typedef enum {
  83. GUI_SIZERULE_PIXELS,
  84. GUI_SIZERULE_TEXTCONTENT,
  85. GUI_SIZERULE_PERCENTOFPARENT,
  86. GUI_SIZERULE_SUMOFCHILDREN,
  87. //GUI_SIZERULE_SHARES,
  88. } GUI_Size_Rule;
  89. typedef struct GUI_Size
  90. {
  91. GUI_Size_Rule size_rule;
  92. int value;
  93. int strictness;
  94. } GUI_Size;
  95. typedef enum GUI_Axis2
  96. {
  97. GUI_AXIS2_X,
  98. GUI_AXIS2_Y,
  99. GUI_AXIS2_COUNT,
  100. } GUI_Axis2;
  101. typedef enum {
  102. GUI_LAYOUT_NONE,
  103. GUI_LAYOUT_HORIZONTAL,
  104. GUI_LAYOUT_VERTICAL,
  105. } GUI_Layout_Direction;
  106. typedef struct GUI_Node {
  107. RDIC_Node rdic_node;
  108. GUI_Style *style;
  109. GUI_String text_string; // Optional.
  110. int text_width, text_height; // Optional. Initialized by lazy_init and cached.
  111. Pixel_Buffer *image;
  112. GUI_String debug_string;
  113. // NOTE(Zelaven): Useful for tab-navigation and other non-mouse navigation.
  114. GUI_Layout_Direction layout_direction;
  115. GUI_Size semantic_size[GUI_AXIS2_COUNT];
  116. // TODO(Zelaven): This needs a better name.
  117. // True iff. it (and its children) should generate draw commands.
  118. // TODO(Zelaven): Should I make it a flags field, which encodes dirty-reasons?
  119. // The "dirty test" would be "dirty != 0", and each bit in the field would be
  120. // a reason that other code can use to figure out why a node was dirtied.
  121. // Multiple reasons for a decision can all be checked in one go as well.
  122. bool dirty;
  123. // NOTE(Zelaven): Don't make decisions about visual things based on this.
  124. // It will be a frame off, and with dirty-redrawing it will result in the
  125. // error persisting on the screen.
  126. // All sizing and positioning should be done using semantic sizes and
  127. // offsets, and should be handled in offline layouting and positioning.
  128. int computed_size[GUI_AXIS2_COUNT];
  129. GUI_Rectangle rect; // NOTE(Zelaven): I have no better name for this.
  130. } GUI_Node;
  131. #define GUI_NODE_PARENT(node) ((GUI_Node*)(node)->rdic_node.parent)
  132. #define GUI_NODE_SIBLING(node) ((GUI_Node*)(node)->rdic_node.sibling)
  133. #define GUI_NODE_FIRST_CHILD(node) ((GUI_Node*)(node)->rdic_node.first_child)
  134. typedef union GUI_Node_Reference {
  135. RDIC_Node_Reference rdic_ref;
  136. struct {
  137. GUI_Node *node;
  138. unsigned int generation;
  139. };
  140. } GUI_Node_Reference;
  141. #if 0
  142. #define gui_node_references_equal(n, m) rdic_node_references_equal((n).rdic_ref,(m).rdic_ref)
  143. #else
  144. // NOTE(Zelaven): This was just for debugging with better debug messages.
  145. int gui_node_references_equal(GUI_Node_Reference n, GUI_Node_Reference m)
  146. {
  147. return rdic_node_references_equal(n.rdic_ref, m.rdic_ref);
  148. }
  149. #endif
  150. typedef struct {
  151. GUI_Rectangle rectangle;
  152. GUI_Color color;
  153. GUI_Color border_color;
  154. int border_thickness;
  155. unsigned char roundedness;
  156. GUI_String text;
  157. Pixel_Buffer *image;
  158. } GUI_Draw_Command;
  159. typedef struct GUI_Subtree GUI_Subtree;
  160. struct GUI_Subtree {
  161. // NOTE(Zelaven): We are maintaining an immediate interface of subtrees too.
  162. RDIC_Node rdic_node;
  163. RDIC_Context rdic;
  164. GUI_Node_Reference clipnode;
  165. GUI_Node_Reference relative_to;
  166. int flat_offset_x;
  167. int flat_offset_y;
  168. int offset_relative_node_percentage_x;
  169. int offset_relative_node_percentage_y;
  170. int offset_own_size_percentage_x;
  171. int offset_own_size_percentage_y;
  172. };
  173. #define GUI_SUBTREE_PARENT(node) ((GUI_Subtree*)(node)->rdic_node.parent)
  174. #define GUI_SUBTREE_SIBLING(node) ((GUI_Subtree*)(node)->rdic_node.sibling)
  175. #define GUI_SUBTREE_FIRST_CHILD(node) ((GUI_Subtree*)(node)->rdic_node.first_child)
  176. typedef union GUI_Subtree_Reference {
  177. RDIC_Node_Reference rdic_ref;
  178. struct {
  179. GUI_Subtree *node;
  180. unsigned int generation;
  181. };
  182. } GUI_Subtree_Reference;
  183. typedef struct {
  184. RDIC_Context subtree_rdic;
  185. //GUI_Subtree *first_subtree;
  186. //GUI_Subtree *last_subtree;
  187. //GUI_Subtree *current_subtree;
  188. GUI_Subtree_Reference root_subtree;
  189. GUI_Draw_Command *first_draw_command;
  190. int num_draw_commands;
  191. Pixel_Buffer *pixel_buffer;
  192. bool should_draw;
  193. // TODO(Zelaven): Offsets like for the subtrees.
  194. int offset_x;
  195. int offset_y;
  196. } GUI_Layer;
  197. typedef struct {
  198. //RDIC_Context rdic;
  199. //GUI_Subtree *first_subtree;
  200. //GUI_Subtree *last_subtree;
  201. //GUI_Subtree *current_subtree;
  202. GUI_Layer background_layer;
  203. GUI_Layer top_layer;
  204. GUI_Layer *current_layer;
  205. GUI_Node_Reference focused_node;
  206. GUI_Node_Reference hovered_node;
  207. GUI_Node_Reference top_node_under_cursor;
  208. int mouse_pressed;
  209. int mouse_down;
  210. int mouse_x;
  211. int mouse_y;
  212. // TODO: An allocator for the nodes.
  213. RDIC_Freelist *node_freelist;
  214. RDIC_Freelist *subtree_freelist;
  215. Memory_Arena *draw_command_arena;
  216. int num_draw_commands;
  217. } GUI_Context;
  218. // ---
  219. #if 1
  220. void print_node_tree(GUI_Node *node, int level)
  221. {
  222. for(int i = 0; i < level; i++) {
  223. printf("-");
  224. }
  225. GUI_String text = node->debug_string;
  226. printf(" %.*s", text.length, text.cstring);
  227. //printf(" (%p)", node);
  228. printf(" (Dirty?: %b)", node->dirty);
  229. printf("\n");
  230. GUI_Node *child = GUI_NODE_FIRST_CHILD(node);
  231. while(child != NULL) {
  232. print_node_tree(child, level+1);
  233. child = GUI_NODE_SIBLING(child);
  234. }
  235. }
  236. #endif
  237. #if 1
  238. void print_subtree_tree(GUI_Subtree *node, int level, bool print_nodes)
  239. {
  240. for(int i = 0; i < level; i++) {
  241. printf("=");
  242. }
  243. printf(" (%p)", node);
  244. printf("\n");
  245. if(print_nodes) {
  246. print_node_tree((GUI_Node*)node->rdic.root, level+1);
  247. }
  248. GUI_Subtree *child = GUI_SUBTREE_FIRST_CHILD(node);
  249. while(child != NULL) {
  250. print_subtree_tree(child, level+1, print_nodes);
  251. child = GUI_SUBTREE_SIBLING(child);
  252. }
  253. }
  254. #endif
  255. // ---
  256. // NOTE(Zelaven): This won't be used, but it will stay around as a reference for
  257. // the technique.
  258. #if 0
  259. #define GUIWITH_INNER2(token) defer ## token
  260. #define GUIWITH_INNER(token) GUIWITH_INNER2(token)
  261. /*
  262. * NOTE(Zelaven): This is a "defer loop" macro, fitted as a "with" construct.
  263. * What it is used for is temporarily overwriting a value, keeping the original
  264. * value safe in a loop-local variable.
  265. * The operation functions by declaring the loop variable of an anonymous struct
  266. * type, which contains the temporary variable as well as the actual loop
  267. * variable.
  268. * The temporary is initialized with the contents of the stored value, which is
  269. * then overwritten with the "with" value, and at the end of the loop the
  270. * stored value is restored to contain the contents of the temporary.
  271. * It is important to note that for this to operate correctly, the temporary
  272. * needs to be filled out before the stored value is overwritten, which is
  273. * dependent on the ORDER OF THE STRUCT MEMBERS.
  274. * This is because the overwriting of the stored value is done in the
  275. * initialization of the loop variable part of the struct, and the members are
  276. * initialized in member order, not initializer declaration order.
  277. * I tested this, but both are arranged in the desired order for both reading
  278. * and in the case that it proves to be compiler-dependent.
  279. * (Note that it appears to be consistent across optimization flags)
  280. */
  281. #define GUIWITH(storage_variable, TYPE, value_to_use)\
  282. 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))
  283. #define GUI_WITH_REDNESS(context, value) GUIWITH(context->style.red, unsigned char, value)
  284. #define GUI_WITH_BLUENESS(context, value) GUIWITH(context->style.blue, unsigned char, value)
  285. #define GUI_WITH_GREENNESS(context, value) GUIWITH(context->style.green, unsigned char, value)
  286. #define GUI_WITH_STYLE(context, value) GUIWITH(context->style, GUI_Style, value)
  287. #define GUI_WITH_BORDER_COLOR(context, value) GUIWITH((context)->style.border_color, GUI_Color, (value))
  288. #define GUI_WITH_BORDER_THICKNESS(context, value) GUIWITH((context)->style.border_thickness, int, (value))
  289. #define GUI_WITH_ROUNDEDNESS(context, value) GUIWITH((context)->style.roundedness, unsigned char, (value))
  290. void fff(GUI_Context *context)
  291. {
  292. GUI_WITH_REDNESS(context, 222)
  293. printf("%d\n", context->style.red);
  294. GUI_Style style = (GUI_Style){2,2,2,0,0,0};
  295. GUI_WITH_STYLE(context, style)
  296. GUI_WITH_STYLE(context, ((GUI_Style){2,2,2,0,0,0}))
  297. printf("%d\n", context->style.red);
  298. }
  299. #endif
  300. #define GUIWITH_INNER2(token) defer ## token
  301. #define GUIWITH_INNER(token) GUIWITH_INNER2(token)
  302. #define GUIWITH(storage_variable, TYPE, value_to_use)\
  303. 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))
  304. #define GUI_ON_LAYER(context, layer) \
  305. (layer)->should_draw = true;\
  306. GUIWITH(context->current_layer, GUI_Layer*, layer)
  307. // ---
  308. // TODO(Zelaven): The mouse coordinates are in the context, so no need to pass
  309. // them as parameters.
  310. #undef ENABLE_DEBUG
  311. #define ENABLE_DEBUG 0
  312. void gui_apply_input(
  313. GUI_Context *context,
  314. int mouse_x,
  315. int mouse_y)
  316. {
  317. (void)context;
  318. (void)mouse_x;
  319. (void)mouse_y;
  320. // --- Mouse Input ---
  321. // NOTE(Zelaven): First hit test against layers.
  322. GUI_Layer *hit_layer = &context->background_layer;
  323. GUI_Subtree *hit_root_subtree = (GUI_Subtree*)hit_layer->subtree_rdic.root;
  324. {
  325. GUI_Layer *top_layer = &context->top_layer;
  326. GUI_Subtree *root_subtree = (GUI_Subtree*)top_layer->subtree_rdic.root;
  327. if(top_layer->should_draw && root_subtree != NULL)
  328. {
  329. GUI_Node *top_layer_root =
  330. (GUI_Node*)root_subtree->rdic.root;
  331. if(top_layer_root != NULL)
  332. if(point_in_rect_with_offset(
  333. mouse_x, mouse_y,
  334. top_layer_root->rect,
  335. top_layer->offset_x, top_layer->offset_y))
  336. {
  337. hit_layer = &context->top_layer;
  338. hit_root_subtree = root_subtree;
  339. }
  340. }
  341. }
  342. (void)hit_layer;
  343. assert(hit_root_subtree != NULL);
  344. GUI_Subtree *top_subtree_under_cursor = hit_root_subtree;
  345. GUI_Subtree *current_subtree = GUI_SUBTREE_FIRST_CHILD(top_subtree_under_cursor);
  346. int mouse_over_subtree = 0;
  347. while(current_subtree != NULL)
  348. {
  349. // TODO(Zelaven): Should actually test against the rect-intersect between
  350. // the clipnode and the subtree root. The clipnode is only a maximal bound.
  351. mouse_over_subtree = point_in_rect_with_offset(
  352. mouse_x, mouse_y,
  353. // TODO(Zelaven): Test clipnode valid.
  354. current_subtree->clipnode.node->rect,
  355. hit_layer->offset_x, hit_layer->offset_y);
  356. if(mouse_over_subtree)
  357. {
  358. top_subtree_under_cursor = current_subtree;
  359. current_subtree = GUI_SUBTREE_FIRST_CHILD(current_subtree);
  360. }
  361. else
  362. {
  363. current_subtree = GUI_SUBTREE_SIBLING(current_subtree);
  364. }
  365. }
  366. hit_root_subtree = top_subtree_under_cursor;
  367. GUI_Node *top_node_under_cursor = (GUI_Node*)hit_root_subtree->rdic.root;
  368. GUI_Node *current_node = (GUI_Node*)top_node_under_cursor->rdic_node.first_child;
  369. int mouse_over_node = 0;
  370. while(current_node != NULL)
  371. {
  372. mouse_over_node = point_in_rect_with_offset(
  373. mouse_x, mouse_y,
  374. current_node->rect,
  375. hit_layer->offset_x, hit_layer->offset_y);
  376. if(mouse_over_node)
  377. {
  378. top_node_under_cursor = current_node;
  379. current_node = (GUI_Node*)current_node->rdic_node.first_child;
  380. }
  381. else
  382. {
  383. current_node = (GUI_Node*)current_node->rdic_node.sibling;
  384. }
  385. }
  386. context->top_node_under_cursor.node = top_node_under_cursor;
  387. context->top_node_under_cursor.generation =
  388. top_node_under_cursor->rdic_node.generation;
  389. DEBUG("Top node under cursor: %.*s\n",
  390. top_node_under_cursor->debug_string.length,
  391. top_node_under_cursor->debug_string.cstring);
  392. return;
  393. }
  394. #if 0
  395. {
  396. // --- Mouse Input ---
  397. // NOTE(Zelaven): First hit test against layers.
  398. GUI_Layer *hit_layer = &context->background_layer;
  399. {
  400. GUI_Layer *top_layer = &context->top_layer;
  401. if(top_layer->first_subtree != NULL)
  402. {
  403. GUI_Node *top_layer_root =
  404. (GUI_Node*)top_layer->first_subtree->rdic.root;
  405. if(point_in_rect(mouse_x, mouse_y, top_layer_root->rect))
  406. {
  407. hit_layer = &context->top_layer;
  408. }
  409. }
  410. }
  411. //GUI_Node *top_node_under_cursor = (GUI_Node*)context->rdic.root;
  412. //GUI_Node *top_node_under_cursor = (GUI_Node*)context->first_subtree->rdic.root;
  413. GUI_Node *top_node_under_cursor = (GUI_Node*)hit_layer->first_subtree->rdic.root;
  414. GUI_Node *current_node = (GUI_Node*)top_node_under_cursor->rdic_node.first_child;
  415. int mouse_over_node = 0;
  416. while(current_node != NULL)
  417. {
  418. mouse_over_node = point_in_rect(mouse_x, mouse_y, current_node->rect);
  419. if(mouse_over_node)
  420. {
  421. top_node_under_cursor = current_node;
  422. current_node = (GUI_Node*)current_node->rdic_node.first_child;
  423. }
  424. else
  425. {
  426. current_node = (GUI_Node*)current_node->rdic_node.sibling;
  427. }
  428. }
  429. context->top_node_under_cursor.node = top_node_under_cursor;
  430. context->top_node_under_cursor.generation =
  431. top_node_under_cursor->rdic_node.generation;
  432. DEBUG("Top node under cursor: %.*s\n",
  433. top_node_under_cursor->debug_string.length,
  434. top_node_under_cursor->debug_string.cstring);
  435. }
  436. #endif
  437. GUI_Node_Reference gui_get_node(
  438. GUI_Context *context,
  439. GUI_Node_Reference last_reference,
  440. GUI_Layout_Direction direction,
  441. GUI_Style *style,
  442. GUI_Size size[static 2])
  443. {
  444. GUI_Layer *current_layer = context->current_layer;
  445. if(current_layer == NULL) {
  446. return (GUI_Node_Reference){0};
  447. }
  448. GUI_Subtree *current_subtree =
  449. //(GUI_Subtree*)current_layer->subtree_rdic.frame_current_node;
  450. // TODO(Zelaven): This has to do with me always pushing the newest subtree
  451. // as a parent, which honestly doesn't sound ideal to me. I should look
  452. // into what what my options are.
  453. (GUI_Subtree*)current_layer->subtree_rdic.current_parent;
  454. int get_node_flags = 0;
  455. GUI_Node_Reference new_reference = {
  456. .rdic_ref = rdic_get_node(
  457. //&context->current_subtree->rdic, last_reference.rdic, &get_node_flags),
  458. &current_subtree->rdic, last_reference.rdic_ref, &get_node_flags),
  459. };
  460. GUI_Node *node = new_reference.node;
  461. node->layout_direction = direction;
  462. node->style = style;
  463. node->semantic_size[GUI_AXIS2_X] = size[GUI_AXIS2_X];
  464. node->semantic_size[GUI_AXIS2_Y] = size[GUI_AXIS2_Y];
  465. // TODO(Zelaven):
  466. // get_node_flags & RDIC_GET_NODE__OUT_OF_FREELIST
  467. // ^ This should result in an attempt to allocate more nodes for the freelist.
  468. // Then rdic_get_node should be retried.
  469. if(get_node_flags & RDIC_GET_NODE__NODES_COLLECTED)
  470. {
  471. GUI_NODE_PARENT(node)->dirty = true;
  472. }
  473. if(get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED)
  474. {
  475. GUI_NODE_PARENT(node)->dirty = true;
  476. }
  477. node->dirty = (get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED) != 0;
  478. return new_reference;
  479. }
  480. GUI_Subtree_Reference gui_get_subtree(
  481. GUI_Context *context,
  482. GUI_Subtree_Reference last_reference)
  483. {
  484. GUI_Layer *current_layer = context->current_layer;
  485. if(current_layer == NULL) {
  486. return (GUI_Subtree_Reference){0};
  487. }
  488. RDIC_Context *subtree_rdic = &current_layer->subtree_rdic;
  489. RDIC_Node *old_subtree_freelist_head = subtree_rdic->freelist->head;
  490. int get_node_flags = 0;
  491. GUI_Subtree_Reference new_reference = {
  492. .rdic_ref = rdic_get_node(
  493. //&context->current_subtree->rdic, last_reference.rdic, &get_node_flags),
  494. subtree_rdic, last_reference.rdic_ref, &get_node_flags),
  495. };
  496. GUI_Subtree *subtree = new_reference.node;
  497. subtree->rdic = (RDIC_Context){0};
  498. subtree->rdic.freelist = context->node_freelist;
  499. subtree->relative_to = (GUI_Node_Reference){0};
  500. subtree->flat_offset_x = 0;
  501. subtree->flat_offset_y = 0;
  502. subtree->offset_relative_node_percentage_x = 0;
  503. subtree->offset_relative_node_percentage_y = 0;
  504. subtree->offset_own_size_percentage_x = 0;
  505. subtree->offset_own_size_percentage_y = 0;
  506. // TODO(Zelaven):
  507. // get_node_flags & RDIC_GET_NODE__OUT_OF_FREELIST
  508. // ^ This should result in an attempt to allocate more nodes for the freelist.
  509. // Then rdic_get_node should be retried.
  510. if(get_node_flags & RDIC_GET_NODE__NODES_COLLECTED)
  511. {
  512. // NOTE(Zelaven): Some subtrees were collected, which means that their RDIC
  513. // node trees should be collected too.
  514. for(
  515. RDIC_Node *i = subtree_rdic->freelist->head;
  516. i != old_subtree_freelist_head;
  517. i = i->sibling)
  518. {
  519. GUI_Subtree *subtree = (GUI_Subtree*)i;
  520. // NOTE(Zelaven): This line falsely triggers -Wstringop-overflow and the
  521. // copy into a temporary variable seemingly fixes it.
  522. // For this reason I simply opted to use -Wno-stringop-overflow, as I
  523. // don't want to have a broken flag enabled.
  524. rdic_cull_subtrees(&subtree->rdic, subtree->rdic.root);
  525. //RDIC_Context *rdic_context = &subtree->rdic;
  526. //rdic_cull_subtrees(rdic_context, subtree->rdic.root);
  527. }
  528. }
  529. #if 0
  530. if(get_node_flags & RDIC_GET_NODE__NODES_COLLECTED)
  531. {
  532. GUI_NODE_PARENT(node)->dirty = true;
  533. }
  534. if(get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED)
  535. {
  536. GUI_NODE_PARENT(node)->dirty = true;
  537. }
  538. node->dirty = (get_node_flags & RDIC_GET_NODE__NODE_ALLOCATED) != 0;
  539. #endif
  540. return new_reference;
  541. }
  542. GUI_Node_Reference gui_context_prepare_layer(
  543. GUI_Context *context,
  544. GUI_Layer *layer,
  545. GUI_Node_Reference last_root_reference,
  546. int width, int height,
  547. GUI_Layout_Direction layout_direction,
  548. GUI_Style *style)
  549. {
  550. layer->should_draw = false;
  551. GUI_Subtree_Reference root_subtree = layer->root_subtree;
  552. //root_subtree = gui_get_subtree(context, root_subtree);
  553. root_subtree.rdic_ref = rdic_context_start_frame(
  554. &layer->subtree_rdic, root_subtree.rdic_ref);
  555. if(root_subtree.node == NULL)
  556. {
  557. return (GUI_Node_Reference){0};
  558. }
  559. layer->root_subtree = root_subtree;
  560. root_subtree.node->rdic.freelist = context->node_freelist;
  561. //static GUI_Subtree background_subtree = {0};
  562. //background_subtree.rdic.freelist = context->node_freelist;
  563. //context->background_layer.first_subtree = &background_subtree;
  564. //context->background_layer.last_subtree = &background_subtree;
  565. //context->current_subtree = &background_subtree;
  566. GUI_Node_Reference new_root_reference = {
  567. .rdic_ref = rdic_context_start_frame(
  568. //&background_subtree.rdic, last_root_reference.rdic)
  569. &root_subtree.node->rdic, last_root_reference.rdic_ref)
  570. };
  571. if(new_root_reference.node == NULL)
  572. {
  573. return (GUI_Node_Reference){0};
  574. }
  575. //RDIC_Node_Reference new_root_reference = rdic_context_start_frame(
  576. // &background_subtree.rdic,
  577. // last_root_reference);
  578. GUI_Node *root = (GUI_Node*)new_root_reference.node;
  579. root->dirty = false;
  580. if(!gui_node_references_equal(last_root_reference, new_root_reference)) {
  581. root->dirty = true;
  582. }
  583. if(layout_direction != root->layout_direction) {
  584. root->dirty = true;
  585. }
  586. root->debug_string = GUI_STRING("root");
  587. root->layout_direction = layout_direction;
  588. root->semantic_size[GUI_AXIS2_X] = (GUI_Size)
  589. {.size_rule = GUI_SIZERULE_PIXELS, .value = width, .strictness = 100,};
  590. root->semantic_size[GUI_AXIS2_Y] = (GUI_Size)
  591. {.size_rule = GUI_SIZERULE_PIXELS, .value = height, .strictness = 100,};
  592. root->style = style;
  593. return new_root_reference;
  594. }
  595. #undef ENABLE_DEBUG
  596. #define ENABLE_DEBUG 0
  597. // TODO(Zelaven): Make this cause redrawing of root on parameter change.
  598. // Maybe an explicit parameter so it can be based on received events?
  599. // Such as expose events, resize events, etc.
  600. // May also be a good idea because struct-comparing styles each frame wouldn't
  601. // be good for performance, so a force-redraw bool sounds like an always-good
  602. // option. That way you can force-dirty the root when you make a style change,
  603. // but it could also be added at other granularity.
  604. // Or should it be something that is done by just setting
  605. // ref.node->dirty = true?
  606. // That is one option, specifying the dirty flag as a part of the API itself.
  607. // I think I like that option.
  608. GUI_Node_Reference gui_context_start_frame(
  609. GUI_Context *context,
  610. GUI_Node_Reference last_root_reference,
  611. int width, int height,
  612. GUI_Layout_Direction layout_direction,
  613. GUI_Style *style)
  614. {
  615. //context->frame_current_node = context->root;
  616. context->num_draw_commands = 0;
  617. memory_arena_reset(context->draw_command_arena);
  618. DEBUG("%s: %d %d %d %d\n", __func__,
  619. context->mouse_x, context->mouse_y,
  620. context->mouse_pressed, context->mouse_down);
  621. context->current_layer = &context->background_layer;
  622. GUI_Node_Reference new_root_reference = gui_context_prepare_layer(
  623. context, context->current_layer, last_root_reference,
  624. width, height, layout_direction, style);
  625. context->current_layer->should_draw = true;
  626. gui_apply_input(context, context->mouse_x, context->mouse_y);
  627. return new_root_reference;
  628. }
  629. void gui_context_finish_frame(
  630. GUI_Context *context)
  631. {
  632. //rdic_context_finish_frame(&context->background_layer.first_subtree->rdic);
  633. rdic_context_finish_frame(&context->background_layer.root_subtree.node->rdic);
  634. //context->node_freelist =
  635. // context->background_layer.first_subtree->rdic.node_freelist;
  636. }
  637. GUI_Node_Reference gui_push_subtree(
  638. GUI_Context *context,
  639. GUI_Subtree_Reference subtree,
  640. GUI_Node_Reference last_root_reference,
  641. GUI_Layout_Direction layout_direction,
  642. GUI_Style *style,
  643. GUI_Size size[static 2],
  644. GUI_Node_Reference relative_to)
  645. {
  646. RDIC_Context *layer_rdic_context = &context->current_layer->subtree_rdic;
  647. rdic_push_parent(layer_rdic_context, subtree.rdic_ref);
  648. //context->node_freelist = context->current_subtree->rdic.node_freelist;
  649. //subtree->rdic.node_freelist = context->node_freelist;
  650. // NOTE(Zelaven): Well, not being able to do this is a problem...
  651. //context->last_subtree->next = subtree;
  652. //subtree->prev = context->last_subtree;
  653. //context->last_subtree = subtree;
  654. //subtree->structural_parent = context->current_subtree;
  655. //context->current_subtree = subtree;
  656. subtree.node->relative_to = relative_to;
  657. subtree.node->clipnode = relative_to;
  658. GUI_Node_Reference new_root_reference = {
  659. .rdic_ref = rdic_context_start_frame(
  660. &subtree.node->rdic, last_root_reference.rdic_ref)
  661. };
  662. GUI_Node *root = (GUI_Node*)new_root_reference.node;
  663. root->dirty = false;
  664. if(!gui_node_references_equal(last_root_reference, new_root_reference)) {
  665. root->dirty = true;
  666. }
  667. if(layout_direction != root->layout_direction) {
  668. root->dirty = true;
  669. }
  670. root->debug_string = GUI_STRING("gui_push_subtree");
  671. root->layout_direction = layout_direction;
  672. root->semantic_size[GUI_AXIS2_X] = size[GUI_AXIS2_X];
  673. root->semantic_size[GUI_AXIS2_Y] = size[GUI_AXIS2_Y];
  674. root->style = style;
  675. return new_root_reference;
  676. }
  677. void gui_pop_subtree(
  678. GUI_Context *context)
  679. {
  680. //context->node_freelist = context->current_subtree->rdic.node_freelist;
  681. //context->current_subtree = context->current_subtree->structural_parent;
  682. //context->current_subtree->rdic.node_freelist = context->node_freelist;
  683. RDIC_Context *layer_rdic_context = &context->current_layer->subtree_rdic;
  684. rdic_pop_parent(layer_rdic_context);
  685. }
  686. void gui_push_parent(
  687. GUI_Context *context,
  688. GUI_Node_Reference parent)
  689. {
  690. GUI_Layer *current_layer = context->current_layer;
  691. GUI_Subtree *current_subtree =
  692. //(GUI_Subtree*)current_layer->subtree_rdic.frame_current_node;
  693. (GUI_Subtree*)current_layer->subtree_rdic.current_parent;
  694. rdic_push_parent(&current_subtree->rdic, parent.rdic_ref);
  695. }
  696. void gui_pop_parent(
  697. GUI_Context *context)
  698. {
  699. GUI_Layer *current_layer = context->current_layer;
  700. GUI_Subtree *current_subtree =
  701. //(GUI_Subtree*)current_layer->subtree_rdic.frame_current_node;
  702. (GUI_Subtree*)current_layer->subtree_rdic.current_parent;
  703. rdic_pop_parent(&current_subtree->rdic);
  704. }
  705. // ---
  706. void gui_layout_calculate_standalone_sizes(
  707. GUI_Node *node,
  708. GUI_Axis2 axis)
  709. {
  710. switch(node->semantic_size[axis].size_rule)
  711. {
  712. case GUI_SIZERULE_PIXELS:
  713. {
  714. node->computed_size[axis] = node->semantic_size[axis].value;
  715. } break;
  716. case GUI_SIZERULE_TEXTCONTENT:
  717. {
  718. // TODO(Zelaven): Calculate text width.
  719. node->computed_size[axis] = 0;
  720. } break;
  721. default:
  722. {
  723. //assert(!"Non-standalone size passed to calculate_standalone_sizes.");
  724. } break;
  725. }
  726. if(node->rdic_node.first_child != NULL) {
  727. gui_layout_calculate_standalone_sizes(GUI_NODE_FIRST_CHILD(node), axis);
  728. }
  729. if(node->rdic_node.sibling != NULL) {
  730. gui_layout_calculate_standalone_sizes(GUI_NODE_SIBLING(node), axis);
  731. }
  732. }
  733. void gui_layout_calculate_parent_percent_sizes(
  734. GUI_Node *node,
  735. GUI_Axis2 axis)
  736. {
  737. if(node->semantic_size[axis].size_rule == GUI_SIZERULE_PERCENTOFPARENT)
  738. {
  739. int percentage = node->semantic_size[axis].value;
  740. node->computed_size[axis] =
  741. (GUI_NODE_PARENT(node)->computed_size[axis] * percentage) / 100;
  742. }
  743. if(node->rdic_node.first_child != NULL) {
  744. gui_layout_calculate_parent_percent_sizes(GUI_NODE_FIRST_CHILD(node), axis);
  745. }
  746. if(node->rdic_node.sibling != NULL) {
  747. gui_layout_calculate_parent_percent_sizes(GUI_NODE_SIBLING(node), axis);
  748. }
  749. }
  750. void gui_layout_calculate_screen_rects(
  751. GUI_Node *node,
  752. int x, int y,
  753. GUI_Layout_Direction layout_direction)
  754. {
  755. int width = node->computed_size[GUI_AXIS2_X];
  756. int height = node->computed_size[GUI_AXIS2_Y];
  757. node->rect = (GUI_Rectangle){x, y, x+width, y+height};
  758. if(node->rdic_node.first_child != NULL) {
  759. gui_layout_calculate_screen_rects(
  760. GUI_NODE_FIRST_CHILD(node), x, y, node->layout_direction);
  761. }
  762. if(node->rdic_node.sibling != NULL) {
  763. int sibling_x = x;
  764. int sibling_y = y;
  765. if(layout_direction == GUI_LAYOUT_HORIZONTAL)
  766. {
  767. sibling_x += width;
  768. }
  769. if(layout_direction == GUI_LAYOUT_VERTICAL)
  770. {
  771. sibling_y += height;
  772. }
  773. gui_layout_calculate_screen_rects(
  774. GUI_NODE_SIBLING(node), sibling_x, sibling_y, layout_direction);
  775. }
  776. }
  777. void gui_layout_nodes(GUI_Subtree *subtree)
  778. {
  779. #if 1
  780. GUI_Node *root = (GUI_Node*)subtree->rdic.root;
  781. assert(root != NULL);
  782. for(GUI_Axis2 axis = 0; axis < GUI_AXIS2_COUNT; axis++)
  783. {
  784. gui_layout_calculate_standalone_sizes(root, axis);
  785. gui_layout_calculate_parent_percent_sizes(root, axis);
  786. }
  787. // TODO(Zelaven): Test reference validity.
  788. // TODO(Zelaven): This probably can be done once and passed in.
  789. int x_offset = 0;
  790. int y_offset = 0;
  791. GUI_Node *relative_node = (GUI_Node*)subtree->relative_to.node;
  792. if(relative_node != NULL){
  793. GUI_Rectangle *relative_rectangle = &relative_node->rect;
  794. x_offset = relative_rectangle->x0;
  795. y_offset = relative_rectangle->y0;
  796. //printf("%.*s: %d, %d\n", relative_node->debug_string.length, relative_node->debug_string.cstring, x_offset, y_offset);
  797. int relative_width = relative_rectangle->x1 - relative_rectangle->x0;
  798. int relative_height = relative_rectangle->y1 - relative_rectangle->y0;
  799. x_offset +=
  800. (relative_width * subtree->offset_relative_node_percentage_x) / 100;
  801. y_offset +=
  802. (relative_height * subtree->offset_relative_node_percentage_y) / 100;
  803. }
  804. x_offset += subtree->flat_offset_x;
  805. y_offset += subtree->flat_offset_y;
  806. x_offset +=
  807. (root->computed_size[GUI_AXIS2_X] * subtree->offset_own_size_percentage_x) / 100;
  808. y_offset +=
  809. (root->computed_size[GUI_AXIS2_Y] * subtree->offset_own_size_percentage_y) / 100;
  810. gui_layout_calculate_screen_rects(root, x_offset, y_offset, GUI_LAYOUT_NONE);
  811. #else
  812. //GUI_Node *root = (GUI_Node*)context->first_subtree->rdic.root;
  813. for(GUI_Axis2 axis = 0; axis < GUI_AXIS2_COUNT; axis++)
  814. {
  815. gui_layout_calculate_standalone_sizes(root, axis);
  816. gui_layout_calculate_parent_percent_sizes(root, axis);
  817. }
  818. gui_layout_calculate_screen_rects(root, 0, 0, GUI_LAYOUT_NONE);
  819. #endif
  820. }
  821. // ---
  822. #undef ENABLE_DEBUG
  823. #define ENABLE_DEBUG 0
  824. void gui_generate_draw_commands_inner(
  825. //int x_offset,
  826. //int y_offset,
  827. GUI_Node *node,
  828. bool dirty, //TODO(Zelaven): Better name.
  829. Memory_Arena *draw_command_arena,
  830. int *out_num_draw_commands)
  831. {
  832. DEBUG("%.*s: dirtiness: %b\n",
  833. node->debug_string.length, node->debug_string.cstring, dirty);
  834. if(dirty) {
  835. node->dirty = true;
  836. GUI_Draw_Command *draw_command =
  837. arena_allocate_draw_command(draw_command_arena);
  838. 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);
  839. *draw_command = (GUI_Draw_Command){
  840. .rectangle = node->rect,
  841. .color = node->style->red<<16 | node->style->green<<8 | node->style->blue,
  842. .border_color = node->style->border_color,
  843. .border_thickness = node->style->border_thickness,
  844. .roundedness = node->style->roundedness,
  845. .text = node->text_string,
  846. .image = node->image,
  847. };
  848. #if 0
  849. (*draw_command).rectangle.x0 += x_offset;
  850. (*draw_command).rectangle.x1 += x_offset;
  851. (*draw_command).rectangle.y0 += y_offset;
  852. (*draw_command).rectangle.y1 += y_offset;
  853. #endif
  854. *out_num_draw_commands += 1;
  855. }
  856. GUI_Node *sibling = GUI_NODE_SIBLING(node);
  857. if(sibling != NULL) {
  858. GUI_Node *parent = GUI_NODE_PARENT(node);
  859. gui_generate_draw_commands_inner(
  860. //x_offset, y_offset,
  861. sibling,
  862. parent->dirty || sibling->dirty,
  863. draw_command_arena, out_num_draw_commands);
  864. }
  865. GUI_Node *first_child = GUI_NODE_FIRST_CHILD(node);
  866. if(node->rdic_node.first_child != NULL) {
  867. gui_generate_draw_commands_inner(
  868. //x_offset, y_offset,
  869. first_child,
  870. dirty || first_child->dirty,
  871. draw_command_arena, out_num_draw_commands);
  872. }
  873. }
  874. void gui_generate_draw_commands(
  875. //GUI_Node *root,
  876. GUI_Subtree *subtree,
  877. Memory_Arena *draw_command_arena,
  878. int *out_num_draw_commands)
  879. {
  880. #if 0
  881. // TODO(Zelaven): Test reference validity.
  882. // TODO(Zelaven): This probably can be done once and passed in.
  883. int x_offset = 0;
  884. int y_offset = 0;
  885. GUI_Node *relative_node = (GUI_Node*)subtree->relative_to.node;
  886. if(relative_node != NULL){
  887. GUI_Rectangle *relative_rectangle = &relative_node->rect;
  888. x_offset = relative_rectangle->x0;
  889. y_offset = relative_rectangle->y0;
  890. //printf("%.*s: %d, %d\n", relative_node->debug_string.length, relative_node->debug_string.cstring, x_offset, y_offset);
  891. int relative_width = relative_rectangle->x1 - relative_rectangle->x0;
  892. int relative_height = relative_rectangle->y1 - relative_rectangle->y0;
  893. x_offset +=
  894. (relative_width * subtree->offset_relative_node_percentage_x) / 100;
  895. y_offset +=
  896. (relative_height * subtree->offset_relative_node_percentage_y) / 100;
  897. }
  898. x_offset += subtree->flat_offset_x;
  899. y_offset += subtree->flat_offset_y;
  900. GUI_Node *root = (GUI_Node*)subtree->rdic.root;
  901. assert(root != NULL);
  902. x_offset +=
  903. (root->computed_size[GUI_AXIS2_X] * subtree->offset_own_size_percentage_x) / 100;
  904. y_offset +=
  905. (root->computed_size[GUI_AXIS2_Y] * subtree->offset_own_size_percentage_y) / 100;
  906. #else
  907. GUI_Node *root = (GUI_Node*)subtree->rdic.root;
  908. assert(root != NULL);
  909. #endif
  910. assert(draw_command_arena != NULL);
  911. assert(out_num_draw_commands != NULL);
  912. *out_num_draw_commands = 0;
  913. memory_arena_reset(draw_command_arena);
  914. bool dirtyness = root->dirty;
  915. GUI_Node_Reference clipnode = subtree->clipnode;
  916. if(rdic_node_reference_valid(clipnode.rdic_ref)) {
  917. dirtyness |= clipnode.node->dirty;
  918. }
  919. gui_generate_draw_commands_inner(
  920. //x_offset, y_offset,
  921. root, dirtyness,
  922. draw_command_arena, out_num_draw_commands);
  923. }
  924. // ---
  925. GUI_Node_Reference gui_layout(
  926. GUI_Context *context,
  927. GUI_Node_Reference last_reference,
  928. GUI_Layout_Direction direction,
  929. GUI_Style *style,
  930. GUI_Size size[static 2])
  931. {
  932. GUI_Node_Reference new_reference = gui_get_node(
  933. context, last_reference, direction, style, size);
  934. GUI_Node *node = new_reference.node;
  935. node->text_string = (GUI_String){0};
  936. node->debug_string = GUI_STRING("gui_layout");
  937. return new_reference;
  938. }
  939. // ---
  940. GUI_Node_Reference gui_dumb_block(
  941. GUI_Context *context,
  942. GUI_Node_Reference last_reference,
  943. GUI_Style *style,
  944. GUI_Size size[static 2])
  945. {
  946. GUI_Node_Reference new_reference = gui_get_node(
  947. context, last_reference, GUI_LAYOUT_NONE, style, size);
  948. GUI_Node *node = new_reference.node;
  949. node->text_string = (GUI_String){0};
  950. node->debug_string = GUI_STRING("gui_dumb_block");
  951. return new_reference;
  952. }
  953. #undef ENABLE_DEBUG
  954. #define ENABLE_DEBUG 0
  955. bool gui_dumb_button(
  956. GUI_Context *context,
  957. GUI_Node_Reference *last_reference,
  958. GUI_String text,
  959. GUI_Style *style,
  960. GUI_Size size[static 2])
  961. {
  962. GUI_Node_Reference new_reference = gui_get_node(
  963. context, *last_reference, GUI_LAYOUT_NONE, style, size);
  964. GUI_Node *node = new_reference.node;
  965. node->debug_string = text;
  966. node->text_string = text;
  967. bool clicked = false;
  968. if(gui_node_references_equal(
  969. new_reference, context->top_node_under_cursor))
  970. {
  971. DEBUG("%.*s: reference is the top node under cursor.\n",
  972. text.length, text.cstring);
  973. if(context->mouse_pressed)
  974. {
  975. DEBUG(" Mouse pressed on node\n");
  976. context->focused_node = new_reference;
  977. }
  978. else if(!context->mouse_down)
  979. {
  980. DEBUG(" Mouse released on node\n");
  981. if(gui_node_references_equal(new_reference, context->focused_node))
  982. {
  983. DEBUG(" Mouse released over same node as pressed\n");
  984. context->focused_node.node = NULL;
  985. clicked = true;
  986. }
  987. }
  988. }
  989. else if(gui_node_references_equal(new_reference, context->focused_node)
  990. && !context->mouse_down)
  991. {
  992. context->focused_node.node = NULL;
  993. }
  994. *last_reference = new_reference;
  995. return clicked;
  996. }
  997. #undef ENABLE_DEBUG
  998. #define ENABLE_DEBUG 0
  999. bool gui_mouseover_box(
  1000. GUI_Context *context,
  1001. GUI_Node_Reference *last_reference,
  1002. GUI_String text,
  1003. GUI_Style *style,
  1004. GUI_Size size[static 2])
  1005. {
  1006. GUI_Node_Reference new_reference = gui_get_node(
  1007. context, *last_reference, GUI_LAYOUT_NONE, style, size);
  1008. GUI_Node *node = new_reference.node;
  1009. node->debug_string = GUI_STRING("gui_mouseover_box");
  1010. node->text_string = text;
  1011. bool new_ref_is_top = gui_node_references_equal(
  1012. new_reference, context->top_node_under_cursor);
  1013. DEBUG(" %p\n | %p\n | %p\n",
  1014. context->top_node_under_cursor.node,
  1015. last_reference->node, new_reference.node);
  1016. bool hovered = new_ref_is_top;
  1017. *last_reference = new_reference;
  1018. return hovered;
  1019. }
  1020. #undef ENABLE_DEBUG
  1021. #define ENABLE_DEBUG 0
  1022. bool gui_slider(
  1023. GUI_Context *context,
  1024. GUI_Node_Reference *last_reference,
  1025. GUI_Node_Reference *inner_box_reference,
  1026. float *value,
  1027. GUI_Style *background_style,
  1028. GUI_Style *bar_style,
  1029. GUI_Size size[static 2])
  1030. {
  1031. GUI_Node_Reference new_reference = gui_get_node(
  1032. context, *last_reference, GUI_LAYOUT_NONE, background_style, size);
  1033. GUI_Node *node = new_reference.node;
  1034. node->debug_string = GUI_STRING("gui_slider");
  1035. node->text_string = (GUI_String){0};
  1036. // NOTE(Zelaven): We need a handle to this node, but we set its values later.
  1037. gui_push_parent(context, new_reference);
  1038. GUI_Node_Reference new_inner_reference = gui_get_node(
  1039. context, *inner_box_reference, GUI_LAYOUT_NONE, bar_style, size);
  1040. bool value_changed = false;
  1041. bool new_ref_is_top = gui_node_references_equal(
  1042. new_reference, context->top_node_under_cursor);
  1043. bool inner_ref_is_top = gui_node_references_equal(
  1044. new_inner_reference, context->top_node_under_cursor);
  1045. /*DEBUG(" %p\n | %p %p\n | %p %p\n",
  1046. context->top_node_under_cursor.node,
  1047. last_reference->node, inner_box_reference->node,
  1048. new_reference.node, new_inner_reference.node);*/
  1049. if(new_ref_is_top || inner_ref_is_top)
  1050. {
  1051. DEBUG("\n%s: reference is the top node under cursor.\n", __func__);
  1052. if(context->mouse_pressed)
  1053. {
  1054. DEBUG(" Mouse pressed on node\n");
  1055. context->focused_node = new_reference;
  1056. }
  1057. else if(!context->mouse_down)
  1058. {
  1059. DEBUG(" Mouse released on node\n");
  1060. if(gui_node_references_equal(new_reference, context->focused_node))
  1061. {
  1062. DEBUG(" Mouse released over same node as pressed\n");
  1063. context->focused_node.node = NULL;
  1064. }
  1065. }
  1066. }
  1067. else if(gui_node_references_equal(new_reference, context->focused_node)
  1068. && !context->mouse_down)
  1069. {
  1070. context->focused_node.node = NULL;
  1071. }
  1072. if(gui_node_references_equal(new_reference, context->focused_node))
  1073. {
  1074. int last_frame_width = node->computed_size[GUI_AXIS2_X];
  1075. if(last_frame_width == 0)
  1076. {
  1077. DEBUG(
  1078. " last_frame_width is 0."
  1079. " This shouldn't really happen as the user shouldn't be able to focus"
  1080. " a node that hasn't been displayed on the screen yet."
  1081. " Not going to change the slider value.");
  1082. }
  1083. else
  1084. {
  1085. int offset_x = context->mouse_x - node->rect.x0;
  1086. float before_value = *value;
  1087. float new_value = ((float)offset_x) / ((float)last_frame_width);
  1088. if(new_value < 0.0f)
  1089. {
  1090. new_value = 0.0f;
  1091. }
  1092. else if(new_value >= 1.0f)
  1093. {
  1094. new_value = 1.0f;
  1095. }
  1096. *value = new_value;
  1097. DEBUG(" Value before: %f - Value after: %f\n", before_value, *value);
  1098. value_changed = (before_value != new_value);
  1099. }
  1100. }
  1101. // NOTE(Zelaven): Modified by input, so handle input first.
  1102. GUI_Node *inner = new_inner_reference.node;
  1103. inner->debug_string = GUI_STRING("gui_slider - inner node");
  1104. inner->text_string = (GUI_String){0};
  1105. assert(*value <= 1.0f);
  1106. //inner->semantic_size[GUI_AXIS2_X].value = last_frame_width*(*value);
  1107. inner->semantic_size[GUI_AXIS2_Y] =
  1108. (GUI_Size){GUI_SIZERULE_PERCENTOFPARENT, 100, 100};
  1109. inner->semantic_size[GUI_AXIS2_X].size_rule = GUI_SIZERULE_PERCENTOFPARENT;
  1110. inner->semantic_size[GUI_AXIS2_X].value = 100 * (*value);
  1111. gui_pop_parent(context);
  1112. *last_reference = new_reference;
  1113. *inner_box_reference = new_inner_reference;
  1114. if(value_changed) {node->dirty = true;}
  1115. //node->dirty = true;
  1116. return value_changed;
  1117. }
  1118. #undef ENABLE_DEBUG
  1119. #define ENABLE_DEBUG 0
  1120. bool gui_vertical_slider(
  1121. GUI_Context *context,
  1122. GUI_Node_Reference *last_reference,
  1123. GUI_Node_Reference *inner_box_reference,
  1124. float *value,
  1125. GUI_Style *background_style,
  1126. GUI_Style *bar_style,
  1127. GUI_Size size[static 2])
  1128. {
  1129. GUI_Node_Reference new_reference = gui_get_node(
  1130. context, *last_reference, GUI_LAYOUT_NONE, background_style, size);
  1131. GUI_Node *node = new_reference.node;
  1132. node->debug_string = GUI_STRING("gui_slider");
  1133. node->text_string = (GUI_String){0};
  1134. // NOTE(Zelaven): We need a handle to this node, but we set its values later.
  1135. gui_push_parent(context, new_reference);
  1136. GUI_Node_Reference new_inner_reference = gui_get_node(
  1137. context, *inner_box_reference, GUI_LAYOUT_NONE, bar_style, size);
  1138. bool value_changed = false;
  1139. bool new_ref_is_top = gui_node_references_equal(
  1140. new_reference, context->top_node_under_cursor);
  1141. bool inner_ref_is_top = gui_node_references_equal(
  1142. new_inner_reference, context->top_node_under_cursor);
  1143. DEBUG("%p\n | %p %p\n | %p %p\n",
  1144. context->top_node_under_cursor.node,
  1145. last_reference->node, inner_box_reference->node,
  1146. new_reference.node, new_inner_reference.node);
  1147. if(new_ref_is_top || inner_ref_is_top)
  1148. {
  1149. DEBUG("\n%s: reference is the top node under cursor.\n", __func__);
  1150. if(context->mouse_pressed)
  1151. {
  1152. DEBUG(" Mouse pressed on node\n");
  1153. context->focused_node = new_reference;
  1154. }
  1155. else if(!context->mouse_down)
  1156. {
  1157. DEBUG(" Mouse released on node\n");
  1158. if(gui_node_references_equal(new_reference, context->focused_node))
  1159. {
  1160. DEBUG(" Mouse released over same node as pressed\n");
  1161. context->focused_node.node = NULL;
  1162. }
  1163. }
  1164. }
  1165. else if(gui_node_references_equal(new_reference, context->focused_node)
  1166. && !context->mouse_down)
  1167. {
  1168. context->focused_node.node = NULL;
  1169. }
  1170. if(gui_node_references_equal(new_reference, context->focused_node))
  1171. {
  1172. int last_frame_height = node->computed_size[GUI_AXIS2_Y];
  1173. if(last_frame_height == 0)
  1174. {
  1175. DEBUG(
  1176. " last_frame_height is 0."
  1177. " This shouldn't really happen as the user shouldn't be able to focus"
  1178. " a node that hasn't been displayed on the screen yet."
  1179. " Not going to change the slider value.");
  1180. }
  1181. else
  1182. {
  1183. int offset_y = context->mouse_y - node->rect.y0;
  1184. float before_value = *value;
  1185. float new_value = ((float)offset_y) / ((float)last_frame_height);
  1186. if(new_value < 0.0f)
  1187. {
  1188. new_value = 0.0f;
  1189. }
  1190. else if(new_value >= 1.0f)
  1191. {
  1192. new_value = 1.0f;
  1193. }
  1194. *value = new_value;
  1195. DEBUG(" Value before: %f - Value after: %f\n", before_value, *value);
  1196. value_changed = (before_value != new_value);
  1197. }
  1198. }
  1199. // NOTE(Zelaven): Modified by input, so handle input first.
  1200. GUI_Node *inner = new_inner_reference.node;
  1201. inner->debug_string = GUI_STRING("gui_slider - inner node");
  1202. inner->text_string = (GUI_String){0};
  1203. assert(*value <= 1.0f);
  1204. inner->semantic_size[GUI_AXIS2_X] =
  1205. (GUI_Size){GUI_SIZERULE_PERCENTOFPARENT, 100, 100};
  1206. inner->semantic_size[GUI_AXIS2_Y].size_rule = GUI_SIZERULE_PERCENTOFPARENT;
  1207. inner->semantic_size[GUI_AXIS2_Y].value = 100 * (*value);
  1208. gui_pop_parent(context);
  1209. *last_reference = new_reference;
  1210. *inner_box_reference = new_inner_reference;
  1211. if(value_changed) {node->dirty = true;}
  1212. return value_changed;
  1213. }
  1214. // ---
  1215. void test_gui(
  1216. GUI_Context *context,
  1217. GUI_Rectangle full_gui_rectangle)
  1218. {
  1219. static float border_thickness = 0;
  1220. float last_border_thickness = border_thickness;
  1221. static GUI_Style root_style = {42, 24, 88, 0,0,0};
  1222. static GUI_Style dumb_button_style = {88, 24, 42, 0,0,0};
  1223. static GUI_Size dumb_button_size[2] = {
  1224. {GUI_SIZERULE_PIXELS, 42, 100},
  1225. {GUI_SIZERULE_PIXELS, 24, 100}};
  1226. static GUI_Style other_dumb_button_style = {24, 42, 88, 0x0000ffff,0,0};
  1227. static GUI_Node_Reference root = {0};
  1228. root = gui_context_start_frame(
  1229. context, root,
  1230. full_gui_rectangle.x1-full_gui_rectangle.x0,
  1231. full_gui_rectangle.y1-full_gui_rectangle.y0,
  1232. GUI_LAYOUT_HORIZONTAL,
  1233. &root_style);
  1234. static GUI_Node_Reference dumb_button = {0};
  1235. if(my_bool)
  1236. if(gui_dumb_button(
  1237. context,
  1238. &dumb_button,
  1239. GUI_STRING("My Dumb Button"),
  1240. &dumb_button_style,
  1241. dumb_button_size))
  1242. {
  1243. printf(
  1244. "**************\n"
  1245. "*** BUTTON ***\n"
  1246. "**************\n");
  1247. border_thickness += 1;
  1248. if(border_thickness > 21) border_thickness = 21;
  1249. printf("border_thickness: %f\n", border_thickness);
  1250. my_bool = false;
  1251. ((GUI_Node*)root.node)->dirty = true;
  1252. }
  1253. static GUI_Node_Reference dumb_button2 = {0};
  1254. if(gui_dumb_button(
  1255. context,
  1256. &dumb_button2,
  1257. GUI_STRING("My Other Dumb Button"),
  1258. &other_dumb_button_style,
  1259. dumb_button_size))
  1260. {
  1261. printf(
  1262. "**************\n"
  1263. "*** OTHER ***\n"
  1264. "**************\n"
  1265. );
  1266. border_thickness -= 1;
  1267. if(border_thickness < 0) border_thickness = 0;
  1268. printf("border_thickness: %f\n", border_thickness);
  1269. my_bool = true;
  1270. }
  1271. if(my_bool)
  1272. {
  1273. static GUI_Style layout_style = {100, 0, 100,0,0,0};
  1274. static GUI_Size layout_size[2] = {
  1275. {GUI_SIZERULE_PIXELS, 400, 100},
  1276. {GUI_SIZERULE_PIXELS, 400, 100}};
  1277. static GUI_Node_Reference layout = {0};
  1278. layout = gui_layout(
  1279. context, layout, GUI_LAYOUT_VERTICAL, &layout_style, layout_size);
  1280. gui_push_parent(context, layout);
  1281. // static variables can be used for isolated styles that:
  1282. // 1) are only used within the current scope.
  1283. // 2) don't need to be changed at runtime.
  1284. static GUI_Style inner_block_2_style = {200, 253, 235, 0,0,0};
  1285. static GUI_Style inner_block_3_style = {235, 253, 200, 0,0,0};
  1286. static GUI_Style inner_block_4_style = {0 , 0, 0, 0,0,0};
  1287. static GUI_Node_Reference dumb_block2 = {0};
  1288. dumb_block2 = gui_dumb_block(
  1289. context,
  1290. dumb_block2,
  1291. &inner_block_2_style,
  1292. dumb_button_size);
  1293. static GUI_Node_Reference dumb_block3 = {0};
  1294. dumb_block3 = gui_dumb_block(
  1295. context,
  1296. dumb_block3,
  1297. &inner_block_3_style,
  1298. dumb_button_size);
  1299. static GUI_Node_Reference dumb_block4 = {0};
  1300. dumb_block4 = gui_dumb_block(
  1301. context,
  1302. dumb_block4,
  1303. &inner_block_4_style,
  1304. dumb_button_size);
  1305. static GUI_Node_Reference dumb_button3 = {0};
  1306. if(gui_dumb_button(
  1307. context,
  1308. &dumb_button3,
  1309. GUI_STRING("Inner Dumb Button"),
  1310. &dumb_button_style,
  1311. dumb_button_size))
  1312. {
  1313. printf(
  1314. "**************\n"
  1315. "*** INNER ***\n"
  1316. "**************\n"
  1317. );
  1318. }
  1319. static GUI_Size dumb_block5_size[2] = {
  1320. {GUI_SIZERULE_PERCENTOFPARENT, 42, 100},
  1321. {GUI_SIZERULE_PERCENTOFPARENT, 24, 100}};
  1322. static GUI_Node_Reference dumb_block5 = {0};
  1323. dumb_block5 = gui_dumb_block(
  1324. context,
  1325. dumb_block5,
  1326. &inner_block_4_style,
  1327. dumb_block5_size);
  1328. gui_pop_parent(context);
  1329. }
  1330. static GUI_Style slider_background = {0, 0, 0, 0,0,0};
  1331. static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
  1332. static GUI_Size slider_size[2] = {
  1333. {GUI_SIZERULE_PIXELS, 100, 100},
  1334. {GUI_SIZERULE_PIXELS, 40, 100}};
  1335. static GUI_Node_Reference slider = {0};
  1336. static GUI_Node_Reference slider_inner = {0};
  1337. static float slider_value = 0.25f;
  1338. //slider_bar.blue = 255 * slider_value;
  1339. //slider_value += 0.01f;
  1340. //if(slider_value >= 1.0f) slider_value = 0.5f;
  1341. // NOTE(Zelaven): This line is not good because it causes jankyness when using
  1342. // the slider, and the slider behaves properly without it.
  1343. // NOTE(Zelaven): This line is actually necessary if the value is writable by
  1344. // anything other than the slider. If border_thickness is a float variable,
  1345. // then there is no issue, though.
  1346. slider_value = ((float)border_thickness) / 21.;
  1347. bool slider_value_changed = gui_slider(
  1348. context,
  1349. &slider, &slider_inner,
  1350. &slider_value,
  1351. &slider_background,
  1352. &slider_bar,
  1353. slider_size);
  1354. border_thickness = 21.*slider_value;
  1355. //printf("Slider value changed?: %b\n", slider_value_changed);
  1356. ((GUI_Node*)root.node)->dirty |= slider_value_changed;
  1357. static GUI_Style block_after_layout_style = {99, 99, 99, 0,0,0};
  1358. static GUI_Size block_after_layout_size[2] = {
  1359. {GUI_SIZERULE_PIXELS, 50, 100},
  1360. {GUI_SIZERULE_PIXELS, 50, 100}};
  1361. static GUI_Node_Reference dumb_block_after_layout = {0};
  1362. dumb_block_after_layout = gui_dumb_block(
  1363. context,
  1364. dumb_block_after_layout,
  1365. &block_after_layout_style,
  1366. block_after_layout_size);
  1367. static GUI_Style my_style = {100, 100, 0, 0, 3, 0};
  1368. static GUI_Size dumb_block_size[2] = {
  1369. {GUI_SIZERULE_PIXELS, 50, 100},
  1370. {GUI_SIZERULE_PIXELS, 100, 100},
  1371. };
  1372. my_style.border_thickness = border_thickness;
  1373. static GUI_Node_Reference new_style_gui_dumb_block = {0};
  1374. new_style_gui_dumb_block = gui_dumb_block(
  1375. context,
  1376. new_style_gui_dumb_block,
  1377. &my_style,
  1378. dumb_block_size);
  1379. other_dumb_button_style.border_thickness = border_thickness;
  1380. if(border_thickness != last_border_thickness) {
  1381. ((GUI_Node*)root.node)->dirty = true;
  1382. }
  1383. gui_context_finish_frame(context);
  1384. }
  1385. // Text field at the top, 4x4 button grid below.
  1386. // See the nuklear example calculator?
  1387. void test_gui__calculator(
  1388. GUI_Context *context,
  1389. GUI_Rectangle full_gui_rectangle)
  1390. {
  1391. (void)full_gui_rectangle;
  1392. static GUI_Style root_style = {0x44,0x44,0x44, 0x00999999,2,0};
  1393. static GUI_Style button_style = {0x33,0x33,0x33, 0x00999999,2,25};
  1394. static GUI_Size button_size[2] = {
  1395. {GUI_SIZERULE_PERCENTOFPARENT, 25, 100},
  1396. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1397. static GUI_Style row_style = {0x44,0x44,0x44, 0,0,0};
  1398. static GUI_Size row_size[2] = {
  1399. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1400. {GUI_SIZERULE_PERCENTOFPARENT, 25, 100}};
  1401. static GUI_Node_Reference root = {0};
  1402. root = gui_context_start_frame(
  1403. context, root,
  1404. //full_gui_rectangle.x1-full_gui_rectangle.x0,
  1405. //full_gui_rectangle.y1-full_gui_rectangle.y0,
  1406. 300, 400,
  1407. GUI_LAYOUT_VERTICAL,
  1408. &root_style);
  1409. #if 1
  1410. static GUI_Node_Reference rows[4] = {0};
  1411. static GUI_Node_Reference buttons[4][4] = {0};
  1412. GUI_String button_labels[4][4] = {
  1413. {GUI_STRING("1"), GUI_STRING("2"), GUI_STRING("3"), GUI_STRING("+")},
  1414. {GUI_STRING("4"), GUI_STRING("5"), GUI_STRING("6"), GUI_STRING("-")},
  1415. {GUI_STRING("7"), GUI_STRING("8"), GUI_STRING("9"), GUI_STRING("*")},
  1416. {GUI_STRING("C"), GUI_STRING("0"), GUI_STRING("="), GUI_STRING("/")},
  1417. };
  1418. for(size_t row = 0; row < ARRAYLENGTH(rows); row++)
  1419. {
  1420. rows[row] = gui_layout(
  1421. context, rows[row], GUI_LAYOUT_HORIZONTAL, &row_style, row_size);
  1422. gui_push_parent(context, rows[row]);
  1423. for(size_t i = 0; i < ARRAYLENGTH(buttons[0]); i++)
  1424. {
  1425. if(gui_dumb_button(
  1426. context, &buttons[row][i],
  1427. button_labels[row][i],
  1428. &button_style, button_size))
  1429. {
  1430. GUI_String button_label = button_labels[row][i];
  1431. printf("%.*s\n", button_label.length, button_label.cstring);
  1432. }
  1433. }
  1434. gui_pop_parent(context);
  1435. }
  1436. #else
  1437. static GUI_Node_Reference row1 = {0};
  1438. row1 = gui_layout2(
  1439. context, row1, GUI_LAYOUT_HORIZONTAL, &row_style, row_size);
  1440. gui_push_parent(context, row1);
  1441. static GUI_Node_Reference row1_buttons[4] = {0};
  1442. char *row1_button_labels[4] = {"1", "2", "3", "+"};
  1443. for(size_t i = 0; i < ARRAYLENGTH(row1_buttons); i++)
  1444. {
  1445. if(gui_dumb_button(
  1446. context, &row1_buttons[i],
  1447. row1_button_labels[i],
  1448. &button_style, button_size))
  1449. {
  1450. printf("%s\n", row1_button_labels[i]);
  1451. }
  1452. }
  1453. gui_pop_parent(context);
  1454. #endif
  1455. gui_context_finish_frame(context);
  1456. }
  1457. void test_gui__scrollbars(
  1458. GUI_Context *context,
  1459. GUI_Rectangle full_gui_rectangle)
  1460. {
  1461. (void)full_gui_rectangle;
  1462. static GUI_Style root_style = {0x44,0x44,0x44, 0x00999999,2,0};
  1463. static GUI_Style element_style = {0,0x33,0x33, 0x00009999,2,0};
  1464. static GUI_Size element_size[2] = {
  1465. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1466. {GUI_SIZERULE_PIXELS, 100, 100}};
  1467. static GUI_Style outer_style = {0x33,0x33,0x33, 0x00999999,2,0};
  1468. static GUI_Size top_bottom_size[2] = {
  1469. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1470. {GUI_SIZERULE_PERCENTOFPARENT, 25, 100}};
  1471. static GUI_Size middle_size[2] = {
  1472. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1473. {GUI_SIZERULE_PERCENTOFPARENT, 50, 100}};
  1474. static GUI_Size side_size[2] = {
  1475. {GUI_SIZERULE_PERCENTOFPARENT, 25, 100},
  1476. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1477. static GUI_Size center_size[2] = {
  1478. {GUI_SIZERULE_PERCENTOFPARENT, 50, 100},
  1479. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1480. static GUI_Node_Reference root = {0};
  1481. root = gui_context_start_frame(
  1482. context, root,
  1483. full_gui_rectangle.x1-full_gui_rectangle.x0,
  1484. full_gui_rectangle.y1-full_gui_rectangle.y0,
  1485. //300, 400,
  1486. GUI_LAYOUT_VERTICAL,
  1487. &root_style);
  1488. static GUI_Node_Reference top = {0};
  1489. static GUI_Node_Reference middle = {0};
  1490. static GUI_Node_Reference bottom = {0};
  1491. top = gui_dumb_block(context, top, &outer_style, top_bottom_size);
  1492. middle = gui_layout(
  1493. context, middle, GUI_LAYOUT_HORIZONTAL, &outer_style, middle_size);
  1494. gui_push_parent(context, middle);
  1495. {
  1496. static GUI_Node_Reference left = {0};
  1497. static GUI_Node_Reference center = {0};
  1498. static GUI_Node_Reference right = {0};
  1499. left = gui_dumb_block(context, left, &outer_style, side_size);
  1500. center = gui_dumb_block(context, center, &outer_style, center_size);
  1501. gui_push_parent(context, center);
  1502. {
  1503. static GUI_Node_Reference scrollbox_layout = {0};
  1504. static GUI_Size full_size[2] = {
  1505. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1506. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1507. scrollbox_layout = gui_layout(
  1508. context, scrollbox_layout, GUI_LAYOUT_HORIZONTAL, &outer_style, full_size);
  1509. gui_push_parent(context, scrollbox_layout);
  1510. {
  1511. static GUI_Node_Reference scrollregion_layout = {0};
  1512. static GUI_Size scrollregion_size[2] = {
  1513. {GUI_SIZERULE_PERCENTOFPARENT, 90, 100},
  1514. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1515. static GUI_Size scrollbar_size[2] = {
  1516. {GUI_SIZERULE_PERCENTOFPARENT, 10, 100},
  1517. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1518. #if 0
  1519. scrollregion_layout = gui_layout(
  1520. context, scrollregion_layout, GUI_LAYOUT_VERTICAL,
  1521. &outer_style, scrollregion_size);
  1522. gui_push_parent(context, scrollregion_layout);
  1523. {
  1524. static GUI_Node_Reference elements[6] = {0};
  1525. for(size_t i = 0; i < ARRAYLENGTH(elements); i++) {
  1526. elements[i] = gui_dumb_block(
  1527. context, elements[i], &element_style, element_size);
  1528. }
  1529. } gui_pop_parent(context);
  1530. #else
  1531. scrollregion_layout = gui_dumb_block(
  1532. context, scrollregion_layout, &outer_style, scrollregion_size);
  1533. static GUI_Subtree_Reference scrollregion_subtree = {0};
  1534. scrollregion_subtree = gui_get_subtree(context, scrollregion_subtree);
  1535. static GUI_Node_Reference scrollregion_root = {0};
  1536. static GUI_Size scrollregion_inner_size[2] = {
  1537. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1538. //{GUI_SIZERULE_PIXELS, 100, 100},
  1539. {GUI_SIZERULE_PIXELS, 880, 100}};
  1540. scrollregion_root = gui_push_subtree(
  1541. context, scrollregion_subtree, scrollregion_root,
  1542. GUI_LAYOUT_VERTICAL, &outer_style, scrollregion_inner_size,
  1543. scrollbox_layout);
  1544. // TODO(Zelaven): Instead of this hack, add to the layout code that it
  1545. // can set the size of the root relative to the size of its relative
  1546. // node.
  1547. scrollregion_root.rdic_ref.node->parent = scrollregion_layout.rdic_ref.node;
  1548. {
  1549. static GUI_Node_Reference elements[6] = {0};
  1550. for(size_t i = 0; i < ARRAYLENGTH(elements); i++) {
  1551. elements[i] = gui_dumb_block(
  1552. context, elements[i], &element_style, element_size);
  1553. }
  1554. } gui_pop_subtree(context);
  1555. #endif
  1556. #if 0
  1557. static GUI_Node_Reference scrollbar_layout = {0};
  1558. scrollbar_layout = gui_layout(
  1559. context, scrollbar_layout, GUI_LAYOUT_VERTICAL,
  1560. &outer_style, scrollbar_size);
  1561. float scroll_position = 0.75f;
  1562. int spacer_total = 90;
  1563. int spacer_upper = scroll_position * spacer_total;
  1564. int spacer_lower = spacer_total - spacer_upper;
  1565. gui_push_parent(context, scrollbar_layout);
  1566. {
  1567. static GUI_Size bar_knob_size[2] = {
  1568. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1569. {GUI_SIZERULE_PERCENTOFPARENT, 10, 100}};
  1570. // NOTE(Zelaven): These sizes are unique to each scrollbar.
  1571. static GUI_Size bar_upper_spacer_size[2] = {
  1572. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1573. {GUI_SIZERULE_PERCENTOFPARENT, 0, 100}};
  1574. static GUI_Size bar_lower_spacer_size[2] = {
  1575. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1576. {GUI_SIZERULE_PERCENTOFPARENT, 90, 100}};
  1577. bar_upper_spacer_size[GUI_AXIS2_Y].value = spacer_upper;
  1578. bar_lower_spacer_size[GUI_AXIS2_Y].value = spacer_lower;
  1579. static GUI_Node_Reference scrollbar_upper_spacer = {0};
  1580. static GUI_Node_Reference scrollbar_knob = {0};
  1581. static GUI_Node_Reference scrollbar_lower_spacer = {0};
  1582. scrollbar_upper_spacer = gui_dumb_block(
  1583. context, scrollbar_upper_spacer, &outer_style, bar_upper_spacer_size);
  1584. scrollbar_knob = gui_dumb_block(
  1585. context, scrollbar_knob, &outer_style, bar_knob_size);
  1586. scrollbar_lower_spacer = gui_dumb_block(
  1587. context, scrollbar_lower_spacer, &outer_style, bar_lower_spacer_size);
  1588. } gui_pop_parent(context); // scrollbar_layout.
  1589. #else
  1590. static float slider_value = 0.0f;
  1591. static GUI_Style slider_background = {0, 0, 0, 0,0,0};
  1592. static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
  1593. static GUI_Node_Reference slider = {0};
  1594. static GUI_Node_Reference slider_inner = {0};
  1595. gui_vertical_slider(context, &slider, &slider_inner,
  1596. &slider_value, &slider_background, &slider_bar, scrollbar_size);
  1597. scrollregion_subtree.node->offset_relative_node_percentage_y =
  1598. slider_value*100;
  1599. scrollregion_subtree.node->offset_own_size_percentage_y =
  1600. slider_value*-100;
  1601. scrollregion_root.node->dirty = true;
  1602. //((GUI_Node*)slider.node)->dirty;
  1603. //printf("Slider value: %f\n", slider_value);
  1604. #endif
  1605. } gui_pop_parent(context); // scrollbox_layout.
  1606. } gui_pop_parent(context); // center.
  1607. right = gui_dumb_block(context, right, &outer_style, side_size);
  1608. } gui_pop_parent(context); // middle.
  1609. bottom = gui_dumb_block(context, bottom, &outer_style, top_bottom_size);
  1610. gui_context_finish_frame(context);
  1611. }
  1612. void test_gui__draw_command_using_sliders(
  1613. GUI_Context *context,
  1614. GUI_Rectangle full_gui_rectangle)
  1615. {
  1616. //static float border_thickness = 0;
  1617. static GUI_Style root_style = {42, 24, 88, 0,0,0};
  1618. static GUI_Node_Reference root = {0};
  1619. root = gui_context_start_frame(
  1620. context, root,
  1621. full_gui_rectangle.x1-full_gui_rectangle.x0,
  1622. full_gui_rectangle.y1-full_gui_rectangle.y0,
  1623. GUI_LAYOUT_VERTICAL,
  1624. &root_style);
  1625. static GUI_Size layout_size[2] = {
  1626. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1627. {GUI_SIZERULE_PERCENTOFPARENT, 50, 100}};
  1628. static GUI_Node_Reference layout = {0};
  1629. layout = gui_layout(
  1630. context, layout, GUI_LAYOUT_VERTICAL, &root_style, layout_size);
  1631. gui_push_parent(context, layout);
  1632. {
  1633. static GUI_Style slider_background = {0, 0, 0, 0,0,0};
  1634. static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
  1635. static GUI_Size slider_size[2] = {
  1636. {GUI_SIZERULE_PIXELS, 200, 100},
  1637. {GUI_SIZERULE_PIXELS, 40, 100}};
  1638. static GUI_Node_Reference slider = {0};
  1639. static GUI_Node_Reference slider_inner = {0};
  1640. static GUI_Style button_style = {200, 0, 0, 0,5,0};
  1641. static GUI_Size button_size[2] = {
  1642. {GUI_SIZERULE_PIXELS, 100, 100},
  1643. {GUI_SIZERULE_PIXELS, 40, 100}};
  1644. static GUI_Style slider_spacer_style = {99, 99, 99, 0,0,0};
  1645. static GUI_Size slider_spacer_size[2] = {
  1646. {GUI_SIZERULE_PIXELS, 200, 100},
  1647. {GUI_SIZERULE_PIXELS, 5, 100}};
  1648. static GUI_Style button_spacer_style = {99, 99, 99, 0,0,0};
  1649. static GUI_Size button_spacer_size[2] = {
  1650. {GUI_SIZERULE_PIXELS, 5, 100},
  1651. {GUI_SIZERULE_PIXELS, 40, 100}};
  1652. static GUI_Size row_layout_size[2] = {
  1653. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1654. {GUI_SIZERULE_PIXELS, 40, 100}};
  1655. static GUI_Node_Reference row1_layout = {0};
  1656. row1_layout = gui_layout(
  1657. context, row1_layout, GUI_LAYOUT_HORIZONTAL, &root_style, row_layout_size);
  1658. #if 1
  1659. gui_push_parent(context, row1_layout);
  1660. {
  1661. static float slider_value = 0.25f;
  1662. // NOTE(Zelaven): This line is not good because it causes jankyness when
  1663. // using the slider, and the slider behaves properly without it.
  1664. // NOTE(Zelaven): This line is actually necessary if the value is writable
  1665. // by anything other than the slider. If border_thickness is a float
  1666. // variable, then there is no issue, though.
  1667. slider_value = ((float)border_thickness) / 51.;
  1668. gui_slider(context, &slider, &slider_inner,
  1669. &slider_value, &slider_background, &slider_bar, slider_size);
  1670. border_thickness = 51.*slider_value;
  1671. static GUI_Node_Reference spacer1 = {0};
  1672. spacer1 = gui_dumb_block(
  1673. context, spacer1, &button_spacer_style, button_spacer_size);
  1674. static GUI_Node_Reference button_thickness_down = {0};
  1675. if(gui_dumb_button(context, &button_thickness_down,
  1676. GUI_STRING("-"), &button_style, button_size))
  1677. {
  1678. border_thickness -= 1;
  1679. printf("-\n");
  1680. }
  1681. static GUI_Node_Reference spacer2 = {0};
  1682. spacer2 = gui_dumb_block(
  1683. context, spacer2, &button_spacer_style, button_spacer_size);
  1684. static GUI_Node_Reference button_thickness_up = {0};
  1685. if(gui_dumb_button(context, &button_thickness_up,
  1686. GUI_STRING("+"), &button_style, button_size))
  1687. {
  1688. border_thickness += 1;
  1689. printf("+\n");
  1690. }
  1691. }
  1692. gui_pop_parent(context);
  1693. #endif
  1694. static GUI_Node_Reference slider_spacer = {0};
  1695. slider_spacer = gui_dumb_block(
  1696. context, slider_spacer, &slider_spacer_style, slider_spacer_size);
  1697. static GUI_Node_Reference slider2 = {0};
  1698. static GUI_Node_Reference slider2_inner = {0};
  1699. static float slider2_value = 0.25f;
  1700. slider2_value = ((float)roundedness) / 100.;
  1701. gui_slider(context, &slider2, &slider2_inner,
  1702. &slider2_value, &slider_background, &slider_bar, slider_size);
  1703. roundedness = 100.*slider2_value;
  1704. }
  1705. gui_pop_parent(context);
  1706. gui_context_finish_frame(context);
  1707. }
  1708. #if 1
  1709. void test_gui__subtree(
  1710. GUI_Context *context,
  1711. GUI_Rectangle full_gui_rectangle)
  1712. {
  1713. static GUI_Style root_style = {0x44,0x33,0x33, 0x00999999,2,0};
  1714. static GUI_Style element_style = {0,0x33,0x33, 0x00009999,2,0};
  1715. static GUI_Size element_size[2] = {
  1716. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1717. {GUI_SIZERULE_PIXELS, 100, 100}};
  1718. static GUI_Style outer_style = {0x33,0x33,0x33, 0x00999999,2,0};
  1719. static GUI_Size top_bottom_size[2] = {
  1720. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1721. {GUI_SIZERULE_PERCENTOFPARENT, 25, 100}};
  1722. static GUI_Size middle_size[2] = {
  1723. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1724. {GUI_SIZERULE_PERCENTOFPARENT, 50, 100}};
  1725. static GUI_Size test_size[2] = {
  1726. {GUI_SIZERULE_PIXELS, 200, 100},
  1727. {GUI_SIZERULE_PIXELS, 600, 100}};
  1728. static GUI_Node_Reference root = {0};
  1729. root = gui_context_start_frame(
  1730. context, root,
  1731. full_gui_rectangle.x1-full_gui_rectangle.x0,
  1732. full_gui_rectangle.y1-full_gui_rectangle.y0,
  1733. GUI_LAYOUT_VERTICAL,
  1734. &root_style);
  1735. static GUI_Node_Reference top_root = {0};
  1736. top_root = gui_context_prepare_layer(
  1737. context, &context->top_layer, top_root,
  1738. context->top_layer.pixel_buffer->width,
  1739. context->top_layer.pixel_buffer->height,
  1740. GUI_LAYOUT_HORIZONTAL, &outer_style);
  1741. context->top_layer.offset_x = 70;
  1742. context->top_layer.offset_y = 20;
  1743. static GUI_Node_Reference top = {0};
  1744. static GUI_Node_Reference middle = {0};
  1745. static GUI_Node_Reference bottom = {0};
  1746. static GUI_Node_Reference slider = {0};
  1747. static float slider_value = 0.25f;
  1748. bool should_dirty = false;
  1749. bool set_pixels = false;
  1750. top = gui_layout(
  1751. context, top, GUI_LAYOUT_HORIZONTAL, &outer_style, top_bottom_size);
  1752. gui_push_parent(context, top);
  1753. {
  1754. static GUI_Style slider_background = {0, 0, 0, 0,0,0};
  1755. static GUI_Style slider_bar = {255, 0, 0, 0,0,0};
  1756. static GUI_Size slider_size[2] = {
  1757. {GUI_SIZERULE_PIXELS, 200, 100},
  1758. {GUI_SIZERULE_PIXELS, 40, 100}};
  1759. //static GUI_Node_Reference slider = {0};
  1760. static GUI_Node_Reference slider_inner = {0};
  1761. gui_slider(context, &slider, &slider_inner,
  1762. &slider_value, &slider_background, &slider_bar, slider_size);
  1763. static GUI_Node_Reference dirty_button = {0};
  1764. static GUI_Style button_style = {0x99,0x99,0x99, 0x00222222,2,0};
  1765. static GUI_Size button_size[2] = {
  1766. {GUI_SIZERULE_PIXELS, 170, 100},
  1767. {GUI_SIZERULE_PIXELS, 40, 100}};
  1768. if(gui_dumb_button(
  1769. context, &dirty_button, GUI_STRING("Dirty middle"),
  1770. &button_style, button_size))
  1771. {
  1772. should_dirty = true;
  1773. printf("Dirtying middle.\n");
  1774. }
  1775. static GUI_Node_Reference dirty_button2 = {0};
  1776. if(gui_dumb_button(
  1777. context, &dirty_button2, GUI_STRING("Set Pixels"),
  1778. &button_style, button_size))
  1779. {
  1780. set_pixels = true;
  1781. printf("Setting pixels.\n");
  1782. }
  1783. static bool tooltip_toggle = false;
  1784. static GUI_Node_Reference dirty_button3 = {0};
  1785. if(gui_dumb_button(
  1786. context, &dirty_button3, GUI_STRING("Toggle tooltip"),
  1787. &button_style, button_size))
  1788. {
  1789. tooltip_toggle = !tooltip_toggle;
  1790. printf("Toggling tooltip.\n");
  1791. }
  1792. static GUI_Node_Reference dirty_button4 = {0};
  1793. if(
  1794. gui_mouseover_box(
  1795. context, &dirty_button4, GUI_STRING("Hover for tooltip"),
  1796. &button_style, button_size)
  1797. || tooltip_toggle)
  1798. {
  1799. GUI_ON_LAYER(context, &context->top_layer)
  1800. {
  1801. static GUI_Size full_size[2] = {
  1802. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
  1803. {GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
  1804. static GUI_Node_Reference top_layer_block = {0};
  1805. if(gui_dumb_button(
  1806. context, &top_layer_block, GUI_STRING("Hi!"),
  1807. &element_style, full_size))
  1808. {
  1809. printf("Top layer says hi!\n");
  1810. }
  1811. }
  1812. }
  1813. } gui_pop_parent(context); // middle.
  1814. middle = gui_dumb_block(context, middle, &outer_style, middle_size);
  1815. #if 1
  1816. static GUI_Subtree_Reference middle_subtree = {0};
  1817. middle_subtree = gui_get_subtree(context, middle_subtree);
  1818. static GUI_Node_Reference middle_subtree_root = {0};
  1819. middle_subtree_root = gui_push_subtree(
  1820. context, middle_subtree, middle_subtree_root,
  1821. GUI_LAYOUT_VERTICAL, &element_style, test_size, middle);
  1822. {
  1823. static GUI_Color test_image_pixels[10*12] = {
  1824. 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
  1825. ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
  1826. 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
  1827. ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
  1828. 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
  1829. ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
  1830. 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
  1831. ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
  1832. 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0,
  1833. ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0,
  1834. ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
  1835. ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
  1836. };
  1837. static Pixel_Buffer test_image = {
  1838. .pixels = test_image_pixels,
  1839. .width = 10,
  1840. .height = 12,
  1841. };
  1842. static GUI_Node_Reference inner_top = {0};
  1843. inner_top = gui_dumb_block(context, inner_top, &outer_style, element_size);
  1844. ((GUI_Node*)inner_top.node)->image = &test_image;
  1845. static GUI_Node_Reference subtree_button = {0};
  1846. if(gui_dumb_button(
  1847. context, &subtree_button, GUI_STRING("In subtree"),
  1848. &element_style, element_size))
  1849. {
  1850. printf("Hi from subtree!\n");
  1851. }
  1852. } gui_pop_subtree(context);
  1853. #endif
  1854. #if 0
  1855. int middle_height =
  1856. ((GUI_Node*)middle.node)->computed_size[GUI_AXIS2_Y];
  1857. int subtree_height =
  1858. ((GUI_Node*)middle_subtree_root.node)->computed_size[GUI_AXIS2_Y];
  1859. int overfill = subtree_height - middle_height;
  1860. printf("\n%d = %d - %d\n", overfill, subtree_height, middle_height);
  1861. if(overfill >= 0)
  1862. {
  1863. printf("?\n");
  1864. middle_subtree.flat_offset_y = -(slider_value * overfill);
  1865. printf("%d\n", middle_subtree.flat_offset_x);
  1866. }
  1867. else
  1868. {
  1869. middle_subtree.flat_offset_y = 0;
  1870. }
  1871. #else
  1872. //printf("slider value: %f\n", slider_value);
  1873. middle_subtree.node->offset_relative_node_percentage_y = slider_value*100;
  1874. middle_subtree.node->offset_own_size_percentage_y = slider_value*-100;
  1875. #endif
  1876. middle_subtree_root.node->dirty = ((GUI_Node*)slider.node)->dirty;
  1877. bottom = gui_dumb_block(context, bottom, &element_style, top_bottom_size);
  1878. middle.node->dirty |= should_dirty;
  1879. if(set_pixels)
  1880. {
  1881. #define SET_PIXEL(pixel_buffer, x, y, color) (pixel_buffer)->pixels[(y)*(pixel_buffer)->width + (x)] = (color)
  1882. Pixel_Buffer *pixbuf = context->background_layer.pixel_buffer;
  1883. SET_PIXEL(pixbuf, 500, 500, 0x00ff0000);
  1884. SET_PIXEL(pixbuf, 500, 501, 0);
  1885. SET_PIXEL(pixbuf, 501, 500, 0);
  1886. SET_PIXEL(pixbuf, 501, 501, 0);
  1887. SET_PIXEL(pixbuf, 500, 900, 0x00ff0000);
  1888. SET_PIXEL(pixbuf, 500, 901, 0);
  1889. SET_PIXEL(pixbuf, 501, 900, 0);
  1890. SET_PIXEL(pixbuf, 501, 901, 0);
  1891. #undef SET_PIXEL
  1892. }
  1893. gui_context_finish_frame(context);
  1894. }
  1895. #endif
  1896. void test_gui__tmp(
  1897. GUI_Context *context,
  1898. GUI_Rectangle full_gui_rectangle)
  1899. {
  1900. static GUI_Style root_style = {0x44,0x33,0x33, 0x00999999,2,0};
  1901. static GUI_Style block_style = {0x33,0x33,0x33, 0x00999999,2,0};
  1902. static GUI_Size block_size[2] = {
  1903. {GUI_SIZERULE_PIXELS, 200, 100},
  1904. {GUI_SIZERULE_PIXELS, 200, 100}};
  1905. static GUI_Node_Reference root = {0};
  1906. root = gui_context_start_frame(
  1907. context, root,
  1908. full_gui_rectangle.x1-full_gui_rectangle.x0,
  1909. full_gui_rectangle.y1-full_gui_rectangle.y0,
  1910. GUI_LAYOUT_VERTICAL,
  1911. &root_style);
  1912. static GUI_Node_Reference block1 = {0};
  1913. static GUI_Node_Reference empty_layout = {0};
  1914. static GUI_Node_Reference block2 = {0};
  1915. block1 = gui_dumb_block(context, block1, &block_style, block_size);
  1916. empty_layout = gui_layout(
  1917. context, empty_layout, GUI_LAYOUT_HORIZONTAL, &block_style, block_size);
  1918. gui_push_parent(context, empty_layout);
  1919. {
  1920. } gui_pop_parent(context);
  1921. block2 = gui_dumb_block(context, block2, &block_style, block_size);
  1922. gui_context_finish_frame(context);
  1923. }
  1924. #if 0
  1925. void test_gui_layout(
  1926. GUI_Context *context,
  1927. GUI_Rectangle full_gui_rectangle)
  1928. {
  1929. static RDIC_Node_Reference root = {0};
  1930. root = gui_context_start_frame(
  1931. context, root,
  1932. full_gui_rectangle.x1-full_gui_rectangle.x0,
  1933. full_gui_rectangle.y1-full_gui_rectangle.y0,
  1934. GUI_LAYOUT_HORIZONTAL);
  1935. static RDIC_Node_Reference dumb_block = {0};
  1936. #if 0
  1937. dumb_block = gui_dumb_block(
  1938. context,
  1939. dumb_block,
  1940. (GUI_Style){255, 0, 0,0,0,0},
  1941. 50, 50);
  1942. #else
  1943. if(gui_dumb_button(
  1944. context, &dumb_block, "BEFORE Button", (GUI_Style){255, 0, 0,0,0,0}, 50, 50))
  1945. {printf(
  1946. "**************\n"
  1947. "*** BEFORE ***\n"
  1948. "**************\n");}
  1949. #endif
  1950. static RDIC_Node_Reference layout = {0};
  1951. layout = gui_layout(
  1952. context,
  1953. layout,
  1954. GUI_LAYOUT_VERTICAL);
  1955. gui_push_parent(context, layout);
  1956. static RDIC_Node_Reference dumb_block2 = {0};
  1957. #if 0
  1958. dumb_block2 = gui_dumb_block(
  1959. context,
  1960. dumb_block2,
  1961. (GUI_Style){0, 255, 0,0,0,0},
  1962. 100, 50);
  1963. #else
  1964. if(gui_dumb_button(
  1965. context, &dumb_block2, "INSIDE Button", (GUI_Style){0, 255, 0,0,0,0}, 100, 50))
  1966. {printf(
  1967. "**************\n"
  1968. "*** INSIDE ***\n"
  1969. "**************\n");}
  1970. #endif
  1971. gui_pop_parent(context);
  1972. static RDIC_Node_Reference dumb_block3 = {0};
  1973. #if 0
  1974. dumb_block_after_layout = gui_dumb_block(
  1975. context,
  1976. dumb_block3,
  1977. (GUI_Style){0, 0, 255,0,0,0},
  1978. 150, 50);
  1979. #else
  1980. if(gui_dumb_button(
  1981. context, &dumb_block3, "AFTER Button", (GUI_Style){0, 0, 255,0,0,0}, 150, 50))
  1982. {printf(
  1983. "**************\n"
  1984. "*** AFTER ***\n"
  1985. "**************\n");}
  1986. #endif
  1987. gui_context_finish_frame(context);
  1988. }
  1989. #endif
  1990. // ---
  1991. // ---
  1992. // ---
  1993. #include <X11/Xlib.h>
  1994. #include <X11/Xutil.h>
  1995. #include <X11/Xatom.h>
  1996. #define WINDOW_WIDTH 800
  1997. #define WINDOW_HEIGHT 600
  1998. typedef struct X11_Window {
  1999. Display *display;
  2000. Window root;
  2001. Visual *visual;
  2002. Colormap colormap;
  2003. XWindowAttributes window_attributes;
  2004. XSetWindowAttributes set_window_attributes;
  2005. Window window;
  2006. GC graphics_context;
  2007. int screen;
  2008. unsigned int width;
  2009. unsigned int height;
  2010. XImage *screen_image;
  2011. Pixel_Buffer pixel_buffer;
  2012. } X11_Window;
  2013. #include <stdlib.h>
  2014. #include <stdarg.h>
  2015. #include <stdnoreturn.h>
  2016. #include <stdio.h>
  2017. noreturn void die(const char *fmt, ...)
  2018. {
  2019. va_list args;
  2020. va_start(args, fmt);
  2021. vfprintf(stderr, fmt, args);
  2022. va_end(args);
  2023. exit(EXIT_FAILURE);
  2024. }
  2025. void print_binary_long(long value)
  2026. {
  2027. int num_bits = sizeof(long)*8;
  2028. unsigned long mask = ((unsigned long)1) << (num_bits-1);
  2029. while(mask != (unsigned long)0)
  2030. {
  2031. int bit = (value & mask) != 0;
  2032. printf("%d", bit);
  2033. mask >>= 1;
  2034. }
  2035. }
  2036. void fill_pixel_buffer(
  2037. uint32_t *pixels,
  2038. unsigned int width,
  2039. unsigned int height,
  2040. uint8_t red_offset,
  2041. uint8_t blue_offset)
  2042. {
  2043. for(unsigned int column = 0; column < width; column++)
  2044. {
  2045. for(unsigned int row = 0; row < height; row++)
  2046. {
  2047. uint8_t red = (uint8_t)((column+ red_offset) & 0xFF);
  2048. uint8_t blue = (uint8_t)((row +blue_offset) & 0xFF);
  2049. pixels[column + row*width] = (red<<16) | blue;
  2050. }
  2051. }
  2052. }
  2053. void draw_window(
  2054. X11_Window *xwindow)
  2055. {
  2056. /*
  2057. int XPutImage(Display *display, Drawable d, GC gc, XImage *image, int src_x, int src_y, int
  2058. dest_x, int dest_y, unsigned int width, unsigned int height);
  2059. */
  2060. int error = XPutImage(
  2061. xwindow->display,
  2062. xwindow->window,
  2063. xwindow->graphics_context,
  2064. xwindow->screen_image,
  2065. 0, 0,
  2066. 0, 0,
  2067. xwindow->width, xwindow->height);
  2068. assert(error == 0);
  2069. }
  2070. typedef unsigned int uint;
  2071. void draw_rect(
  2072. uint32_t *pixels,
  2073. unsigned int width,
  2074. unsigned int height,
  2075. uint x0, uint y0, uint x1, uint y1,
  2076. uint32_t color)
  2077. {
  2078. //x0 = x0 < 0 ? 0 : x0;
  2079. //y0 = y0 < 0 ? 0 : y0;
  2080. x1 = x1 > width ? width : x1;
  2081. y1 = y1 > width ? height : y1;
  2082. for(unsigned int column = x0; column < x1; column++)
  2083. {
  2084. for(unsigned int row = y0; row < y1; row++)
  2085. {
  2086. pixels[column + row*width] = color;
  2087. }
  2088. }
  2089. }
  2090. void draw_rect2(
  2091. Pixel_Buffer *pixel_buffer,
  2092. GUI_Draw_Command *draw_command)
  2093. {
  2094. int width = pixel_buffer->width;
  2095. int height = pixel_buffer->height;
  2096. int x0 = draw_command->rectangle.x0;
  2097. int y0 = draw_command->rectangle.y0;
  2098. int x1 = draw_command->rectangle.x1;
  2099. int y1 = draw_command->rectangle.y1;
  2100. x0 = x0 < 0 ? 0 : x0;
  2101. y0 = y0 < 0 ? 0 : y0;
  2102. x1 = x1 > width ? width : x1;
  2103. y1 = y1 > width ? height : y1;
  2104. for(int column = x0; column < x1; column++)
  2105. {
  2106. for(int row = y0; row < y1; row++)
  2107. {
  2108. pixel_buffer->pixels[column + row*width] = draw_command->color;
  2109. }
  2110. }
  2111. }
  2112. void draw_rect3(
  2113. Pixel_Buffer *pixel_buffer,
  2114. GUI_Rectangle rectangle,
  2115. GUI_Color color)
  2116. {
  2117. int width = pixel_buffer->width;
  2118. int height = pixel_buffer->height;
  2119. int x0 = rectangle.x0;
  2120. int y0 = rectangle.y0;
  2121. int x1 = rectangle.x1;
  2122. int y1 = rectangle.y1;
  2123. x0 = x0 < 0 ? 0 : x0;
  2124. y0 = y0 < 0 ? 0 : y0;
  2125. x1 = x1 > width ? width : x1;
  2126. y1 = y1 > height ? height : y1;
  2127. for(int column = x0; column < x1; column++)
  2128. {
  2129. for(int row = y0; row < y1; row++)
  2130. {
  2131. pixel_buffer->pixels[column + row*width] = color;
  2132. }
  2133. }
  2134. }
  2135. #define SET_PIXEL(pixel_buffer, x, y, color) (pixel_buffer)->pixels[(y)*(pixel_buffer)->width + (x)] = (color)
  2136. #define GET_PIXEL(pixel_buffer, x, y) (pixel_buffer)->pixels[(y)*(pixel_buffer)->width + (x)]
  2137. void test_draw_horizontal_pixel_line(
  2138. Pixel_Buffer *pixel_buffer,
  2139. int x0, int x1, int y,
  2140. GUI_Color color)
  2141. {
  2142. for(int i = x0; i < x1; i++)
  2143. {
  2144. SET_PIXEL(pixel_buffer, i, y, color);
  2145. }
  2146. }
  2147. void test_draw_vertical_pixel_line(
  2148. Pixel_Buffer *pixel_buffer,
  2149. GUI_Color color,
  2150. int x, int y0, int y1)
  2151. {
  2152. for(int i = y0; i < y1; i++)
  2153. {
  2154. SET_PIXEL(pixel_buffer, x, i, color);
  2155. }
  2156. }
  2157. // NOTE(Zelaven): Based on the technique and code for drawing circles
  2158. // showcased by Casey here:
  2159. // https://www.computerenhance.com/p/efficient-dda-circle-outlines
  2160. void gui_draw_rounded_rect(
  2161. Pixel_Buffer *pixel_buffer,
  2162. GUI_Draw_Command *draw_command)
  2163. {
  2164. int roundedness = draw_command->roundedness;
  2165. // NOTE(Zelaven): Roundedness is a function of width and height, whichever
  2166. // is smaller.
  2167. int width = draw_command->rectangle.x1 - draw_command->rectangle.x0;
  2168. int height = draw_command->rectangle.y1 - draw_command->rectangle.y0;
  2169. short r = 0;
  2170. {
  2171. int shortest_dimension = width < height ? width : height;
  2172. r = (shortest_dimension * roundedness) / 200;
  2173. }
  2174. int Cx = draw_command->rectangle.x0+r;
  2175. int Cy = draw_command->rectangle.y0+r;
  2176. int R = r;
  2177. int R2, X, Y, dY, dX, D;
  2178. // TODO(Zelaven): Remove this static limit.
  2179. assert(R < 500);
  2180. // NOTE(Zelaven): Both of these are used to cache calculations.
  2181. // NOTE(Zelaven): This one is also used to prevent redrawing the same pixels.
  2182. int Y_to_X_map[500];
  2183. int Y_to_X_map2[500];
  2184. #if 0
  2185. for(size_t i = 0; i < ARRAYLENGTH(Y_to_X_map); i++)
  2186. {
  2187. Y_to_X_map[i] = -1;
  2188. Y_to_X_map2[i] = -1;
  2189. }
  2190. #endif
  2191. //printf("\n\n");
  2192. R2 = R+R;
  2193. Y = R; X = 0;
  2194. dX = -2;
  2195. dY = R2+R2 - 4;
  2196. D = R2 - 1;
  2197. while(X <= Y)
  2198. {
  2199. //printf("X=%d, Y=%d\n", X, Y);
  2200. //setPixel(Cx - X, Cy - Y);
  2201. Y_to_X_map[Y] = X;
  2202. //setPixel(Cx - X, Cy + Y);
  2203. //setPixel(Cx + X, Cy - Y);
  2204. //setPixel(Cx + X, Cy + Y);
  2205. //setPixel(Cx - Y, Cy - X);
  2206. Y_to_X_map2[X] = Y;
  2207. //setPixel(Cx - Y, Cy + X);
  2208. //setPixel(Cx + Y, Cy - X);
  2209. //setPixel(Cx + Y, Cy + X);
  2210. D += dX;
  2211. dX -= 4;
  2212. ++X;
  2213. // NOTE(casey): Branchless version
  2214. int Mask = (D >> 31);
  2215. D += dY & Mask;
  2216. dY -= 4 & Mask;
  2217. Y += Mask;
  2218. }
  2219. //SET_PIXEL(pixel_buffer, draw_command->rectangle.x0, draw_command->rectangle.y0, draw_command->border_color);
  2220. //SET_PIXEL(pixel_buffer, draw_command->rectangle.x1-1, draw_command->rectangle.y1-1, draw_command->border_color);
  2221. // top.
  2222. int top_y0 = Cy - R;
  2223. int top_y1 = Cy - Y;
  2224. //int top_height = top_y1 - top_y0;
  2225. for(int y = top_y0; y < top_y1; y++)
  2226. {
  2227. int Y_ = Cy - y;
  2228. int X_ = Y_to_X_map[Y_];
  2229. //printf("X_: %d\n", X_);
  2230. test_draw_horizontal_pixel_line(
  2231. pixel_buffer,
  2232. Cx - X_, draw_command->rectangle.x1 - R + X_, y,
  2233. draw_command->color);
  2234. }
  2235. // lower.
  2236. int lower_y0 = Cy - Y;
  2237. int lower_y1 = Cy;
  2238. //int lower_height = lower_y1 - lower_y0;
  2239. //printf("lower: %d to %d\n", lower_y0, lower_y1);
  2240. for(int y = lower_y0; y < lower_y1; y++)
  2241. {
  2242. int Y_ = Cy - y;
  2243. int X_ = Y_to_X_map2[Y_];
  2244. //printf("X_: %d\n", X_);
  2245. test_draw_horizontal_pixel_line(
  2246. pixel_buffer,
  2247. Cx - X_, draw_command->rectangle.x1 - R + X_, y,
  2248. draw_command->color);
  2249. }
  2250. // middle.
  2251. GUI_Rectangle middle = draw_command->rectangle;
  2252. middle.y0 = middle.y0 + r;
  2253. middle.y1 -= r;
  2254. draw_rect3(pixel_buffer, middle, draw_command->color);
  2255. int middle_height = middle.y1-middle.y0;
  2256. int Cy1 = Cy + middle_height - 1;
  2257. // lower.
  2258. lower_y0 = Cy1 +1;
  2259. lower_y1 = Cy1 + Y +1;
  2260. //printf("lower: %d = %d = %d - %d\n", lower_height, lower_y1 - lower_y0, lower_y1, lower_y0);
  2261. for(int y = lower_y0; y < lower_y1; y++)
  2262. {
  2263. int Y_ = y - Cy1;
  2264. int X_ = Y_to_X_map2[Y_];
  2265. //printf("X_: %d\n", X_);
  2266. test_draw_horizontal_pixel_line(
  2267. pixel_buffer,
  2268. Cx - X_, draw_command->rectangle.x1 - R + X_, y,
  2269. draw_command->color);
  2270. }
  2271. // top.
  2272. top_y0 = Cy1 + Y +1;
  2273. top_y1 = Cy1 + R +1;
  2274. //printf("top: %d = %d = %d - %d\n", top_height, top_y1 - top_y0, top_y1, top_y0);
  2275. for(int y = top_y0; y < top_y1; y++)
  2276. {
  2277. int Y_ = y - Cy1;
  2278. int X_ = Y_to_X_map[Y_];
  2279. //printf("X_: %d\n", X_);
  2280. test_draw_horizontal_pixel_line(
  2281. pixel_buffer,
  2282. Cx - X_, draw_command->rectangle.x1 - R + X_, y,
  2283. draw_command->color);
  2284. }
  2285. }
  2286. void gui_draw_rounded_rect_with_border(
  2287. Pixel_Buffer *pixel_buffer,
  2288. GUI_Draw_Command *draw_command)
  2289. {
  2290. int width = draw_command->rectangle.x1 - draw_command->rectangle.x0;
  2291. int height = draw_command->rectangle.y1 - draw_command->rectangle.y0;
  2292. int roundedness = draw_command->roundedness;
  2293. int border_thickness = draw_command->border_thickness;
  2294. if(border_thickness > (height+1)/2) border_thickness = (height+1)/2;
  2295. //printf("\n\n");
  2296. //printf("border_thickness: %d\n", border_thickness);
  2297. // NOTE(Zelaven): Roundedness is a function of width and height, whichever
  2298. // is smaller.
  2299. short r = 0;
  2300. {
  2301. int shortest_dimension = width < height ? width : height;
  2302. r = (shortest_dimension * roundedness) / 200;
  2303. }
  2304. int Cx = draw_command->rectangle.x0+r;
  2305. int Cy = draw_command->rectangle.y0+r;
  2306. int R = r;
  2307. int R2, X, Y, dY, dX, D;
  2308. // TODO(Zelaven): Remove this static limit.
  2309. assert(R < 500);
  2310. // NOTE(Zelaven): Both of these are used to cache calculations.
  2311. // NOTE(Zelaven): This one is also used to prevent redrawing the same pixels.
  2312. int Y_to_X_map[500];
  2313. int Y_to_X_map2[500];
  2314. #if 1
  2315. for(size_t i = 0; i < ARRAYLENGTH(Y_to_X_map); i++)
  2316. {
  2317. Y_to_X_map[i] = -1;
  2318. Y_to_X_map2[i] = -1;
  2319. }
  2320. #endif
  2321. {
  2322. //printf("\n\n");
  2323. R2 = R+R;
  2324. Y = R; X = 0;
  2325. dX = -2;
  2326. dY = R2+R2 - 4;
  2327. D = R2 - 1;
  2328. while(X <= Y)
  2329. {
  2330. //printf("X=%d, Y=%d\n", X, Y);
  2331. //setPixel(Cx - X, Cy - Y);
  2332. Y_to_X_map[Y] = X;
  2333. //setPixel(Cx - X, Cy + Y);
  2334. //setPixel(Cx + X, Cy - Y);
  2335. //setPixel(Cx + X, Cy + Y);
  2336. //setPixel(Cx - Y, Cy - X);
  2337. Y_to_X_map2[X] = Y;
  2338. //setPixel(Cx - Y, Cy + X);
  2339. //setPixel(Cx + Y, Cy - X);
  2340. //setPixel(Cx + Y, Cy + X);
  2341. //if((Cx - X) == (Cx - Y) && (Cy - Y)==(Cy - X))
  2342. // printf("SAMENESS: X: %d , Y: %d\n", X, Y);
  2343. D += dX;
  2344. dX -= 4;
  2345. ++X;
  2346. // NOTE(casey): Branchless version
  2347. int Mask = (D >> 31);
  2348. D += dY & Mask;
  2349. dY -= 4 & Mask;
  2350. Y += Mask;
  2351. }
  2352. }
  2353. //printf("R: %d , X: %d , Y: %d\n", R, X, Y);
  2354. // inner circle.
  2355. int R_inner = r - border_thickness;
  2356. int R2_inner, X_inner, Y_inner, dY_inner, dX_inner, D_inner;
  2357. assert(R_inner < 500);
  2358. // NOTE(Zelaven): Both of these are used to cache calculations.
  2359. // NOTE(Zelaven): This one is also used to prevent redrawing the same pixels.
  2360. int Y_to_X_map_inner[500];
  2361. int Y_to_X_map2_inner[500];
  2362. #if 1
  2363. for(size_t i = 0; i < ARRAYLENGTH(Y_to_X_map_inner); i++)
  2364. {
  2365. Y_to_X_map_inner[i] = -1;
  2366. Y_to_X_map2_inner[i] = -1;
  2367. }
  2368. #endif
  2369. {
  2370. //printf("\n\n");
  2371. R2_inner = R_inner+R_inner;
  2372. Y_inner = R_inner; X_inner = 0;
  2373. dX_inner = -2;
  2374. dY_inner = R2_inner+R2_inner - 4;
  2375. D_inner = R2_inner - 1;
  2376. while(X_inner <= Y_inner)
  2377. {
  2378. //printf("X_inner=%d, Y_inner=%d\n", X_inner, Y_inner);
  2379. Y_to_X_map_inner[Y_inner] = X_inner;
  2380. Y_to_X_map2_inner[X_inner] = Y_inner;
  2381. //if((Cx - X_inner) == (Cx - Y_inner) && (Cy - Y_inner)==(Cy - X_inner))
  2382. // printf("SAMENESS: X: %d , Y: %d\n", X_inner, Y_inner);
  2383. D_inner += dX_inner;
  2384. dX_inner -= 4;
  2385. ++X_inner;
  2386. // NOTE(casey): Branchless version
  2387. int Mask = (D_inner >> 31);
  2388. D_inner += dY_inner & Mask;
  2389. dY_inner -= 4 & Mask;
  2390. Y_inner += Mask;
  2391. }
  2392. }
  2393. //printf("R_inner: %d , X_inner: %d , Y_inner: %d\n", R_inner, X_inner, Y_inner);
  2394. // Drawing.
  2395. int y_ = draw_command->rectangle.y0;
  2396. int rect_x0 = draw_command->rectangle.x0;
  2397. int rect_x1 = draw_command->rectangle.x1;
  2398. int draw_guide_lines = 0;
  2399. int border_y = y_ + border_thickness;
  2400. #if 0
  2401. - top1 : upper octant of outer, above inner.
  2402. - top2 : upper octant of outer, upper octant of inner.
  2403. - lower1: lower octant of outer, above inner.
  2404. Happens when border is thicker than height of outer-upper-octant.
  2405. - lower2: lower octant of outer, upper octant of inner.
  2406. - lower3: lower octant of outer, lower octant of inner.
  2407. #endif
  2408. // top1.
  2409. int top1_y0 = Cy-R;
  2410. int top1_ycap = Cy-Y;
  2411. //printf("%d %d\n", border_y, top1_ycap);
  2412. int top1_y1 = top1_ycap < border_y ? top1_ycap : border_y;
  2413. for(int top1_y = top1_y0; top1_y < top1_y1; top1_y++)
  2414. {
  2415. int Y_ = Cy - top1_y;
  2416. int X_ = Y_to_X_map[Y_];
  2417. //printf("%d = %d - %d\n", Y_, Cy, top1_y);
  2418. //printf("X_: %d\n", X_);
  2419. test_draw_horizontal_pixel_line(
  2420. pixel_buffer,
  2421. Cx - X_, rect_x1 - R + X_, top1_y,
  2422. draw_command->border_color);
  2423. }
  2424. if(draw_guide_lines)test_draw_horizontal_pixel_line(
  2425. pixel_buffer,
  2426. rect_x0, rect_x1, Cy - top1_ycap-1,
  2427. 0x00ffffff);
  2428. // top2.
  2429. int top2_y0 = Cy-R_inner;
  2430. int top2_y1 = Cy - Y;
  2431. for(int top2_y = top2_y0; top2_y < top2_y1; top2_y++)
  2432. {
  2433. int Y_ = Cy - top2_y;
  2434. int X_ = Y_to_X_map[Y_];
  2435. int X_inn = Y_to_X_map_inner[Y_];
  2436. //printf("%d = %d - %d\n", Y_, Cy, top2_y);
  2437. //printf("X_: %d , X_inn: %d\n", X_, X_inn);
  2438. test_draw_horizontal_pixel_line(pixel_buffer,
  2439. Cx - X_, Cx - X_inn, top2_y,
  2440. draw_command->border_color);
  2441. test_draw_horizontal_pixel_line(pixel_buffer,
  2442. Cx - X_inn, rect_x1 - R + X_inn, top2_y,
  2443. draw_command->color);
  2444. test_draw_horizontal_pixel_line(pixel_buffer,
  2445. rect_x1 - R + X_inn, rect_x1 - R + X_, top2_y,
  2446. draw_command->border_color);
  2447. }
  2448. if(draw_guide_lines)test_draw_horizontal_pixel_line(
  2449. pixel_buffer,
  2450. rect_x0, rect_x1, top2_y1,
  2451. 0x00ffffff);
  2452. // lower1.
  2453. int lower1_y0 = Cy - Y;
  2454. int lower1_y1 = border_y;
  2455. if(border_y > Cy) lower1_y1 = Cy;
  2456. for(int lower1_y = lower1_y0; lower1_y < lower1_y1; lower1_y++)
  2457. {
  2458. int Y_ = Cy - lower1_y;
  2459. int X_ = Y_to_X_map2[Y_];
  2460. //printf("%d = %d - %d\n", Y_, Cy, lower1_y);
  2461. //printf("X_: %d\n", X_);
  2462. test_draw_horizontal_pixel_line(pixel_buffer,
  2463. Cx - X_, rect_x1 - R + X_, lower1_y,
  2464. draw_command->border_color);
  2465. }
  2466. if(draw_guide_lines)test_draw_horizontal_pixel_line(
  2467. pixel_buffer,
  2468. draw_command->rectangle.x0, draw_command->rectangle.x1, lower1_y1,
  2469. 0x00ffffff);
  2470. // lower2.
  2471. int lower2_y0 = Cy - Y;
  2472. if(border_y > lower2_y0) lower2_y0 = border_y;
  2473. if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
  2474. int lower2_y1 = Cy - Y_inner;
  2475. for(int lower2_y = lower2_y0; lower2_y < lower2_y1; lower2_y++)
  2476. {
  2477. int Y_ = Cy - lower2_y;
  2478. int X_ = Y_to_X_map2[Y_];
  2479. int X_inn = Y_to_X_map_inner[Y_];
  2480. //printf("%d = %d - %d\n", Y_, Cy, lower2_y);
  2481. //printf("X_: %d , X_inn: %d\n", X_, X_inn);
  2482. int x0 = Cx - X_; int x1 = Cx - X_inn;
  2483. int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
  2484. test_draw_horizontal_pixel_line(
  2485. pixel_buffer, x0, x1, lower2_y,
  2486. draw_command->border_color);
  2487. test_draw_horizontal_pixel_line(
  2488. pixel_buffer, x1, x2, lower2_y,
  2489. draw_command->color);
  2490. test_draw_horizontal_pixel_line(
  2491. pixel_buffer, x2, x3, lower2_y,
  2492. draw_command->border_color);
  2493. }
  2494. if(draw_guide_lines)test_draw_horizontal_pixel_line(
  2495. pixel_buffer,
  2496. draw_command->rectangle.x0, draw_command->rectangle.x1, lower2_y1,
  2497. 0x00ffffff);
  2498. // lower3.
  2499. int lower3_y0 = Cy - Y_inner;
  2500. int lower3_y1 = Cy;
  2501. for(int lower3_y = lower3_y0; lower3_y < lower3_y1; lower3_y++)
  2502. {
  2503. int Y_ = Cy - lower3_y;
  2504. int X_ = Y_to_X_map2[Y_];
  2505. int X_inn = Y_to_X_map2_inner[Y_];
  2506. //printf("%d = %d - %d\n", Y_, Cy, lower3_y);
  2507. //printf("X_: %d , X_inn: %d\n", X_, X_inn);
  2508. int x0 = Cx - X_; int x1 = Cx - X_inn;
  2509. int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
  2510. test_draw_horizontal_pixel_line(
  2511. pixel_buffer, x0, x1, lower3_y,
  2512. draw_command->border_color);
  2513. test_draw_horizontal_pixel_line(
  2514. pixel_buffer, x1, x2, lower3_y,
  2515. draw_command->color);
  2516. test_draw_horizontal_pixel_line(
  2517. pixel_buffer, x2, x3, lower3_y,
  2518. draw_command->border_color);
  2519. }
  2520. if(draw_guide_lines)test_draw_horizontal_pixel_line(
  2521. pixel_buffer,
  2522. draw_command->rectangle.x0, draw_command->rectangle.x1, lower3_y1,
  2523. 0x00ffffff);
  2524. // Middle section.
  2525. GUI_Rectangle middle = draw_command->rectangle;
  2526. middle.y0 = middle.y0 + r;
  2527. middle.y1 -= r;
  2528. //printf("%d %d -> %d %d\n", draw_command->rectangle.y0, draw_command->rectangle.y1, middle.y0, middle.y1);
  2529. int y = middle.y0;
  2530. for(; y < middle.y0 + border_thickness-r; y++)
  2531. {
  2532. test_draw_horizontal_pixel_line(
  2533. pixel_buffer, middle.x0, middle.x1, y,
  2534. draw_command->border_color);
  2535. }
  2536. for(; y < middle.y1 - (border_thickness-r) && y < middle.y1; y++)
  2537. {
  2538. int x = middle.x0;
  2539. for(; x < middle.x0+border_thickness && x < middle.x1; x++)
  2540. {SET_PIXEL(pixel_buffer, x, y, draw_command->border_color);}
  2541. for(; x < middle.x1-border_thickness; x++)
  2542. {SET_PIXEL(pixel_buffer, x, y, draw_command->color);}
  2543. for(; x < middle.x1; x++)
  2544. {SET_PIXEL(pixel_buffer, x, y, draw_command->border_color);}
  2545. }
  2546. for(; y < middle.y1; y++)
  2547. {
  2548. test_draw_horizontal_pixel_line(
  2549. pixel_buffer, middle.x0, middle.x1, y,
  2550. draw_command->border_color);
  2551. }
  2552. int middle_height = middle.y1-middle.y0;
  2553. int Cy1 = Cy + middle_height -1;
  2554. border_y = draw_command->rectangle.y1 - border_thickness;
  2555. //printf("middle_height: %d, Cy1: %d, border_y: %d\n", middle_height, Cy1, border_y);
  2556. // top1.
  2557. {
  2558. int border_y = draw_command->rectangle.y1 - border_thickness;
  2559. int top1_y1 = Cy1+R + 1;
  2560. int top1_ycap = Cy1 + Y +1;
  2561. //int top1_y0 = 1 + (border_y > top1_ycap ? border_y : top1_ycap);
  2562. int top1_y0 = 0 + (border_y > top1_ycap ? border_y : top1_ycap);
  2563. for(int top1_y = top1_y0; top1_y < top1_y1; top1_y++)
  2564. {
  2565. int Y_ = top1_y - Cy1;
  2566. //printf("%d = %d + %d\n", Y_, Cy1, top1_y);
  2567. int X_ = Y_to_X_map[Y_];
  2568. //printf("X_: %d\n", X_);
  2569. test_draw_horizontal_pixel_line(
  2570. pixel_buffer,
  2571. Cx - X_, rect_x1 - R + X_, top1_y,
  2572. draw_command->border_color);
  2573. }
  2574. // top2.
  2575. int top2_y0 = Cy1 + Y +1;
  2576. int top2_y1 = Cy1+R_inner +1;
  2577. //printf("top2: %d to %d\n", top2_y0, top2_y1);
  2578. for(int top2_y = top2_y0; top2_y < top2_y1; top2_y++)
  2579. {
  2580. int Y_ = top2_y - Cy1;
  2581. int X_ = Y_to_X_map[Y_];
  2582. int X_inn = Y_to_X_map_inner[Y_];
  2583. //printf("%d = %d - %d\n", Y_, Cy, top2_y);
  2584. //printf("X_: %d , X_inn: %d\n", X_, X_inn);
  2585. test_draw_horizontal_pixel_line(pixel_buffer,
  2586. Cx - X_, Cx - X_inn, top2_y,
  2587. draw_command->border_color);
  2588. test_draw_horizontal_pixel_line(pixel_buffer,
  2589. Cx - X_inn, rect_x1 - R + X_inn, top2_y,
  2590. draw_command->color);
  2591. test_draw_horizontal_pixel_line(pixel_buffer,
  2592. rect_x1 - R + X_inn, rect_x1 - R + X_, top2_y,
  2593. draw_command->border_color);
  2594. }
  2595. // lower1.
  2596. int lower1_y0 = border_y;
  2597. int lower1_y1 = Cy1 + Y +1;
  2598. if(border_y < (Cy1+1)) lower1_y0 = Cy1+1;
  2599. for(int lower1_y = lower1_y0; lower1_y < lower1_y1; lower1_y++)
  2600. {
  2601. int Y_ = lower1_y - Cy1;
  2602. int X_ = Y_to_X_map2[Y_];
  2603. //printf("%d = %d - %d\n", Y_, Cy, lower1_y);
  2604. //printf("X_: %d\n", X_);
  2605. test_draw_horizontal_pixel_line(pixel_buffer,
  2606. Cx - X_, rect_x1 - R + X_, lower1_y,
  2607. draw_command->border_color);
  2608. }
  2609. // lower2.
  2610. if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
  2611. int lower2_y0 = Cy1 + Y_inner +1;
  2612. int lower2_y1 = Cy1 + Y +1;
  2613. if(border_y < lower2_y1) lower2_y1 = border_y;
  2614. for(int lower2_y = lower2_y0; lower2_y < lower2_y1; lower2_y++)
  2615. {
  2616. int Y_ = lower2_y - Cy1;
  2617. int X_ = Y_to_X_map2[Y_];
  2618. int X_inn = Y_to_X_map_inner[Y_];
  2619. //printf("%d = %d - %d\n", Y_, Cy, lower2_y);
  2620. //printf("X_: %d , X_inn: %d\n", X_, X_inn);
  2621. int x0 = Cx - X_; int x1 = Cx - X_inn;
  2622. int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
  2623. test_draw_horizontal_pixel_line(
  2624. pixel_buffer, x0, x1, lower2_y,
  2625. draw_command->border_color);
  2626. test_draw_horizontal_pixel_line(
  2627. pixel_buffer, x1, x2, lower2_y,
  2628. draw_command->color);
  2629. test_draw_horizontal_pixel_line(
  2630. pixel_buffer, x2, x3, lower2_y,
  2631. draw_command->border_color);
  2632. }
  2633. // lower3.
  2634. int lower3_y0 = Cy1 +1;
  2635. int lower3_y1 = Cy1 + Y_inner+1;
  2636. for(int lower3_y = lower3_y0; lower3_y < lower3_y1; lower3_y++)
  2637. {
  2638. int Y_ = lower3_y - Cy1;
  2639. int X_ = Y_to_X_map2[Y_];
  2640. int X_inn = Y_to_X_map2_inner[Y_];
  2641. //printf("%d = %d - %d\n", Y_, Cy, lower3_y);
  2642. //printf("X_: %d , X_inn: %d\n", X_, X_inn);
  2643. int x0 = Cx - X_; int x1 = Cx - X_inn;
  2644. int x2 = rect_x1 - R + X_inn; int x3 = rect_x1 - R + X_;
  2645. test_draw_horizontal_pixel_line(
  2646. pixel_buffer, x0, x1, lower3_y,
  2647. draw_command->border_color);
  2648. test_draw_horizontal_pixel_line(
  2649. pixel_buffer, x1, x2, lower3_y,
  2650. draw_command->color);
  2651. test_draw_horizontal_pixel_line(
  2652. pixel_buffer, x2, x3, lower3_y,
  2653. draw_command->border_color);
  2654. }
  2655. }
  2656. if(draw_guide_lines)test_draw_horizontal_pixel_line(
  2657. pixel_buffer,
  2658. rect_x0, rect_x1, Cy - top1_ycap-1,
  2659. 0x00ffffff);
  2660. // Debug.
  2661. #if 0
  2662. GUI_Color white = 0x00ffffff;
  2663. {R2 = R+R;Y = R; X = 0;dX = -2;dY = R2+R2 - 4;D = R2 - 1;
  2664. while(X <= Y){
  2665. //setPixel(Cx - X, Cy - Y);
  2666. //setPixel(Cx - X, Cy + Y + middle_height -1);
  2667. SET_PIXEL(pixel_buffer, Cx-X, Cy-Y, white);
  2668. SET_PIXEL(pixel_buffer, Cx-X, Cy+Y + middle_height -1, white);
  2669. //setPixel(Cx + X, Cy - Y);
  2670. //setPixel(Cx + X, Cy + Y);
  2671. //setPixel(Cx - Y, Cy - X);
  2672. //setPixel(Cx - Y, Cy + X + middle_height -1);
  2673. SET_PIXEL(pixel_buffer, Cx-Y, Cy-X, white);
  2674. SET_PIXEL(pixel_buffer, Cx-Y, Cy+X + middle_height -1, white);
  2675. //setPixel(Cx + Y, Cy - X);
  2676. //setPixel(Cx + Y, Cy + X);
  2677. D += dX;dX -= 4;++X;
  2678. int Mask = (D >> 31);D += dY & Mask;dY -= 4 & Mask;Y += Mask;}}
  2679. {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;
  2680. while(X_inner <= Y_inner){
  2681. //setPixel(Cx - X_inner, Cy - Y_inner);
  2682. //setPixel(Cx - X_inner, Cy + Y_inner + middle_height-1);
  2683. SET_PIXEL(pixel_buffer, Cx-X_inner, Cy-Y_inner, white);
  2684. SET_PIXEL(pixel_buffer, Cx-X_inner, Cy+Y_inner + middle_height-1, white);
  2685. //setPixel(Cx + X_inner, Cy - Y_inner);
  2686. //setPixel(Cx + X_inner, Cy + Y_inner);
  2687. //setPixel(Cx - Y_inner, Cy - X_inner);
  2688. //setPixel(Cx - Y_inner, Cy + X_inner + middle_height-1);
  2689. SET_PIXEL(pixel_buffer, Cx-Y_inner, Cy-X_inner, white);
  2690. SET_PIXEL(pixel_buffer, Cx-Y_inner, Cy+X_inner + middle_height-1, white);
  2691. //setPixel(Cx + Y_inner, Cy - X_inner);
  2692. //setPixel(Cx + Y_inner, Cy + X_inner);
  2693. D_inner += dX_inner;dX_inner -= 4;++X_inner;
  2694. int Mask = (D_inner >> 31);D_inner += dY_inner & Mask;dY_inner -= 4 & Mask;Y_inner += Mask;}}
  2695. {
  2696. printf("%%%%%%%%%%%%%%%%%%%%\n");
  2697. GUI_Color red = 0x00ff4444;
  2698. GUI_Color cyan = 0x0000ffff;
  2699. GUI_Color yellow = 0x00ffff00;
  2700. int x_ = draw_command->rectangle.x0 + R;
  2701. int y_ = draw_command->rectangle.y0;
  2702. int Y_ = Y + 1;
  2703. printf("rect corner: x: %d, y: %d\n", x_ -R, y_);
  2704. printf("R: %d, R_inner: %d, Cx: %d, Cy: %d\n", R, R_inner, Cx, Cy);
  2705. printf("Y: %d, Y_: %d, Y_inner: %d\n", Y, Y_, Y_inner);
  2706. SET_PIXEL(pixel_buffer, Cx, Cy, white);
  2707. if(0)test_draw_horizontal_pixel_line(
  2708. pixel_buffer, draw_command->rectangle.x0, draw_command->rectangle.x1,
  2709. Cy-Y,
  2710. 0x00ffffff);
  2711. int top1_height, top2_height, lower1_height, lower2_height, lower3_height;
  2712. {
  2713. // top1.
  2714. int border_y = y_ + border_thickness;
  2715. int top1_y0 = Cy-R;
  2716. int top1_y = Cy-Y;
  2717. //printf("%d %d\n", border_y, top1_y);
  2718. int top1_y1 = top1_y < border_y ? top1_y : border_y;
  2719. top1_height = top1_y1 - top1_y0; //debug.
  2720. test_draw_vertical_pixel_line(pixel_buffer, cyan,
  2721. x_, top1_y0, top1_y1);
  2722. // top2.
  2723. int top2_y0 = Cy-R_inner;
  2724. int top2_y1 = Cy - Y;
  2725. top2_height = top2_y1 - top2_y0; // debug.
  2726. test_draw_vertical_pixel_line(pixel_buffer, red,
  2727. x_+1, top2_y0, top2_y1);
  2728. // lower1.
  2729. int lower1_y0 = Cy - Y;
  2730. int lower1_y1 = border_y;
  2731. if(border_y > Cy) lower1_y1 = Cy;
  2732. lower1_height = lower1_y1 - lower1_y0; //debug.
  2733. test_draw_vertical_pixel_line(pixel_buffer, yellow,
  2734. x_+2, lower1_y0, lower1_y1);
  2735. // lower2.
  2736. int lower2_y0 = Cy - Y;
  2737. if(border_y > lower2_y0) lower2_y0 = border_y;
  2738. if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
  2739. int lower2_y1 = Cy - Y_inner;
  2740. lower2_height = lower2_y1 - lower2_y0; //debug.
  2741. //printf("lower2: %d %d\n", lower2_y0, lower2_y1);
  2742. test_draw_vertical_pixel_line(pixel_buffer, red,
  2743. x_+3, lower2_y0, lower2_y1);
  2744. // lower3.
  2745. int lower3_y0 = Cy - Y_inner;
  2746. int lower3_y1 = Cy;
  2747. lower3_height = lower3_y1 - lower3_y0; //debug.
  2748. test_draw_vertical_pixel_line(pixel_buffer, cyan,
  2749. x_+4, lower3_y0, lower3_y1);
  2750. }
  2751. if(0)test_draw_horizontal_pixel_line(
  2752. pixel_buffer, draw_command->rectangle.x0, draw_command->rectangle.x1,
  2753. Cy1+Y,
  2754. 0x00ffffff);
  2755. {
  2756. int Cy1 = Cy + middle_height -1;
  2757. printf("Cy1: %d\n", Cy1);
  2758. SET_PIXEL(pixel_buffer, Cx, Cy1, white);
  2759. // top1.
  2760. int border_y = draw_command->rectangle.y1 - border_thickness;
  2761. int top1_y1 = Cy1+R+1;
  2762. int top1_ycap = Cy1 + Y +1;
  2763. //int top1_y0 = 1 + (border_y > top1_ycap ? border_y : top1_ycap);
  2764. int top1_y0 = 0 + (border_y > top1_ycap ? border_y : top1_ycap);
  2765. //printf("%d %d\n", border_y, top1_y);
  2766. if((top1_y1 - top1_y0) != top1_height) printf("top1 height error.\n");
  2767. test_draw_vertical_pixel_line(pixel_buffer, cyan,
  2768. x_, top1_y0, top1_y1);
  2769. // top2.
  2770. int top2_y0 = Cy1 + Y +1;
  2771. int top2_y1 = Cy1+R_inner+1;
  2772. if((top2_y1 - top2_y0) != top2_height) printf("top2 height error.\n");
  2773. test_draw_vertical_pixel_line(pixel_buffer, red,
  2774. x_+1, top2_y0, top2_y1);
  2775. // lower1.
  2776. int lower1_y0 = border_y;
  2777. int lower1_y1 = Cy1 + Y +1;
  2778. if(border_y < (Cy1+1)) lower1_y0 = Cy1+1;
  2779. if((lower1_y1 - lower1_y0) != lower1_height) printf("lower1 height error.\n");
  2780. test_draw_vertical_pixel_line(pixel_buffer, yellow,
  2781. x_+2, lower1_y0, lower1_y1);
  2782. // lower2.
  2783. if(Y_inner < 0) Y_inner = 0; // Will happen if border_thickness > R.
  2784. int lower2_y0 = Cy1 + Y_inner +1;
  2785. int lower2_y1 = Cy1 + Y +1;
  2786. if(border_y < lower2_y1) lower2_y1 = border_y;
  2787. //printf("lower2: %d %d\n", lower2_y0, lower2_y1);
  2788. if((lower2_y1 - lower2_y0) != lower2_height) printf("lower2 height error.\n");
  2789. test_draw_vertical_pixel_line(pixel_buffer, red,
  2790. x_+3, lower2_y0, lower2_y1);
  2791. // lower3.
  2792. int lower3_y0 = Cy1 +1;
  2793. int lower3_y1 = Cy1 + Y_inner+1;
  2794. if((lower3_y1 - lower3_y0) != lower3_height) printf("lower3 height error.\n");
  2795. test_draw_vertical_pixel_line(pixel_buffer, cyan,
  2796. x_+4, lower3_y0, lower3_y1);
  2797. }
  2798. test_draw_vertical_pixel_line(pixel_buffer, cyan,
  2799. draw_command->rectangle.x0+80, y_, y_+border_thickness);
  2800. test_draw_vertical_pixel_line(pixel_buffer, red,
  2801. draw_command->rectangle.x0+90, y_, y_+height);
  2802. }
  2803. #endif
  2804. }
  2805. void gui_draw_rect(
  2806. Pixel_Buffer *pixel_buffer,
  2807. GUI_Draw_Command *draw_command)
  2808. {
  2809. if(draw_command->roundedness == 0)
  2810. {
  2811. // TODO(Zelaven) Don't double-draw on the space covered by the inner
  2812. // rectangle.
  2813. draw_rect3(
  2814. pixel_buffer, draw_command->rectangle, draw_command->border_color);
  2815. GUI_Rectangle inner = draw_command->rectangle;
  2816. inner.x0 += draw_command->border_thickness;
  2817. inner.y0 += draw_command->border_thickness;
  2818. inner.x1 -= draw_command->border_thickness;
  2819. inner.y1 -= draw_command->border_thickness;
  2820. if(inner.x0 < inner.x1 && inner.y0 < inner.y1)
  2821. {
  2822. draw_rect3(pixel_buffer, inner, draw_command->color);
  2823. }
  2824. }
  2825. else
  2826. {
  2827. if(draw_command->border_thickness == 0)
  2828. {
  2829. gui_draw_rounded_rect(pixel_buffer, draw_command);
  2830. }
  2831. else
  2832. {
  2833. gui_draw_rounded_rect_with_border(pixel_buffer, draw_command);
  2834. }
  2835. }
  2836. }
  2837. int init_x11(
  2838. X11_Window *xwindow)
  2839. {
  2840. xwindow->display = XOpenDisplay(NULL);
  2841. if(xwindow->display == NULL)
  2842. {
  2843. return EXIT_FAILURE;
  2844. }
  2845. xwindow->root = DefaultRootWindow(xwindow->display);
  2846. xwindow->screen = XDefaultScreen(xwindow->display);
  2847. xwindow->visual = XDefaultVisual(xwindow->display, xwindow->screen);
  2848. xwindow->colormap = XCreateColormap(
  2849. xwindow->display, xwindow->root, xwindow->visual, AllocNone);
  2850. xwindow->set_window_attributes.colormap = xwindow->colormap;
  2851. xwindow->set_window_attributes.event_mask =
  2852. StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask |
  2853. ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
  2854. Button1MotionMask | Button3MotionMask |
  2855. Button4MotionMask | Button5MotionMask |
  2856. PointerMotionMask | KeymapStateMask | EnterWindowMask | LeaveWindowMask;
  2857. xwindow->window = XCreateWindow(
  2858. xwindow->display, xwindow->root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
  2859. XDefaultDepth(xwindow->display, xwindow->screen), InputOutput,
  2860. xwindow->visual, CWEventMask | CWColormap, &xwindow->set_window_attributes);
  2861. #if 0
  2862. XSelectInput(
  2863. xwindow->display,
  2864. xwindow->window,
  2865. StructureNotifyMask | KeyPressMask | KeyReleaseMask |
  2866. ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
  2867. #endif
  2868. XStoreName(xwindow->display, xwindow->window, "X11 Test Program");
  2869. XMapWindow(xwindow->display, xwindow->window);
  2870. XGetWindowAttributes(
  2871. xwindow->display, xwindow->window, &xwindow->window_attributes);
  2872. xwindow->width = (unsigned int)xwindow->window_attributes.width;
  2873. xwindow->height = (unsigned int)xwindow->window_attributes.height;
  2874. #if 0
  2875. printf("Initial window dimensions: %u x %u\n", xwindow->width, xwindow->height);
  2876. printf("Window depth: %d\n", xwindow->window_attributes.depth);
  2877. printf("ALL Event mask: %lx\n", xwindow->window_attributes.all_event_masks);
  2878. print_binary_long(xwindow->window_attributes.all_event_masks); printf("\n");
  2879. printf("YOUR Event mask: %lx\n", xwindow->window_attributes.your_event_mask);
  2880. print_binary_long(xwindow->window_attributes.your_event_mask); printf("\n");
  2881. #endif
  2882. // TODO: This is an experiment.
  2883. #if 0
  2884. {
  2885. int display_width = XDisplayWidth(xwindow->display, xwindow->screen);
  2886. int display_height = XDisplayHeight(xwindow->display, xwindow->screen);
  2887. int display_width_mm = XDisplayWidthMM(xwindow->display, xwindow->screen);
  2888. int display_height_mm = XDisplayHeightMM(xwindow->display, xwindow->screen);
  2889. printf("Display Resolution: %d, %d.\n", display_width, display_height);
  2890. printf("Display Size: %d, %d.\n", display_width_mm, display_height_mm);
  2891. printf("Display DPmm: %d, %d.\n",
  2892. display_width / display_width_mm,
  2893. display_height / display_height_mm);
  2894. printf("Display DPI: %d, %d.\n",
  2895. display_width / ((display_width_mm*10)/254),
  2896. display_height / ((display_height_mm*10)/254));
  2897. Screen *screen = XScreenOfDisplay(xwindow->display, xwindow->screen);
  2898. int screen_width = XWidthOfScreen(screen);
  2899. int screen_height = XHeightOfScreen(screen);
  2900. int screen_width_mm = XWidthMMOfScreen(screen);
  2901. int screen_height_mm = XHeightMMOfScreen(screen);
  2902. printf("Screen Resolution: %d, %d.\n", screen_width, screen_height);
  2903. printf("Screen Size: %d, %d.\n", screen_width_mm, screen_height_mm);
  2904. printf("Screen DPmm: %d, %d.\n",
  2905. screen_width / screen_width_mm,
  2906. screen_height / screen_height_mm);
  2907. printf("Screen DPI: %d, %d.\n",
  2908. screen_width / ((screen_width_mm*10)/254),
  2909. screen_height / ((screen_height_mm*10)/254));
  2910. }
  2911. #endif
  2912. // .
  2913. #if 0
  2914. XSelectInput(
  2915. xwindow->display,
  2916. xwindow->window,
  2917. StructureNotifyMask | KeyPressMask | KeyReleaseMask |
  2918. ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
  2919. #endif
  2920. // Discard everything preceding the MapNotify event that tells us that we
  2921. // have been properly mapped.
  2922. // This requires StructureNotifyMask to be selected.
  2923. // https://tronche.com/gui/x/xlib-tutorial/2nd-program-anatomy.html
  2924. {
  2925. XEvent e;
  2926. e.type = 0;
  2927. assert(MapNotify != 0);
  2928. while(e.type != MapNotify)
  2929. {
  2930. XNextEvent(xwindow->display, &e);
  2931. }
  2932. }
  2933. // Re-get in case the window manager decides to instantiate the window with a
  2934. // different size than the one we ask for.
  2935. XGetWindowAttributes(
  2936. xwindow->display, xwindow->window, &xwindow->window_attributes);
  2937. xwindow->width = (unsigned int)xwindow->window_attributes.width;
  2938. xwindow->height = (unsigned int)xwindow->window_attributes.height;
  2939. #if 0
  2940. printf("Window dimensions: %u x %u\n", xwindow->width, xwindow->height);
  2941. printf("Window depth: %d\n", xwindow->window_attributes.depth);
  2942. printf("ALL Event mask: %lx\n", xwindow->window_attributes.all_event_masks);
  2943. print_binary_long(xwindow->window_attributes.all_event_masks); printf("\n");
  2944. printf("YOUR Event mask: %lx\n", xwindow->window_attributes.your_event_mask);
  2945. print_binary_long(xwindow->window_attributes.your_event_mask); printf("\n");
  2946. #endif
  2947. uint32_t *pixels = malloc(sizeof(*pixels) * xwindow->width * xwindow->height);
  2948. assert(pixels != NULL);
  2949. xwindow->graphics_context = XDefaultGC(xwindow->display, xwindow->screen);
  2950. XSetForeground(xwindow->display, xwindow->graphics_context, 0x123456);
  2951. XImage *screen_image = XCreateImage(
  2952. xwindow->display,
  2953. xwindow->visual,
  2954. XDefaultDepth(xwindow->display, xwindow->screen),
  2955. // NOTE(Zelaven): I can't find an explanation to what this actually is
  2956. // anywhere. All the documentation I can find just assumes that you
  2957. // magically know.
  2958. ZPixmap,
  2959. 0,
  2960. (char*)pixels,
  2961. xwindow->width, xwindow->height,
  2962. 8, // NOTE(Zelaven): No clue
  2963. // NOTE(Zelaven): This is how many bytes there are in a row of pixels.
  2964. xwindow->width * sizeof(uint32_t));
  2965. assert(screen_image != NULL);
  2966. xwindow->pixel_buffer = (Pixel_Buffer){
  2967. .pixels = (GUI_Color*)pixels,
  2968. .width = xwindow->width,
  2969. .height = xwindow->height,
  2970. };
  2971. xwindow->screen_image = screen_image;
  2972. return EXIT_SUCCESS;
  2973. }
  2974. // ---
  2975. // ---
  2976. // ---
  2977. void init_node_freelist(GUI_Node *nodes, int node_count)
  2978. {
  2979. // NOTE(Zelaven): We special-case the last node.
  2980. for(int i = 0; i < node_count -1; i++)
  2981. {
  2982. nodes[i] = (GUI_Node){0};
  2983. nodes[i].rdic_node = (RDIC_Node){
  2984. .sibling = &((nodes+i+1)->rdic_node),
  2985. };
  2986. }
  2987. nodes[node_count-1].rdic_node = (RDIC_Node){0};
  2988. }
  2989. void init_subtree_freelist(GUI_Subtree *nodes, int subtree_count)
  2990. {
  2991. // NOTE(Zelaven): We special-case the last node.
  2992. for(int i = 0; i < subtree_count -1; i++)
  2993. {
  2994. nodes[i] = (GUI_Subtree){0};
  2995. nodes[i].rdic_node = (RDIC_Node){
  2996. .sibling = &((nodes+i+1)->rdic_node),
  2997. };
  2998. }
  2999. nodes[subtree_count-1].rdic_node = (RDIC_Node){0};
  3000. }
  3001. GUI_Node g_gui_node_freelist[128];
  3002. GUI_Subtree g_gui_subtree_freelist[16];
  3003. #include "size_of_file.c"
  3004. struct File_Read_Result {
  3005. unsigned char *data;
  3006. size_t size;
  3007. } read_file__cruddy(
  3008. FILE *file)
  3009. {
  3010. struct File_Read_Result retval = {0};
  3011. size_t status = 0;
  3012. long filesize = size_of_file(file);
  3013. if(filesize == -1) {
  3014. status = 1;}
  3015. if(status == 0) {
  3016. size_t memory_size = filesize;
  3017. memory_size = ((memory_size + 4096 - 1) / 4096) * 4096;
  3018. void *file_memory = mmap(
  3019. NULL, memory_size,
  3020. PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
  3021. if(file_memory == (void*)-1) {
  3022. //perror("mmap");
  3023. status = 2;
  3024. }
  3025. else
  3026. {
  3027. retval.data = file_memory;
  3028. }
  3029. }
  3030. if(status == 0) {
  3031. if(fread(retval.data, filesize, 1, file) != 1) {
  3032. status = 3;}
  3033. }
  3034. if(status == 0) {
  3035. retval.size = (size_t)filesize;}
  3036. else {
  3037. if(retval.data != NULL) {
  3038. free(retval.data);
  3039. retval.data = NULL;}
  3040. retval.size = status;
  3041. }
  3042. return retval;
  3043. }
  3044. void copy_from_atlas(
  3045. Pixel_Buffer *pixel_buffer,
  3046. int off_x, int off_y,
  3047. int x, int y, int w, int h)
  3048. {
  3049. draw_rect(
  3050. pixel_buffer->pixels,
  3051. pixel_buffer->width,
  3052. pixel_buffer->height,
  3053. off_x, off_y, off_x+w, off_y+h,
  3054. 0x00ffffff);
  3055. for(int j=0; j < h; ++j) {
  3056. for(int i=0; i < w; ++i)
  3057. {
  3058. int atlas_x = x + i;
  3059. int atlas_y = y + j;
  3060. int atlas_index = atlas_y * g_font_bitmap_width + atlas_x;
  3061. unsigned char atlas_shade = g_font_bitmap[atlas_index];
  3062. int color = (atlas_shade << 16) | (atlas_shade << 8) | atlas_shade;
  3063. //printf("%d ", color);
  3064. SET_PIXEL(pixel_buffer, x+off_x+i, y+off_y+j, color);
  3065. }
  3066. }
  3067. //printf("\n");
  3068. }
  3069. void blend_glyph(
  3070. Pixel_Buffer *pixel_buffer,
  3071. stbtt_bakedchar *bakedchar,
  3072. int x,
  3073. int y)
  3074. {
  3075. int glyph_height = bakedchar->y1 - bakedchar->y0;
  3076. int glyph_width = bakedchar->x1 - bakedchar->x0;
  3077. //printf("%d, %d - %d, %d\n", x, y, glyph_width, glyph_height);
  3078. if(0)draw_rect(
  3079. pixel_buffer->pixels,
  3080. pixel_buffer->width,
  3081. pixel_buffer->height,
  3082. x, y, x+glyph_width, y+glyph_height,
  3083. 0x00ffffff);
  3084. for(int j=0; j < glyph_height; ++j) {
  3085. for(int i=0; i < glyph_width; ++i)
  3086. {
  3087. //unsigned char font_pixel_shade = glyph_bitmap[j*glyph_size.w+i];
  3088. int atlas_x = bakedchar->x0 + i;
  3089. int atlas_y = bakedchar->y0 + j;
  3090. int atlas_index = atlas_y * g_font_bitmap_width + atlas_x;
  3091. GUI_Color atlas_shade = (GUI_Color)g_font_bitmap[atlas_index];
  3092. //GUI_Color color = (atlas_shade << 16) | (atlas_shade << 8) | atlas_shade;
  3093. //GUI_Color color = atlas_shade;
  3094. GUI_Color pixel_color = GET_PIXEL(pixel_buffer, x+i, y+j);
  3095. //GUI_Color pixel_color = 0x00aa764a;
  3096. int red = ((pixel_color & 0x00ff0000) >> 16) * (256-atlas_shade) / 256;
  3097. int green = ((pixel_color & 0x0000ff00) >> 8) * (256-atlas_shade) / 256;
  3098. int blue = ((pixel_color & 0x000000ff)) * (256-atlas_shade) / 256;
  3099. GUI_Color new_color = (red << 16) | (green << 8) | blue;
  3100. //GUI_Color new_color = pixel_color * (255-color) / 255;
  3101. //GUI_Color new_color = (atlas_shade << 16) | (atlas_shade << 8) | atlas_shade;
  3102. //printf("%x %x %x\n", color, pixel_color, new_color);
  3103. SET_PIXEL(pixel_buffer, x+i, y+j, new_color);
  3104. //*pixel_color = *pixel_color * (255-font_pixel_shade) / 255;
  3105. //*pixel_color = font_pixel_shade;
  3106. }
  3107. }
  3108. //printf("\n");
  3109. }
  3110. int text_measure_string_width(char *string, size_t str_length)
  3111. {
  3112. int result = 0;
  3113. for(size_t i = 0; i < str_length; i++)
  3114. {
  3115. int glyph_index = string[i] - 32;
  3116. stbtt_bakedchar *glyph = &g_baked_font[glyph_index];
  3117. result += glyph->xadvance;
  3118. }
  3119. return result;
  3120. }
  3121. #include <limits.h>
  3122. struct Text_Y_Bounds {int upper; int lower;}
  3123. text_measure_string_y_bounds(char *string, size_t str_length)
  3124. {
  3125. struct Text_Y_Bounds result = {.upper = INT_MAX, .lower = INT_MIN};
  3126. for(size_t i = 0; i < str_length; i++)
  3127. {
  3128. int glyph_index = string[i] - 32;
  3129. stbtt_bakedchar *glyph = &g_baked_font[glyph_index];
  3130. int height = glyph->y1 - glyph->y0;
  3131. int offset = glyph->yoff; // This is negative.
  3132. int uppermost_pixel = offset;
  3133. int lowermost_pixel = height + offset;
  3134. //print_bakedchar(string[i], glyph);
  3135. if(uppermost_pixel < result.upper) {
  3136. result.upper = uppermost_pixel;
  3137. }
  3138. if(lowermost_pixel > result.lower) {
  3139. result.lower = lowermost_pixel;
  3140. }
  3141. }
  3142. return result;
  3143. }
  3144. void blend_string(
  3145. Pixel_Buffer *pixel_buffer,
  3146. GUI_String text,
  3147. int x, int y)
  3148. {
  3149. int next_x = x;
  3150. for(int i = 0; i < text.length; i++)
  3151. {
  3152. int glyph_index = text.cstring[i] - 32;
  3153. stbtt_bakedchar *g = &g_baked_font[glyph_index];
  3154. blend_glyph(
  3155. pixel_buffer,
  3156. g,
  3157. next_x + g->xoff, y + g->yoff);
  3158. next_x += g->xadvance;
  3159. }
  3160. }
  3161. void gui_draw_text(
  3162. Pixel_Buffer *pixel_buffer,
  3163. GUI_Draw_Command *draw_command)
  3164. {
  3165. if(draw_command->text.cstring == NULL) {
  3166. return;
  3167. }
  3168. //printf("%.*s: %d\n", draw_command->text.length, draw_command->text.cstring, draw_command->text.length);
  3169. int text_width = text_measure_string_width(
  3170. draw_command->text.cstring, draw_command->text.length);
  3171. int width = draw_command->rectangle.x1 - draw_command->rectangle.x0;
  3172. int x = draw_command->rectangle.x0 + width/2 - text_width/2;
  3173. struct Text_Y_Bounds y_bounds = text_measure_string_y_bounds(
  3174. draw_command->text.cstring, draw_command->text.length);
  3175. int y_bounds_middle = (y_bounds.lower + y_bounds.upper)/2;
  3176. int height = draw_command->rectangle.y1 - draw_command->rectangle.y0;
  3177. int y = draw_command->rectangle.y0 + height/2 - y_bounds_middle;
  3178. #if 0
  3179. printf("%.*s: %d, (%d,%d) %d -> %d, %d\n",
  3180. draw_command->text.length, draw_command->text.cstring,
  3181. text_width, y_bounds.upper, y_bounds.lower, y_bounds_middle,
  3182. x, y);
  3183. #endif
  3184. blend_string(
  3185. pixel_buffer,
  3186. draw_command->text,
  3187. x, y);
  3188. #if 0
  3189. SET_PIXEL(pixel_buffer, x, draw_command->rectangle.y0 + height/2, 0x00ff0000);
  3190. SET_PIXEL(pixel_buffer, draw_command->rectangle.x0 + width/2, draw_command->rectangle.y0 + height/2, 0x00ffff00);
  3191. SET_PIXEL(pixel_buffer, x, y, 0x0000ff00);
  3192. #endif
  3193. }
  3194. void gui_draw_image_direct(
  3195. Pixel_Buffer *pixel_buffer,
  3196. Pixel_Buffer *image,
  3197. int off_x, int off_y)
  3198. {
  3199. if(image == NULL) {
  3200. return;
  3201. }
  3202. int w = image->width;
  3203. int h = image->height;
  3204. for(int j=0; j < h; ++j)
  3205. {
  3206. for(int i=0; i < w; ++i)
  3207. {
  3208. int image_x = i;
  3209. int image_y = j;
  3210. int image_index = image_y * w + image_x;
  3211. GUI_Color pixel = image->pixels[image_index];
  3212. SET_PIXEL(pixel_buffer, off_x+i, off_y+j, pixel);
  3213. }
  3214. }
  3215. }
  3216. void gui_draw_image(
  3217. Pixel_Buffer *pixel_buffer,
  3218. GUI_Draw_Command *draw_command)
  3219. {
  3220. if(draw_command->image == NULL) {
  3221. return;
  3222. }
  3223. int off_x = draw_command->rectangle.x0;
  3224. int off_y = draw_command->rectangle.y0;
  3225. Pixel_Buffer *image = draw_command->image;
  3226. int w = image->width;
  3227. int h = image->height;
  3228. for(int j=0; j < h; ++j)
  3229. {
  3230. for(int i=0; i < w; ++i)
  3231. {
  3232. int image_x = i;
  3233. int image_y = j;
  3234. int image_index = image_y * w + image_x;
  3235. GUI_Color pixel = image->pixels[image_index];
  3236. SET_PIXEL(pixel_buffer, off_x+i, off_y+j, pixel);
  3237. }
  3238. }
  3239. }
  3240. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  3241. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  3242. void gui_draw_image_clipped(
  3243. Pixel_Buffer *pixel_buffer,
  3244. GUI_Draw_Command *draw_command,
  3245. GUI_Rectangle *cliprect)
  3246. {
  3247. if(draw_command->image == NULL) {
  3248. return;
  3249. }
  3250. //int off_x = cliprect->x0;
  3251. //int off_y = cliprect->y0;
  3252. Pixel_Buffer *image = draw_command->image;
  3253. int w = image->width;
  3254. int clipwidth = cliprect->x1 - cliprect->x0;
  3255. w = MIN(w, clipwidth);
  3256. int h = image->height;
  3257. int clipheight = cliprect->y1 - cliprect->y0;
  3258. h = MIN(h, clipheight);
  3259. int startx = cliprect->x0 - draw_command->rectangle.x0;
  3260. startx = MAX(startx, 0);
  3261. int starty = cliprect->y0 - draw_command->rectangle.y0;
  3262. starty = MAX(starty, 0);
  3263. int off_x = cliprect->x0 - startx;
  3264. int off_y = cliprect->y0 - starty;
  3265. for(int j=starty; j < h; ++j)
  3266. {
  3267. for(int i=startx; i < w; ++i)
  3268. {
  3269. int image_x = i;
  3270. int image_y = j;
  3271. int image_index = image_y * w + image_x;
  3272. GUI_Color pixel = image->pixels[image_index];
  3273. SET_PIXEL(pixel_buffer, off_x+i, off_y+j, pixel);
  3274. }
  3275. }
  3276. }
  3277. GUI_Rectangle gui_intersect_rectangles(
  3278. GUI_Rectangle *r1,
  3279. GUI_Rectangle *r2)
  3280. {
  3281. GUI_Rectangle r = {
  3282. .x0 = MAX(r1->x0, r2->x0),
  3283. .x1 = MIN(r1->x1, r2->x1),
  3284. .y0 = MAX(r1->y0, r2->y0),
  3285. .y1 = MIN(r1->y1, r2->y1),
  3286. };
  3287. return r;
  3288. }
  3289. void gui_draw_rect_clipped(
  3290. Pixel_Buffer *pixel_buffer,
  3291. GUI_Draw_Command *draw_command,
  3292. GUI_Rectangle *clip)
  3293. {
  3294. if(clip->x0 <= draw_command->rectangle.x0
  3295. && clip->y0 <= draw_command->rectangle.y0
  3296. && clip->x1 <= draw_command->rectangle.x1
  3297. && clip->y1 <= draw_command->rectangle.y1)
  3298. {
  3299. gui_draw_rect(pixel_buffer, draw_command);
  3300. }
  3301. else
  3302. {
  3303. if(draw_command->roundedness == 0)
  3304. {
  3305. GUI_Rectangle clipped_rect = gui_intersect_rectangles(
  3306. clip,
  3307. &draw_command->rectangle);
  3308. // TODO(Zelaven) Don't double-draw on the space covered by the inner
  3309. // rectangle.
  3310. draw_rect3(
  3311. pixel_buffer, clipped_rect, draw_command->border_color);
  3312. GUI_Rectangle inner = clipped_rect;
  3313. inner.x0 += draw_command->border_thickness;
  3314. inner.y0 += draw_command->border_thickness;
  3315. inner.x1 -= draw_command->border_thickness;
  3316. inner.y1 -= draw_command->border_thickness;
  3317. if(inner.x0 < inner.x1 && inner.y0 < inner.y1)
  3318. {
  3319. draw_rect3(pixel_buffer, inner, draw_command->color);
  3320. }
  3321. }
  3322. else
  3323. {
  3324. assert(!"TODO");
  3325. if(draw_command->border_thickness == 0)
  3326. {
  3327. gui_draw_rounded_rect(pixel_buffer, draw_command);
  3328. }
  3329. else
  3330. {
  3331. gui_draw_rounded_rect_with_border(pixel_buffer, draw_command);
  3332. }
  3333. }
  3334. }
  3335. }
  3336. void gui_layout_and_draw_subtree(
  3337. GUI_Context *context,
  3338. GUI_Subtree *subtree,
  3339. Pixel_Buffer *pixel_buffer)
  3340. {
  3341. //gui_layout_nodes((GUI_Node*)subtree->rdic.root);
  3342. gui_layout_nodes(subtree);
  3343. gui_generate_draw_commands(
  3344. subtree,
  3345. context->draw_command_arena,
  3346. &context->num_draw_commands);
  3347. GUI_Draw_Command *draw_commands =
  3348. (GUI_Draw_Command*)(context->draw_command_arena->memory);
  3349. GUI_Node_Reference clipnode = subtree->clipnode;
  3350. if(rdic_node_reference_valid(clipnode.rdic_ref)) {
  3351. GUI_Rectangle *cliprect = &clipnode.node->rect;
  3352. for(int i = 0; i < context->num_draw_commands; i++)
  3353. {
  3354. GUI_Draw_Command *draw_command = draw_commands+i;
  3355. gui_draw_rect_clipped(pixel_buffer, draw_command, cliprect);
  3356. //gui_draw_image(pixel_buffer, draw_command);//, cliprect);
  3357. gui_draw_image_clipped(pixel_buffer, draw_command, cliprect);
  3358. gui_draw_text (pixel_buffer, draw_command);//, cliprect);
  3359. }
  3360. }
  3361. else {
  3362. for(int i = 0; i < context->num_draw_commands; i++)
  3363. {
  3364. GUI_Draw_Command *draw_command = draw_commands+i;
  3365. gui_draw_rect (pixel_buffer, draw_command);
  3366. gui_draw_image(pixel_buffer, draw_command);
  3367. gui_draw_text (pixel_buffer, draw_command);
  3368. }
  3369. }
  3370. // TODO NOTE(Zelaven): There may arise an issue where the subtrees won't
  3371. // generate draw commands even if they are overdrawn by changes in a
  3372. // parent subtree.
  3373. GUI_Subtree *first_child = GUI_SUBTREE_FIRST_CHILD(subtree);
  3374. if(first_child != NULL)
  3375. {
  3376. gui_layout_and_draw_subtree(context, first_child, pixel_buffer);
  3377. }
  3378. GUI_Subtree *sibling = GUI_SUBTREE_SIBLING(subtree);
  3379. if(sibling != NULL)
  3380. {
  3381. gui_layout_and_draw_subtree(context, sibling, pixel_buffer);
  3382. }
  3383. }
  3384. void gui_layout_and_draw(GUI_Context *context)
  3385. {
  3386. // TODO(Zelaven): Make the layers in the context iteratable.
  3387. GUI_Layer *layers[] = {
  3388. &context->background_layer,
  3389. &context->top_layer,
  3390. };
  3391. for(
  3392. size_t i = 0;
  3393. i < ARRAYLENGTH(layers);
  3394. i++)
  3395. {
  3396. GUI_Layer *layer = layers[i];
  3397. GUI_Subtree *subtree_root = (GUI_Subtree*)layer->subtree_rdic.root;
  3398. if(subtree_root != NULL) {
  3399. gui_layout_and_draw_subtree(
  3400. context,
  3401. subtree_root,
  3402. layer->pixel_buffer);
  3403. }
  3404. }
  3405. }
  3406. void gui_compose_layers(
  3407. GUI_Context *context,
  3408. Pixel_Buffer *target_buffer)
  3409. {
  3410. // TODO(Zelaven): Make the layers in the context iteratable.
  3411. GUI_Layer *layers[] = {
  3412. &context->background_layer,
  3413. &context->top_layer,
  3414. };
  3415. for(
  3416. size_t i = 0;
  3417. i < ARRAYLENGTH(layers);
  3418. i++)
  3419. {
  3420. GUI_Layer *layer = layers[i];
  3421. if(layer->should_draw) {
  3422. gui_draw_image_direct(
  3423. target_buffer,
  3424. layer->pixel_buffer,
  3425. layer->offset_x,
  3426. layer->offset_y);
  3427. }
  3428. }
  3429. }
  3430. #include <unistd.h> // usleep.
  3431. int main(void)
  3432. {
  3433. void (*gui)(GUI_Context *,GUI_Rectangle);
  3434. // Font initialization.
  3435. Memory_Arena font_arena = {0};
  3436. assert(linux_allocate_arena_memory(
  3437. &font_arena,
  3438. g_font_bitmap_width*g_font_bitmap_height) == 0);
  3439. FILE *font_file = fopen("michroma/Michroma-Regular.ttf", "r");
  3440. //FILE *font_file = fopen("/usr/share/fonts/TTF/Roboto-Black.ttf", "r");
  3441. struct File_Read_Result font_data = read_file__cruddy(font_file);
  3442. // TODO(Zelaven): How much data do I have to make sure that I read at minimum?
  3443. assert(font_data.size > 16);
  3444. {
  3445. int font_bitmap_size = g_font_bitmap_width * g_font_bitmap_height;
  3446. g_font_bitmap = memory_arena_allocate(
  3447. &font_arena, font_bitmap_size, _Alignof(char));
  3448. int bake_font_return_value = stbtt_BakeFontBitmap(
  3449. font_data.data, 0,
  3450. 20.0,
  3451. g_font_bitmap, g_font_bitmap_width, g_font_bitmap_height,
  3452. 32, 96, g_baked_font);
  3453. //printf("bake_font_return_value: %d\n", bake_font_return_value);
  3454. if(bake_font_return_value < 1)
  3455. {
  3456. return EXIT_FAILURE;
  3457. }
  3458. }
  3459. // GUI initializaiton.
  3460. //gui = test_gui;
  3461. //gui = test_gui__calculator;
  3462. //gui = test_gui__scrollbars;
  3463. //gui = test_gui__draw_command_using_sliders;
  3464. gui = test_gui__subtree;
  3465. //gui = test_gui__tmp;
  3466. X11_Window xwindow = {0};
  3467. int xinit_status = init_x11(&xwindow);
  3468. if(xinit_status != EXIT_SUCCESS)
  3469. {
  3470. return EXIT_FAILURE;
  3471. }
  3472. Memory_Arena draw_command_arena = {0};
  3473. assert(linux_allocate_arena_memory(
  3474. &draw_command_arena,
  3475. 1024*4) == 0);
  3476. GUI_Context context = {0};
  3477. #if 0
  3478. init_node_freelist(g_gui_node_freelist, ARRAYLENGTH(g_gui_node_freelist));
  3479. context.rdic.node_freelist = &g_gui_node_freelist[0].rdic_node;
  3480. #else
  3481. init_node_freelist(g_gui_node_freelist, ARRAYLENGTH(g_gui_node_freelist));
  3482. RDIC_Freelist node_freelist = {&g_gui_node_freelist[0].rdic_node};
  3483. context.node_freelist = &node_freelist;
  3484. init_subtree_freelist(g_gui_subtree_freelist, ARRAYLENGTH(g_gui_subtree_freelist));
  3485. RDIC_Freelist subtree_freelist = {&g_gui_subtree_freelist[0].rdic_node};
  3486. context.subtree_freelist = &subtree_freelist;
  3487. Pixel_Buffer background_pixel_buffer = (Pixel_Buffer){
  3488. .pixels = malloc(xwindow.pixel_buffer.width*xwindow.pixel_buffer.height*sizeof(GUI_Color)),
  3489. .width = xwindow.pixel_buffer.width,
  3490. .height = xwindow.pixel_buffer.height,
  3491. };
  3492. Pixel_Buffer top_pixel_buffer = (Pixel_Buffer){
  3493. .pixels = malloc(300*400*sizeof(GUI_Color)),
  3494. .width = 300,
  3495. .height = 400,
  3496. };
  3497. assert(background_pixel_buffer.pixels);
  3498. assert(top_pixel_buffer.pixels);
  3499. context.background_layer = (GUI_Layer){
  3500. .subtree_rdic.freelist = &subtree_freelist,
  3501. //.pixel_buffer = &xwindow.pixel_buffer,
  3502. .pixel_buffer = &background_pixel_buffer,
  3503. };
  3504. context.top_layer = (GUI_Layer){
  3505. .subtree_rdic.freelist = &subtree_freelist,
  3506. .pixel_buffer = &top_pixel_buffer,
  3507. };
  3508. #endif
  3509. context.draw_command_arena = &draw_command_arena;
  3510. context.num_draw_commands = 0;
  3511. fill_pixel_buffer(
  3512. xwindow.pixel_buffer.pixels,
  3513. xwindow.width, xwindow.height,
  3514. 0, 0);
  3515. fill_pixel_buffer(
  3516. background_pixel_buffer.pixels,
  3517. background_pixel_buffer.width, background_pixel_buffer.height,
  3518. 0, 0);
  3519. fill_pixel_buffer(
  3520. top_pixel_buffer.pixels,
  3521. top_pixel_buffer.width, top_pixel_buffer.height,
  3522. 0, 0);
  3523. GUI_Rectangle screen_rectangle = {
  3524. .x0 = 0, .y0 = 0,
  3525. .x1 = xwindow.width, .y1 = xwindow.height,
  3526. };
  3527. bool running = true;
  3528. while(running)
  3529. {
  3530. usleep(2*100000);
  3531. context.mouse_pressed = false;
  3532. while(XPending(xwindow.display))
  3533. {
  3534. XEvent x_event = {0};
  3535. XNextEvent(xwindow.display, &x_event);
  3536. if(XFilterEvent(&x_event, xwindow.window))
  3537. {
  3538. continue;
  3539. }
  3540. switch(x_event.type)
  3541. {
  3542. case ButtonPress:
  3543. {
  3544. //printf("Button pressed: %d\n", x_event.xbutton.button);
  3545. context.mouse_pressed = true;
  3546. context.mouse_down = true;
  3547. } break;
  3548. case ButtonRelease:
  3549. {
  3550. //printf("Button released: %d\n", x_event.xbutton.button);
  3551. context.mouse_down = false;
  3552. } break;
  3553. case MotionNotify:
  3554. {
  3555. //printf("Pointer motion: %d, %d\n", x_event.xmotion.x, x_event.xmotion.y);
  3556. context.mouse_x = x_event.xmotion.x;
  3557. context.mouse_y = x_event.xmotion.y;
  3558. } break;
  3559. case KeyPress:
  3560. {
  3561. KeySym keysym = XLookupKeysym(
  3562. &x_event.xkey,
  3563. 0); // What does 0 mean here?
  3564. (void) keysym;
  3565. //printf("Keysym pressed: %s\n", XKeysymToString(keysym));
  3566. //printf("\tkeycode: %d\n", x_event.xkey.keycode);
  3567. //printf("\tkeysym code: %ld\n", keysym);
  3568. switch(x_event.xkey.keycode)
  3569. {
  3570. case 38: break; // a
  3571. case 40: break; // d
  3572. case 25: break; // w
  3573. case 39: break; // s
  3574. //case 24: running = false; break; // q
  3575. case 24: // q
  3576. {
  3577. // Setting the flag here is necessary.
  3578. running = false;
  3579. // Can I just do this after the loop iteration finishes?
  3580. XDestroyWindow(xwindow.display, xwindow.window);
  3581. } break;
  3582. }
  3583. } break;
  3584. case KeyRelease:
  3585. {
  3586. KeySym keysym = XLookupKeysym(
  3587. &x_event.xkey,
  3588. 0); // What does 0 mean here?
  3589. (void) keysym;
  3590. //printf("Keysym released: %s\n", XKeysymToString(keysym));
  3591. switch(x_event.xkey.keycode)
  3592. {
  3593. case 38: break; // a
  3594. case 40: break; // d
  3595. case 25: break; // w
  3596. case 39: break; // s
  3597. }
  3598. } break;
  3599. case DestroyNotify:
  3600. {
  3601. running = false;
  3602. } break;
  3603. default:
  3604. {
  3605. //printf("Unknown event, type: %d\n", x_event.type);
  3606. } break;
  3607. }
  3608. }
  3609. static bool meh = true;
  3610. if(running && meh)
  3611. {
  3612. gui(&context, screen_rectangle);
  3613. if(0)print_node_tree(
  3614. (GUI_Node*)((GUI_Subtree*)context.background_layer.subtree_rdic.root)->rdic.root, 1);
  3615. if(0)print_subtree_tree((GUI_Subtree*)context.background_layer.subtree_rdic.root, 1, true);
  3616. //gui_layout_nodes(&context);
  3617. #if 1
  3618. gui_layout_and_draw(&context);
  3619. gui_compose_layers(&context, &xwindow.pixel_buffer);
  3620. //SET_PIXEL(&xwindow.pixel_buffer, 200, 388, 0x00ff0000);
  3621. #else
  3622. for(
  3623. GUI_Subtree *current = (GUI_Subtree*)context.background_layer.subtree_rdic.root;
  3624. current != NULL;
  3625. current = NULL)//current->next)
  3626. {
  3627. gui_layout_nodes((GUI_Node*)current->rdic.root);
  3628. gui_generate_draw_commands(
  3629. //(GUI_Node*)current->rdic.root,
  3630. current,
  3631. &draw_command_arena,
  3632. &context.num_draw_commands);
  3633. GUI_Draw_Command *draw_command =
  3634. (GUI_Draw_Command*)(draw_command_arena.memory);
  3635. for(int i = 0; i < context.num_draw_commands; i++)
  3636. {
  3637. #if 0
  3638. if(i > 0)
  3639. (draw_command+i)->roundedness = roundedness;
  3640. #endif
  3641. gui_draw_rect(
  3642. &xwindow.pixel_buffer,
  3643. draw_command+i);
  3644. gui_draw_image(
  3645. &xwindow.pixel_buffer,
  3646. draw_command+i);
  3647. gui_draw_text(
  3648. &xwindow.pixel_buffer,
  3649. draw_command+i);
  3650. }
  3651. }
  3652. #elseif 0
  3653. gui_generate_draw_commands(
  3654. (GUI_Node*)context.first_subtree->rdic.root,
  3655. &draw_command_arena,
  3656. &context.num_draw_commands);
  3657. GUI_Draw_Command *draw_command =
  3658. (GUI_Draw_Command*)(draw_command_arena.memory);
  3659. for(int i = 0; i < context.num_draw_commands; i++)
  3660. {
  3661. #if 0
  3662. if(i > 0)
  3663. (draw_command+i)->roundedness = roundedness;
  3664. #endif
  3665. gui_draw_rect(
  3666. &xwindow.pixel_buffer,
  3667. draw_command+i);
  3668. gui_draw_text(
  3669. &xwindow.pixel_buffer,
  3670. draw_command+i);
  3671. }
  3672. #endif
  3673. #if 0
  3674. GUI_Draw_Command test_draw_command = {
  3675. .rectangle = {50, 150, 250, 250},
  3676. .color = 0x00aa8888,
  3677. .border_color = 0x00ffaaff,
  3678. .border_thickness = border_thickness,
  3679. .roundedness = roundedness,
  3680. };
  3681. gui_draw_rounded_rect(&xwindow.pixel_buffer, &test_draw_command);
  3682. GUI_Draw_Command test_draw_command2 = {
  3683. .rectangle = {50, 300, 250, 400},
  3684. .color = 0x00aa8888,
  3685. .border_color = 0x00ffaaff,
  3686. .border_thickness = border_thickness,
  3687. .roundedness = roundedness,
  3688. };
  3689. gui_draw_rounded_rect_with_border(&xwindow.pixel_buffer, &test_draw_command2);
  3690. //meh = false;
  3691. #endif
  3692. #if 0
  3693. //print_bakedchar(32+1, &g_baked_font[1]);
  3694. blend_glyph(
  3695. &xwindow.pixel_buffer,
  3696. &g_baked_font[1],
  3697. 80, 170);
  3698. blend_glyph(
  3699. &xwindow.pixel_buffer,
  3700. &g_baked_font[1],
  3701. 80+g_baked_font[1].xadvance, 170);
  3702. char *text = "This is a text! VA";
  3703. int textlen = sizeof("This is a text! VA")-1;
  3704. int text_width = text_measure_string_width(text, textlen);
  3705. //printf("Text width: %d\n", text_width);
  3706. int next_x = 80;
  3707. test_draw_horizontal_pixel_line(
  3708. &xwindow.pixel_buffer,
  3709. next_x, next_x + text_width, 195,
  3710. 0);
  3711. for(int i = 0; i < textlen; i++)
  3712. {
  3713. int glyph_index = text[i] - 32;
  3714. stbtt_bakedchar *g = &g_baked_font[glyph_index];
  3715. blend_glyph(
  3716. &xwindow.pixel_buffer,
  3717. g,
  3718. next_x + g->xoff, 195 + g->yoff);
  3719. next_x += g->xadvance;
  3720. }
  3721. blend_string(
  3722. &xwindow.pixel_buffer,
  3723. //GUI_STRING("This is a text! VA"),
  3724. GUI_STRING("a = 19 + 23; 1234567890C+-*/="),
  3725. 360, 260);
  3726. test_draw_horizontal_pixel_line(
  3727. &xwindow.pixel_buffer,
  3728. 360, 360+200, 260,
  3729. 0x00ff0000);
  3730. copy_from_atlas(
  3731. &xwindow.pixel_buffer,
  3732. 300, 100,
  3733. 0, 0, 512, 100);
  3734. //SET_PIXEL(&xwindow.pixel_buffer, 100, 100, 0x00ffffff);
  3735. #endif
  3736. draw_window(&xwindow);
  3737. XFlush(xwindow.display);
  3738. }
  3739. }
  3740. XDestroyImage(xwindow.screen_image);
  3741. //XUnmapWindow(xwindow.display, xwindow.window);
  3742. //XDestroyWindow(xwindow.display, xwindow.window);
  3743. XFreeColormap(xwindow.display, xwindow.colormap);
  3744. XCloseDisplay(xwindow.display);
  3745. //getc(stdin);
  3746. return 0;
  3747. }