]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/uilib/uilib.h
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / libs / uilib / uilib.h
1 #ifndef INCLUDED_UILIB_H
2 #define INCLUDED_UILIB_H
3
4 #include <cstdint>
5 #include <string>
6 #include <glib-object.h>
7
8 struct _GdkEventKey;
9 struct _GtkAccelGroup;
10 struct _GtkAdjustment;
11 struct _GtkAlignment;
12 struct _GtkBin;
13 struct _GtkBox;
14 struct _GtkButton;
15 struct _GtkCellEditable;
16 struct _GtkCellRenderer;
17 struct _GtkCellRendererText;
18 struct _GtkCheckButton;
19 struct _GtkCheckMenuItem;
20 struct _GtkComboBox;
21 struct _GtkComboBoxText;
22 struct _GtkContainer;
23 struct _GtkDialog;
24 struct _GtkEditable;
25 struct _GtkEntry;
26 struct _GtkEntryCompletion;
27 struct _GtkFrame;
28 struct _GtkHBox;
29 struct _GtkHPaned;
30 struct _GtkHScale;
31 struct _GtkImage;
32 struct _GtkItem;
33 struct _GtkLabel;
34 struct _GtkListStore;
35 struct _GtkTreeIter;
36 struct _GtkMenu;
37 struct _GtkMenuBar;
38 struct _GtkMenuItem;
39 struct _GtkMenuShell;
40 struct _GtkMisc;
41 struct _GtkObject;
42 struct _GtkPaned;
43 struct _GtkRadioButton;
44 struct _GtkRadioMenuItem;
45 struct _GtkRadioToolButton;
46 struct _GtkRange;
47 struct _GtkScale;
48 struct _GtkScrolledWindow;
49 struct _GtkSpinButton;
50 struct _GtkTable;
51 struct _GtkTearoffMenuItem;
52 struct _GtkTextView;
53 struct _GtkToggleButton;
54 struct _GtkToggleToolButton;
55 struct _GtkToolbar;
56 struct _GtkToolButton;
57 struct _GtkToolItem;
58 struct _GtkTreeModel;
59 struct _GtkTreePath;
60 struct _GtkTreeSelection;
61 struct _GtkTreeStore;
62 struct _GtkTreeView;
63 struct _GtkTreeViewColumn;
64 struct _GtkVBox;
65 struct _GtkVPaned;
66 struct _GtkWidget;
67 struct _GtkWindow;
68 struct _GTypeInstance;
69
70 #if GTK_TARGET == 3
71 struct _GtkGLArea;
72 #endif
73
74 #if GTK_TARGET == 2
75 using _GtkGLArea = struct _GtkDrawingArea;
76 #endif
77
78 struct ModalDialog;
79
80 namespace ui {
81
82     bool init(int *argc, char **argv[], char const *parameter_string, char const **error);
83
84     void main();
85
86     void process();
87
88     enum class window_type {
89         TOP,
90         POPUP
91     };
92
93     enum class Shadow {
94         NONE,
95         IN,
96         OUT,
97         ETCHED_IN,
98         ETCHED_OUT
99     };
100
101     enum class Policy {
102         ALWAYS,
103         AUTOMATIC,
104         NEVER
105     };
106
107         enum class Packing {
108                 START,
109                 END
110         };
111
112     namespace details {
113
114         enum class Convert {
115             Implicit, Explicit
116         };
117
118         template<class Self, class T, Convert mode>
119         struct Convertible;
120
121         template<class Self, class T>
122         struct Convertible<Self, T, Convert::Implicit> {
123             operator T() const
124             { return reinterpret_cast<T>(static_cast<Self const *>(this)->_handle); }
125         };
126
127         template<class Self, class T>
128         struct Convertible<Self, T, Convert::Explicit> {
129             explicit operator T() const
130             { return reinterpret_cast<T>(static_cast<Self const *>(this)->_handle); }
131         };
132
133         template<class Self, class... T>
134         struct All : T ... {
135             All()
136             {};
137         };
138
139         template<class Self, class Interfaces>
140         struct Mixin;
141         template<class Self>
142         struct Mixin<Self, void()> {
143             using type = All<Self>;
144         };
145         template<class Self, class... Interfaces>
146         struct Mixin<Self, void(Interfaces...)> {
147             using type = All<Self, Interfaces...>;
148         };
149     }
150
151     const struct Null {} null = {};
152     const struct New_t {} New = {};
153
154     class Object :
155             public details::Convertible<Object, _GtkObject *, details::Convert::Explicit>,
156             public details::Convertible<Object, _GTypeInstance *, details::Convert::Explicit> {
157     public:
158         using self = Object *;
159         using native = _GtkObject *;
160         native _handle;
161
162         explicit Object(native h) : _handle(h)
163         {}
164
165         explicit operator bool() const
166         { return _handle != nullptr; }
167
168         explicit operator void *() const
169         { return _handle; }
170
171         void unref()
172         { g_object_unref(_handle); }
173
174         void ref()
175         { g_object_ref(_handle); }
176
177         template<class Lambda>
178         gulong connect(char const *detailed_signal, Lambda &&c_handler, void *data);
179
180         template<class Lambda>
181         gulong connect(char const *detailed_signal, Lambda &&c_handler, Object data);
182     };
183     static_assert(sizeof(Object) == sizeof(Object::native), "object slicing");
184
185 #define WRAP(name, super, T, interfaces, ctors, methods) \
186     class name; \
187     class I##name : public details::Convertible<name, T *, details::Convert::Implicit> { \
188     public: \
189         using self = name *; \
190         methods \
191     }; \
192     class name : public super, public I##name, public details::Mixin<name, void interfaces>::type { \
193     public: \
194         using self = name *; \
195         using native = T *; \
196     protected: \
197         explicit name(native h) noexcept : super(reinterpret_cast<super::native>(h)) {} \
198     public: \
199         explicit name(Null n) noexcept : name((native) nullptr) {} \
200         explicit name(New_t); \
201         static name from(native h) { return name(h); } \
202         static name from(void *ptr) { return name((native) ptr); } \
203         ctors \
204     }; \
205     inline bool operator<(name self, name other) { return self._handle < other._handle; } \
206     static_assert(sizeof(name) == sizeof(super), "object slicing")
207
208     // https://developer.gnome.org/gtk2/stable/ch01.html
209
210     // GInterface
211
212     WRAP(CellEditable, Object, _GtkCellEditable, (),
213     ,
214     );
215
216     WRAP(Editable, Object, _GtkEditable, (),
217     ,
218          void editable(bool value);
219     );
220
221     WRAP(TreeModel, Object, _GtkTreeModel, (),
222     ,
223     );
224
225     // GObject
226
227     struct Dimensions {
228         int width;
229         int height;
230     };
231
232     class Window;
233     WRAP(Widget, Object, _GtkWidget, (),
234     ,
235          Window window();
236          const char *file_dialog(
237                  bool open,
238                  const char *title,
239                  const char *path = nullptr,
240                  const char *pattern = nullptr,
241                  bool want_load = false,
242                  bool want_import = false,
243                  bool want_save = false
244          );
245          bool visible();
246          void visible(bool shown);
247          void show();
248          void hide();
249          Dimensions dimensions();
250          void dimensions(int width, int height);
251          void destroy();
252     );
253
254     WRAP(Container, Widget, _GtkContainer, (),
255     ,
256          void add(Widget widget);
257
258          void remove(Widget widget);
259
260          template<class Lambda>
261          void foreach(Lambda &&lambda);
262     );
263
264     WRAP(Bin, Container, _GtkBin, (),
265     ,
266     );
267
268     class AccelGroup;
269     WRAP(Window, Bin, _GtkWindow, (),
270          explicit Window(window_type type);
271     ,
272          Window create_dialog_window(
273                  const char *title,
274                  void func(),
275                  void *data,
276                  int default_w = -1,
277                  int default_h = -1
278          );
279
280          Window create_modal_dialog_window(
281                  const char *title,
282                  ModalDialog &dialog,
283                  int default_w = -1,
284                  int default_h = -1
285          );
286
287          Window create_floating_window(const char *title);
288
289          std::uint64_t on_key_press(
290                  bool (*f)(Widget widget, _GdkEventKey *event, void *extra),
291                  void *extra = nullptr
292          );
293
294          void add_accel_group(AccelGroup group);
295     );
296
297     WRAP(Dialog, Window, _GtkDialog, (),
298     ,
299     );
300
301     WRAP(Alignment, Bin, _GtkAlignment, (),
302          Alignment(float xalign, float yalign, float xscale, float yscale);
303     ,
304     );
305
306     WRAP(Frame, Bin, _GtkFrame, (),
307          explicit Frame(const char *label = nullptr);
308     ,
309     );
310
311     WRAP(Button, Bin, _GtkButton, (),
312          explicit Button(const char *label);
313     ,
314     );
315
316     WRAP(ToggleButton, Button, _GtkToggleButton, (),
317     ,
318          bool active() const;
319          void active(bool value);
320     );
321
322     WRAP(CheckButton, ToggleButton, _GtkCheckButton, (),
323          explicit CheckButton(const char *label);
324     ,
325     );
326
327     WRAP(RadioButton, CheckButton, _GtkRadioButton, (),
328     ,
329     );
330
331     WRAP(Item, Bin, _GtkItem, (),
332     ,
333     );
334
335     WRAP(MenuItem, Item, _GtkMenuItem, (),
336          explicit MenuItem(const char *label, bool mnemonic = false);
337     ,
338     );
339
340     WRAP(CheckMenuItem, MenuItem, _GtkCheckMenuItem, (),
341     ,
342     );
343
344     WRAP(RadioMenuItem, CheckMenuItem, _GtkRadioMenuItem, (),
345     ,
346     );
347
348     WRAP(TearoffMenuItem, MenuItem, _GtkTearoffMenuItem, (),
349     ,
350     );
351
352     WRAP(ComboBox, Bin, _GtkComboBox, (),
353     ,
354     );
355
356     WRAP(ComboBoxText, ComboBox, _GtkComboBoxText, (),
357     ,
358     );
359
360     WRAP(ToolItem, Bin, _GtkToolItem, (),
361     ,
362     );
363
364     WRAP(ToolButton, ToolItem, _GtkToolButton, (),
365     ,
366     );
367
368     WRAP(ToggleToolButton, ToolButton, _GtkToggleToolButton, (),
369     ,
370     );
371
372     WRAP(RadioToolButton, ToggleToolButton, _GtkRadioToolButton, (),
373     ,
374     );
375
376     WRAP(ScrolledWindow, Bin, _GtkScrolledWindow, (),
377     ,
378          void overflow(Policy x, Policy y);
379     );
380
381     WRAP(Box, Container, _GtkBox, (),
382     ,
383          void pack_start(ui::Widget child, bool expand, bool fill, unsigned int padding);
384          void pack_end(ui::Widget child, bool expand, bool fill, unsigned int padding);
385          void set_child_packing(ui::Widget child, bool expand, bool fill, unsigned int padding, ui::Packing packing);
386     );
387
388     WRAP(VBox, Box, _GtkVBox, (),
389          VBox(bool homogenous, int spacing);
390     ,
391     );
392
393     WRAP(HBox, Box, _GtkHBox, (),
394          HBox(bool homogenous, int spacing);
395     ,
396     );
397
398     WRAP(Paned, Container, _GtkPaned, (),
399     ,
400     );
401
402     WRAP(HPaned, Paned, _GtkHPaned, (),
403     ,
404     );
405
406     WRAP(VPaned, Paned, _GtkVPaned, (),
407     ,
408     );
409
410     WRAP(MenuShell, Container, _GtkMenuShell, (),
411     ,
412     );
413
414     WRAP(MenuBar, MenuShell, _GtkMenuBar, (),
415     ,
416     );
417
418     WRAP(Menu, MenuShell, _GtkMenu, (),
419     ,
420     );
421
422     struct TableAttach {
423         unsigned int left, right, top, bottom;
424     };
425
426     struct TableAttachOptions {
427         // todo: type safety
428         unsigned int x, y;
429     };
430
431     struct TablePadding {
432         unsigned int x, y;
433     };
434
435     WRAP(Table, Container, _GtkTable, (),
436          Table(std::size_t rows, std::size_t columns, bool homogenous);
437     ,
438          // 5 = expand | fill
439          void attach(Widget child, TableAttach attach, TableAttachOptions options = {5, 5}, TablePadding padding = {0, 0});
440     );
441
442     WRAP(TextView, Container, _GtkTextView, (),
443     ,
444          void text(char const *str);
445     );
446
447     WRAP(Toolbar, Container, _GtkToolbar, (),
448     ,
449     );
450
451     class TreeModel;
452     WRAP(TreeView, Widget, _GtkTreeView, (),
453          TreeView(TreeModel model);
454     ,
455     );
456
457     WRAP(Misc, Widget, _GtkMisc, (),
458     ,
459     );
460
461     WRAP(Label, Widget, _GtkLabel, (),
462          explicit Label(const char *label);
463     ,
464          void text(char const *str);
465     );
466
467     WRAP(Image, Widget, _GtkImage, (),
468     ,
469     );
470
471     WRAP(Entry, Widget, _GtkEntry, (IEditable, ICellEditable),
472          explicit Entry(std::size_t max_length);
473     ,
474         char const *text();
475         void text(char const *str);
476     );
477
478     class Adjustment;
479     WRAP(SpinButton, Entry, _GtkSpinButton, (),
480          SpinButton(Adjustment adjustment, double climb_rate, std::size_t digits);
481     ,
482     );
483
484     WRAP(Range, Widget, _GtkRange, (),
485     ,
486     );
487
488     WRAP(Scale, Range, _GtkScale, (),
489     ,
490     );
491
492     WRAP(HScale, Scale, _GtkHScale, (),
493          explicit HScale(Adjustment adjustment);
494          HScale(double min, double max, double step);
495     ,
496     );
497
498     WRAP(Adjustment, Object, _GtkAdjustment, (),
499          Adjustment(double value,
500                     double lower, double upper,
501                     double step_increment, double page_increment,
502                     double page_size);
503     ,
504     );
505
506     WRAP(CellRenderer, Object, _GtkCellRenderer, (),
507     ,
508     );
509
510     WRAP(CellRendererText, CellRenderer, _GtkCellRendererText, (),
511     ,
512     );
513
514     struct TreeViewColumnAttribute {
515         const char *attribute;
516         int column;
517     };
518     WRAP(TreeViewColumn, Object, _GtkTreeViewColumn, (),
519          TreeViewColumn(const char *title, CellRenderer renderer, std::initializer_list<TreeViewColumnAttribute> attributes);
520     ,
521     );
522
523     WRAP(AccelGroup, Object, _GtkAccelGroup, (),
524     ,
525     );
526
527     WRAP(EntryCompletion, Object, _GtkEntryCompletion, (),
528     ,
529     );
530
531     WRAP(ListStore, Object, _GtkListStore, (ITreeModel),
532     ,
533          void clear();
534
535          template<class... T>
536          void append(T... args);
537
538          void append();
539     );
540
541     WRAP(TreeStore, Object, _GtkTreeStore, (ITreeModel),
542     ,
543     );
544
545     WRAP(TreeSelection, Object, _GtkTreeSelection, (),
546     ,
547     );
548
549     // GBoxed
550
551     WRAP(TreePath, Object, _GtkTreePath, (),
552          explicit TreePath(const char *path);
553     ,
554     );
555
556     // Custom
557
558     WRAP(GLArea, Widget, _GtkGLArea, (),
559     ,
560          guint on_render(GCallback pFunction, void *data);
561     );
562
563 #undef WRAP
564
565     // global
566
567     enum class alert_response {
568         OK,
569         CANCEL,
570         YES,
571         NO,
572     };
573
574     enum class alert_type {
575         OK,
576         OKCANCEL,
577         YESNO,
578         YESNOCANCEL,
579         NOYES,
580     };
581
582     enum class alert_icon {
583         Default,
584         Error,
585         Warning,
586         Question,
587         Asterisk,
588     };
589
590     extern class Window root;
591
592     alert_response alert(
593             Window parent,
594             std::string text,
595             std::string title = RADIANT_NAME,
596             alert_type type = alert_type::OK,
597             alert_icon icon = alert_icon::Default
598     );
599
600     // callbacks
601
602     namespace {
603         using GtkCallback = void (*)(_GtkWidget *, void *);
604         extern "C" {
605         void gtk_container_foreach(_GtkContainer *, GtkCallback, void *);
606         }
607     }
608
609 #define this (*static_cast<self>(this))
610
611     template<class Lambda>
612     gulong Object::connect(char const *detailed_signal, Lambda &&c_handler, void *data)
613     {
614         return g_signal_connect(G_OBJECT(this), detailed_signal, c_handler, data);
615     }
616
617     template<class Lambda>
618     gulong Object::connect(char const *detailed_signal, Lambda &&c_handler, Object data)
619     {
620         return g_signal_connect(G_OBJECT(this), detailed_signal, c_handler, (_GtkObject *) data);
621     }
622
623     template<class Lambda>
624     void IContainer::foreach(Lambda &&lambda)
625     {
626         GtkCallback cb = [](_GtkWidget *widget, void *data) -> void {
627             using Function = typename std::decay<Lambda>::type;
628             Function *f = static_cast<Function *>(data);
629             (*f)(Widget::from(widget));
630         };
631         gtk_container_foreach(this, cb, &lambda);
632     }
633
634     namespace {
635         extern "C" {
636         void gtk_list_store_insert_with_values(_GtkListStore *, _GtkTreeIter *, gint position, ...);
637         }
638     }
639
640     template<class... T>
641     void IListStore::append(T... args) {
642         static_assert(sizeof...(args) % 2 == 0, "received an odd number of arguments");
643         gtk_list_store_insert_with_values(this, NULL, -1, args..., -1);
644     }
645
646 #undef this
647
648 }
649
650 #endif