diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a01b28a21..fb34e4c88 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -242,6 +242,8 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + info.enchant = ref->base->enchant; + info.text = text; return info; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index aa87b009b..ab659b480 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -130,6 +130,8 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + info.enchant = ref->base->enchant; + info.text = text; return info; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 669407d84..620b664cc 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -195,6 +195,8 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + info.enchant = ref->base->enchant; + info.text = text; return info; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 1caedce62..fcfaebcb7 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -328,35 +328,7 @@ namespace MWClass text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); - // this should be going into a custom mygui widget MWEnchantment - /* - // enchantments - if (ref->base->enchant != "") - { - const ESM::Enchantment* enchant = environment.mWorld->getStore().enchants.search(ref->base->enchant); - if (enchant->data.type == ESM::Enchantment::CastOnce) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastOnce")->str; - else if (enchant->data.type == ESM::Enchantment::WhenStrikes) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastWhenStrikes")->str; - else if (enchant->data.type == ESM::Enchantment::WhenUsed) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastWhenUsed")->str; - else if (enchant->data.type == ESM::Enchantment::ConstantEffect) - text += "\n" + environment.mWorld->getStore().gameSettings.search("sItemCastConstant")->str; - - if (enchant->data.type == ESM::Enchantment::WhenStrikes - || enchant->data.type == ESM::Enchantment::WhenUsed) - { - /// \todo store the current enchantment charge somewhere - // info.currentCharge = enchant->data.charge; - //info.totalCharge = enchant->data.charge; - } - } - */ - if (ref->base->enchant != "") - { - const ESM::Enchantment* enchant = store.enchants.search(ref->base->enchant); - info.enchant = enchant; - } + info.enchant = ref->base->enchant; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2386cf9a3..aec405f46 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -50,9 +50,9 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) //An EditBox cannot receive mouse click events, so we use an //invisible widget on top of the editbox to receive them - /// \todo scrolling the dialogue history with the mouse wheel doesn't work using this solution getWidget(eventbox, "EventBox"); eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); + eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); //Topics list getWidget(topicsList, "TopicsList"); @@ -88,6 +88,14 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) } } +void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (history->getVScrollPosition() - _rel*0.3 < 0) + history->setVScrollPosition(0); + else + history->setVScrollPosition(history->getVScrollPosition() - _rel*0.3); +} + void DialogueWindow::open() { topicsList->removeAllItems(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 61e8c124c..5921ca57a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -45,6 +45,7 @@ namespace MWGui void onSelectTopic(MyGUI::ListBox* _sender, size_t _index); void onByeClicked(MyGUI::Widget* _sender); void onHistoryClicked(MyGUI::Widget* _sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); private: void updateOptions(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index ef30b88d7..f5b140ec1 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -1,7 +1,10 @@ #include "tooltips.hpp" -#include "window_manager.hpp" +#include "window_manager.hpp" +#include "widgets.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" #include @@ -177,6 +180,21 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) if (text.size() > 0 && text[0] == '\n') text.erase(0, 1); + const ESM::Enchantment* enchant; + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + if (info.enchant != "") + { + enchant = store.enchants.search(info.enchant); + if (enchant->data.type == ESM::Enchantment::CastOnce) + text += "\n" + store.gameSettings.search("sItemCastOnce")->str; + else if (enchant->data.type == ESM::Enchantment::WhenStrikes) + text += "\n" + store.gameSettings.search("sItemCastWhenStrikes")->str; + else if (enchant->data.type == ESM::Enchantment::WhenUsed) + text += "\n" + store.gameSettings.search("sItemCastWhenUsed")->str; + else if (enchant->data.type == ESM::Enchantment::ConstantEffect) + text += "\n" + store.gameSettings.search("sItemCastConstant")->str; + } + // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -207,13 +225,55 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - if (image != "") + if (info.enchant != "") { - ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", - IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), - Align::Left | Align::Top, "ToolTipImage"); - imageWidget->setImageTexture(realImage); - imageWidget->setPosition (imageWidget->getPosition() + padding); + Widget* enchantArea = mDynamicToolTipBox->createWidget("", + IntCoord(0, totalSize.height, 300, 300-totalSize.height), + Align::Stretch, "ToolTipEnchantArea"); + + IntCoord coord(0, 6, totalSize.width, 24); + + Widgets::MWEnchantmentPtr enchantWidget = enchantArea->createWidget + ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); + enchantWidget->setWindowManager(mWindowManager); + enchantWidget->setEnchantmentId(info.enchant); + + std::vector enchantEffectItems; + enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, (enchant->data.type == ESM::Enchantment::ConstantEffect)); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + + if (enchant->data.type == ESM::Enchantment::WhenStrikes + || enchant->data.type == ESM::Enchantment::WhenUsed) + { + /// \todo store the current enchantment charge somewhere + int charge = enchant->data.charge; + + const int chargeWidth = 204; + + TextBox* chargeText = enchantArea->createWidget("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText"); + chargeText->setCaption(store.gameSettings.search("sCharges")->str); + chargeText->setProperty("Static", "true"); + const int chargeTextWidth = chargeText->getTextSize().width + 5; + + const int chargeAndTextWidth = chargeWidth + chargeTextWidth; + chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); + + IntCoord chargeCoord; + if (totalSize.width < chargeWidth) + { + totalSize.width = chargeWidth; + chargeCoord = IntCoord(0, coord.top+6, chargeWidth, 18); + } + else + { + chargeCoord = IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); + } + Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget + ("MW_ChargeBar", chargeCoord, Align::Default, "ToolTipEnchantCharge"); + chargeWidget->setValue(charge, charge); + totalSize.height += 24; + } } captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, @@ -224,6 +284,15 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) captionWidget->setPosition (captionWidget->getPosition() + padding); textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + if (image != "") + { + ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), + Align::Left | Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + imageWidget->setPosition (imageWidget->getPosition() + padding); + } + totalSize += IntSize(padding.left*2, padding.top*2); return totalSize; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index c00faba86..fafe471a5 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -14,7 +14,6 @@ namespace MWGui { public: ToolTipInfo() : - enchant(0), effects(0) { }; @@ -24,7 +23,7 @@ namespace MWGui std::string icon; // enchantment (for cloth, armor, weapons) - const ESM::Enchantment* enchant; + std::string enchant; // effects (for potions, ingredients) const ESM::EffectList* effects; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 58cfee991..769220f7b 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -238,6 +238,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: effect->setSpellEffect(*it); effects.push_back(effect); coord.top += effect->getHeight(); + coord.width = std::max(coord.width, effect->getRequestedWidth()); } } @@ -278,22 +279,49 @@ void MWEnchantment::setEnchantmentId(const std::string &enchantId) updateWidgets(); } -void MWEnchantment::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) +void MWEnchantment::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant) { const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Enchantment *enchant = store.enchants.search(id); MYGUI_ASSERT(enchant, "enchantment with id '" << id << "' not found"); + // We don't know the width of all the elements beforehand, so we do it in + // 2 steps: first, create all widgets and check their width MWSpellEffectPtr effect = nullptr; std::vector::const_iterator end = enchant->effects.list.end(); + int maxwidth = coord.width; for (std::vector::const_iterator it = enchant->effects.list.begin(); it != end; ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); effect->setSpellEffect(*it); + effect->setConstant(constant); effects.push_back(effect); + + if (effect->getRequestedWidth() > maxwidth) + maxwidth = effect->getRequestedWidth(); + coord.top += effect->getHeight(); } + + // then adjust the size for all widgets + for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + { + effect = static_cast(*it); + bool needcenter = center && (maxwidth > effect->getRequestedWidth()); + int diff = maxwidth - effect->getRequestedWidth(); + if (needcenter) + { + effect->setCoord(diff/2, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + else + { + effect->setCoord(0, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + } + + // inform the parent about width + coord.width = maxwidth; } void MWEnchantment::updateWidgets() @@ -315,6 +343,8 @@ MWSpellEffect::MWSpellEffect() : mWindowManager(nullptr) , imageWidget(nullptr) , textWidget(nullptr) + , mRequestedWidth(0) + , mIsConstant(0) { } @@ -366,7 +396,7 @@ void MWSpellEffect::updateWidgets() spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); else { - spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMin) + " " + pts; + spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMax) + " " + pts; } } @@ -388,6 +418,7 @@ void MWSpellEffect::updateWidgets() } static_cast(textWidget)->setCaption(spellLine); + mRequestedWidth = textWidget->getTextSize().width + 24; } else static_cast(textWidget)->setCaption(""); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 8ac27795d..b4915ac6a 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -119,6 +119,14 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); + + /** + * @param vector to store the created effect widgets + * @param parent widget + * @param coordinates to use, will be expanded if more space is needed + * @param spell category, if this is 0, this means the spell effects are permanent and won't display e.g. duration + * @param center the effect widgets horizontally + */ void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, const int category); const std::string &getSpellId() const { return id; } @@ -147,7 +155,15 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setEnchantmentId(const std::string &enchantId); - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord); + + /** + * @param vector to store the created effect widgets + * @param parent widget + * @param coordinates to use, will be expanded if more space is needed + * @param center the effect widgets horizontally + * @param are the effects of this enchantment constant? + */ + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, bool constant); const std::string &getSpellId() const { return id; } @@ -180,6 +196,8 @@ namespace MWGui const SpellEffectValue &getSpellEffect() const { return effect; } + int getRequestedWidth() const { return mRequestedWidth; } + protected: virtual ~MWSpellEffect(); @@ -194,6 +212,7 @@ namespace MWGui bool mIsConstant; // constant effect MyGUI::ImageBox* imageWidget; MyGUI::TextBox* textWidget; + int mRequestedWidth; }; typedef MWSpellEffect* MWSpellEffectPtr; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index a3e44f65b..ccf558de5 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -104,6 +104,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 9f87c93b3..36d97e153 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -93,6 +93,11 @@ + + + + +