1111#include " shell/panel/panel_button_style.h"
1212#include " shell/panel/panel_manager.h"
1313#include " shell/wallpaper/panel/wallpaper_tile.h"
14- #include " ui/controls/button.h"
15- #include " ui/controls/flex.h"
16- #include " ui/controls/input.h"
17- #include " ui/controls/label.h"
18- #include " ui/controls/scroll_view.h"
19- #include " ui/controls/select.h"
20- #include " ui/controls/spacer.h"
21- #include " ui/controls/toggle.h"
22- #include " ui/controls/virtual_grid_view.h"
14+ #include " ui/builders.h"
2315#include " ui/dialogs/color_picker_dialog.h"
2416#include " ui/palette.h"
2517#include " ui/style.h"
@@ -127,172 +119,169 @@ PanelPlacement WallpaperPanel::panelPlacement() const noexcept {
127119
128120void WallpaperPanel::create () {
129121 const float scale = contentScale ();
130- const auto configureIconButton = [scale](Button* button) {
131- if (button == nullptr ) {
132- return ;
133- }
134- button->setGlyphSize (Style::fontSizeBody * scale);
135- button->setMinWidth (Style::controlHeightSm * scale);
136- button->setMinHeight (Style::controlHeightSm * scale);
137- button->setPadding (Style::spaceXs * scale);
138- button->setRadius (Style::scaledRadiusMd (scale));
122+ const auto configureIconButton = [scale](Button& button) {
123+ button.setGlyphSize (Style::fontSizeBody * scale);
124+ button.setMinWidth (Style::controlHeightSm * scale);
125+ button.setMinHeight (Style::controlHeightSm * scale);
126+ button.setPadding (Style::spaceXs * scale);
127+ button.setRadius (Style::scaledRadiusMd (scale));
139128 };
140129
141- auto root = std::make_unique<Flex>();
142- root->setDirection (FlexDirection::Vertical);
143- root->setAlign (FlexAlign::Stretch);
144- root->setGap (Style::spaceSm * scale);
145- root->setPadding (Style::spaceMd * scale);
146- m_rootLayout = root.get ();
147-
148- auto header = std::make_unique<Flex>();
149- header->setDirection (FlexDirection::Horizontal);
150- header->setAlign (FlexAlign::Center);
151- header->setGap (Style::spaceSm * scale);
152- header->setFillWidth (true );
153- m_header = header.get ();
154-
155- auto headerLeft = std::make_unique<Flex>();
156- headerLeft->setDirection (FlexDirection::Horizontal);
157- headerLeft->setAlign (FlexAlign::Center);
158- headerLeft->setJustify (FlexJustify::Start);
159- headerLeft->setFlexGrow (1 .0f );
160- headerLeft->setFillWidth (true );
161-
162- auto title = std::make_unique<Label>();
163- title->setText (i18n::tr (" wallpaper.panel.title" ));
164- title->setFontSize (Style::fontSizeTitle * scale);
165- title->setFontWeight (FontWeight::Bold);
166- title->setColor (colorSpecFromRole (ColorRole::Primary));
167- m_title = title.get ();
168- headerLeft->addChild (std::move (title));
169- header->addChild (std::move (headerLeft));
170-
171- auto breadcrumb = std::make_unique<Label>();
172- breadcrumb->setFontSize (Style::fontSizeBody * scale);
173- breadcrumb->setColor (colorSpecFromRole (ColorRole::OnSurfaceVariant));
174- breadcrumb->setMaxLines (1 );
175- m_breadcrumb = breadcrumb.get ();
176- header->addChild (std::move (breadcrumb));
177-
178- auto headerRight = std::make_unique<Flex>();
179- headerRight->setDirection (FlexDirection::Horizontal);
180- headerRight->setAlign (FlexAlign::Center);
181- headerRight->setJustify (FlexJustify::End);
182- headerRight->setFlexGrow (1 .0f );
183- headerRight->setFillWidth (true );
184-
185- auto closeButton = std::make_unique<Button>();
186- closeButton->setGlyph (" close" );
187- panel_button_style::configureHeaderIconButton (*closeButton, scale, panelCardOpacity ());
188- closeButton->setOnClick ([]() { PanelManager::instance ().close (); });
189- m_closeButton = closeButton.get ();
190- headerRight->addChild (std::move (closeButton));
191- header->addChild (std::move (headerRight));
130+ auto root = ui::column ({
131+ .out = &m_rootLayout,
132+ .align = FlexAlign::Stretch,
133+ .gap = Style::spaceSm * scale,
134+ .padding = Style::spaceMd * scale,
135+ });
136+
137+ auto header = ui::row ({
138+ .out = &m_header,
139+ .align = FlexAlign::Center,
140+ .gap = Style::spaceSm * scale,
141+ .fillWidth = true ,
142+ });
143+
144+ header->addChild (
145+ ui::row ({.align = FlexAlign::Center, .justify = FlexJustify::Start, .fillWidth = true , .flexGrow = 1 .0f },
146+ ui::label ({
147+ .out = &m_title,
148+ .text = i18n::tr (" wallpaper.panel.title" ),
149+ .fontSize = Style::fontSizeTitle * scale,
150+ .color = colorSpecFromRole (ColorRole::Primary),
151+ .fontWeight = FontWeight::Bold,
152+ })));
153+
154+ header->addChild (ui::label ({
155+ .out = &m_breadcrumb,
156+ .fontSize = Style::fontSizeBody * scale,
157+ .color = colorSpecFromRole (ColorRole::OnSurfaceVariant),
158+ .maxLines = 1 ,
159+ }));
160+
161+ header->addChild (ui::row (
162+ {.align = FlexAlign::Center, .justify = FlexJustify::End, .fillWidth = true , .flexGrow = 1 .0f },
163+ ui::button ({
164+ .out = &m_closeButton,
165+ .glyph = " close" ,
166+ .onClick = []() { PanelManager::instance ().close (); },
167+ .configure = [scale, opacity = panelCardOpacity ()](
168+ Button& button) { panel_button_style::configureHeaderIconButton (button, scale, opacity); },
169+ })));
192170
193171 root->addChild (std::move (header));
194172
195173 // ── Toolbar ────────────────────────────────────────────────────────────
196- auto toolbar = std::make_unique<Flex>();
197- toolbar->setDirection (FlexDirection::Horizontal);
198- toolbar->setAlign (FlexAlign::Center);
199- toolbar->setGap (Style::spaceSm * scale);
200- toolbar->setFillWidth (true );
201- m_toolbar = toolbar.get ();
202-
203- auto filter = std::make_unique<Input>();
204- filter->setPlaceholder (i18n::tr (" wallpaper.panel.filter-placeholder" ));
205- filter->setFontSize (Style::fontSizeBody * scale);
206- filter->setControlHeight (Style::controlHeight * scale);
207- filter->setHorizontalPadding (Style::spaceMd * scale);
208- filter->setSize (360 .0f * scale, 0 .0f );
209- filter->setOnChange ([this ](const std::string& text) {
210- if (text == m_pendingFilterQuery) {
211- return ;
212- }
213- m_pendingFilterQuery = text;
214- m_filterDebounceTimer.start (kFilterDebounceInterval , [this ]() {
215- if (m_pendingFilterQuery == m_filterQuery) {
216- return ;
217- }
218- m_filterQuery = m_pendingFilterQuery;
219- applyFilter ();
220- resetSelection ();
221- rebindGrid ();
222- m_dirty = true ;
223- PanelManager::instance ().refresh ();
224- });
225- });
226- filter->setOnKeyEvent ([this ](std::uint32_t sym, std::uint32_t modifiers) { return handleKeyEvent (sym, modifiers); });
227- m_filterInput = static_cast <Input*>(toolbar->addChild (std::move (filter)));
228-
229- auto back = std::make_unique<Button>();
230- back->setGlyph (" arrow-big-up" );
231- back->setVariant (ButtonVariant::Secondary);
232- configureIconButton (back.get ());
233- back->setOnClick ([this ]() { navigateUp (); });
234- m_backButton = static_cast <Button*>(toolbar->addChild (std::move (back)));
235-
236- auto spacer = std::make_unique<Spacer>();
237- toolbar->addChild (std::move (spacer));
238-
239- auto flattenLabel = std::make_unique<Label>();
240- flattenLabel->setText (i18n::tr (" wallpaper.panel.flatten" ));
241- flattenLabel->setFontSize (Style::fontSizeBody * scale);
242- flattenLabel->setColor (colorSpecFromRole (ColorRole::OnSurfaceVariant));
243- m_flattenLabel = static_cast <Label*>(toolbar->addChild (std::move (flattenLabel)));
244-
245- auto flatten = std::make_unique<Toggle>();
246- flatten->setChecked (false );
247- flatten->setOnChange ([this ](bool checked) {
248- m_flatten = checked;
249- refreshScan ();
250- applyFilter ();
251- resetSelection ();
252- rebindGrid ();
253- m_dirty = true ;
254- PanelManager::instance ().refresh ();
255- });
256- m_flattenToggle = static_cast <Toggle*>(toolbar->addChild (std::move (flatten)));
257-
258- auto monitorSelect = std::make_unique<Select>();
259- monitorSelect->setFontSize (Style::fontSizeBody * scale);
260- monitorSelect->setControlHeight (Style::controlHeight * scale);
261- monitorSelect->setMinWidth (kMonitorSelectMinWidth * scale);
262- monitorSelect->setOnSelectionChanged ([this ](std::size_t idx, std::string_view) {
263- m_selectedMonitorIndex = idx;
264- m_navStack.clear ();
265- refreshScan ();
266- applyFilter ();
267- resetSelection ();
268- rebindGrid ();
269- rebuildBreadcrumb ();
270- m_dirty = true ;
271- PanelManager::instance ().refresh ();
174+ auto toolbar = ui::row ({
175+ .out = &m_toolbar,
176+ .align = FlexAlign::Center,
177+ .gap = Style::spaceSm * scale,
178+ .fillWidth = true ,
272179 });
273- m_monitorSelect = static_cast <Select*>(toolbar->addChild (std::move (monitorSelect)));
274-
275- auto color = std::make_unique<Button>();
276- color->setGlyph (" color-picker" );
277- color->setVariant (ButtonVariant::Default);
278- configureIconButton (color.get ());
279- color->setOnClick ([this ]() { applyColorWallpaper (); });
280- m_colorButton = static_cast <Button*>(toolbar->addChild (std::move (color)));
281-
282- auto refresh = std::make_unique<Button>();
283- refresh->setGlyph (" refresh" );
284- refresh->setVariant (ButtonVariant::Default);
285- configureIconButton (refresh.get ());
286- refresh->setOnClick ([this ]() {
287- m_scanner.invalidate ();
288- refreshScan ();
289- applyFilter ();
290- resetSelection ();
291- rebindGrid ();
292- m_dirty = true ;
293- PanelManager::instance ().refresh ();
294- });
295- m_refreshButton = static_cast <Button*>(toolbar->addChild (std::move (refresh)));
180+
181+ toolbar->addChild (ui::input ({
182+ .out = &m_filterInput,
183+ .placeholder = i18n::tr (" wallpaper.panel.filter-placeholder" ),
184+ .fontSize = Style::fontSizeBody * scale,
185+ .controlHeight = Style::controlHeight * scale,
186+ .horizontalPadding = Style::spaceMd * scale,
187+ .width = 360 .0f * scale,
188+ .height = 0 .0f ,
189+ .onChange =
190+ [this ](const std::string& text) {
191+ if (text == m_pendingFilterQuery) {
192+ return ;
193+ }
194+ m_pendingFilterQuery = text;
195+ m_filterDebounceTimer.start (kFilterDebounceInterval , [this ]() {
196+ if (m_pendingFilterQuery == m_filterQuery) {
197+ return ;
198+ }
199+ m_filterQuery = m_pendingFilterQuery;
200+ applyFilter ();
201+ resetSelection ();
202+ rebindGrid ();
203+ m_dirty = true ;
204+ PanelManager::instance ().refresh ();
205+ });
206+ },
207+ .onKeyEvent = [this ](std::uint32_t sym, std::uint32_t modifiers) { return handleKeyEvent (sym, modifiers); },
208+ }));
209+
210+ toolbar->addChild (ui::button ({
211+ .out = &m_backButton,
212+ .glyph = " arrow-big-up" ,
213+ .variant = ButtonVariant::Secondary,
214+ .onClick = [this ]() { navigateUp (); },
215+ .configure = configureIconButton,
216+ }));
217+
218+ toolbar->addChild (ui::spacer ());
219+
220+ toolbar->addChild (ui::label ({
221+ .out = &m_flattenLabel,
222+ .text = i18n::tr (" wallpaper.panel.flatten" ),
223+ .fontSize = Style::fontSizeBody * scale,
224+ .color = colorSpecFromRole (ColorRole::OnSurfaceVariant),
225+ }));
226+
227+ toolbar->addChild (ui::toggle ({
228+ .out = &m_flattenToggle,
229+ .checked = false ,
230+ .onChange =
231+ [this ](bool checked) {
232+ m_flatten = checked;
233+ refreshScan ();
234+ applyFilter ();
235+ resetSelection ();
236+ rebindGrid ();
237+ m_dirty = true ;
238+ PanelManager::instance ().refresh ();
239+ },
240+ }));
241+
242+ toolbar->addChild (ui::select ({
243+ .out = &m_monitorSelect,
244+ .fontSize = Style::fontSizeBody * scale,
245+ .controlHeight = Style::controlHeight * scale,
246+ .onSelectionChanged =
247+ [this ](std::size_t idx, std::string_view) {
248+ m_selectedMonitorIndex = idx;
249+ m_navStack.clear ();
250+ refreshScan ();
251+ applyFilter ();
252+ resetSelection ();
253+ rebindGrid ();
254+ rebuildBreadcrumb ();
255+ m_dirty = true ;
256+ PanelManager::instance ().refresh ();
257+ },
258+ .configure = [scale](Select& select) { select.setMinWidth (kMonitorSelectMinWidth * scale); },
259+ }));
260+
261+ toolbar->addChild (ui::button ({
262+ .out = &m_colorButton,
263+ .glyph = " color-picker" ,
264+ .variant = ButtonVariant::Default,
265+ .onClick = [this ]() { applyColorWallpaper (); },
266+ .configure = configureIconButton,
267+ }));
268+
269+ toolbar->addChild (ui::button ({
270+ .out = &m_refreshButton,
271+ .glyph = " refresh" ,
272+ .variant = ButtonVariant::Default,
273+ .onClick =
274+ [this ]() {
275+ m_scanner.invalidate ();
276+ refreshScan ();
277+ applyFilter ();
278+ resetSelection ();
279+ rebindGrid ();
280+ m_dirty = true ;
281+ PanelManager::instance ().refresh ();
282+ },
283+ .configure = configureIconButton,
284+ }));
296285
297286 root->addChild (std::move (toolbar));
298287
@@ -308,21 +297,23 @@ void WallpaperPanel::create() {
308297 }
309298 });
310299
311- auto grid = std::make_unique<VirtualGridView>();
312- grid->setMinCellWidth (kMinTileWidth * scale);
313- grid->setSquareCells (false );
314- grid->setColumnGap (Style::spaceMd * scale);
315- grid->setRowGap (Style::spaceMd * scale);
316- grid->setOverscanRows (2 );
317- grid->setFlexGrow (1 .0f );
318- grid->setFillWidth (true );
319- grid->setAdapter (m_adapter.get ());
320- grid->setOnSelectionChanged ([this ](std::optional<std::size_t > idx) {
321- if (idx.has_value () && *idx < m_visibleEntries.size ()) {
322- m_selectedVisibleIndex = *idx;
323- }
324- });
325- m_grid = static_cast <VirtualGridView*>(root->addChild (std::move (grid)));
300+ root->addChild (ui::virtualGridView ({
301+ .out = &m_grid,
302+ .minCellWidth = kMinTileWidth * scale,
303+ .squareCells = false ,
304+ .columnGap = Style::spaceMd * scale,
305+ .rowGap = Style::spaceMd * scale,
306+ .overscanRows = 2 ,
307+ .adapter = m_adapter.get (),
308+ .flexGrow = 1 .0f ,
309+ .onSelectionChanged =
310+ [this ](std::optional<std::size_t > idx) {
311+ if (idx.has_value () && *idx < m_visibleEntries.size ()) {
312+ m_selectedVisibleIndex = *idx;
313+ }
314+ },
315+ .configure = [](VirtualGridView& grid) { grid.setFillWidth (true ); },
316+ }));
326317
327318 setRoot (std::move (root));
328319 if (m_animations != nullptr ) {
0 commit comments