21
21
occur. The application may need the ability to inspect the state of the GUI elements or set
22
22
them to a specific state at any given time.
23
23
24
- We all know how to implement 1.
25
-
26
- A common and straight-forward way to implement 2 and 3 is to expose various GUI elements as
27
- members of an application or GUI class. For example, here's a code snippet of an old plugin I
28
- wrote a few years back:
29
-
30
- private:
31
-
32
- input_box_ptr _program_id;
33
- label_ptr _position_text;
34
- button_ptr _enable;
35
- toggle_button_ptr _sync;
36
- menu_ptr _preset_menu;
37
- input_box_ptr _save_as_name;
38
- slider_ptr _master_volume;
39
- label_ptr _master_volume_text;
40
-
41
- The `input_box_ptr`, `button_ptr`, and so on, are `std::shared_ptr`s that are created using the
42
- `share(e)` function and held in the element hieiarchy using the `hold(p)` function. These are
43
- kept as private members in a GUI class which manages the interconnections and presents a
44
- higher-level view to the application through a well-defined API.
45
-
46
- This example presents a more elegant way to structure an elements application using Models.
47
-
48
- The Model (elements/model.hpp) serves as an abstraction for a data type that is linked to one
49
- or more user interface elements. The actual data is accessed and modified through the `get` and
24
+ A typical approach for steps 2 and 3 involves holding different GUI elements as private members
25
+ within an application or GUI class. These elements are managed as shared pointers, created
26
+ using the `share(e)` function and held in the element hieiarchy using the `hold(p)` function.
27
+ The GUI class oversees the interconnections and presents a higher-level view to the application
28
+ through a well-defined API.
29
+
30
+ This example presents a more elegant way to structure an elements application using Models. The
31
+ Model (elements/model.hpp) serves as an abstraction for a data type that is linked to one or
32
+ more user interface elements. The actual data is accessed and modified through the `get` and
50
33
`set` member functions of the derived class. A user interface element can be linked to a
51
- `model` by supplying an `update_function` via the `on_update_ui (f)` member function.
34
+ `model` by supplying an `update_function` via the `on_update (f)` member function.
52
35
53
36
The Model does not care about the GUI element types it is interacting with. It is an abstract
54
- data type that models its underlying data type (e.g. float, int, enum, etc.). In the view point
55
- of the application, it looks and acts like a concrete type. For example, a `value_model<float>`
56
- acts just like a float. You can assign a value to it:
37
+ data type that models its underlying data type (e.g. float, int, enum, etc.). It looks and acts
38
+ like a concrete type.
39
+
40
+ For example, a `value_model<float>` acts just like a float. You can assign a value to it:
57
41
58
42
m = 1.0;
59
43
63
47
64
48
You can also update the GUI elements that are linked to it:
65
49
66
- m.update_ui (0.5);
50
+ m.update (0.5);
67
51
68
52
These capabilities implement 2 and 3 of the requirements.
69
53
92
76
5. The GUI and the application are both unaware of each other.
93
77
94
78
Number 5 is an important design principle known as "decoupling," emphasizing the separation of
95
- concerns and promoting independence between the GUI and the application components.
96
-
97
- The advantages of decoupling in a software design context include:
98
-
99
- 1. Scalability: Decoupling facilitates scalability by enabling the addition or removal of
100
- components without disrupting the entire system. This is particularly important as the
101
- application evolves.
102
-
103
- 2. Parallel Development: The GUI and application can be developed independently.
104
-
105
- 3. Reusability: Decoupled components are more reusable in other contexts. They can be extracted
106
- and utilized in different projects without carrying unnecessary dependencies.
107
-
108
- 4. Maintainability: The overall maintainability of the system is improved because changes to
109
- one component are less likely to cascade through the entire codebase. Maintenance is more
110
- straightforward. Updates or bug fixes to one component can be made without impacting the
111
- rest of the system.
112
-
113
- 5. Modularity: A notable advantage of this approach is that the user interface elements do not
114
- need to be exposed beyond their creation function. Consequently, all GUI logic is localized
115
- and established within the same element creation function.
79
+ concerns and promoting independence between the GUI and the application components. The
80
+ advantages of decoupling in a software design context include, modularity, scalability, and
81
+ reusability, and ease of maintainance.
116
82
117
83
In this example, we present a very simple model, comprising of a floating point value and a
118
84
preset. As the GUI elements are being built, they attach themselves to the model by utilizing
119
- its on_update_ui (f) member function at different nodes within the elements hierarchy. This
85
+ its on_update (f) member function at different nodes within the elements hierarchy. This
120
86
illustrates the approach of designing the user interface based on models.
121
87
=================================================================================================*/
122
88
namespace elements = cycfi::elements;
@@ -185,7 +151,7 @@ auto make_dial(my_model& model, view& view_)
185
151
186
152
// When a new value is assigned to the model, we want to update
187
153
// the dial and refresh the view.
188
- model._value .on_update_ui (
154
+ model._value .on_update (
189
155
[&view_, dial_ptr](double val)
190
156
{
191
157
dial_ptr->value (val);
@@ -265,11 +231,12 @@ auto make_preset_menu(my_model& model, view& view_)
265
231
266
232
// When a new preset is assigned to the model, we want to update
267
233
// the menu text and refresh the view.
268
- model._preset .on_update_ui (
234
+ model._preset .on_update (
269
235
[&view_, label = preset_menu.second , &model](my_model::preset val)
270
236
{
271
237
if (val == my_model::preset_none)
272
238
{
239
+ // Prepend '*' to the string to indicate that it is being edited.
273
240
auto text = label->get_text ();
274
241
if (text[0 ] != ' *' )
275
242
label->set_text (" *" + std::string{text});
@@ -300,7 +267,7 @@ auto make_input_box(my_model& model, view& view_)
300
267
301
268
// When a new value is assigned to the model, we want to update
302
269
// the input text box and refresh the view.
303
- model._value .on_update_ui (
270
+ model._value .on_update (
304
271
[&view_, input = tbox.second ](double val)
305
272
{
306
273
input->set_text (std::to_string (val));
@@ -351,7 +318,7 @@ auto make_input_box(my_model& model, view& view_)
351
318
[&model]()
352
319
{
353
320
// When errors are enountered, reset the model's value to its previous state.
354
- model._value .update_ui ();
321
+ model._value .update ();
355
322
};
356
323
357
324
// Bring up a message box.
@@ -360,7 +327,7 @@ auto make_input_box(my_model& model, view& view_)
360
327
}
361
328
};
362
329
363
- return halign ( 0.5 , hsize (70 , tbox.first ));
330
+ return align_center ( hsize (70 , tbox.first ));
364
331
}
365
332
366
333
// Finally, we have our main content.
0 commit comments