1616#include " shell/tooltip/tooltip_manager.h"
1717#include " system/app_identity.h"
1818#include " system/desktop_entry.h"
19- #include " ui/controls/box .h"
19+ #include " ui/builders .h"
2020#include " ui/controls/context_menu.h"
21- #include " ui/controls/flex.h"
22- #include " ui/controls/glyph.h"
23- #include " ui/controls/image.h"
24- #include " ui/controls/label.h"
2521#include " ui/palette.h"
2622#include " ui/popup_chrome.h"
2723#include " ui/style.h"
@@ -167,6 +163,15 @@ namespace {
167163 };
168164 }
169165
166+ std::unique_ptr<Flex> makeDockItemRow (const DockConfig& cfg, bool vertical) {
167+ return ui::makeFlex (vertical ? FlexDirection::Vertical : FlexDirection::Horizontal,
168+ {
169+ .align = FlexAlign::Center,
170+ .gap = static_cast <float >(cfg.itemSpacing ),
171+ .padding = static_cast <float >(cfg.padding ),
172+ });
173+ }
174+
170175} // namespace
171176
172177// ── Lifecycle ─────────────────────────────────────────────────────────────────
@@ -859,22 +864,16 @@ void Dock::buildScene(DockInstance& instance) {
859864
860865 // Shadow
861866 if (shell::surface_shadow::enabled (cfg.shadow , shadowConfig)) {
862- auto shadow = std::make_unique<Box>();
863- instance.shadow = static_cast <Box*>(instance.slideRoot ->addChild (std::move (shadow)));
867+ instance.shadow = static_cast <Box*>(instance.slideRoot ->addChild (ui::box ()));
864868 }
865869
866870 // Panel background
867- auto panel = std::make_unique <Box>();
868- panel-> setRadii (radii);
869- instance. panel = static_cast <Box*>(instance. slideRoot -> addChild ( std::move (panel )));
871+ instance. panel = static_cast <Box*>(instance. slideRoot -> addChild ( ui::box ({
872+ . configure = [radii](Box& box) { box. setRadii (radii); },
873+ } )));
870874
871875 // Item row
872- auto row = std::make_unique<Flex>();
873- row->setDirection (vert ? FlexDirection::Vertical : FlexDirection::Horizontal);
874- row->setGap (static_cast <float >(cfg.itemSpacing ));
875- row->setAlign (FlexAlign::Center);
876- row->setPadding (static_cast <float >(cfg.padding ));
877- instance.row = static_cast <Flex*>(instance.panel ->addChild (std::move (row)));
876+ instance.row = static_cast <Flex*>(instance.panel ->addChild (makeDockItemRow (cfg, vert)));
878877
879878 // Wire up InputDispatcher.
880879 instance.inputDispatcher .setSceneRoot (instance.sceneRoot .get ());
@@ -1027,11 +1026,7 @@ void Dock::rebuildItems(DockInstance& instance) {
10271026 instance.items .clear ();
10281027
10291028 // Create a fresh row.
1030- auto freshRow = std::make_unique<Flex>();
1031- freshRow->setDirection (vert ? FlexDirection::Vertical : FlexDirection::Horizontal);
1032- freshRow->setGap (static_cast <float >(cfg.itemSpacing ));
1033- freshRow->setAlign (FlexAlign::Center);
1034- freshRow->setPadding (static_cast <float >(cfg.padding ));
1029+ auto freshRow = makeDockItemRow (cfg, vert);
10351030 instance.row = static_cast <Flex*>(instance.panel != nullptr ? instance.panel ->addChild (std::move (freshRow))
10361031 : instance.sceneRoot ->addChild (std::move (freshRow)));
10371032
@@ -1097,12 +1092,14 @@ void Dock::rebuildItems(DockInstance& instance) {
10971092 }
10981093
10991094 // Hover background — fills cell, radius matches dock panel.
1100- auto bg = std::make_unique<Box>();
1101- bg->setSize (cellMain, cellMain); // square — excludes indicator strip
1102- bg->setPosition (0 .0f , 0 .0f );
1103- bg->setRadius (static_cast <float >(cfg.radius ));
1104- bg->setFill (clearColorSpec ());
1105- item.background = static_cast <Box*>(areaNode->addChild (std::move (bg)));
1095+ areaNode->addChild (ui::box ({
1096+ .out = &item.background ,
1097+ .fill = clearColorSpec (),
1098+ .radius = static_cast <float >(cfg.radius ),
1099+ .width = cellMain,
1100+ .height = cellMain, // square — excludes indicator strip
1101+ .configure = [](Box& box) { box.setPosition (0 .0f , 0 .0f ); },
1102+ }));
11061103
11071104 // Icon centred inside the padded cell.
11081105 const std::string& iconPath = [&]() -> const std::string& {
@@ -1114,46 +1111,54 @@ void Dock::rebuildItems(DockInstance& instance) {
11141111 }
11151112 return m_iconResolver.resolve (" application-x-executable" , cfg.iconSize );
11161113 }();
1117- auto iconImg = std::make_unique<Image>();
1118- if (!iconPath.empty () && m_renderContext != nullptr ) {
1119- iconImg->setSourceFile (*m_renderContext, iconPath, cfg.iconSize , true );
1120- }
1121- iconImg->setSize (iSize, iSize);
1122- iconImg->setPosition (kCellPad , kCellPad );
1114+ auto iconImg = ui::image ({
1115+ .width = iSize,
1116+ .height = iSize,
1117+ .configure =
1118+ [this , &iconPath, &cfg, kCellPad ](Image& image) {
1119+ if (!iconPath.empty () && m_renderContext != nullptr ) {
1120+ image.setSourceFile (*m_renderContext, iconPath, cfg.iconSize , true );
1121+ }
1122+ image.setPosition (kCellPad , kCellPad );
1123+ },
1124+ });
11231125
11241126 if (iconImg->hasImage ()) {
11251127 item.iconImage = static_cast <Image*>(areaNode->addChild (std::move (iconImg)));
11261128 } else {
11271129 // Fallback: Tabler app-window glyph (matches launcher when theme icons are unavailable).
1128- auto glyph = std::make_unique<Glyph>();
1129- glyph->setGlyph (" app-window" );
1130- glyph->setGlyphSize (iSize);
1131- glyph->setColor (colorSpecFromRole (ColorRole::OnSurface));
1132- glyph->setSize (iSize, iSize);
1133- glyph->setPosition (kCellPad , kCellPad );
1134- item.iconGlyph = static_cast <Glyph*>(areaNode->addChild (std::move (glyph)));
1130+ item.iconGlyph = static_cast <Glyph*>(areaNode->addChild (ui::glyph ({
1131+ .glyph = " app-window" ,
1132+ .glyphSize = iSize,
1133+ .color = colorSpecFromRole (ColorRole::OnSurface),
1134+ .width = iSize,
1135+ .height = iSize,
1136+ .configure = [kCellPad ](Glyph& glyph) { glyph.setPosition (kCellPad , kCellPad ); },
1137+ })));
11351138 }
11361139
11371140 if (cfg.showDots ) {
11381141 const float dot = std::max (kDotMinSize , std::round (iSize * kDotSizeRatio ));
11391142 const bool verticalDots = cfg.position == " left" || cfg.position == " right" ;
11401143
11411144 for (std::size_t dotIndex = 0 ; dotIndex < item.dotIndicators .size (); ++dotIndex) {
1142- auto dotNode = std::make_unique<Box>();
1143- dotNode->setRadius (dot * 0 .5f );
1144- dotNode->setSize (dot, dot);
1145- dotNode->setFill (colorSpecFromRole (ColorRole::Secondary));
1146- dotNode->setVisible (false );
1147-
1148- if (verticalDots) {
1149- const float x = cfg.position == " left" ? std::round (cellMain - dot - 1 .0f ) : 1 .0f ;
1150- dotNode->setPosition (x, std::round ((cellMain - dot) * 0 .5f ));
1151- } else {
1152- const float y = cfg.position == " bottom" ? 1 .0f : std::round (cellMain - dot - 1 .0f );
1153- dotNode->setPosition (std::round ((cellMain - dot) * 0 .5f ), y);
1154- }
1155-
1156- item.dotIndicators [dotIndex] = static_cast <Box*>(areaNode->addChild (std::move (dotNode)));
1145+ item.dotIndicators [dotIndex] = static_cast <Box*>(areaNode->addChild (ui::box ({
1146+ .fill = colorSpecFromRole (ColorRole::Secondary),
1147+ .radius = dot * 0 .5f ,
1148+ .width = dot,
1149+ .height = dot,
1150+ .visible = false ,
1151+ .configure =
1152+ [verticalDots, position = cfg.position , cellMain, dot](Box& box) {
1153+ if (verticalDots) {
1154+ const float x = position == " left" ? std::round (cellMain - dot - 1 .0f ) : 1 .0f ;
1155+ box.setPosition (x, std::round ((cellMain - dot) * 0 .5f ));
1156+ } else {
1157+ const float y = position == " bottom" ? 1 .0f : std::round (cellMain - dot - 1 .0f );
1158+ box.setPosition (std::round ((cellMain - dot) * 0 .5f ), y);
1159+ }
1160+ },
1161+ })));
11571162 }
11581163 }
11591164
@@ -1163,19 +1168,22 @@ void Dock::rebuildItems(DockInstance& instance) {
11631168 const float badgeX = kCellPad + iSize - bd * 0 .55f ;
11641169 const float badgeY = kCellPad - bd * 0 .45f ;
11651170
1166- auto badgeBox = std::make_unique<Box>();
1167- badgeBox->setRadius (bd * 0 .5f );
1168- badgeBox->setSize (bd, bd);
1169- badgeBox->setPosition (badgeX, badgeY);
1170- badgeBox->setVisible (false );
1171- item.badge = static_cast <Box*>(areaNode->addChild (std::move (badgeBox)));
1171+ areaNode->addChild (ui::box ({
1172+ .out = &item.badge ,
1173+ .radius = bd * 0 .5f ,
1174+ .width = bd,
1175+ .height = bd,
1176+ .visible = false ,
1177+ .configure = [badgeX, badgeY](Box& box) { box.setPosition (badgeX, badgeY); },
1178+ }));
11721179
1173- auto labelNode = std::make_unique<Label>();
1174- labelNode->setFontSize (bd * kBadgeFontRatio );
1175- labelNode->setFontWeight (FontWeight::Bold);
1176- labelNode->setMaxLines (1 );
1177- labelNode->setVisible (false );
1178- item.badgeLabel = static_cast <Label*>(item.badge ->addChild (std::move (labelNode)));
1180+ item.badge ->addChild (ui::label ({
1181+ .out = &item.badgeLabel ,
1182+ .fontSize = bd * kBadgeFontRatio ,
1183+ .maxLines = 1 ,
1184+ .fontWeight = FontWeight::Bold,
1185+ .visible = false ,
1186+ }));
11791187 }
11801188
11811189 // Pointer callbacks.
@@ -1392,23 +1400,29 @@ std::unique_ptr<InputArea> Dock::createLauncherButton(DockInstance& instance) {
13921400 areaNode->setSize (cellCross, cellMain);
13931401 }
13941402
1395- auto bg = std::make_unique<Box>();
1396- bg->setSize (cellMain, cellMain);
1397- bg->setPosition (0 .0f , 0 .0f );
1398- bg->setRadius (static_cast <float >(cfg.radius ));
1399- bg->setFill (clearColorSpec ());
1400- auto * bgPtr = bg.get ();
1401- areaNode->addChild (std::move (bg));
1402-
1403- auto glyph = std::make_unique<Glyph>();
1404- if (!glyph->setGlyph (dockLauncherIconGlyph (cfg))) {
1405- glyph->setGlyph (" grid-dots" );
1406- }
1407- glyph->setGlyphSize (glyphSize);
1408- glyph->setColor (colorSpecFromRole (ColorRole::OnSurface));
1409- glyph->setSize (iSize, iSize);
1410- glyph->setPosition (kCellPad , glyphOffsetY);
1411- areaNode->addChild (std::move (glyph));
1403+ Box* bgPtr = nullptr ;
1404+ areaNode->addChild (ui::box ({
1405+ .out = &bgPtr,
1406+ .fill = clearColorSpec (),
1407+ .radius = static_cast <float >(cfg.radius ),
1408+ .width = cellMain,
1409+ .height = cellMain,
1410+ .configure = [](Box& box) { box.setPosition (0 .0f , 0 .0f ); },
1411+ }));
1412+
1413+ areaNode->addChild (ui::glyph ({
1414+ .glyphSize = glyphSize,
1415+ .color = colorSpecFromRole (ColorRole::OnSurface),
1416+ .width = iSize,
1417+ .height = iSize,
1418+ .configure =
1419+ [&cfg, kCellPad , glyphOffsetY](Glyph& glyph) {
1420+ if (!glyph.setGlyph (dockLauncherIconGlyph (cfg))) {
1421+ glyph.setGlyph (" grid-dots" );
1422+ }
1423+ glyph.setPosition (kCellPad , glyphOffsetY);
1424+ },
1425+ }));
14121426
14131427 auto * instPtr = &instance;
14141428 areaNode->setOnEnter ([bgPtr, instPtr](const InputArea::PointerData&) {
0 commit comments