20 Sml::Font* g_DefaultFont =
nullptr;
22 #define ASSERT_CATEGORY(eventClass) \
23 assert(event != nullptr); \
24 assert(event->isInCategory(eventClass::getStaticCategory()))
26 #define ASSERT_EITHER_CATEGORY(eventClass1, eventClass2) \
27 assert(event != nullptr); \
28 assert(event->isInCategory(eventClass1::getStaticCategory() || \
29 eventClass2::getStaticCategory()))
31 #define INVALID_EVENT_TYPE(handler) LOG_LIB_ERROR("Invalid event type in " #handler)
36 ButtonBaseSkin::StaticStyle::StaticStyle(
const Insets& paddingLabelOnly,
37 const Insets& paddingIconOnly,
38 const Insets& paddingIconAndLabel,
41 : paddingLabelOnly(paddingLabelOnly),
42 paddingIconOnly(paddingIconOnly),
43 paddingIconAndLabel(paddingIconAndLabel),
47 ButtonBaseSkin::StaticStyle::StaticStyle(
const Insets& padding, int32_t margin,
const Border& border)
48 : StaticStyle(padding, padding, padding, margin, border) {}
53 DEFINE_STATIC_LISTENED_EVENT_TYPES(MouseEnteredEvent::getStaticType(),
54 MouseExitedEvent::getStaticType(),
55 Sml::MouseButtonPressedEvent::getStaticType())
60 virtual void onEvent(Sml::Event* event)
override
62 ASSERT_CATEGORY(Sml::MouseEvent);
65 switch (event->getType())
67 case MouseEnteredEvent::getStaticType():
69 skin.applyInteractionStyle(ButtonBaseSkin::InteractionStyle::Type::HOVERED);
73 case MouseExitedEvent::getStaticType():
75 skin.applyInteractionStyle(ButtonBaseSkin::InteractionStyle::Type::IDLE);
79 case Sml::MouseButtonPressedEvent::getStaticType():
81 if (getComponent()->getOnAction() !=
nullptr)
85 getComponent()->getOnAction()->onAction(&event);
102 ButtonBaseSkin::ButtonBaseSkin(
const StaticStyle* staticStyle,
103 const InteractionStyle* idleStyle,
104 const InteractionStyle* hoveredStyle,
105 const InteractionStyle* pressedStyle)
106 : m_StaticStyle(staticStyle),
107 m_IdleStyle(idleStyle),
108 m_HoveredStyle(hoveredStyle),
109 m_PressedStyle(pressedStyle),
110 m_Text(*g_DefaultFont, nullptr) {}
112 ButtonBaseSkin::ButtonBaseSkin(
Button* button,
113 const StaticStyle* staticStyle,
114 const InteractionStyle* idleStyle,
115 const InteractionStyle* hoveredStyle,
116 const InteractionStyle* pressedStyle)
117 : ButtonBaseSkin(staticStyle, idleStyle, hoveredStyle, pressedStyle)
123 void ButtonBaseSkin::attach(Button* button)
127 m_Handler =
new ButtonBaseSkinEventListener(m_Button);
128 m_Button->getEventDispatcher()->attachHandler(ButtonBaseSkinEventListener::EVENT_TYPES, m_Handler);
134 applyInteractionStyle(InteractionStyle::Type::IDLE);
139 m_Button->getEventDispatcher()->detachHandler(m_Handler);
146 void ButtonBaseSkin::prerenderControl()
148 if (m_Button->getBackground() !=
nullptr)
150 Background::fillArea(m_Button->getBackground(), m_Button->getOriginBounds());
153 if (m_Button->getBorder() !=
nullptr)
155 Border::encloseArea(m_Button->getBorder(), m_Button->getOriginBounds());
159 const Control* ButtonBaseSkin::getControl()
const {
return m_Button; }
160 Control* ButtonBaseSkin::getModifiableControl() {
return m_Button; }
162 int32_t ButtonBaseSkin::computePrefHeight(int32_t width)
const
164 Insets insets = m_Button->getInsets();
166 return insets.top + insets.bottom +
167 std::max(m_Text.computePrefHeight(width), m_Icon.computePrefHeight(width));
170 int32_t ButtonBaseSkin::computePrefWidth(int32_t height)
const
172 Insets insets = m_Button->getInsets();
174 int32_t textPrefWidth = m_Text.computePrefWidth(height);
175 int32_t iconPrefWidth = m_Icon.computePrefWidth(height);
177 return insets.left + insets.right +
178 ((textPrefWidth != 0 && iconPrefWidth != 0) ? getMargin() : 0) +
179 textPrefWidth + iconPrefWidth;
182 void ButtonBaseSkin::layoutChildren()
184 Sml::Rectangle<int32_t> contentArea = m_Button->getContentArea();
186 m_Text.setString(m_Button->getLabel());
187 m_Icon.setImage(m_Button->getIcon());
190 m_Text.setLayoutWidth(m_Text.computePrefWidth());
191 m_Text.setLayoutHeight(m_Text.computePrefHeight());
193 int32_t iconHeight = std::min(m_Icon.computePrefHeight(), contentArea.height);
194 int32_t iconWidth = m_Icon.computePrefWidth(iconHeight);
195 m_Icon.setLayoutWidth(iconWidth);
196 m_Icon.setLayoutHeight(iconHeight);
198 int32_t centerY = contentArea.pos.y + contentArea.height / 2;
200 m_Icon.setLayoutX(contentArea.pos.x);
201 m_Icon.setLayoutY(centerY - m_Icon.getLayoutHeight() / 2);
203 m_Text.setLayoutX(m_Icon.getLayoutX() + m_Icon.getLayoutWidth());
204 if (m_Icon.getLayoutWidth() != 0)
206 m_Text.setLayoutX(m_Text.getLayoutX() + getMargin());
209 m_Text.setLayoutY(centerY - m_Text.getLayoutHeight() / 2);
212 int32_t ButtonBaseSkin::getMargin()
const
214 return m_StaticStyle ==
nullptr ? 0 : m_StaticStyle->margin;
217 void ButtonBaseSkin::applyStaticStyle()
219 if (m_StaticStyle !=
nullptr)
221 bool isLabelSet = m_Button->getLabel() !=
nullptr;
222 bool isIconSet = m_Button->getIcon() !=
nullptr;
224 if (isLabelSet && !isIconSet)
226 m_Button->setPadding(m_StaticStyle->paddingLabelOnly);
228 else if (!isLabelSet && isIconSet)
230 m_Button->setPadding(m_StaticStyle->paddingIconOnly);
232 else if (isLabelSet && isIconSet)
234 m_Button->setPadding(m_StaticStyle->paddingIconAndLabel);
237 m_Button->setBorder(&m_StaticStyle->border);
241 m_Button->setPadding(Insets::EMPTY);
242 m_Button->setBorder(
nullptr);
246 void ButtonBaseSkin::applyInteractionStyle(InteractionStyle::Type type)
248 const InteractionStyle* style =
nullptr;
251 case InteractionStyle::Type::IDLE: { style = m_IdleStyle;
break; }
252 case InteractionStyle::Type::HOVERED: { style = m_HoveredStyle;
break; }
253 case InteractionStyle::Type::PRESSED: { style = m_PressedStyle;
break; }
256 if (style !=
nullptr)
258 m_Text.setColor(style->foreground);
259 m_Button->setBackground(style->background);
263 m_Text.setColor(Sml::COLOR_BLACK);
264 m_Button->setBackground(
nullptr);
271 ButtonPlaneSkin::ButtonPlaneSkin()
272 : ButtonBaseSkin(nullptr, nullptr, nullptr, nullptr) {}
274 ButtonPlaneSkin::ButtonPlaneSkin(
Sgl::Button* button)
275 : ButtonBaseSkin(button, nullptr, nullptr, nullptr, nullptr) {}
280 const Insets ButtonSkin::PADDING_LABEL_ONLY = Insets{5, 10};
281 const Insets ButtonSkin::PADDING_ICON_ONLY = Insets{5};
282 const Insets ButtonSkin::PADDING_LABEL_AND_ICON = Insets{5, 10};
283 const int32_t ButtonSkin::MARGIN = 5;
284 const Border ButtonSkin::BORDER = Border{1, 0xE9'E9'E9'FF};
285 const ButtonBaseSkin::StaticStyle ButtonSkin::STATIC_STYLE = {PADDING_LABEL_ONLY,
287 PADDING_LABEL_AND_ICON,
292 const Sml::Color ButtonSkin::IDLE_FOREGROUND = Sml::COLOR_BLACK;
293 const ColorFill ButtonSkin::IDLE_BACKGROUND_FILL = {0xF5'F5'F5'FF};
294 const Background ButtonSkin::IDLE_BACKGROUND = {&IDLE_BACKGROUND_FILL};
295 const ButtonBaseSkin::InteractionStyle ButtonSkin::IDLE_STYLE = {IDLE_FOREGROUND,
299 const Sml::Color ButtonSkin::HOVERED_FOREGROUND = Sml::COLOR_WHITE;
300 const ColorFill ButtonSkin::HOVERED_BACKGROUND_FILL = {0x25'92'FF'FF};
301 const Background ButtonSkin::HOVERED_BACKGROUND = {&HOVERED_BACKGROUND_FILL};
302 const ButtonBaseSkin::InteractionStyle ButtonSkin::HOVERED_STYLE = {HOVERED_FOREGROUND,
303 &HOVERED_BACKGROUND};
305 ButtonSkin::ButtonSkin()
306 : ButtonBaseSkin(&STATIC_STYLE, &IDLE_STYLE, &HOVERED_STYLE, nullptr) {}
309 : ButtonBaseSkin(button, &STATIC_STYLE, &IDLE_STYLE, &HOVERED_STYLE, nullptr) {}
314 const Insets MenuItemSkin::PADDING = Insets{5, 10};
315 const int32_t MenuItemSkin::MARGIN = 5;
316 const Border MenuItemSkin::BORDER = Border{0, 0};
317 const ButtonBaseSkin::StaticStyle MenuItemSkin::STATIC_STYLE = {PADDING, MARGIN, BORDER};
320 const Sml::Color MenuItemSkin::IDLE_FOREGROUND = Sml::COLOR_BLACK;
321 const ColorFill MenuItemSkin::IDLE_BACKGROUND_FILL = {Sml::COLOR_TRANSPARENT};
322 const Background MenuItemSkin::IDLE_BACKGROUND = {&IDLE_BACKGROUND_FILL};
323 const ButtonBaseSkin::InteractionStyle MenuItemSkin::IDLE_STYLE = {IDLE_FOREGROUND,
327 const Sml::Color MenuItemSkin::HOVERED_FOREGROUND = 0xEF'F8'FF'FF;
328 const ColorFill MenuItemSkin::HOVERED_BACKGROUND_FILL = {0x5A'B9'FF'FF};
329 const Background MenuItemSkin::HOVERED_BACKGROUND = {&HOVERED_BACKGROUND_FILL};
330 const ButtonBaseSkin::InteractionStyle MenuItemSkin::HOVERED_STYLE = {HOVERED_FOREGROUND,
331 &HOVERED_BACKGROUND};
333 MenuItemSkin::MenuItemSkin()
334 : ButtonBaseSkin(&STATIC_STYLE, &IDLE_STYLE, &HOVERED_STYLE, nullptr) {}
337 : ButtonBaseSkin(button, &STATIC_STYLE, &IDLE_STYLE, &HOVERED_STYLE, nullptr) {}
342 const ShadowSpecification SliderSkin::KNOB_SHADOW = {{0, 0}, {1.1, 1.1}, 3, 0x00'00'00'88};
343 const ColorFill SliderSkin::NOT_SELECTED_FILL = {0xE0'E0'E0'FF};
344 const ColorFill SliderSkin::SELECTED_FILL = {0x32'73'F6'FF};
345 const Sml::Color SliderSkin::KNOB_COLOR = 0x27'5B'E1'FF;
346 const int32_t SliderSkin::THICKNESS = 6;
347 const int32_t SliderSkin::KNOB_SIZE_ALONG = 6;
348 const int32_t SliderSkin::KNOB_SIZE_ACROSS = 11;
355 void updateValue(
const Sml::Vec2i& mousePos)
357 Slider& slider = *getComponent();
360 Sml::Vec2i localPos = slider.computeSceneToLocalPos(mousePos);
362 int32_t posAlong = slider.getOrientation() == Orientation::HORIZONTAL ? localPos.x : localPos.y;
363 int32_t lineLength = slider.getOrientation() == Orientation::HORIZONTAL ? skin.getLineRect().width :
364 skin.getLineRect().height;
366 slider.setValue(slider.getRangeMin() +
367 (
static_cast<float>(posAlong - SliderSkin::KNOB_SIZE_ALONG / 2) /
368 static_cast<float>(lineLength - SliderSkin::KNOB_SIZE_ALONG)) *
369 (slider.getRangeMax() - slider.getRangeMin()));
374 LOG_LIB_INFO(
"SliderSkinDragListener::onDragStart() called");
376 updateValue(Sml::Vec2i(event->getX(), event->getY()));
381 LOG_LIB_INFO(
"SliderSkinDragListener::onDragMove() called");
383 updateValue(Sml::Vec2i(event->getX(), event->getY()));
390 DEFINE_STATIC_LISTENED_EVENT_TYPES(Sml::MouseButtonPressedEvent::getStaticType())
395 virtual void onEvent(Sml::Event* event)
override
397 LOG_LIB_INFO(
"SliderSkinMousePressListener called");
398 getComponent()->requestDrag();
402 SliderSkin::SliderSkin(
const Fill* notSelectedFill,
403 const Fill* selectedFill,
404 Sml::Color knobColor,
406 int32_t knobSizeAlong,
407 int32_t knobSizeAcross)
408 : m_NotSelectedFill(notSelectedFill),
409 m_SelectedFill(selectedFill),
410 m_Thickness(thickness),
411 m_KnobSizeAlong(knobSizeAlong),
412 m_KnobSizeAcross(knobSizeAcross),
415 m_KnobRect->setFillColor(knobColor);
416 m_KnobRect->setShadow(&KNOB_SHADOW);
419 SliderSkin::SliderSkin(
Slider* slider) : SliderSkin(&NOT_SELECTED_FILL, &SELECTED_FILL)
430 m_Slider->getEventDispatcher()->detachHandler(m_MousePressListener);
431 delete m_MousePressListener;
433 m_Slider->getEventDispatcher()->detachHandler(m_DragListener);
434 delete m_DragListener;
437 void SliderSkin::attach(
Slider* slider)
445 m_Slider->getEventDispatcher()->attachHandler(SliderSkinMousePressListener::EVENT_TYPES, m_MousePressListener);
448 m_Slider->getEventDispatcher()->attachHandler(SliderSkinDragListener::EVENT_TYPES, m_DragListener);
451 Component* SliderSkin::getHitComponent(int32_t x, int32_t y)
453 Sml::Rectangle<int32_t> translatedRect = getLineRect();
454 translatedRect.pos += m_Slider->getLayoutPos();
456 if (Sml::isPointInsideRectangle({x, y}, translatedRect))
461 translatedRect = getKnobRect();
462 translatedRect.pos += m_Slider->getLayoutPos();
463 if (Sml::isPointInsideRectangle({x, y}, translatedRect))
471 void SliderSkin::prerenderControl()
473 Sml::Rectangle<int32_t> lineRect = getLineRect();
475 if (m_NotSelectedFill !=
nullptr)
477 m_NotSelectedFill->fillArea(lineRect, m_Slider->getOriginBounds());
480 if (m_Slider->getOrientation() == Orientation::HORIZONTAL)
482 lineRect.width *= getPercentage();
486 lineRect.height *= getPercentage();
489 if (m_SelectedFill !=
nullptr)
491 m_SelectedFill->fillArea(lineRect, m_Slider->getOriginBounds());
495 const Control* SliderSkin::getControl()
const {
return m_Slider; }
496 Control* SliderSkin::getModifiableControl() {
return m_Slider; }
498 int32_t SliderSkin::computePrefWidth(int32_t height)
const
500 if (m_Slider->getOrientation() == Orientation::HORIZONTAL)
502 return m_KnobSizeAlong;
505 return m_KnobSizeAcross;
508 int32_t SliderSkin::computePrefHeight(int32_t width)
const
510 if (m_Slider->getOrientation() == Orientation::VERTICAL)
512 return m_KnobSizeAlong;
515 return m_KnobSizeAcross;
518 void SliderSkin::layoutChildren()
520 Sml::Rectangle<int32_t> knobRect = getKnobRect();
522 m_KnobRect->setLayoutWidth(knobRect.width);
523 m_KnobRect->setLayoutHeight(knobRect.height);
524 m_KnobRect->setLayoutX(knobRect.pos.x);
525 m_KnobRect->setLayoutY(knobRect.pos.y);
528 int32_t SliderSkin::getThickness()
const {
return m_Thickness; }
529 void SliderSkin::setThickness(int32_t thickness) { m_Thickness = thickness; }
531 int32_t SliderSkin::getKnobSizeAlong()
const {
return m_KnobSizeAlong; }
532 void SliderSkin::setKnobSizeAlong(int32_t knobSizeAlong) { m_KnobSizeAlong = knobSizeAlong; }
534 int32_t SliderSkin::getKnobSizeAcross()
const {
return m_KnobSizeAcross; }
535 void SliderSkin::setKnobSizeAcross(int32_t knobSizeAcross) { m_KnobSizeAcross = knobSizeAcross; }
537 void SliderSkin::setKnobShadow(
const ShadowSpecification* shadow) { m_KnobRect->setShadow(shadow); }
539 Sml::Rectangle<int32_t> SliderSkin::getLineRect()
541 if (m_Slider->getOrientation() == Orientation::HORIZONTAL)
543 Sml::Rectangle<int32_t> originBounds = m_Slider->getOriginBounds();
544 int32_t centerY = originBounds.height / 2;
546 return Sml::Rectangle<int32_t>{0, centerY - m_Thickness / 2, originBounds.width, m_Thickness};
550 Sml::Rectangle<int32_t> originBounds = m_Slider->getOriginBounds();
551 int32_t centerX = originBounds.width / 2;
553 return Sml::Rectangle<int32_t>{centerX - m_Thickness / 2, 0, m_Thickness, originBounds.height};
557 Sml::Rectangle<int32_t> SliderSkin::getKnobRect()
559 if (m_Slider->getOrientation() == Orientation::HORIZONTAL)
561 Sml::Rectangle<int32_t> originBounds = m_Slider->getOriginBounds();
562 int32_t centerY = originBounds.height / 2;
563 int32_t knobCenterX = m_KnobSizeAlong / 2 + getPercentage() * (originBounds.width - m_KnobSizeAlong);
565 return Sml::Rectangle<int32_t>{knobCenterX - m_KnobSizeAlong / 2, centerY - m_KnobSizeAcross / 2,
566 m_KnobSizeAlong, m_KnobSizeAcross};
570 Sml::Rectangle<int32_t> originBounds = m_Slider->getOriginBounds();
571 int32_t centerX = originBounds.width / 2;
572 int32_t knobCenterY = m_KnobSizeAlong / 2 + getPercentage() * (originBounds.height - m_KnobSizeAlong);
574 return Sml::Rectangle<int32_t>{centerX - m_KnobSizeAcross / 2, knobCenterY - m_KnobSizeAlong / 2,
575 m_KnobSizeAcross, m_KnobSizeAlong};
579 float SliderSkin::getPercentage()
581 return (m_Slider->getValue() - m_Slider->getRangeMin()) / (m_Slider->getRangeMax() - m_Slider->getRangeMin());
587 const Sml::Color ScrollBarSkin::KNOB_COLOR = 0xF5'F5'F5'FF;
590 ScrollBarSkin::ScrollBarSkin(ScrollBar* scrollBar)
591 : m_Box(new BoxContainer()),
592 m_SliderSkin(new SliderSkin(&SliderSkin::NOT_SELECTED_FILL, nullptr, KNOB_COLOR)),
593 m_Slider(new Slider(m_SliderSkin, 0, 1)),
594 m_DecrementButton(new Button(new ButtonPlaneSkin())),
595 m_IncrementButton(new Button(new ButtonPlaneSkin()))
599 m_Box->addChildren(m_DecrementButton, m_Slider, m_IncrementButton);
600 m_Box->setGrowPriority(m_Slider, BoxContainer::GrowPriority::ALWAYS);
601 m_Box->setFillAcross(
true);
603 m_SliderSkin->setKnobShadow(
nullptr);
614 void ScrollBarSkin::attach(
ScrollBar* scrollBar)
617 m_ScrollBar = scrollBar;
619 if (m_ScrollBar->getOrientation() == Orientation::HORIZONTAL)
621 m_Box->setDirection(BoxContainer::Direction::LEFT_TO_RIGHT);
623 m_DecrementButton->setIcon(
new Image(
"res/sgl/arrow_left.png", ImageFormat::PNG));
624 m_IncrementButton->setIcon(
new Image(
"res/sgl/arrow_right.png", ImageFormat::PNG));
628 m_Box->setDirection(BoxContainer::Direction::TOP_TO_BOTTOM);
630 m_DecrementButton->setIcon(
new Image(
"res/sgl/arrow_up.png", ImageFormat::PNG));
631 m_IncrementButton->setIcon(
new Image(
"res/sgl/arrow_down.png", ImageFormat::PNG));
636 class ChangeValueButtonListener :
public ActionListener<Button>
639 ChangeValueButtonListener(Button* button, ScrollBar* scrollBar,
float multiplier)
640 : ActionListener<Button>(button), m_ScrollBar(scrollBar), m_Multiplier(multiplier) {}
642 virtual void onAction(ActionEvent* event)
override
644 m_ScrollBar->setValue(m_ScrollBar->getValue() + m_ScrollBar->getIncrement() * m_Multiplier);
648 ScrollBar* m_ScrollBar =
nullptr;
649 float m_Multiplier = 0;
652 m_DecrementButton->setOnAction(
new ChangeValueButtonListener(m_DecrementButton, m_ScrollBar, -1));
653 m_IncrementButton->setOnAction(
new ChangeValueButtonListener(m_IncrementButton, m_ScrollBar, 1));
655 class SliderPropertyChangeListener :
public Sml::PropertyChangeListener<float>
658 SliderPropertyChangeListener(ScrollBar* scrollBar) : m_ScrollBar(scrollBar) {}
660 virtual void onPropertyChange(Sml::PropertyChangeEvent<float>* event)
override
662 m_ScrollBar->setValue(event->getNewValue());
666 ScrollBar* m_ScrollBar =
nullptr;
669 m_Slider->addOnPropertyChange(
new SliderPropertyChangeListener(m_ScrollBar));
672 const Control* ScrollBarSkin::getControl()
const {
return m_ScrollBar; }
673 Control* ScrollBarSkin::getModifiableControl() {
return m_ScrollBar; }
675 void ScrollBarSkin::layoutChildren()
677 int32_t layoutWidth = m_ScrollBar->getLayoutWidth();
678 int32_t layoutHeight = m_ScrollBar->getLayoutHeight();
680 m_Box->setLayoutX(0);
681 m_Box->setLayoutY(0);
682 m_Box->setLayoutWidth(layoutWidth);
683 m_Box->setLayoutHeight(layoutHeight);
685 m_Slider->setRangeMin(m_ScrollBar->getRangeMin());
686 m_Slider->setRangeMax(m_ScrollBar->getRangeMax());
687 m_Slider->setValue(m_ScrollBar->getValue());
688 m_Slider->setOrientation(m_ScrollBar->getOrientation());
690 if (m_ScrollBar->getOrientation() == Orientation::HORIZONTAL)
692 m_SliderSkin->setThickness(layoutHeight);
693 m_SliderSkin->setKnobSizeAcross(layoutHeight - 4);
694 m_SliderSkin->setKnobSizeAlong(m_Slider->getLayoutWidth() * m_ScrollBar->getVisibleRange() /
695 (m_ScrollBar->getRangeMax() - m_ScrollBar->getRangeMin()));
699 m_SliderSkin->setThickness(layoutWidth);
700 m_SliderSkin->setKnobSizeAcross(layoutWidth - 4);
701 m_SliderSkin->setKnobSizeAlong(m_Slider->getLayoutHeight() * m_ScrollBar->getVisibleRange() /
702 (m_ScrollBar->getRangeMax() - m_ScrollBar->getRangeMin()));
714 virtual void onPropertyChange(Sml::PropertyChangeEvent<float>* event)
override
718 if (scrollPane->getContent() !=
nullptr)
724 scrollPane->setViewportX(event->getNewValue() * (scrollPane->getContent()->getLayoutWidth() - scrollPane->getViewportWidth()));
737 virtual void onPropertyChange(Sml::PropertyChangeEvent<float>* event)
override
741 if (scrollPane->getContent() !=
nullptr)
748 scrollPane->setViewportY(event->getNewValue() * (scrollPane->getContent()->getLayoutHeight() - scrollPane->getViewportHeight()));
756 ScrollPaneSkin::ScrollPaneSkin(
ScrollPane* scrollPane)
757 : m_HorizontalScrollBar(new Sgl::
ScrollBar(Orientation::HORIZONTAL, 0, 1)),
758 m_VerticalScrollBar(new Sgl::
ScrollBar(Orientation::VERTICAL, 0, 1))
762 m_HorizontalScrollBar->setIncrement(0.1);
763 m_VerticalScrollBar->setIncrement(0.1);
770 m_ScrollPane->
removeChild(m_ScrollPane->getContent());
773 void ScrollPaneSkin::attach(
ScrollPane* scrollPane)
776 m_ScrollPane = scrollPane;
778 m_ScrollPane->addChildren(m_HorizontalScrollBar, m_VerticalScrollBar);
784 Component* ScrollPaneSkin::getHitComponent(int32_t x, int32_t y)
786 Sml::Vec2i posInPane = Sml::Vec2i(x, y) - m_ScrollPane->getLayoutPos();
788 if (m_ScrollPane->getContent() !=
nullptr && Sml::isPointInsideRectangle(posInPane, computeContentRegion()))
790 return m_ScrollPane->getContent()->getHitComponent(x, y);
793 if (Sml::isPointInsideRectangle(posInPane, m_HorizontalScrollBar->getLayoutBounds()))
795 const Sml::Vec2i& layoutPos = m_HorizontalScrollBar->getLayoutPos();
796 return m_HorizontalScrollBar->getHitComponent(layoutPos.x + x, layoutPos.y + y);
799 if (Sml::isPointInsideRectangle(posInPane, m_VerticalScrollBar->getLayoutBounds()))
801 const Sml::Vec2i& layoutPos = m_VerticalScrollBar->getLayoutPos();
802 return m_VerticalScrollBar->getHitComponent(layoutPos.x + x, layoutPos.y + y);
805 if (Sml::isPointInsideRectangle(posInPane, m_ScrollPane->getLayoutBounds()))
813 void ScrollPaneSkin::prerenderControl()
815 if (m_ScrollPane->getContent() ==
nullptr)
820 updateRenderedContentTexture();
822 if (m_RenderedContentTexture !=
nullptr)
824 Sml::Rectangle<int32_t> snapshotRegion = computeContentRegion();
825 m_RenderedContentTexture->copyTo(m_ScrollPane->getSnapshot(), &snapshotRegion, &m_ScrollPane->getViewport());
829 const Control* ScrollPaneSkin::getControl()
const {
return m_ScrollPane; }
830 Control* ScrollPaneSkin::getModifiableControl() {
return m_ScrollPane; }
832 int32_t ScrollPaneSkin::computePrefWidth(int32_t height)
const
834 return m_VerticalScrollBar->computePrefWidth(height) +
835 m_ScrollPane->getContent() !=
nullptr ? m_ScrollPane->getContent()->computePrefWidth(height) : 0;
838 int32_t ScrollPaneSkin::computePrefHeight(int32_t width)
const
840 return m_HorizontalScrollBar->computePrefHeight(width) +
841 m_ScrollPane->getContent() !=
nullptr ? m_ScrollPane->getContent()->computePrefHeight(width) : 0;
844 void ScrollPaneSkin::layoutChildren()
846 Sml::Rectangle<int32_t> contentArea = m_ScrollPane->getContentArea();
848 int32_t scrollWidth = m_VerticalScrollBar->computePrefWidth();
849 int32_t scrollHeight = m_HorizontalScrollBar->computePrefHeight();
851 m_ScrollPane->getContent()->setLayoutWidth(m_ScrollPane->getContent()->computePrefWidth());
852 m_ScrollPane->getContent()->setLayoutHeight(m_ScrollPane->getContent()->computePrefHeight());
854 m_VerticalScrollBar->setLayoutWidth(scrollWidth);
855 m_VerticalScrollBar->setLayoutHeight(contentArea.height - scrollHeight);
856 m_VerticalScrollBar->setLayoutX(contentArea.pos.x + contentArea.width - m_VerticalScrollBar->getLayoutWidth());
857 m_VerticalScrollBar->setLayoutY(contentArea.pos.y);
859 m_HorizontalScrollBar->setLayoutWidth(contentArea.width - scrollWidth);
860 m_HorizontalScrollBar->setLayoutHeight(scrollHeight);
861 m_HorizontalScrollBar->setLayoutX(contentArea.pos.x);
862 m_HorizontalScrollBar->setLayoutY(contentArea.pos.y + contentArea.height -
863 m_HorizontalScrollBar->getLayoutHeight());
866 if (m_ScrollPane->getContent() !=
nullptr)
868 m_VerticalScrollBar->setVisibleRange(
static_cast<float>(m_ScrollPane->getViewportHeight()) /
869 m_ScrollPane->getContent()->getLayoutHeight());
870 m_HorizontalScrollBar->setVisibleRange(
static_cast<float>(m_ScrollPane->getViewportWidth()) /
871 m_ScrollPane->getContent()->getLayoutWidth());
874 m_ScrollPane->getContent()->setInteractable(
false);
875 m_ScrollPane->getContent()->setVisible(
false);
878 m_ScrollPane->
addChild(m_ScrollPane->getContent());
879 m_ScrollPane->
addChild(m_HorizontalScrollBar);
880 m_ScrollPane->
addChild(m_VerticalScrollBar);
884 m_VerticalScrollBar->setVisibleRange(1);
885 m_HorizontalScrollBar->setVisibleRange(1);
888 if (m_PrevContent != m_ScrollPane->getContent())
890 m_PrevContent = m_ScrollPane->getContent();
892 if (m_PrevContent !=
nullptr)
894 m_ScrollPane->setViewport({0, 0, computeContentRegion().width, computeContentRegion().height});
899 Sml::Rectangle<int32_t> ScrollPaneSkin::computeContentRegion()
const
901 Sml::Rectangle<int32_t> contentArea = m_ScrollPane->getContentArea();
903 return {contentArea.pos, contentArea.width - m_VerticalScrollBar->getLayoutWidth(),
904 contentArea.height - m_HorizontalScrollBar->getLayoutHeight()};
907 void ScrollPaneSkin::updateRenderedContentTexture()
909 Component* content = m_ScrollPane->getContent();
910 int32_t contentWidth = content->getLayoutWidth();
911 int32_t contentHeight = content->getLayoutHeight();
913 if (content ==
nullptr || contentWidth == 0 || contentHeight == 0)
918 if (m_RenderedContentTexture ==
nullptr ||
919 m_RenderedContentTexture->getWidth() != contentWidth ||
920 m_RenderedContentTexture->getHeight() != contentHeight)
922 if (m_RenderedContentTexture ==
nullptr)
924 delete m_RenderedContentTexture;
927 m_RenderedContentTexture =
new Sml::Texture(contentWidth, contentHeight);
930 Sml::Renderer& renderer = Sml::Renderer::getInstance();
931 renderer.pushSetTarget(m_RenderedContentTexture);
933 content->render({0, 0, contentWidth, contentHeight});
935 renderer.popTarget();
virtual void dispose() override
Should be called by Control when this skin is replaced.
void addChild(Component *child)
Convenience method for adding a child to Parent.
void removeChild(Component *child)
Convenience method for removing a child to Parent.