From 9a1b7cbe52c082c923d19bfdd87e623cbb70db27 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Dec 2014 16:50:09 +0100 Subject: [PATCH] Add SharedStateButton, used in spell window and controls box to apply mouseover effect to all buttons within one row (Fixes #1986) --- apps/openmw/mwgui/settingswindow.cpp | 11 +- apps/openmw/mwgui/spellwindow.cpp | 42 +++++--- components/CMakeLists.txt | 2 +- components/widgets/sharedstatebutton.cpp | 128 +++++++++++++++++++++++ components/widgets/sharedstatebutton.hpp | 51 +++++++++ components/widgets/widgets.cpp | 2 + 6 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 components/widgets/sharedstatebutton.cpp create mode 100644 components/widgets/sharedstatebutton.hpp diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 948423a35..8ef0a331a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -9,6 +9,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -454,16 +456,21 @@ namespace MWGui std::string binding = MWBase::Environment::get().getInputManager()->getActionBindingName (*it); - MyGUI::TextBox* leftText = mControlsBox->createWidget("SandText", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); + Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); - MyGUI::Button* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); + Gui::SharedStateButton* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); rightText->setCaptionWithReplacing(binding); rightText->setTextAlign (MyGUI::Align::Right); rightText->setUserData(*it); // save the action id for callbacks rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction); rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel); curH += h; + + Gui::ButtonGroup group; + group.push_back(leftText); + group.push_back(rightText); + Gui::SharedStateButton::createButtonGroup(group); } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 97ebbcde2..7904c249a 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -177,7 +179,7 @@ namespace MWGui for (std::vector::const_iterator it = spellList.begin(); it != spellList.end(); ++it) { const ESM::Spell* spell = esmStore.get().find(*it); - MyGUI::Button* t = mSpellView->createWidget("SandTextButton", + Gui::SharedStateButton* t = mSpellView->createWidget("SandTextButton", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(spell->mName); t->setTextAlign(MyGUI::Align::Left); @@ -185,20 +187,28 @@ namespace MWGui t->setUserString("Spell", *it); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); - t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); // cost / success chance - MyGUI::Button* costChance = mSpellView->createWidget("SandTextButton", + Gui::SharedStateButton* costChance = mSpellView->createWidget("SandTextButton", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); std::string cost = boost::lexical_cast(spell->mData.mCost); std::string chance = boost::lexical_cast(int(MWMechanics::getSpellSuccessChance(*it, player))); costChance->setCaption(cost + "/" + chance); costChance->setTextAlign(MyGUI::Align::Right); - costChance->setNeedMouseFocus(false); - costChance->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); + costChance->setUserString("ToolTipType", "Spell"); + costChance->setUserString("Spell", *it); + costChance->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); + costChance->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); t->setSize(mWidth-12-costChance->getTextSize().width, t->getHeight()); + Gui::ButtonGroup group; + group.push_back(t); + group.push_back(costChance); + Gui::SharedStateButton::createButtonGroup(group); + + t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); + mHeight += spellHeight; } @@ -224,7 +234,7 @@ namespace MWGui } } - MyGUI::Button* t = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", + Gui::SharedStateButton* t = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(item.getClass().getName(item)); t->setTextAlign(MyGUI::Align::Left); @@ -233,12 +243,9 @@ namespace MWGui t->setUserString("Equipped", equipped ? "true" : "false"); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); - if (store.getSelectedEnchantItem() != store.end()) - t->setStateSelected(item == *store.getSelectedEnchantItem()); - // cost / charge - MyGUI::Button* costCharge = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", + Gui::SharedStateButton* costCharge = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); float enchantCost = enchant->mData.mCost; @@ -257,11 +264,22 @@ namespace MWGui charge = "100"; } + + costCharge->setUserData(item); + costCharge->setUserString("ToolTipType", "ItemPtr"); + costCharge->setUserString("Equipped", equipped ? "true" : "false"); + costCharge->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); + costCharge->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); costCharge->setCaption(cost + "/" + charge); costCharge->setTextAlign(MyGUI::Align::Right); - costCharge->setNeedMouseFocus(false); + + Gui::ButtonGroup group; + group.push_back(t); + group.push_back(costCharge); + Gui::SharedStateButton::createButtonGroup(group); + if (store.getSelectedEnchantItem() != store.end()) - costCharge->setStateSelected(item == *store.getSelectedEnchantItem()); + t->setStateSelected(item == *store.getSelectedEnchantItem()); t->setSize(mWidth-12-costCharge->getTextSize().width, t->getHeight()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6a1db371d..234325718 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -96,7 +96,7 @@ add_component_dir (ogreinit ) add_component_dir (widgets - box imagebutton tags list numericeditbox widgets + box imagebutton tags list numericeditbox sharedstatebutton widgets ) add_component_dir (fontloader diff --git a/components/widgets/sharedstatebutton.cpp b/components/widgets/sharedstatebutton.cpp new file mode 100644 index 000000000..6859a3065 --- /dev/null +++ b/components/widgets/sharedstatebutton.cpp @@ -0,0 +1,128 @@ +#include "sharedstatebutton.hpp" + +namespace Gui +{ + + SharedStateButton::SharedStateButton() + : mIsMousePressed(false) + , mIsMouseFocus(false) + { + + } + + void SharedStateButton::shutdownOverride() + { + ButtonGroup group = mSharedWith; // make a copy so that we don't nuke the vector during iteration + for (ButtonGroup::iterator it = group.begin(); it != group.end(); ++it) + { + (*it)->shareStateWith(ButtonGroup()); + } + } + + void SharedStateButton::shareStateWith(ButtonGroup shared) + { + mSharedWith = shared; + } + + void SharedStateButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) + { + mIsMousePressed = true; + Base::onMouseButtonPressed(_left, _top, _id); + updateButtonState(); + } + + void SharedStateButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) + { + mIsMousePressed = false; + Base::onMouseButtonReleased(_left, _top, _id); + updateButtonState(); + } + + void SharedStateButton::onMouseSetFocus(MyGUI::Widget *_old) + { + mIsMouseFocus = true; + Base::onMouseSetFocus(_old); + updateButtonState(); + } + + void SharedStateButton::onMouseLostFocus(MyGUI::Widget *_new) + { + mIsMouseFocus = false; + Base::onMouseLostFocus(_new); + updateButtonState(); + } + + void SharedStateButton::baseUpdateEnable() + { + Base::baseUpdateEnable(); + updateButtonState(); + } + + void SharedStateButton::setStateSelected(bool _value) + { + Base::setStateSelected(_value); + updateButtonState(); + + for (ButtonGroup::iterator it = mSharedWith.begin(); it != mSharedWith.end(); ++it) + { + (*it)->MyGUI::Button::setStateSelected(getStateSelected()); + } + } + + bool SharedStateButton::_setState(const std::string &_value) + { + bool ret = _setWidgetState(_value); + if (ret) + { + for (ButtonGroup::iterator it = mSharedWith.begin(); it != mSharedWith.end(); ++it) + { + (*it)->_setWidgetState(_value); + } + } + return ret; + } + + void SharedStateButton::updateButtonState() + { + if (getStateSelected()) + { + if (!getInheritedEnabled()) + { + if (!_setState("disabled_checked")) + _setState("disabled"); + } + else if (mIsMousePressed) + { + if (!_setState("pushed_checked")) + _setState("pushed"); + } + else if (mIsMouseFocus) + { + if (!_setState("highlighted_checked")) + _setState("pushed"); + } + else + _setState("normal_checked"); + } + else + { + if (!getInheritedEnabled()) + _setState("disabled"); + else if (mIsMousePressed) + _setState("pushed"); + else if (mIsMouseFocus) + _setState("highlighted"); + else + _setState("normal"); + } + } + + void SharedStateButton::createButtonGroup(ButtonGroup group) + { + for (ButtonGroup::iterator it = group.begin(); it != group.end(); ++it) + { + (*it)->shareStateWith(group); + } + } + +} diff --git a/components/widgets/sharedstatebutton.hpp b/components/widgets/sharedstatebutton.hpp new file mode 100644 index 000000000..3d7fbc84e --- /dev/null +++ b/components/widgets/sharedstatebutton.hpp @@ -0,0 +1,51 @@ +#ifndef OPENMW_WIDGETS_SHAREDSTATEBUTTON_HPP +#define OPENMW_WIDGETS_SHAREDSTATEBUTTON_HPP + +#include + +namespace Gui +{ + + class SharedStateButton; + + typedef std::vector ButtonGroup; + + /// @brief A button that applies its own state changes to other widgets, to do this you define it as part of a ButtonGroup. + class SharedStateButton : public MyGUI::Button + { + MYGUI_RTTI_DERIVED(SharedStateButton) + + public: + SharedStateButton(); + + protected: + void updateButtonState(); + + virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id); + virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id); + virtual void onMouseSetFocus(MyGUI::Widget* _old); + virtual void onMouseLostFocus(MyGUI::Widget* _new); + virtual void baseUpdateEnable(); + + virtual void shutdownOverride(); + + bool _setState(const std::string &_value); + + public: + void shareStateWith(ButtonGroup shared); + + /// @note The ButtonGroup connection will be destroyed when any widget in the group gets destroyed. + static void createButtonGroup(ButtonGroup group); + + //! Set button selected state + void setStateSelected(bool _value); + + private: + ButtonGroup mSharedWith; + + bool mIsMousePressed; + bool mIsMouseFocus; + }; +} + +#endif diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index b35dc88a4..82839c6c9 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -6,6 +6,7 @@ #include "numericeditbox.hpp" #include "box.hpp" #include "imagebutton.hpp" +#include "sharedstatebutton.hpp" namespace Gui { @@ -20,6 +21,7 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } }