v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
380
source/windowing/StarButtonWidget.cpp
Normal file
380
source/windowing/StarButtonWidget.cpp
Normal file
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue