-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy paththe_debuginator.h
4565 lines (3849 loc) · 187 KB
/
the_debuginator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// clang-format off
/*
the_debuginator.h - v0.01 - public domain - Anders Elfgren @srekel, 2017
# THE DEBUGINATOR
A super sweet hierarchical debug menu intended for games.
See github for latest version: https://github.com/Srekel/the-debuginator
## Usage
In *ONE* source file, put:
```C
#define DEBUGINATOR_IMPLEMENTATION
// Define any of these if you wish to override them.
// (There are more. Find them in the beginning of the code.)
#define DEBUGINATOR_assert
#define DEBUGINATOR_memcpy
#define DEBUGINATOR_fabs
#include "the_debuginator.h"
```
Other source files should just include the_debuginator.h
## Notes
See the accompanying SDL demo project for references on how to use it.
Or the documentation on the github page.
## License
Basically Public Domain / MIT.
See end of file for license information.
*/
#ifndef INCLUDE_THE_DEBUGINATOR_H
#define INCLUDE_THE_DEBUGINATOR_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DEBUGINATOR_ENABLE_WARNINGS
#ifdef _MSC_VER
#pragma warning( push, 0 )
// member padding, nameless struct/union
#pragma warning( disable: 4820 4201)
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
// cast from 'char *' to 'DebuginatorBlockAllocator **'
// increases required alignment from 1 to 8 [-Werror,-Wcast-align]
// Seems *slighly* scary but should be fine.
#pragma clang diagnostic ignored "-Wcast-align"
// if (mouse_over || debuginator->hot_item == item && item->leaf.hot_index == i) {
#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
// (void)debuginator, item, position;
#pragma clang diagnostic ignored "-Wunused-value"
// (void)debuginator, item, position;
#pragma clang diagnostic ignored "-Wcomma"
// block_address *= capacity;
#pragma clang diagnostic ignored "-Wsign-conversion"
// DEBUGINATOR_assert(path_indices[current_path_index + 1] < sizeof(current_full_path));
#pragma clang diagnostic ignored "-Wsign-compare"
// filter_color.a = alpha * DEBUGINATOR_sin(debuginator->draw_timer) < 0.5 ? 220u : 50u;
#pragma clang diagnostic ignored "-Wdouble-promotion"
// int filter_len = DEBUGINATOR_strlen(filter);
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#endif
#endif // DEBUGINATOR_ENABLE_WARNINGS
#ifndef DEBUGINATOR_THEMES_MAX
#define DEBUGINATOR_THEMES_MAX 16
#endif
#ifndef DEBUGINATOR_BOOL_OVERRIDE
#ifndef __cplusplus
#include <stdbool.h>
#endif
#endif
typedef enum DebuginatorDrawType {
DEBUGINATOR_Background,
DEBUGINATOR_BackgroundAlt,
DEBUGINATOR_FolderTitle,
DEBUGINATOR_ItemTitle,
DEBUGINATOR_ItemTitleOverridden,
DEBUGINATOR_ItemTitleHot,
DEBUGINATOR_ItemTitleActive,
DEBUGINATOR_ItemTitleActive1,
DEBUGINATOR_ItemTitleActive2,
DEBUGINATOR_ItemDescription,
DEBUGINATOR_LineHighlight,
DEBUGINATOR_LineHighlightMouse,
DEBUGINATOR_ItemValueDefault,
DEBUGINATOR_ItemValueOverridden,
DEBUGINATOR_ItemValueHot,
DEBUGINATOR_ItemEditorOff,
DEBUGINATOR_ItemEditorOn,
DEBUGINATOR_ItemEditorBackground,
DEBUGINATOR_ItemEditorForeground,
DEBUGINATOR_NumDrawTypes
} DebuginatorDrawType;
typedef enum DebuginatorExpand {
DEBUGINATOR_Collapse = 0,
DEBUGINATOR_Expand,
DEBUGINATOR_Toggle
} DebuginatorExpand;
typedef struct DebuginatorItem DebuginatorItem;
typedef struct DebuginatorVector2 {
float x;
float y;
} DebuginatorVector2;
typedef struct DebuginatorColor {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} DebuginatorColor;
typedef struct DebuginatorFont {
void* userdata;
DebuginatorDrawType draw_type;
int size;
bool bold;
bool italic;
} DebuginatorFont;
typedef struct DebuginatorTheme {
DebuginatorColor colors[DEBUGINATOR_NumDrawTypes];
DebuginatorFont fonts[DEBUGINATOR_NumDrawTypes];
} DebuginatorTheme;
typedef struct DebuginatorSortedItem {
struct DebuginatorItem* item;
struct DebuginatorSortedItem* prev;
struct DebuginatorSortedItem* next;
int score;
} DebuginatorSortedItem;
typedef struct DebuginatorItem DebuginatorItem;
typedef struct TheDebuginatorConfig TheDebuginatorConfig;
struct TheDebuginator;
typedef struct DebuginatorImageHandle {
union {
const char* str_value;
const void* ptr_value;
unsigned long long ull_value;
signed long long sll_value;
} h;
} DebuginatorImageHandle;
enum DebuginatorSoundEvent {
DEBUGINATOR_SoundEventEnter,
DEBUGINATOR_SoundEventActivate,
DEBUGINATOR_SoundEventCollapse,
DEBUGINATOR_SoundEventExpand,
};
#define PLAYSOUND(event) if (debuginator->play_sound) debuginator->play_sound((event), debuginator->app_user_data);
typedef void (*DebuginatorDrawTextCallback)
(const char* text, DebuginatorVector2* position, DebuginatorColor* color, DebuginatorFont* font, void* userdata);
typedef void (*DebuginatorDrawRectCallback)
(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorColor* color, void* userdata);
typedef void (*DebuginatorDrawImageCallback)
(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorImageHandle handle, void* userdata);
typedef void (*DebuginatorPlaySoundCallback)
(enum DebuginatorSoundEvent, void* userdata);
// Of note: New line characters should be at the beginning of any row rather than at the end of them.
typedef void(*DebuginatorWordWrapCallback)
(const char* text, DebuginatorFont* font, float max_width, int* row_count, int* row_lengths, int row_lengths_buffer_size, void* app_userdata);
typedef DebuginatorVector2 (*DebuginatorTextSizeCallback)
(const char* text, DebuginatorFont* font, void* userdata);
typedef void (*DebuginatorLogCallback)
(const char* text, void* userdata);
typedef void (*DebuginatorOnOpenChangedCallback)
(bool opened, bool done, void* app_userdata);
typedef void(*DebuginatorOnItemChangedCallback)(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata);
typedef bool(*DebuginatorSaveItemCallback)(const char* key, const char* value, void* userdata);
typedef enum DebuginatorItemEditorDataType {
DEBUGINATOR_EditTypeArray, // The default
DEBUGINATOR_EditTypeArrayExpand, // When you want it to expand rather than toggle
DEBUGINATOR_EditTypeActionArray, // For items with direct actions and no state
DEBUGINATOR_EditTypeActionArrayExpand, // When you want it to expand rather than toggle
DEBUGINATOR_EditTypeBoolean,
DEBUGINATOR_EditTypePreset,
DEBUGINATOR_EditTypeColorPicker,
DEBUGINATOR_EditTypeNumberRange,
/*DEBUGINATOR_EditTypeUserType1,
...
DEBUGINATOR_EditTypeUserTypeN,*/
DEBUGINATOR_EditTypeCount = 16,
} DebuginatorItemEditorDataType;
typedef enum DebuginatorDrawMode {
DEBUGINATOR_DrawModeHierarchy,
DEBUGINATOR_DrawModeSortedFilter,
} DebuginatorDrawMode;
// API START
// Call to create an instance of the debuginator. Make sure the config has
// all the necessary stuff in it.
// debuginator_get_default_config is recommended but not necessary.
void debuginator_create(TheDebuginatorConfig* config, struct TheDebuginator* debuginator);
// Provides a decent default config for debuginator_create. NOTE Does not initialize
// EVERYTHING that's needed, you still need to set some things.
void debuginator_get_default_config(TheDebuginatorConfig* config);
// Returns true when it's started to show, returns false as soon as it's closing.
bool debuginator_is_open(struct TheDebuginator* debuginator);
// Starts opening or closing
void debuginator_set_open(struct TheDebuginator* debuginator, bool open);
void debuginator_update(struct TheDebuginator* debuginator, float dt);
void debuginator_draw(struct TheDebuginator* debuginator, float dt);
// parent is optional, can be used for a bit of performance I suppose.
// path is on the format a_parent/the_new_item
// description is optional
// on item changed callback is optional
// userdata is optional
// value_titles is optional if num_values == 0.
// values is optional if num_values == 0. Should otherwise be an array of num_values items that are value_size bytes large.
// num_values can be >= 0.
// value size can be 0 if num_values == 0
DebuginatorItem* debuginator_create_array_item(struct TheDebuginator* debuginator,
DebuginatorItem* parent, const char* path, const char* description,
DebuginatorOnItemChangedCallback on_item_changed_callback, void* user_data,
const char** value_titles, void* values, int num_values, int value_size);
// Wraps create_array_item. user_data should point to a single byte. It'll get 1 or 0 written to it.
DebuginatorItem* debuginator_create_bool_item(struct TheDebuginator* debuginator, const char* path, const char* description, void* user_data);
// Like above but when you want a custom callback
DebuginatorItem* debuginator_create_bool_item_with_callback(struct TheDebuginator* debuginator, const char* path, const char* description, void* user_data, DebuginatorOnItemChangedCallback callback);
// Useful simple callback function for setting a small value
void debuginator_copy_1byte(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata);
// Wraps create_array_item. Creates an item which, upon activation, sets the value of all items referenced to by paths, to
// have the value from the corresponding index in value_titles.
// value_indices is currently not used
// paths and value_titles need to be of length num_paths.
DebuginatorItem* debuginator_create_preset_item(struct TheDebuginator* debuginator, const char* path, const char** paths, const char** value_titles, int** value_indices, int num_paths);
// Wraps create_array_item. Creates an item that contains a color picker.
DebuginatorItem* debuginator_create_colorpicker_item(struct TheDebuginator* debuginator, const char* path, const char* description, DebuginatorOnItemChangedCallback on_item_changed_callback, void* user_data, DebuginatorColor* start_color);
DebuginatorItem* debuginator_create_numberrange_float_item(struct TheDebuginator* debuginator, const char* path, const char* description, float* user_data, float range_min, float range_max);
// If you want to create a new empty folder.
DebuginatorItem* debuginator_create_folder_item(struct TheDebuginator* debuginator, DebuginatorItem* parent, const char* path);
DebuginatorItem* debuginator_new_folder_item(struct TheDebuginator* debuginator, DebuginatorItem* parent, const char* title, int title_length);
// Get an item by its path.
// If create_if_not_exist is a valid pointer, the item will be created if not found. The pointer will then be set to true.
DebuginatorItem* debuginator_get_item(struct TheDebuginator* debuginator, DebuginatorItem* parent, const char* path, bool* create_if_not_exist);
// Returns the menu root item.
DebuginatorItem* debuginator_get_root_item(struct TheDebuginator* debuginator);
// Returns first child of the folder item, or NULL if it oesn't have any children.
DebuginatorItem* debuginator_get_first_child(struct TheDebuginator* debuginator, DebuginatorItem* item);
// Returns the item's next sibling, or NULL if it doesn't have any, i.e. it's the last item under a folder.
DebuginatorItem* debuginator_get_next_sibling(struct TheDebuginator* debuginator, DebuginatorItem* item);
// Remove an item by reference
void debuginator_remove_item(struct TheDebuginator* debuginator, DebuginatorItem* item);
// Remove an item by its path
void debuginator_remove_item_by_path(struct TheDebuginator* debuginator, const char* path);
void debuginator_set_hot_item(struct TheDebuginator* debuginator, DebuginatorItem* item);
DebuginatorItem* debuginator_get_hot_item(struct TheDebuginator* debuginator, int* out_hot_item_index);
// Get item's parent
DebuginatorItem* debuginator_get_parent(DebuginatorItem* item);
// Get item's path. If buffer size isn't big enough, it'll be set to the needed amount.
void debuginator_get_path(struct TheDebuginator* debuginator, DebuginatorItem* item, char* buffer, int* buffer_size);
// Is folder
bool debuginator_is_folder(DebuginatorItem* item);
// Save the state. Each item whose current active_index is different from its default_index will be saved, by a call to the
// callback you pass in.
bool debuginator_save(struct TheDebuginator* debuginator, DebuginatorSaveItemCallback callback, void* userdata);
// Preload an item. If the item doesn't exist, it will be created but be hidden until properly created later.
// value_title should be the value you want it to have when finally created.
void debuginator_load_item(struct TheDebuginator* debuginator, const char* key, const char* value);
// Set an item's default value. If value_title is NULL, value_index will be used instead.
// value index is used if value_title == NULL
void debuginator_set_default_value(struct TheDebuginator* debuginator, const char* path, const char* value_title, int value_index);
// Resets item and children to default values.
void debuginator_reset_items_recursively(struct TheDebuginator* debuginator, DebuginatorItem* item);
// For number range and color pickers etc
void debuginator_modify_value(struct TheDebuginator* debuginator, DebuginatorItem* item, float x_axis, float y_axis, bool snap);
// Set an item's edit type.
void debuginator_set_edit_type(struct TheDebuginator* debuginator, const char* path, DebuginatorItemEditorDataType edit_type);
// Set an item's callback. Only for leaves.
void debuginator_item_set_on_changed_callback_by_path(struct TheDebuginator* debuginator, const char* path, DebuginatorOnItemChangedCallback callback);
// Set an item's callback. Only for leaves.
void debuginator_item_set_on_changed_callback(DebuginatorItem* item, DebuginatorOnItemChangedCallback callback);
// Set an item's userdata. Only for leaves.
void debuginator_item_set_user_data_by_path(struct TheDebuginator* debuginator, const char* path, void* user_data);
// Set an item's userdata. Only for leaves.
void debuginator_item_set_user_data(DebuginatorItem* item, void* user_data);
// Change an item's active index to its hot index, and trigger an activation - callbacks and animations and all.
void debuginator_activate(struct TheDebuginator* debuginator, DebuginatorItem* item, bool animate);
// Collapsability (for folders)
bool debuginator_is_collapsed(DebuginatorItem* item);
void debuginator_set_collapsed(struct TheDebuginator* debuginator, DebuginatorItem* item, bool collapsed);
void debuginator_collapse_to_depth(struct TheDebuginator* debuginator, int depth);
// Navigation functions
// Moves the hot item or hot index to the next/previous visible item or index.
// If long_move is true, it will move to the next item that either has a different parent
// or a different overridden state.
void debuginator_move_to_next_leaf(struct TheDebuginator* debuginator, bool long_move);
void debuginator_move_to_prev_leaf(struct TheDebuginator* debuginator, bool long_move);
// Expands a leaf item (makes it "active") if it's closed, activates it if it's already opened.
// If toggle_and_activate is true, it will increase the hot index once and then activate,
// even if it's not expanded. If the item's edit type's toggle_by_default is true,
// this behaviour is inverted.
void debuginator_move_to_child(struct TheDebuginator* debuginator, bool toggle_and_activate);
// Closes an expanded item.
void debuginator_move_to_parent(struct TheDebuginator* debuginator);
void debuginator_move_sibling_next(struct TheDebuginator* debuginator);
void debuginator_move_sibling_previous(struct TheDebuginator* debuginator);
void debuginator_move_to_root(struct TheDebuginator* debuginator);
// Filter (search) functionality
bool debuginator_is_filtering_enabled(struct TheDebuginator* debuginator);
void debuginator_set_filtering_enabled(struct TheDebuginator* debuginator, bool enabled);
const char* debuginator_get_filter(struct TheDebuginator* debuginator);
void debuginator_set_filter(struct TheDebuginator* debuginator, const char* wanted_filter);
void debuginator_update_filter(struct TheDebuginator* debuginator, const char* wanted_filter);
// Mouse / Touch API
void debuginator_apply_scroll(struct TheDebuginator* debuginator, int distance);
void debuginator_reset_scrolling(struct TheDebuginator* debuginator);
void debuginator_set_mouse_cursor_pos(struct TheDebuginator* debuginator, DebuginatorVector2* mouse_cursor_pos);
void debuginator_activate_item_at_mouse_cursor(struct TheDebuginator* debuginator);
void debuginator_expand_item_at_mouse_cursor(struct TheDebuginator* debuginator, DebuginatorExpand expand);
DebuginatorItem* debuginator_get_item_at_mouse_cursor(struct TheDebuginator* debuginator, int* out_hot_item_index);
bool debuginator_is_mouse_over(struct TheDebuginator* debuginator, bool* out_over_quick_draw_area);
// Hot key API
// Activate returns true if there was an item bound to that key
void debuginator_assign_hot_key(struct TheDebuginator* debuginator, const char* key, const char* path, int value_index, const char* optional_value_title);
void debuginator_unassign_hot_key(struct TheDebuginator* debuginator, const char* key);
DebuginatorItem* debuginator_get_first_assigned_hot_key_item(struct TheDebuginator* debuginator, const char* key);
bool debuginator_activate_hot_key(struct TheDebuginator* debuginator, const char* key);
void debuginator_clear_hot_keys(struct TheDebuginator* debuginator);
// Sets the height of all items. Default 32.
// Recommended to use a power of 2
void debuginator_set_item_height(struct TheDebuginator* debuginator, int item_height);
// Sets width and height of The Debuginator
void debuginator_set_size(struct TheDebuginator* debuginator, int width, int height);
// Sets screen resolution for The Debuginator. Only used for right-aligned mode.
void debuginator_set_screen_resolution(struct TheDebuginator* debuginator, int width, int height);
// Not sure there'a valid use case for this but.. it doesn't exactly hurt.
int debuginator_total_height(struct TheDebuginator* debuginator);
// True for left, false for right. Use in conjunction with screen resolution.
void debuginator_set_left_aligned(struct TheDebuginator* debuginator, bool left_aligned);
bool debuginator_is_left_aligned(struct TheDebuginator* debuginator);
float debuginator_distance_from_edge(struct TheDebuginator* debuginator);
// Notification API
void debuginator_set_notifications_enabled(struct TheDebuginator* debuginator, bool enabled);
void debuginator_trigger_nondefault_notifications(struct TheDebuginator* debuginator);
// Copies a string and returns a pointer to one that the debuginator owns and will
// free if assigned as the description. (TODO: Add for value_titles)
char* debuginator_copy_string(struct TheDebuginator* debuginator, const char* string, int length);
// Logs current value
void debuginator_log_item(struct TheDebuginator* debuginator, DebuginatorItem* item);
// API END
typedef struct DebuginatorFolderData {
DebuginatorItem* first_child;
DebuginatorItem* hot_child;
int num_visible_children;
bool is_collapsed; // Note collapsed as opposed to expanded - because I want false/0 to be default
bool is_sorted; // Uses alphabetic sorting
} DebuginatorFolderData;
typedef struct DebuginatorLeafData {
// A helpful text for the user
const char* description;
int description_line_count;
// The values and the UI titles
const char** value_titles;
void* values;
int num_values;
// How big each element in values is
int array_element_size;
// Gets called when item is activated
DebuginatorOnItemChangedCallback on_item_changed_callback;
// How the item is visualized and how its user interaction works.
DebuginatorItemEditorDataType edit_type;
// For animations.
float draw_t;
// The currently "hovered" value index.
size_t hot_index;
// The currently set value index. Will be set to hot_index upon activation.
size_t active_index;
// The item's default index. Used for saving, and for UI.
size_t default_index;
// If the item is expanded (opened).
bool is_expanded;
// -1 (DEBUGINATOR_NO_HOT_INDEX) if not assigned to hot key.
int hot_key_index;
} DebuginatorLeafData;
typedef enum DebuginatorAnimationType {
DEBUGINATOR_ItemActivate
} DebuginatorAnimationType;
typedef struct DebuginatorItemEditorData {
// Draws the active value to the right of the item title.
void(*quick_draw)(struct TheDebuginator* debuginator, DebuginatorItem* item_data, DebuginatorVector2* position);
// Draws stuff under the title when the item is expanded.
void(*expanded_draw)(struct TheDebuginator* debuginator, DebuginatorItem* item_data, DebuginatorVector2* position);
// Currently not used
void(*on_expanded)(struct TheDebuginator* debuginator, DebuginatorItem* item, void* userdata);
// For controls that don't have simple list style values
void(*modify_value)(struct TheDebuginator* debuginator, DebuginatorItem* item, float x_axis, float y_axis, bool snap);
// If the item should revert to its default value after activation
bool forget_state;
// If the default behaviour should be to insta-activate the item rather than expand it.
bool toggle_by_default;
} DebuginatorItemEditorData;
typedef struct DebuginatorItem {
// The 'name' of the item.
const char* title;
// Gets passed in the on changed callback function
void* user_data;
// Intrinsic linked list to navigate
DebuginatorItem* prev_sibling;
DebuginatorItem* next_sibling;
DebuginatorItem* parent;
union {
DebuginatorLeafData leaf;
DebuginatorFolderData folder;
};
// For folders: includes own title and children.
// For leaves: includes own title, and if expanded, description and values
int total_height;
// So we know to look in leaf or folder.
bool is_folder;
// If it's filtered out by the search
bool is_filtered;
} DebuginatorItem;
// Used for creating an instance of TheDebuginator
// You can initialize this with good default values by calling debuginator_get_default_config.
// However, you will always need to set some fields.
typedef struct TheDebuginatorConfig {
// Whether or not to add things like About and Help.
bool create_default_debuginator_items;
// Must be set. Where The Debuginator is allowed to do stuff.
char* memory_arena;
unsigned int memory_arena_capacity;
// Color and font themes
DebuginatorTheme themes[DEBUGINATOR_THEMES_MAX];
// Edit types.
DebuginatorItemEditorData edit_types[DEBUGINATOR_EditTypeCount];
// Gets passed to draw functions.
void* app_user_data;
// Must be set. Functions that will get called during the draw step.
DebuginatorDrawTextCallback draw_text;
DebuginatorDrawRectCallback draw_rect;
DebuginatorWordWrapCallback word_wrap;
DebuginatorTextSizeCallback text_size;
DebuginatorLogCallback log;
// Optional. Will be called during draw.
DebuginatorDrawImageCallback draw_image;
// Optional.
DebuginatorPlaySoundCallback play_sound;
// Optional. Gets called when The Debuginator is opened or closed.
DebuginatorOnOpenChangedCallback on_opened_changed;
// The dimensions of the "panel".
DebuginatorVector2 size; // Might not be needed in the future
// How much space the quick draw functions will get
int quick_draw_size;
// Screen resolution. Used when setting open_direction to -1.
DebuginatorVector2 screen_resolution;
// Set to -1 to put The Debuginator on the right side of the screen.
// Remember to keep screen_resolution up to date.
int open_direction;
// If items should be sorted automatically or not
bool sort_items;
// Where the hot item should be, height-wise, on the screen.
float focus_height;
// The height of each item.
int item_height;
// Optional, use if you want to use a color picker editor.
DebuginatorImageHandle colorpicker_image;
// Whether or not notifications should be shown when items are activated
bool notifications_enabled;
// The root position for the notifications
DebuginatorVector2 notification_position;
} TheDebuginatorConfig;
typedef struct NumberRangeFloatState {
float value_max;
float value_min;
float value_current;
} NumberRangeFloatState;
#ifdef __cplusplus
}
#endif
#ifdef DEBUGINATOR_IMPLEMENTATION
void debuginator_assert(bool condition);
// void debuginator_sprintf_s(char* dest, int dest_size, const char* format, ...);
void debuginator_strcpy_s(char* dest, int dest_size, const char* src);
#ifndef DEBUGINATOR_assert
#include <assert.h>
#define DEBUGINATOR_assert assert
#endif
#ifndef DEBUGINATOR_static_assert
#include <assert.h>
#define DEBUGINATOR_static_assert(test) assert(test);
#endif
#ifndef DEBUGINATOR_memcpy
#include <string.h>
#define DEBUGINATOR_memcpy memcpy
#endif
#ifndef DEBUGINATOR_memcmp
#include <string.h>
#define DEBUGINATOR_memcmp memcmp
#endif
#ifndef DEBUGINATOR_memset
#include <string.h>
#define DEBUGINATOR_memset memset
#endif
#ifndef DEBUGINATOR_strchr
#include <string.h>
#define DEBUGINATOR_strchr strchr
#endif
#ifndef DEBUGINATOR_strlen
#include <string.h>
#define DEBUGINATOR_strlen strlen
#endif
#ifndef DEBUGINATOR_strcpy_s
#include <string.h>
#define DEBUGINATOR_strcpy_s strcpy_s
#endif
#ifndef DEBUGINATOR_strncpy_s
#include <string.h>
#define DEBUGINATOR_strncpy_s strncpy_s
#endif
#ifndef DEBUGINATOR_sprintf_s
#include <stdio.h>
#define DEBUGINATOR_sprintf_s sprintf_s
#endif
#ifndef DEBUGINATOR_strcmp
#include <string.h>
#define DEBUGINATOR_strcmp strcmp
#endif
#ifndef DEBUGINATOR_tolower
#include <ctype.h>
#define DEBUGINATOR_tolower tolower
#endif
#ifndef DEBUGINATOR_toupper
#include <ctype.h>
#define DEBUGINATOR_toupper toupper
#endif
#ifndef DEBUGINATOR_isalpha
#include <ctype.h>
// must override all
#define DEBUGINATOR_isalpha isalpha
#define DEBUGINATOR_isdigit isdigit
#define DEBUGINATOR_isupper isupper
#endif
#ifndef DEBUGINATOR_fabs
#include <math.h>
#define DEBUGINATOR_fabs fabs
#endif
#ifndef DEBUGINATOR_min
#define DEBUGINATOR_min(a,b) (((a)<(b))?(a):(b))
#define DEBUGINATOR_max(a,b) (((a)>(b))?(a):(b))
#endif
#ifndef DEBUGINATOR_sin
#include <math.h>
#define DEBUGINATOR_sin sin
#endif
#ifndef DEBUGINATOR_FOLDER_COLLAPSED_STRING
#define DEBUGINATOR_FOLDER_COLLAPSED_STRING "folder_collapsed"
#endif
#ifndef DEBUGINATOR_intptr
#define DEBUGINATOR_intptr uintptr_t
#endif
#ifndef DEBUGINATOR_LEFT_MARGIN
#define DEBUGINATOR_LEFT_MARGIN 24
#endif
#ifndef DEBUGINATOR_INDENT
#define DEBUGINATOR_INDENT 24
#endif
#ifndef DEBUGINATOR_FILTER_HEIGHT
#define DEBUGINATOR_FILTER_HEIGHT 50.0f
#endif
#ifndef DEBUGINATOR_FILTER_MAX_LENGTH
#define DEBUGINATOR_FILTER_MAX_LENGTH 32
#endif
#ifndef DEBUGINATOR_SCORE_OVERRIDE
#define DEBUGINATOR_SCORE_WORD_BREAK_START 10
#define DEBUGINATOR_SCORE_WORD_BREAK_END 5
#define DEBUGINATOR_SCORE_ITEM_TITLE_MATCH 5
#endif
#ifndef DEBUGINATOR_MAX_NUM_HOT_KEYS
#define DEBUGINATOR_MAX_NUM_HOT_KEYS 128
#endif
#ifndef DEBUGINATOR_MAX_NOTIFICATIONS
#define DEBUGINATOR_MAX_NOTIFICATIONS 64
#endif
#ifndef DEBUGINATOR_MAX_NOTIFICATION_TEXT
#define DEBUGINATOR_MAX_NOTIFICATION_TEXT 32
#endif
#ifndef DEBUGINATOR_NOTIFICATION_WIDTH
#define DEBUGINATOR_NOTIFICATION_WIDTH 700
#endif
#ifndef DEBUGINATOR_NOTIFICATION_VALUE_WIDTH
#define DEBUGINATOR_NOTIFICATION_VALUE_WIDTH 200
#endif
#ifndef DEBUGINATOR_MAX_HIERARCHY_SIZE
#define DEBUGINATOR_MAX_HIERARCHY_SIZE 16
#endif
#ifndef DEBUGINATOR_MAX_PATH_LENGTH
#define DEBUGINATOR_MAX_PATH_LENGTH 256
#endif
#define DEBUGINATOR_NO_HOT_INDEX -1
#define DEBUGINATOR_CUSTOM_VALUE_STATE_COUNT -1
#ifndef DEBUGINATOR_DO_NOT_HOT_KEY_UPPERCASING
#define DEBUGINATOR_DO_HOT_KEY_UPPERCASING 1
#endif
#ifndef DEBUGINATOR_ALLOCATOR_BLOCK_SIZE
#define DEBUGINATOR_ALLOCATOR_BLOCK_SIZE 0x10000 // 64 kilobytes
#endif
#ifndef DEBUGINATOR_UNUSED
#define DEBUGINATOR_UNUSED(x) ((void)x)
#endif
#ifndef DEBUGINATOR_SORTED_ITEM_COUNT
#define DEBUGINATOR_SORTED_ITEM_COUNT 4
#endif
#ifndef DEBUGINATOR_TOOLTIP_DELAY
#define DEBUGINATOR_TOOLTIP_DELAY -1
#define DEBUGINATOR_TOOLTIP_FADEIN 0.25
#endif
static float debuginator__ceil(float v) {
if ((int)v == v) {
return v;
}
return (float)((int)v) + 1;
}
static float debuginator__floor(float v) {
if ((int)v == v) {
return v;
}
return (float)((int)v);
}
typedef struct DebuginatorBlockAllocator DebuginatorBlockAllocator;
typedef struct DebuginatorBlockAllocatorStaticData {
char* arena_end;
size_t arena_capacity;
size_t block_capacity;
char* next_free_block;
} DebuginatorBlockAllocatorStaticData;
typedef struct DebuginatorBlockAllocator {
DebuginatorBlockAllocatorStaticData* data;
size_t element_size;
char* current_block;
size_t current_block_size;
char* next_free_slot;
size_t stat_total_used;
size_t stat_num_allocations;
size_t stat_num_freed;
size_t stat_num_blocks;
size_t stat_wasted_block_space;
} DebuginatorBlockAllocator;
static void debuginator__block_allocator_init(DebuginatorBlockAllocator* allocator, int element_size, DebuginatorBlockAllocatorStaticData* data) {
DEBUGINATOR_memset(allocator, 0, sizeof(*allocator));
allocator->data = data;
allocator->element_size = element_size;
allocator->current_block = data->next_free_block;
// We're throwing some memory away here to not have to check if the current block is NULL for every allocate.
allocator->current_block_size = sizeof(DebuginatorBlockAllocator*); // Make room for allocator ptr at start of block
data->next_free_block += data->block_capacity;
DEBUGINATOR_assert(allocator->data->arena_end > allocator->data->next_free_block);
*((DebuginatorBlockAllocator**)(void*)allocator->current_block) = allocator;
allocator->stat_wasted_block_space += sizeof(DebuginatorBlockAllocator*);
allocator->stat_num_blocks++;
}
static void* debuginator__block_allocate(DebuginatorBlockAllocator* allocator, int num_bytes) {
(void)num_bytes;
if (allocator->data->block_capacity - allocator->current_block_size < allocator->element_size) {
if (allocator->data->arena_end <= allocator->data->next_free_block) {
return NULL;
}
allocator->stat_wasted_block_space += allocator->data->block_capacity - allocator->current_block_size;
allocator->current_block_size = sizeof(DebuginatorBlockAllocator*); // Make room for allocator ptr at start of block
allocator->current_block = allocator->data->next_free_block;
allocator->data->next_free_block += allocator->data->block_capacity;
DEBUGINATOR_assert(allocator->data->arena_end >= allocator->data->next_free_block);
*((DebuginatorBlockAllocator**)allocator->current_block) = allocator;
allocator->stat_wasted_block_space += sizeof(DebuginatorBlockAllocator*);
allocator->stat_num_blocks++;
}
allocator->stat_num_allocations++;
allocator->stat_total_used += allocator->element_size;
allocator->stat_wasted_block_space += allocator->element_size - num_bytes;
if (allocator->next_free_slot) {
void* result = allocator->next_free_slot;
allocator->next_free_slot = *(char**)allocator->next_free_slot;
allocator->stat_num_freed--;
return result;
}
void* result = allocator->current_block + allocator->current_block_size;
allocator->current_block_size += allocator->element_size;
return result;
}
static void debuginator__block_deallocate(DebuginatorBlockAllocator* allocator, const void* ptr) {
DEBUGINATOR_intptr* next_ptr = (DEBUGINATOR_intptr*)(DEBUGINATOR_intptr)ptr;
if (allocator->next_free_slot == NULL) {
*next_ptr = 0;
}
else {
*next_ptr = (DEBUGINATOR_intptr)allocator->next_free_slot;
}
allocator->next_free_slot = (char*)(DEBUGINATOR_intptr)ptr;
allocator->stat_total_used -= allocator->element_size;
allocator->stat_num_freed++;
allocator->stat_num_allocations--;
}
typedef struct DebuginatorAnimation {
DebuginatorAnimationType type;
union {
struct {
DebuginatorItem* item;
int value_index;
DebuginatorVector2 start_pos;
} item_activate;
} data;
float duration;
float time;
} DebuginatorAnimation;
struct TheDebuginator {
DebuginatorItem* root;
DebuginatorItem* hot_item;
DebuginatorItem* hot_mouse_item;
int hot_mouse_item_index;
bool is_open;
float openness_timer; // range [0,1]
float openness; // range [0,1]
DebuginatorTheme themes[DEBUGINATOR_THEMES_MAX];
DebuginatorTheme theme; // current theme
int theme_index;
DebuginatorItemEditorData edit_types[DEBUGINATOR_EditTypeCount];
float dt;
float draw_timer;
float filter_timer;
float tooltip_timer;
void* app_user_data;
DebuginatorDrawImageCallback draw_image;
DebuginatorDrawRectCallback draw_rect;
DebuginatorDrawTextCallback draw_text;
DebuginatorWordWrapCallback word_wrap;
DebuginatorTextSizeCallback text_size;
DebuginatorLogCallback log;
DebuginatorOnOpenChangedCallback on_opened_changed;
DebuginatorPlaySoundCallback play_sound;
int item_height;
DebuginatorVector2 size;
DebuginatorVector2 root_position; // The fixed position where The Debuginator is when it's closed
DebuginatorVector2 top_left; // The top-left position where The Debuginator currently is
DebuginatorVector2 screen_resolution;
int quick_draw_size;
int scroll_wanted;
int scroll_current;
DebuginatorVector2 mouse_cursor_pos;
char open_direction; // char so I can be lazy and use copy_1_byte.
float focus_height;
float current_height_offset;
bool sort_items;
DebuginatorAnimation animations[8];
int animation_count;
bool filter_enabled;
DebuginatorVector2 filter_pos;
DebuginatorVector2 filter_size;
char filter[DEBUGINATOR_FILTER_MAX_LENGTH];
int filter_length;
DebuginatorSortedItem sorted_items[DEBUGINATOR_SORTED_ITEM_COUNT];
DebuginatorSortedItem* best_sorted_item;
DebuginatorDrawMode draw_mode;
char* memory_arena; // char* for pointer arithmetic
unsigned int memory_arena_capacity;
DebuginatorBlockAllocatorStaticData allocator_data;
DebuginatorBlockAllocator allocators[6];
const char** loaded_settings;
int num_loaded_settings;
int loaded_settings_capacity;
struct {
const char* key;
const char* path;
int value_index;
} hot_keys[DEBUGINATOR_MAX_NUM_HOT_KEYS];
int num_hot_keys;
bool bool_values[2];
const char* bool_titles[2];
DebuginatorImageHandle colorpicker_image;
int notification_count;
DebuginatorVector2 notification_position;
float notification_anims[DEBUGINATOR_MAX_NOTIFICATIONS];
char notification_texts[DEBUGINATOR_MAX_NOTIFICATIONS][DEBUGINATOR_MAX_NOTIFICATION_TEXT];
char notification_paths[DEBUGINATOR_MAX_NOTIFICATIONS][DEBUGINATOR_MAX_PATH_LENGTH];
DebuginatorItem* notification_items[DEBUGINATOR_MAX_NOTIFICATIONS];
bool notifications_enabled;
};
static DebuginatorVector2 debuginator__vector2(float x, float y) {
DebuginatorVector2 v; v.x = x; v.y = y;
return v;
}
static struct DebuginatorColor debuginator__color(int r, int g, int b, int a) {
DEBUGINATOR_assert(0 <= r && r <= 255);
DEBUGINATOR_assert(0 <= g && g <= 255);
DEBUGINATOR_assert(0 <= b && b <= 255);
DEBUGINATOR_assert(0 <= a && a <= 255);
struct DebuginatorColor c;
c.r = (unsigned char)r;
c.g = (unsigned char)g;
c.b = (unsigned char)b;
c.a = (unsigned char)a;
return c;
}
static float debuginator__ease_out(float t, float start_value, float change, float duration) {