1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3
4#include "dashboard.h"
5
6#include <fmt/core.h>
7
8void Widget::set_property(std::string_view name, const slint::interpreter::Value &value)
9{
10 if (m_ui)
11 (*m_ui)->set_property(name: qualified_property_name(name), value);
12}
13
14std::optional<slint::interpreter::Value> Widget::property(std::string_view name) const
15{
16 if (m_ui)
17 return (*m_ui)->get_property(name: qualified_property_name(name));
18 return {};
19}
20
21void Widget::connect_ui(const slint::ComponentHandle<slint::interpreter::ComponentInstance> &ui,
22 std::string_view properties_prefix)
23{
24 m_ui = ui;
25 m_properties_prefix = properties_prefix;
26}
27
28std::string Widget::qualified_property_name(std::string_view name) const
29{
30 std::string qname(m_properties_prefix);
31 qname += name;
32 return qname;
33}
34
35std::string WidgetLocation::location_bindings() const
36{
37 auto maybe_binding = [](std::string_view name, const auto &opt_value) -> std::string {
38 if (opt_value.has_value()) {
39 return fmt::format(" {}: {};\n", name, *opt_value);
40 } else {
41 return "";
42 }
43 };
44
45 return fmt::format(
46 R"slint(row: {};
47 col: {};
48{}{})slint",
49 row, column, maybe_binding("rowspan", row_span), maybe_binding("colspan", col_span));
50}
51
52void DashboardBuilder::add_grid_widget(WidgetPtr widget, const WidgetLocation &location)
53{
54 auto widget_id = register_widget(widget);
55 grid_widgets.push_back(x: { widget_id, location });
56}
57
58void DashboardBuilder::add_top_bar_widget(WidgetPtr widget)
59{
60 auto widget_id = register_widget(widget);
61 top_bar_widgets.push_back(x: widget_id);
62}
63
64int DashboardBuilder::register_widget(WidgetPtr widget)
65{
66 auto widget_type_name = widget->type_name();
67 widgets_used.insert(x: widget_type_name);
68
69 auto widget_id = int(widgets.size());
70 auto widget_name = fmt::format("widget_{}", widget_id);
71 widgets.push_back({ widget_name, widget });
72 return widget_id;
73}
74
75std::optional<slint::ComponentHandle<slint::interpreter::ComponentInstance>>
76DashboardBuilder::build(slint::interpreter::ComponentCompiler &compiler) const
77{
78 std::string widget_imports;
79
80 for (const auto &widget : widgets_used) {
81 if (widget_imports.size() > 0) {
82 widget_imports.append(s: ", ");
83 }
84 widget_imports.append(str: widget);
85 }
86
87 if (widget_imports.size() > 0) {
88 widget_imports =
89 fmt::format("import {{ {} }} from \"iot-dashboard.slint\";", widget_imports);
90 }
91
92 // Vector of name/type_name of properties forwarded through the MainContent {} element.
93 std::string main_content_properties;
94 std::string main_grid;
95 std::string top_bar;
96 std::string exposed_properties;
97
98 for (const auto &[widget_id, location] : grid_widgets) {
99 const auto &[widget_name, widget_ptr] = widgets[widget_id];
100
101 main_grid.append(fmt::format(
102 R"slint(
103 {0} := {1} {{
104 {2}
105 }}
106 )slint",
107 widget_name, widget_ptr->type_name(), location.location_bindings()));
108
109 std::string properties_prefix = widget_name;
110 properties_prefix.append(s: "__");
111
112 for (const auto &property : widget_ptr->properties()) {
113 std::string forwarded_property_name = properties_prefix;
114 forwarded_property_name.append(str: property.name);
115
116 main_content_properties.append(
117 fmt::format(" in-out property <{0}> {1} <=> {2}.{3};\n", property.type_name,
118 forwarded_property_name, widget_name, property.name));
119
120 exposed_properties.append(
121 fmt::format(" in-out property <{0}> {1} <=> main_content.{1};\n",
122 property.type_name, forwarded_property_name));
123 }
124 }
125
126 for (const auto widget_id : top_bar_widgets) {
127 const auto &[widget_name, widget_ptr] = widgets[widget_id];
128
129 top_bar.append(fmt::format(
130 R"slint(
131 {0} := {1} {{
132 }}
133 )slint",
134 widget_name, widget_ptr->type_name()));
135
136 std::string properties_prefix = widget_name;
137 properties_prefix.append(s: "__");
138
139 for (const auto &property : widget_ptr->properties()) {
140 std::string forwarded_property_name = properties_prefix;
141 forwarded_property_name.append(str: property.name);
142
143 exposed_properties.append(fmt::format(" in-out property <{0}> {1} <=> {2}.{3};\n",
144 property.type_name, forwarded_property_name,
145 widget_name, property.name));
146 }
147 }
148
149 auto source_code = fmt::format(
150 R"slint(
151
152{0}
153
154component MainContent inherits VerticalLayout {{
155{4}
156
157 spacing: 24px;
158 TopBar {{
159 @children
160 }}
161
162 GridLayout {{
163 spacing: 6px;
164 padding-left: 19px;
165 padding-top: 0px;
166 padding-right: 17px;
167 padding-bottom: 24px;
168
169 {2}
170 }}
171}}
172
173export component MainWindow inherits Window {{
174 title: "IOT dashboard";
175
176{3}
177
178 HorizontalLayout {{
179 padding: 0; spacing: 0;
180 MenuBar {{
181 }}
182 main_content := MainContent {{
183 {1}
184 }}
185 }}
186}}
187)slint",
188 widget_imports, top_bar, main_grid, exposed_properties, main_content_properties);
189
190 auto definition = compiler.build_from_source(source_code, SOURCE_DIR);
191
192 for (auto diagnostic : compiler.diagnostics()) {
193 std::cerr << (diagnostic.level == slint::interpreter::DiagnosticLevel::Warning ? "warning: "
194 : "error: ")
195 << diagnostic.message << std::endl;
196 std::cerr << "location: " << diagnostic.source_file;
197 if (diagnostic.line > 0)
198 std::cerr << ":" << diagnostic.line;
199 if (diagnostic.column > 0)
200 std::cerr << ":" << diagnostic.column;
201 std::cerr << std::endl;
202 }
203
204 if (!definition) {
205 std::cerr << "compilation failure!" << std::endl;
206 std::cerr << "generated source:" << std::endl << source_code << std::endl;
207 return {};
208 }
209
210 // std::cerr << source_code << std::endl;
211
212 auto ui = definition->create();
213
214 for (const auto &entry : widgets) {
215 auto [widget_name, widget_ptr] = entry;
216
217 std::string properties_prefix = widget_name;
218 properties_prefix += "__";
219
220 widget_ptr->connect_ui(ui: ui, properties_prefix);
221 }
222
223 return ui;
224}
225

source code of slint/examples/iot-dashboard/dashboard.cpp