Skip to content

Commit 5a88c58

Browse files
committed
Merge branch 'develop'
2 parents 5eb220a + b0d4bce commit 5a88c58

28 files changed

+1060
-365
lines changed

examples/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ add_subdirectory(table_list)
2626
add_subdirectory(drop_file)
2727
add_subdirectory(range_slider)
2828
add_subdirectory(model)
29+
add_subdirectory(selection_list)

examples/custom_control/main.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ void my_custom_control::keep_tracking(context const& ctx, tracker_info& track_in
164164
clamp(_radius, 50, 150);
165165
if (on_change)
166166
on_change(_radius);
167-
ctx.view.refresh(ctx.bounds);
167+
ctx.view.refresh(ctx);
168168
}
169169

170170
///////////////////////////////////////////////////////////////////////////////
@@ -177,7 +177,7 @@ bool my_custom_control::cursor(context const& ctx, point p, cursor_tracking stat
177177
case cursor_tracking::hovering:
178178
case cursor_tracking::entering:
179179
_mouse_over = true;
180-
ctx.view.refresh(ctx.bounds);
180+
ctx.view.refresh(ctx);
181181
break;
182182
case cursor_tracking::leaving:
183183
_mouse_over = false;

examples/list/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ auto background = box(bkd_color);
1414

1515
int main(int argc, char* argv[])
1616
{
17-
app _app(argc, argv, "Dynamic Lists", "com.cycfi.dynamic_lists");
17+
app _app(argc, argv, "Lists", "com.cycfi.list");
1818
window _win(_app.name());
1919
_win.on_close = [&_app]() { _app.stop(); };
2020

examples/list_arranger/main.cpp

+37-27
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,32 @@ auto make_bkd()
1616

1717
// Probably shouldn't be global, but hey, it's a demo. You know what to do :-)
1818
std::vector<std::filesystem::path> paths = {
19-
"/home/user/documents/quantum_energy_matrix_42.txt",
20-
"/var/www/html/interdimensional_portal_manifest.html",
21-
"/usr/bin/elixir_of_eternal_life.exe",
22-
"/mnt/data/enigmatic_astral_code_vortex.jpg",
23-
"/opt/software/ancient_relics_archeology.ini",
24-
"/tmp/temp/mystic_scroll_of_knowledge.tmp",
25-
"/home/user/documents/hyperdimensional_cosmic_key_99.txt",
26-
"/var/log/transcendental_being_encounter.log",
27-
"/usr/lib/quantum_realm_gateway.so",
28-
"/mnt/data/sacred_harmonic_resonance_music.mp3",
29-
"/opt/software/ethereal_data_oracle.json",
30-
"/tmp/temp/ancient_prophecy_tablet.zip",
31-
"/home/user/documents/esoteric_mind_matrix.txt",
32-
"/var/www/html/arcane_ritual_summoning_page.html",
33-
"/usr/bin/ouroboros_eternal_loop_script.sh",
34-
"/mnt/data/celestial_beauty_revelation_video.mp4",
35-
"/opt/software/sacred_geometry_universe.cfg",
36-
"/tmp/temp/profound_astral_chart.csv",
37-
"/home/user/documents/elixir_of_infinite_wisdom.txt",
38-
"/var/log/mystical_realm_access_error.log",
39-
"/usr/bin/magical_portal_activation.exe",
40-
"/mnt/data/cosmic_energy_matrix_manifest.jpg",
41-
"/opt/software/ancient_tome_of_knowledge.log",
42-
"/tmp/temp/akashic_records_of_creation.txt",
43-
"/home/user/documents/quantum_cosmic_frequencies.txt",
44-
"/var/www/html/ethereal_realm_connection.css",
19+
"a/home/user/documents/quantum_energy_matrix_42.txt",
20+
"b/var/www/html/interdimensional_portal_manifest.html",
21+
"c/usr/bin/elixir_of_eternal_life.exe",
22+
"d/mnt/data/enigmatic_astral_code_vortex.jpg",
23+
"e/opt/software/ancient_relics_archeology.ini",
24+
"f/tmp/temp/mystic_scroll_of_knowledge.tmp",
25+
"g/home/user/documents/hyperdimensional_cosmic_key_99.txt",
26+
"h/var/log/transcendental_being_encounter.log",
27+
"i/usr/lib/quantum_realm_gateway.so",
28+
"j/mnt/data/sacred_harmonic_resonance_music.mp3",
29+
"k/opt/software/ethereal_data_oracle.json",
30+
"l/tmp/temp/ancient_prophecy_tablet.zip",
31+
"m/home/user/documents/esoteric_mind_matrix.txt",
32+
"n/var/www/html/arcane_ritual_summoning_page.html",
33+
"o/usr/bin/ouroboros_eternal_loop_script.sh",
34+
"p/mnt/data/celestial_beauty_revelation_video.mp4",
35+
"q/opt/software/sacred_geometry_universe.cfg",
36+
"r/tmp/temp/profound_astral_chart.csv",
37+
"s/home/user/documents/elixir_of_infinite_wisdom.txt",
38+
"t/var/log/mystical_realm_access_error.log",
39+
"u/usr/bin/magical_portal_activation.exe",
40+
"v/mnt/data/cosmic_energy_matrix_manifest.jpg",
41+
"w/opt/software/ancient_tome_of_knowledge.log",
42+
"x/tmp/temp/akashic_records_of_creation.txt",
43+
"y/home/user/documents/quantum_cosmic_frequencies.txt",
44+
"z/var/www/html/ethereal_realm_connection.css",
4545
"/usr/bin/astral_projection_script.rb",
4646
"/mnt/data/ancient_chants_of_enlightenment_music.mp3",
4747
"/opt/software/celestial_beings_communication.png",
@@ -83,7 +83,17 @@ int main(int argc, char* argv[])
8383
size_t list_size = paths.size();
8484
auto && make_row = [&](size_t index)
8585
{
86-
return share(draggable(align_left(label(paths[index].u8string()))));
86+
// If we start with an empty paths vector, we still need to give it a prototypical
87+
// element in order to establish the size limits.
88+
std::string path = paths.empty()? std::string{"Empty"} : paths[index].u8string();
89+
90+
return share(
91+
(
92+
draggable(
93+
align_left(label(path))
94+
)
95+
)
96+
);
8797
};
8898

8999
auto cp = basic_vcell_composer(list_size, make_row);

examples/model/main.cpp

+25-58
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,23 @@
2121
occur. The application may need the ability to inspect the state of the GUI elements or set
2222
them to a specific state at any given time.
2323
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
5033
`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.
5235
5336
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:
5741
5842
m = 1.0;
5943
@@ -63,7 +47,7 @@
6347
6448
You can also update the GUI elements that are linked to it:
6549
66-
m.update_ui(0.5);
50+
m.update(0.5);
6751
6852
These capabilities implement 2 and 3 of the requirements.
6953
@@ -92,31 +76,13 @@
9276
5. The GUI and the application are both unaware of each other.
9377
9478
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.
11682
11783
In this example, we present a very simple model, comprising of a floating point value and a
11884
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
12086
illustrates the approach of designing the user interface based on models.
12187
=================================================================================================*/
12288
namespace elements = cycfi::elements;
@@ -185,7 +151,7 @@ auto make_dial(my_model& model, view& view_)
185151

186152
// When a new value is assigned to the model, we want to update
187153
// the dial and refresh the view.
188-
model._value.on_update_ui(
154+
model._value.on_update(
189155
[&view_, dial_ptr](double val)
190156
{
191157
dial_ptr->value(val);
@@ -265,11 +231,12 @@ auto make_preset_menu(my_model& model, view& view_)
265231

266232
// When a new preset is assigned to the model, we want to update
267233
// the menu text and refresh the view.
268-
model._preset.on_update_ui(
234+
model._preset.on_update(
269235
[&view_, label = preset_menu.second, &model](my_model::preset val)
270236
{
271237
if (val == my_model::preset_none)
272238
{
239+
// Prepend '*' to the string to indicate that it is being edited.
273240
auto text = label->get_text();
274241
if (text[0] != '*')
275242
label->set_text("*" + std::string{text});
@@ -300,7 +267,7 @@ auto make_input_box(my_model& model, view& view_)
300267

301268
// When a new value is assigned to the model, we want to update
302269
// the input text box and refresh the view.
303-
model._value.on_update_ui(
270+
model._value.on_update(
304271
[&view_, input = tbox.second](double val)
305272
{
306273
input->set_text(std::to_string(val));
@@ -351,7 +318,7 @@ auto make_input_box(my_model& model, view& view_)
351318
[&model]()
352319
{
353320
// When errors are enountered, reset the model's value to its previous state.
354-
model._value.update_ui();
321+
model._value.update();
355322
};
356323

357324
// Bring up a message box.
@@ -360,7 +327,7 @@ auto make_input_box(my_model& model, view& view_)
360327
}
361328
};
362329

363-
return halign(0.5, hsize(70, tbox.first));
330+
return align_center(hsize(70, tbox.first));
364331
}
365332

366333
// Finally, we have our main content.
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.9.6...3.15.0)
2+
project(DynamicLists LANGUAGES C CXX VERSION "1.0.0")
3+
4+
if (NOT ELEMENTS_ROOT)
5+
message(FATAL_ERROR "ELEMENTS_ROOT is not set")
6+
endif()
7+
8+
# Make sure ELEMENTS_ROOT is an absolute path to add to the CMake module path
9+
get_filename_component(ELEMENTS_ROOT "${ELEMENTS_ROOT}" ABSOLUTE)
10+
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${ELEMENTS_ROOT}/cmake")
11+
12+
# If we are building outside the project, you need to set ELEMENTS_ROOT:
13+
if (NOT ELEMENTS_BUILD_EXAMPLES)
14+
include(ElementsConfigCommon)
15+
set(ELEMENTS_BUILD_EXAMPLES OFF)
16+
add_subdirectory(${ELEMENTS_ROOT} elements)
17+
endif()
18+
19+
set(ELEMENTS_APP_PROJECT "SelectionList")
20+
set(ELEMENTS_APP_TITLE "Selection List")
21+
set(ELEMENTS_APP_COPYRIGHT "Copyright (c) 2016-2024 Joel de Guzman")
22+
set(ELEMENTS_APP_ID "com.cycfi.selection_list")
23+
set(ELEMENTS_APP_VERSION "1.0")
24+
25+
set(ELEMENTS_APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
26+
27+
# For your custom application icon on macOS or Windows see cmake/AppIcon.cmake module
28+
include(AppIcon)
29+
include(ElementsConfigApp)

examples/selection_list/main.cpp

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*=================================================================================================
2+
Copyright (c) 2016-2024 Joel de Guzman
3+
4+
Distributed under the MIT License (https://opensource.org/licenses/MIT)
5+
=================================================================================================*/
6+
#include <elements.hpp>
7+
8+
using namespace cycfi::elements;
9+
using namespace cycfi::artist;
10+
11+
// Main window background color
12+
auto constexpr bkd_color = rgba(35, 35, 37, 255);
13+
auto background = box(bkd_color);
14+
15+
struct my_element : element, selectable
16+
{
17+
my_element(int n)
18+
: _n{n}
19+
{}
20+
21+
void draw(context const& ctx) override
22+
{
23+
auto& cnv = ctx.canvas;
24+
auto state = cnv.new_state();
25+
auto const& theme_ = get_theme();
26+
27+
if (_is_selected)
28+
{
29+
cnv.begin_path();
30+
cnv.add_rect(ctx.bounds);
31+
cnv.fill_style(theme_.indicator_color.opacity(0.6));
32+
cnv.fill();
33+
}
34+
35+
auto middle = ctx.bounds.top + (ctx.bounds.height()/2);
36+
cnv.fill_style(theme_.label_font_color);
37+
cnv.font(theme_.label_font);
38+
cnv.text_align(cnv.left | cnv.middle);
39+
cnv.fill_text(std::string{"Item "} + std::to_string(_n), point{ctx.bounds.left+10, middle});
40+
}
41+
42+
bool is_selected() const override
43+
{
44+
return _is_selected;
45+
}
46+
47+
void select(bool state) override
48+
{
49+
_is_selected = state;
50+
}
51+
52+
int _n;
53+
bool _is_selected = false;
54+
};
55+
56+
int main(int argc, char* argv[])
57+
{
58+
app _app(argc, argv, "Selection Lists", "com.cycfi.selection_lists");
59+
window _win(_app.name());
60+
_win.on_close = [&_app]() { _app.stop(); };
61+
62+
view view_(_win);
63+
64+
auto&& draw_cell =
65+
[](std::size_t index)
66+
{
67+
return share(
68+
margin({20, 0, 20, 0},
69+
align_left(
70+
vsize(25, my_element(index+1))
71+
)
72+
)
73+
);
74+
};
75+
76+
auto my_composer =
77+
basic_cell_composer(
78+
200, // size (number of rows)
79+
draw_cell // Composer function
80+
);
81+
82+
auto content = share(
83+
selection_list(
84+
list{my_composer, false}
85+
)
86+
);
87+
88+
view_.content(
89+
vscroller(hold(content)),
90+
background
91+
);
92+
93+
_app.run();
94+
return 0;
95+
}

0 commit comments

Comments
 (0)