#include "Button.h" #include namespace UI { Button::Button(const std::string& label, std::function onClick) : label(label), onClick(onClick) { focusable = true; padding = Thickness(12.0f, 6.0f); minSize = Size(80.0f, 32.0f); horizontalAlignment = HorizontalAlignment::Center; } void Button::SetLabel(const std::string& newLabel) { label = newLabel; MarkDirty(DirtyFlags::Layout | DirtyFlags::Render); } void Button::RefreshPrimitives() { bgRect = std::make_unique(globalBounds.X, globalBounds.Y, globalBounds.Width, globalBounds.Height); Color drawColor = normalColor; if (pressed) { drawColor = activeColor; } else if (hovered) { drawColor = hoverColor; } bgRect->SetColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a); previousColor = drawColor; UI::Size textSize = Text::Measure(label); float contentW = std::max(0.0f, globalBounds.Width - padding.HorizontalTotal()); float contentH = std::max(0.0f, globalBounds.Height - padding.VerticalTotal()); float textX = globalBounds.X + padding.Left + std::max(0.0f, (contentW - textSize.width) * 0.5f); float textY = globalBounds.Y + padding.Top + std::max(0.0f, (contentH - textSize.height) * 0.5f); labelText = std::make_unique(textX, textY, label); } void Button::Measure(Size /*availableSpace*/) { UI::Size textSize = Text::Measure(label); desiredSize.width = std::clamp(textSize.width + padding.HorizontalTotal() + margin.HorizontalTotal(), minSize.width, maxSize.width); desiredSize.height = std::clamp(textSize.height + padding.VerticalTotal() + margin.VerticalTotal(), minSize.height, maxSize.height); } void Button::Arrange(Rect finalBounds) { Rect oldGlobal = globalBounds; bool doWeRefreshMaybe = IsDirty(DirtyFlags::Render | DirtyFlags::Layout); Widget::Arrange(finalBounds); if (doWeRefreshMaybe || globalBounds != oldGlobal) { RefreshPrimitives(); } } void Button::Draw() { if (!visible) return; if (!bgRect || IsDirty(DirtyFlags::Layout)) { RefreshPrimitives(); } // Determine primitive color based on input interaction state // TODO: needs dedup Color drawColor = normalColor; if (pressed) { drawColor = activeColor; } else if (hovered) { drawColor = hoverColor; } if (drawColor != previousColor) { bgRect->SetColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a); previousColor = drawColor; } if (bgRect) { bgRect->Render(); } if (labelText) { labelText->Render(); } Widget::Draw(); } bool Button::OnPointerStream(const std::shared_ptr& stream) { if (!enabled || !visible) return false; const auto event = stream->PeekLatestInput(); if (event.actDirection == PointerDirection::Down) { SetPressed(true); return true; } else if (event.actDirection == PointerDirection::Up) { if (pressed) { SetPressed(false); if (globalBounds.Contains(event.screenX, event.screenY)) { if (onClick) { onClick(); } } return true; } } return false; } }