@@ -273,6 +273,37 @@ void Button::setCursorShape(std::uint32_t shape) {
273273 }
274274}
275275
276+ void Button::setBadge (std::string_view text) {
277+ ensureBadge ();
278+ m_badgeLabel->setText (text);
279+ m_badge->setVisible (!text.empty ());
280+ }
281+
282+ void Button::setBadgeFontSize (float size) {
283+ ensureBadge ();
284+ m_badgeLabel->setFontSize (size);
285+ }
286+
287+ void Button::ensureBadge () {
288+ if (m_badge != nullptr ) {
289+ return ;
290+ }
291+ auto badge = std::make_unique<Flex>();
292+ badge->setDirection (FlexDirection::Horizontal);
293+ badge->setAlign (FlexAlign::Center);
294+ badge->setJustify (FlexJustify::Center);
295+ badge->setPadding (2 .0f , Style::spaceXs);
296+ badge->setRadius (Style::scaledRadiusSm ());
297+ badge->setParticipatesInLayout (false );
298+ badge->setVisible (false );
299+
300+ auto label = std::make_unique<Label>();
301+ label->setFontSize (Style::fontSizeCaption * 0 .85f );
302+ m_badgeLabel = static_cast <Label*>(badge->addChild (std::move (label)));
303+
304+ m_badge = static_cast <Flex*>(addChild (std::move (badge)));
305+ }
306+
276307void Button::updateInputArea () {
277308 if (m_inputArea != nullptr ) {
278309 m_inputArea->setPosition (0 .0f , 0 .0f );
@@ -394,7 +425,7 @@ void Button::applyColors(const Color& bg, const Color& border, const Color& labe
394425 m_glyph->setColor (label);
395426 }
396427 for (auto & child : children ()) {
397- if (child.get () == m_label || child.get () == m_glyph) {
428+ if (child.get () == m_label || child.get () == m_glyph || child. get () == m_badge ) {
398429 continue ;
399430 }
400431 if (auto * lbl = dynamic_cast <Label*>(child.get ())) {
@@ -403,6 +434,12 @@ void Button::applyColors(const Color& bg, const Color& border, const Color& labe
403434 gl->setColor (label);
404435 }
405436 }
437+ if (m_badge != nullptr ) {
438+ m_badge->setFill (Color{label.r , label.g , label.b , label.a * 0 .85f });
439+ if (m_badgeLabel != nullptr ) {
440+ m_badgeLabel->setColor (bg);
441+ }
442+ }
406443 m_visualStateInitialized = true ;
407444}
408445
@@ -565,6 +602,16 @@ void Button::doLayout(Renderer& renderer) {
565602 m_inputArea->setSize (width (), height ());
566603 }
567604
605+ if (m_badge != nullptr && m_badge->visible ()) {
606+ m_badgeLabel->measure (renderer);
607+ m_badge->setMinWidth (0 .0f );
608+ m_badge->layout (renderer);
609+ m_badge->setMinWidth (m_badge->height ());
610+ m_badge->layout (renderer);
611+ const float margin = Style::spaceXs;
612+ m_badge->setPosition (width () - m_badge->width () - margin, margin);
613+ }
614+
568615 // Only apply visual state if no animation is in progress — a running
569616 // animation already owns the color transition and re-calling here would
570617 // reset its from/to snapshot, collapsing the animation to a no-op.
0 commit comments