Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/windowing/StarButtonWidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/windowing/StarButtonWidget.cpp')
-rw-r--r--source/windowing/StarButtonWidget.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/source/windowing/StarButtonWidget.cpp b/source/windowing/StarButtonWidget.cpp
new file mode 100644
index 0000000..88b3996
--- /dev/null
+++ b/source/windowing/StarButtonWidget.cpp
@@ -0,0 +1,380 @@
+#include "StarButtonWidget.hpp"
+#include "StarRoot.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarRandom.hpp"
+#include "StarAssets.hpp"
+
+namespace Star {
+
+ButtonWidget::ButtonWidget() {
+ m_hovered = false;
+ m_pressed = false;
+ m_checkable = false;
+ m_checked = false;
+ m_disabled = false;
+ m_highlighted = false;
+ m_hasCheckedImages = false;
+ m_sustain = false;
+ m_invisible = false;
+ m_hTextAnchor = HorizontalAnchor::HMidAnchor;
+ m_fontColor = Color::White;
+ m_fontColorDisabled = Color::Gray;
+
+ auto assets = Root::singleton().assets();
+
+ auto interfaceConfig = assets->json("/interface.config");
+ m_pressedOffset = jsonToVec2I(interfaceConfig.get("buttonPressedOffset"));
+ m_fontSize = interfaceConfig.query("font.buttonSize").toInt();
+}
+
+ButtonWidget::ButtonWidget(WidgetCallbackFunc callback,
+ String const& baseImage,
+ String const& hoverImage,
+ String const& pressedImage,
+ String const& disabledImage)
+ : ButtonWidget() {
+ setCallback(callback);
+ setImages(baseImage, hoverImage, pressedImage, disabledImage);
+}
+
+ButtonWidget::~ButtonWidget() {
+ if (m_buttonGroup)
+ m_buttonGroup->removeButton(this);
+}
+
+void ButtonWidget::renderImpl() {
+ if (isPressed() && sustainCallbackOnDownHold())
+ if (m_callback)
+ m_callback(this);
+
+ Vec2F position = Vec2F(screenPosition());
+ Vec2F textPosition = position + Vec2F(m_textOffset);
+ if (m_hTextAnchor == HorizontalAnchor::HMidAnchor)
+ textPosition += Vec2F(size()) / 2;
+ else if (m_hTextAnchor == HorizontalAnchor::RightAnchor)
+ textPosition += Vec2F(size()[0], size()[1] / 2);
+ else if (m_hTextAnchor == HorizontalAnchor::LeftAnchor)
+ textPosition += Vec2F(0, size()[1] / 2);
+ // We need to show the down button offset if we're pressing the button or
+ // don't have checked images and thus need some way to show that the button
+ // is checked (there's probably some better default behavior in that case)
+ if (m_pressed || (m_checked && !m_hasCheckedImages)) {
+ position += Vec2F(m_pressedOffset);
+ textPosition += Vec2F(m_pressedOffset);
+ }
+
+ if (m_hasCheckedImages && m_checked) {
+ if (m_disabled)
+ drawButtonPart(m_disabledImageChecked, position);
+ else if ((m_pressed || m_highlighted) && !m_pressedImageChecked.empty())
+ drawButtonPart(m_pressedImageChecked, position);
+ else if ((m_pressed || m_hovered || m_highlighted) && !m_hoverImageChecked.empty())
+ drawButtonPart(m_hoverImageChecked, position);
+ else
+ drawButtonPart(m_baseImageChecked, position);
+ } else {
+ if (m_disabled)
+ drawButtonPart(m_disabledImage, position);
+ else if ((m_pressed || m_highlighted) && !m_pressedImage.empty())
+ drawButtonPart(m_pressedImage, position);
+ else if ((m_pressed || m_hovered || m_highlighted) && !m_hoverImage.empty())
+ drawButtonPart(m_hoverImage, position);
+ else if (!m_invisible)
+ drawButtonPart(m_baseImage, position);
+ }
+
+ if (!m_overlayImage.empty())
+ drawButtonPart(m_overlayImage, position);
+
+ if (!m_text.empty()) {
+ auto& guiContext = GuiContext::singleton();
+ guiContext.setFontSize(m_fontSize);
+ if (m_disabled)
+ guiContext.setFontColor(m_fontColorDisabled.toRgba());
+ else if (m_fontColorChecked && m_checked)
+ guiContext.setFontColor(m_fontColorChecked.value().toRgba());
+ else
+ guiContext.setFontColor(m_fontColor.toRgba());
+ guiContext.setFontMode(FontMode::Shadow);
+ guiContext.renderInterfaceText(m_text, {textPosition, m_hTextAnchor, VerticalAnchor::VMidAnchor});
+ guiContext.setFontMode(FontMode::Normal);
+ }
+}
+
+bool ButtonWidget::sendEvent(InputEvent const& event) {
+ if (m_visible && !m_disabled) {
+ if (event.is<MouseButtonDownEvent>() && event.get<MouseButtonDownEvent>().mouseButton == MouseButton::Left) {
+ if (inMember(*context()->mousePosition(event))) {
+ if (!isPressed()) {
+ auto assets = Root::singleton().assets();
+ auto sound = Random::randValueFrom(assets->json("/interface.config:buttonClickSound").toArray(), "").toString();
+ if (!sound.empty())
+ context()->playAudio(sound);
+ }
+ setPressed(true);
+ if (m_callback) {
+ focus();
+ return true;
+ }
+ } else {
+ blur();
+ return false;
+ }
+ } else if (event.is<MouseButtonUpEvent>()) {
+ setPressed(false);
+ return false;
+ }
+ }
+
+ return false;
+}
+
+void ButtonWidget::mouseOver() {
+ Widget::mouseOver();
+ if (!m_disabled) {
+ if (!m_hovered) {
+ auto assets = Root::singleton().assets();
+ auto sound = Random::randValueFrom(assets->json("/interface.config:buttonHoverSound").toArray(), "").toString();
+ if (!sound.empty())
+ context()->playAudio(sound);
+ }
+ m_hovered = true;
+ }
+}
+
+void ButtonWidget::mouseOut() {
+ Widget::mouseOut();
+ m_hovered = false;
+ m_pressed = false;
+}
+
+void ButtonWidget::mouseReturnStillDown() {
+ Widget::mouseReturnStillDown();
+ m_hovered = true;
+ m_pressed = true;
+}
+
+void ButtonWidget::hide() {
+ Widget::hide();
+ m_pressed = false;
+ m_hovered = false;
+}
+
+void ButtonWidget::setCallback(WidgetCallbackFunc callback) {
+ m_callback = callback;
+}
+
+ButtonGroupPtr ButtonWidget::buttonGroup() const {
+ return m_buttonGroup;
+}
+
+void ButtonWidget::setButtonGroup(ButtonGroupPtr newGroup, int id) {
+ if (m_buttonGroup != newGroup) {
+ if (m_buttonGroup)
+ m_buttonGroup->removeButton(this);
+
+ m_buttonGroup = move(newGroup);
+
+ if (m_buttonGroup) {
+ setCheckable(true);
+ m_buttonGroup->addButton(this, id);
+ }
+ }
+}
+
+int ButtonWidget::buttonGroupId() {
+ if (m_buttonGroup)
+ return m_buttonGroup->id(this);
+ else
+ return ButtonGroup::NoButton;
+}
+
+bool ButtonWidget::isHovered() const {
+ return m_hovered;
+}
+
+bool ButtonWidget::isPressed() const {
+ return m_pressed;
+}
+
+void ButtonWidget::setPressed(bool pressed) {
+ if (m_pressed != pressed) {
+ // Button action is triggered when the button is released after being pressed
+ if (m_pressed) {
+ check();
+ if (m_callback) {
+ m_callback(this);
+ }
+ }
+ m_pressed = pressed;
+ }
+}
+
+bool ButtonWidget::isCheckable() const {
+ return m_checkable;
+}
+
+void ButtonWidget::setCheckable(bool checkable) {
+ m_checkable = checkable;
+}
+
+bool ButtonWidget::isHighlighted() const {
+ return m_highlighted;
+}
+
+void ButtonWidget::setHighlighted(bool highlighted) {
+ m_highlighted = highlighted;
+}
+
+bool ButtonWidget::isChecked() const {
+ return m_checked;
+}
+
+void ButtonWidget::setChecked(bool checked) {
+ // might cause button groups to have multiple selected against its rules, be careful with direct poking, use check()
+ // instead.
+ m_checked = checked;
+}
+
+void ButtonWidget::check() {
+ if (m_checkable) {
+ // If we are part of an exclusive button group, then don't uncheck if
+ // we are already checked and pressed again.
+ if (m_buttonGroup) {
+ if (m_buttonGroup->toggle() || !isChecked()) {
+ setChecked(!m_buttonGroup->toggle() || !isChecked());
+ m_buttonGroup->wasChecked(this);
+ }
+ } else {
+ setChecked(!isChecked());
+ }
+ }
+}
+
+bool ButtonWidget::sustainCallbackOnDownHold() {
+ return m_sustain;
+}
+
+void ButtonWidget::setSustainCallbackOnDownHold(bool sustain) {
+ m_sustain = sustain;
+}
+
+void ButtonWidget::setImages(String const& baseImage, String const& hoverImage, String const& pressedImage, String const& disabledImage) {
+ m_baseImage = baseImage;
+ m_hoverImage = hoverImage;
+ m_pressedImage = pressedImage;
+ m_disabledImage = disabledImage;
+ if (m_disabledImage.empty() && !m_baseImage.empty())
+ m_disabledImage = m_baseImage + Root::singleton().assets()->json("/interface.config:disabledButton").toString();
+ updateSize();
+}
+
+void ButtonWidget::setCheckedImages(String const& baseImage, String const& hoverImage, String const& pressedImage, String const& disabledImage) {
+ m_hasCheckedImages = !baseImage.empty();
+ m_baseImageChecked = baseImage;
+ m_hoverImageChecked = hoverImage;
+ m_pressedImageChecked = pressedImage;
+ m_disabledImageChecked = disabledImage;
+ if (m_hasCheckedImages && m_disabledImageChecked.empty())
+ m_disabledImageChecked = m_baseImageChecked + Root::singleton().assets()->json("/interface.config:disabledButton").toString();
+ updateSize();
+}
+
+void ButtonWidget::setOverlayImage(String const& overlayImage) {
+ m_overlayImage = overlayImage;
+}
+
+Vec2I const& ButtonWidget::pressedOffset() const {
+ return m_pressedOffset;
+}
+
+void ButtonWidget::setPressedOffset(Vec2I const& offset) {
+ m_pressedOffset = offset;
+}
+
+void ButtonWidget::setText(String const& text) {
+ m_text = text;
+}
+
+void ButtonWidget::setFontSize(int size) {
+ m_fontSize = size;
+}
+
+void ButtonWidget::setTextOffset(Vec2I textOffset) {
+ m_textOffset = textOffset;
+}
+
+void ButtonWidget::setTextAlign(HorizontalAnchor hAnchor) {
+ m_hTextAnchor = hAnchor;
+}
+
+void ButtonWidget::setFontColor(Color color) {
+ m_fontColor = color;
+}
+
+void ButtonWidget::setFontColorDisabled(Color color) {
+ m_fontColorDisabled = color;
+}
+
+void ButtonWidget::setFontColorChecked(Color color) {
+ m_fontColorChecked = color;
+}
+
+// Although ButtonWidget wraps other widgets from time to time. These should never be "accessible"
+WidgetPtr ButtonWidget::getChildAt(Vec2I const&) {
+ return {};
+}
+
+void ButtonWidget::disable() {
+ m_disabled = true;
+ m_pressed = false;
+}
+
+void ButtonWidget::enable() {
+ m_disabled = false;
+}
+
+void ButtonWidget::setEnabled(bool enabled) {
+ m_disabled = !enabled;
+ m_pressed &= enabled; // and off the pressed flag if the button is no longer enabled.
+}
+
+void ButtonWidget::setInvisible(bool invisible) {
+ m_invisible = invisible;
+}
+
+RectI ButtonWidget::getScissorRect() const {
+ if (m_pressed) {
+ return RectI::withSize(screenPosition(), size() + m_pressedOffset);
+ }
+ return RectI::withSize(screenPosition(), size());
+}
+
+void ButtonWidget::drawButtonPart(String const& image, Vec2F const& position) {
+ auto& guiContext = GuiContext::singleton();
+ auto imageSize = guiContext.textureSize(image);
+ guiContext.drawInterfaceQuad(image, position + Vec2F(m_buttonBoundSize - imageSize) / 2);
+}
+
+void ButtonWidget::updateSize() {
+ if (m_invisible || m_baseImage.empty())
+ return;
+ auto& guiContext = GuiContext::singleton();
+ m_buttonBoundSize = guiContext.textureSize(m_baseImage);
+ if (!m_hoverImage.empty())
+ m_buttonBoundSize = m_buttonBoundSize.piecewiseMax(guiContext.textureSize(m_hoverImage));
+ if (!m_pressedImage.empty())
+ m_buttonBoundSize = m_buttonBoundSize.piecewiseMax(guiContext.textureSize(m_pressedImage));
+ if (!m_baseImageChecked.empty())
+ m_buttonBoundSize = m_buttonBoundSize.piecewiseMax(guiContext.textureSize(m_baseImageChecked));
+ if (!m_hoverImageChecked.empty())
+ m_buttonBoundSize = m_buttonBoundSize.piecewiseMax(guiContext.textureSize(m_hoverImageChecked));
+ if (!m_pressedImageChecked.empty())
+ m_buttonBoundSize = m_buttonBoundSize.piecewiseMax(guiContext.textureSize(m_pressedImageChecked));
+ if (!m_disabledImageChecked.empty())
+ m_buttonBoundSize = m_buttonBoundSize.piecewiseMax(guiContext.textureSize(m_disabledImageChecked));
+
+ setSize(Vec2I(m_buttonBoundSize));
+}
+
+}