1 /*
2  * preferences.h
3  * Copyright 2007-2014 Tomasz Moń, Ariadne Conill, and John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions, and the following disclaimer in the documentation
13  *    provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #ifndef LIBAUDCORE_PREFERENCES_H
21 #define LIBAUDCORE_PREFERENCES_H
22 
23 #include <libaudcore/objects.h>
24 
25 struct PreferencesWidget;
26 
27 enum class FileSelectMode
28 {
29     File,
30     Folder
31 };
32 
33 struct ComboItem
34 {
35     const char * label;
36     const char * str;
37     int num;
38 
ComboItemComboItem39     constexpr ComboItem(const char * label, const char * str)
40         : label(label), str(str), num(-1)
41     {
42     }
43 
ComboItemComboItem44     constexpr ComboItem(const char * label, int num)
45         : label(label), str(nullptr), num(num)
46     {
47     }
48 };
49 
50 struct WidgetVButton
51 {
52     void (*callback)();
53     const char * icon;
54 };
55 
56 struct WidgetVRadio
57 {
58     int value;
59 };
60 
61 struct WidgetVSpin
62 {
63     double min, max, step;
64     const char * right_label; /* text right to widget */
65 };
66 
67 struct WidgetVTable
68 {
69     ArrayRef<PreferencesWidget> widgets;
70 };
71 
72 struct WidgetVFonts
73 {
74     const char * title;
75 };
76 
77 struct WidgetVEntry
78 {
79     bool password;
80 };
81 
82 struct WidgetVFileEntry
83 {
84     FileSelectMode mode;
85 };
86 
87 struct WidgetVCombo
88 {
89     /* static init */
90     ArrayRef<ComboItem> elems;
91 
92     /* runtime init */
93     ArrayRef<ComboItem> (*fill)();
94 };
95 
96 struct WidgetVBox
97 {
98     ArrayRef<PreferencesWidget> widgets;
99 
100     bool horizontal; /* false gives vertical, true gives horizontal alignment of
101                         child widgets */
102     bool frame;      /* whether to draw frame around box */
103 };
104 
105 struct NotebookTab
106 {
107     const char * name;
108     ArrayRef<PreferencesWidget> widgets;
109 };
110 
111 struct WidgetVNotebook
112 {
113     ArrayRef<NotebookTab> tabs;
114 };
115 
116 struct WidgetVSeparator
117 {
118     bool horizontal; /* false gives vertical, true gives horizontal separator */
119 };
120 
121 union WidgetVariant {
122     WidgetVButton button;
123     WidgetVRadio radio_btn;
124     WidgetVSpin spin_btn;
125     WidgetVTable table;
126     WidgetVFonts font_btn;
127     WidgetVEntry entry;
128     WidgetVFileEntry file_entry;
129     WidgetVCombo combo;
130     WidgetVBox box;
131     WidgetVNotebook notebook;
132     WidgetVSeparator separator;
133 
134     /* for custom GTK or Qt widgets */
135     /* GtkWidget * (* populate) (); */
136     /* QWidget * (* populate) (); */
137     void * (*populate)();
138 
WidgetVariant(WidgetVButton button)139     constexpr WidgetVariant(WidgetVButton button) : button(button) {}
WidgetVariant(WidgetVRadio radio)140     constexpr WidgetVariant(WidgetVRadio radio) : radio_btn(radio) {}
WidgetVariant(WidgetVSpin spin)141     constexpr WidgetVariant(WidgetVSpin spin) : spin_btn(spin) {}
WidgetVariant(WidgetVTable table)142     constexpr WidgetVariant(WidgetVTable table) : table(table) {}
WidgetVariant(WidgetVFonts fonts)143     constexpr WidgetVariant(WidgetVFonts fonts) : font_btn(fonts) {}
WidgetVariant(WidgetVEntry entry)144     constexpr WidgetVariant(WidgetVEntry entry) : entry(entry) {}
WidgetVariant(WidgetVFileEntry file_entry)145     constexpr WidgetVariant(WidgetVFileEntry file_entry)
146         : file_entry(file_entry)
147     {
148     }
WidgetVariant(WidgetVCombo combo)149     constexpr WidgetVariant(WidgetVCombo combo) : combo(combo) {}
WidgetVariant(WidgetVBox box)150     constexpr WidgetVariant(WidgetVBox box) : box(box) {}
WidgetVariant(WidgetVNotebook notebook)151     constexpr WidgetVariant(WidgetVNotebook notebook) : notebook(notebook) {}
WidgetVariant(WidgetVSeparator separator)152     constexpr WidgetVariant(WidgetVSeparator separator) : separator(separator)
153     {
154     }
155 
156     /* also serves as default constructor */
populate(populate)157     constexpr WidgetVariant(void * (*populate)() = 0) : populate(populate) {}
158 };
159 
160 struct WidgetConfig
161 {
162     enum Type
163     {
164         None,
165         Bool,
166         Int,
167         Float,
168         String
169     };
170 
171     Type type;
172 
173     /* pointer to immediate value */
174     void * value;
175     /* identifier for configuration value */
176     const char *section, *name;
177     /* called when value is changed  */
178     void (*callback)();
179     /* widget updates when this hook is called */
180     const char * hook;
181 
WidgetConfigWidgetConfig182     constexpr WidgetConfig()
183         : type(None), value(nullptr), section(nullptr), name(nullptr),
184           callback(nullptr), hook(nullptr)
185     {
186     }
187 
WidgetConfigWidgetConfig188     constexpr WidgetConfig(Type type, void * value, const char * section,
189                            const char * name, void (*callback)(),
190                            const char * hook)
191         : type(type), value(value), section(section), name(name),
192           callback(callback), hook(hook)
193     {
194     }
195 
196     bool get_bool() const;
197     void set_bool(bool val) const;
198     int get_int() const;
199     void set_int(int val) const;
200     double get_float() const;
201     void set_float(double val) const;
202     ::String get_string() const;
203     void set_string(const char * val) const;
204 };
205 
206 constexpr WidgetConfig WidgetBool(bool & value, void (*callback)() = nullptr,
207                                   const char * hook = nullptr)
208 {
209     return WidgetConfig(WidgetConfig::Bool, (void *)&value, 0, 0, callback,
210                         hook);
211 }
212 constexpr WidgetConfig WidgetInt(int & value, void (*callback)() = nullptr,
213                                  const char * hook = nullptr)
214 {
215     return WidgetConfig(WidgetConfig::Int, (void *)&value, 0, 0, callback,
216                         hook);
217 }
218 constexpr WidgetConfig WidgetFloat(double & value, void (*callback)() = nullptr,
219                                    const char * hook = nullptr)
220 {
221     return WidgetConfig(WidgetConfig::Float, (void *)&value, 0, 0, callback,
222                         hook);
223 }
224 constexpr WidgetConfig WidgetString(String & value,
225                                     void (*callback)() = nullptr,
226                                     const char * hook = nullptr)
227 {
228     return WidgetConfig(WidgetConfig::String, (void *)&value, 0, 0, callback,
229                         hook);
230 }
231 
232 constexpr WidgetConfig WidgetBool(const char * section, const char * name,
233                                   void (*callback)() = nullptr,
234                                   const char * hook = nullptr)
235 {
236     return WidgetConfig(WidgetConfig::Bool, 0, section, name, callback, hook);
237 }
238 constexpr WidgetConfig WidgetInt(const char * section, const char * name,
239                                  void (*callback)() = nullptr,
240                                  const char * hook = nullptr)
241 {
242     return WidgetConfig(WidgetConfig::Int, 0, section, name, callback, hook);
243 }
244 constexpr WidgetConfig WidgetFloat(const char * section, const char * name,
245                                    void (*callback)() = nullptr,
246                                    const char * hook = nullptr)
247 {
248     return WidgetConfig(WidgetConfig::Float, 0, section, name, callback, hook);
249 }
250 constexpr WidgetConfig WidgetString(const char * section, const char * name,
251                                     void (*callback)() = nullptr,
252                                     const char * hook = nullptr)
253 {
254     return WidgetConfig(WidgetConfig::String, 0, section, name, callback, hook);
255 }
256 
257 struct PreferencesWidget
258 {
259     enum Type
260     {
261         Label,
262         Button,
263         CheckButton,
264         RadioButton,
265         SpinButton,
266         Entry,
267         FileEntry,
268         ComboBox,
269         FontButton,
270         Box,
271         Table,
272         Notebook,
273         Separator,
274         CustomGTK,
275         CustomQt
276     };
277 
278     Type type;
279     const char *
280         label; /* widget title (for SPIN_BTN it's text left to widget) */
281     bool child;
282 
283     WidgetConfig cfg;
284     WidgetVariant data;
285 };
286 
287 enum WidgetIsChild
288 {
289     WIDGET_NOT_CHILD,
290     WIDGET_CHILD
291 };
292 
293 constexpr PreferencesWidget WidgetLabel(const char * label,
294                                         WidgetIsChild child = WIDGET_NOT_CHILD)
295 {
296     return {PreferencesWidget::Label, label, (child == WIDGET_CHILD)};
297 }
298 
299 constexpr PreferencesWidget WidgetButton(const char * label,
300                                          WidgetVButton button,
301                                          WidgetIsChild child = WIDGET_NOT_CHILD)
302 {
303     return {
304         PreferencesWidget::Button, label, (child == WIDGET_CHILD), {}, button};
305 }
306 
307 constexpr PreferencesWidget WidgetCheck(const char * label, WidgetConfig cfg,
308                                         WidgetIsChild child = WIDGET_NOT_CHILD)
309 {
310     return {PreferencesWidget::CheckButton, label, (child == WIDGET_CHILD),
311             cfg};
312 }
313 
314 constexpr PreferencesWidget WidgetRadio(const char * label, WidgetConfig cfg,
315                                         WidgetVRadio radio,
316                                         WidgetIsChild child = WIDGET_NOT_CHILD)
317 {
318     return {PreferencesWidget::RadioButton, label, (child == WIDGET_CHILD), cfg,
319             radio};
320 }
321 
322 constexpr PreferencesWidget WidgetSpin(const char * label, WidgetConfig cfg,
323                                        WidgetVSpin spin,
324                                        WidgetIsChild child = WIDGET_NOT_CHILD)
325 {
326     return {PreferencesWidget::SpinButton, label, (child == WIDGET_CHILD), cfg,
327             spin};
328 }
329 
330 constexpr PreferencesWidget WidgetEntry(const char * label, WidgetConfig cfg,
331                                         WidgetVEntry entry = WidgetVEntry(),
332                                         WidgetIsChild child = WIDGET_NOT_CHILD)
333 {
334     return {PreferencesWidget::Entry, label, (child == WIDGET_CHILD), cfg,
335             entry};
336 }
337 
338 constexpr PreferencesWidget
339 WidgetFileEntry(const char * label, WidgetConfig cfg,
340                 WidgetVFileEntry file_entry = WidgetVFileEntry(),
341                 WidgetIsChild child = WIDGET_NOT_CHILD)
342 {
343     return {PreferencesWidget::FileEntry, label, (child == WIDGET_CHILD), cfg,
344             file_entry};
345 }
346 
347 constexpr PreferencesWidget WidgetCombo(const char * label, WidgetConfig cfg,
348                                         WidgetVCombo combo,
349                                         WidgetIsChild child = WIDGET_NOT_CHILD)
350 {
351     return {PreferencesWidget::ComboBox, label, (child == WIDGET_CHILD), cfg,
352             combo};
353 }
354 
355 constexpr PreferencesWidget WidgetFonts(const char * label, WidgetConfig cfg,
356                                         WidgetVFonts fonts,
357                                         WidgetIsChild child = WIDGET_NOT_CHILD)
358 {
359     return {PreferencesWidget::FontButton, label, (child == WIDGET_CHILD), cfg,
360             fonts};
361 }
362 
363 constexpr PreferencesWidget WidgetBox(WidgetVBox box,
364                                       WidgetIsChild child = WIDGET_NOT_CHILD)
365 {
366     return {PreferencesWidget::Box, 0, (child == WIDGET_CHILD), {}, box};
367 }
368 
369 constexpr PreferencesWidget WidgetTable(WidgetVTable table,
370                                         WidgetIsChild child = WIDGET_NOT_CHILD)
371 {
372     return {PreferencesWidget::Table, 0, (child == WIDGET_CHILD), {}, table};
373 }
374 
WidgetNotebook(WidgetVNotebook notebook)375 constexpr PreferencesWidget WidgetNotebook(WidgetVNotebook notebook)
376 {
377     return {PreferencesWidget::Notebook, 0, 0, {}, notebook};
378 }
379 
380 constexpr PreferencesWidget
381 WidgetSeparator(WidgetVSeparator separator = WidgetVSeparator())
382 {
383     return {PreferencesWidget::Separator, 0, 0, {}, separator};
384 }
385 
386 constexpr PreferencesWidget
387 WidgetCustomGTK(void * (*populate)(), WidgetIsChild child = WIDGET_NOT_CHILD)
388 {
389     return {
390         PreferencesWidget::CustomGTK, 0, (child == WIDGET_CHILD), {}, populate};
391 }
392 
393 constexpr PreferencesWidget
394 WidgetCustomQt(void * (*populate)(), WidgetIsChild child = WIDGET_NOT_CHILD)
395 {
396     return {
397         PreferencesWidget::CustomQt, 0, (child == WIDGET_CHILD), {}, populate};
398 }
399 
400 struct PluginPreferences
401 {
402     ArrayRef<PreferencesWidget> widgets;
403 
404     void (*init)();
405     void (*apply)();
406     void (*cleanup)();
407 };
408 
409 #endif /* LIBAUDCORE_PREFERENCES_H */
410