Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

4181 rinda
121 KiB

pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 1 gada
pirms 1 gada
pirms 1 gada
pirms 1 gada
pirms 11 mēnešiem
pirms 1 gada
pirms 1 gada
pirms 1 gada
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 1 gada
pirms 1 gada
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 1 gada
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 1 gada
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 1 gada
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
pirms 11 mēnešiem
  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. }