diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index deb57cfec0..c675fb1d7c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,7 +26,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace + map_window window_pinnable_base cursorreplace tooltips ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4ae6ae747c..539afe1c87 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -74,47 +74,6 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -void OMW::Engine::updateFocusReport (float duration) -{ - - if ((mFocusTDiff += duration)>0.25) - { - mFocusTDiff = 0; - - std::string name; - - std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); - - if (!handle.empty()) - { - // the faced handle is not updated immediately, so on a cell change it might - // point to an object that doesn't exist anymore - // therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case - try - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle); - - if (!ptr.isEmpty()){ - name = MWWorld::Class::get (ptr).getName (ptr); - - } - } - catch (std::runtime_error& e) - {} - } - - if (name!=mFocusName) - { - mFocusName = name; - - if (mFocusName.empty()) - std::cout << "Unfocus" << std::endl; - else - std::cout << "Focus: " << name << std::endl; - } - } -} - void OMW::Engine::setAnimationVerbose(bool animverbose){ if(animverbose){ NifOgre::NIFLoader::getSingletonPtr()->setOutputAnimFiles(true); @@ -135,14 +94,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) if (mUseSound) MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame); - // update GUI - Ogre::RenderWindow* window = mOgre->getWindow(); - MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), - window->getTriangleCount(), - window->getBatchCount()); - - MWBase::Environment::get().getWindowManager()->onFrame(mEnvironment.getFrameDuration()); - // global scripts MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); @@ -173,9 +124,13 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update world MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame); - // report focus object (for debugging) - if (mReportFocus) - updateFocusReport (mEnvironment.getFrameDuration()); + // update GUI + Ogre::RenderWindow* window = mOgre->getWindow(); + MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), + window->getTriangleCount(), + window->getBatchCount()); + + MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); } catch (const std::exception& e) { @@ -193,7 +148,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mNewGame (false) , mUseSound (true) , mCompileAll (false) - , mReportFocus (false) , mFocusTDiff (0) , mScriptContext (0) , mFSStrict (false) @@ -305,11 +259,6 @@ void OMW::Engine::setNewGame(bool newGame) mNewGame = newGame; } -void OMW::Engine::setReportFocus (bool report) -{ - mReportFocus = report; -} - // Initialise and enter main loop. void OMW::Engine::go() diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index ccd7314cbc..c834ee438d 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -74,7 +74,6 @@ namespace OMW bool mNewGame; bool mUseSound; bool mCompileAll; - bool mReportFocus; float mFocusTDiff; std::string mFocusName; std::map mFallbackMap; @@ -101,8 +100,6 @@ namespace OMW void executeLocalScripts(); - void updateFocusReport (float duration); - virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); public: @@ -145,9 +142,6 @@ namespace OMW /// Start as a new game. void setNewGame(bool newGame); - /// Write name of focussed object to cout - void setReportFocus (bool report); - /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index df52faab14..68aa12fb36 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -155,9 +155,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" "\n\twin1252 - Western European (Latin) alphabet, used by default") - ("report-focus", bpo::value()->implicit_value(true) - ->default_value(false), "write name of focussed object to cout") - ("fallback", bpo::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") @@ -265,7 +262,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setSoundUsage(!variables["nosound"].as()); engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setCompileAll(variables["script-all"].as()); - engine.setReportFocus(variables["report-focus"].as()); engine.setAnimationVerbose(variables["anim-verbose"].as()); engine.setFallbackValues(variables["fallback"].as().mMap); diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 5b5028f1ca..6faaacf319 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -1,13 +1,14 @@ #include "activator.hpp" -#include "../mwrender/objects.hpp" #include #include #include "../mwworld/ptr.hpp" - +#include "../mwrender/objects.hpp" +#include "../mwbase/environment.hpp" +#include "../mwgui/window_manager.hpp" namespace MWClass { @@ -63,4 +64,28 @@ namespace MWClass registerClass (typeid (ESM::Activator).name(), instance); } + + bool Activator::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index d0b1f25e06..223dd0a36b 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -18,6 +18,12 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index e7c208d4a2..215183dca7 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -9,9 +9,13 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" #include "../mwrender/objects.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" + #include "../mwsound/soundmanager.hpp" namespace MWClass @@ -95,4 +99,37 @@ namespace MWClass { return std::string("Item Apparatus Down"); } + + bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + text += "\n" + store.gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 9015aedb85..e99ea1c1d3 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -28,6 +28,12 @@ namespace MWClass virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 3a34032611..fb34e4c883 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,8 @@ #include "../mwrender/objects.hpp" +#include "../mwgui/window_manager.hpp" + #include "../mwsound/soundmanager.hpp" namespace MWClass @@ -138,8 +140,7 @@ namespace MWClass case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break; case ESM::Armor::LGauntlet: case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break; -/// \todo how to determine if shield light, medium or heavy? -// case ESM::Armor::Shield: + case ESM::Armor::Shield: typeGmst = "iShieldWeight"; break; case ESM::Armor::LBracer: case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break; } @@ -196,4 +197,55 @@ namespace MWClass else return std::string("Item Armor Heavy Down"); } + + bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + // get armor type string (light/medium/heavy) + int armorType = getEquipmentSkill(ptr); + std::string typeText; + if (armorType == ESM::Skill::LightArmor) + typeText = store.gameSettings.search("sLight")->str; + else if (armorType == ESM::Skill::MediumArmor) + typeText = store.gameSettings.search("sMedium")->str; + else + typeText = store.gameSettings.search("sHeavy")->str; + + text += "\n" + store.gameSettings.search("sArmorRating")->str + ": " + MWGui::ToolTips::toString(ref->base->data.armor); + + /// \todo store the current armor health somewhere + text += "\n" + store.gameSettings.search("sCondition")->str + ": " + MWGui::ToolTips::toString(ref->base->data.health); + + text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight) + " (" + typeText + ")"; + text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.enchant = ref->base->enchant; + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 6cba077264..c757587e5e 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -39,6 +39,12 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index b3b71104b6..ab659b4805 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -9,9 +9,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" #include "../mwrender/objects.hpp" +#include "../mwgui/window_manager.hpp" + #include "../mwsound/soundmanager.hpp" namespace MWClass @@ -97,4 +100,40 @@ namespace MWClass { return std::string("Item Book Down"); } + + bool Book::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + 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.hpp b/apps/openmw/mwclass/book.hpp index 975cdf12b3..e85fbfb7f9 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -25,6 +25,12 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 15f00bb053..620b664cc4 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -10,6 +10,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/tooltips.hpp" +#include "../mwgui/window_manager.hpp" #include "../mwrender/objects.hpp" @@ -161,4 +165,40 @@ namespace MWClass } return std::string("Item Clothes Down"); } + + bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + 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.hpp b/apps/openmw/mwclass/clothing.hpp index 7fc05bef35..afb1849995 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -33,6 +33,12 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index a229cbe9b0..a9def96aa6 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -11,6 +11,10 @@ #include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -138,4 +142,38 @@ namespace MWClass registerClass (typeid (ESM::Container).name(), instance); } + + bool Container::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + if (ref->ref.lockLevel > 0) + text += "\n" + store.gameSettings.search("sLockLevel")->str + ": " + MWGui::ToolTips::toString(ref->ref.lockLevel); + if (ref->ref.trap != "") + text += "\n" + store.gameSettings.search("sTrapped")->str; + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index c371e8898d..3b1c8de09a 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -24,6 +24,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index b5a17b2b52..cf00f361bc 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -13,6 +13,8 @@ #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwgui/window_manager.hpp" + namespace { struct CustomData : public MWWorld::CustomData @@ -141,4 +143,27 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } + + bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const + { + /// \todo We don't want tooltips for Creatures in combat mode. + + return true; + } + + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index fa07f9625a..4a1a8285fd 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -32,6 +32,12 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWMechanics::CreatureStats& getCreatureStats (const MWWorld::Ptr& ptr) const; ///< Return creature stats diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 003beaa304..7041de1c68 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -13,6 +13,9 @@ #include "../mwworld/actionteleport.hpp" #include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" + #include "../mwrender/objects.hpp" #include "../mwsound/soundmanager.hpp" @@ -143,4 +146,63 @@ namespace MWClass registerClass (typeid (ESM::Door).name(), instance); } + + bool Door::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + if (ref->ref.teleport) + { + std::string dest; + if (ref->ref.destCell != "") + { + // door leads to an interior, use interior name as tooltip + dest = ref->ref.destCell; + } + else + { + // door leads to exterior, use cell name (if any), otherwise translated region name + int x,y; + MWBase::Environment::get().getWorld()->positionToIndex (ref->ref.doorDest.pos[0], ref->ref.doorDest.pos[1], x, y); + const ESM::Cell* cell = store.cells.findExt(x,y); + if (cell->name != "") + dest = cell->name; + else + { + const ESM::Region* region = store.regions.search(cell->region); + dest = region->name; + } + } + text += "\n" + store.gameSettings.search("sTo")->str; + text += "\n"+dest; + } + + if (ref->ref.lockLevel > 0) + text += "\n" + store.gameSettings.search("sLockLevel")->str + ": " + MWGui::ToolTips::toString(ref->ref.lockLevel); + if (ref->ref.trap != "") + text += "\n" + store.gameSettings.search("sTrapped")->str; + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 4779ed174a..63d1c1ab8b 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; ///< Lock object diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 79b1bb92f3..068ae0cde2 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -9,6 +9,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -93,4 +97,38 @@ namespace MWClass { return std::string("Item Ingredient Down"); } + + bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index d8190c8fc2..36756b6c33 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index deb8c25671..0c6892d247 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -11,6 +11,10 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwsound/soundmanager.hpp" @@ -135,4 +139,38 @@ namespace MWClass { return std::string("Item Misc Down"); } + + bool Light::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 5d139cb8fd..7149a41a9c 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -23,6 +23,12 @@ namespace MWClass ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index d682538eac..bd5849f669 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -10,6 +10,9 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -106,4 +109,42 @@ namespace MWClass { return std::string("Item Lockpick Down"); } + + bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + /// \todo store remaining uses somewhere + + text += "\n" + store.gameSettings.search("sUses")->str + ": " + MWGui::ToolTips::toString(ref->base->data.uses); + text += "\n" + store.gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 042c726e44..0eaaa5af9b 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index bcbf268708..facee1bbbe 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -9,11 +9,17 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" #include "../mwsound/soundmanager.hpp" +#include + namespace MWClass { void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -91,7 +97,7 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - if (ref->base->name =="Gold") + if (ref->base->name == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) { return std::string("Item Gold Up"); } @@ -103,10 +109,55 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - if (ref->base->name =="Gold") + if (ref->base->name == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) { return std::string("Item Gold Down"); } return std::string("Item Misc Down"); } + + bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + if (ref->ref.soul != "") + { + const ESM::Creature *creature = store.creatures.search(ref->ref.soul); + info.caption += " (" + creature->name + ")"; + } + + std::string text; + + if (ref->base->name == store.gameSettings.search("sGold")->str) + info.caption += " (" + boost::lexical_cast(ref->base->data.value) + ")"; + else + { + 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); + } + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index bc05169c0e..fbe721cf3d 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5a151decb6..ae0167639d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -18,6 +18,8 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" +#include "../mwgui/window_manager.hpp" + #include "../mwbase/environment.hpp" namespace @@ -299,4 +301,27 @@ namespace MWClass boost::shared_ptr instance (new Npc); registerClass (typeid (ESM::NPC).name(), instance); } + + bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const + { + /// \todo We don't want tooltips for NPCs in combat mode. + + return true; + } + + MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + + std::string text; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1ef77bd1b2..38b0ba03f0 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -38,6 +38,12 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; ///< Return inventory store diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 790b4d13ef..07e7663b38 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -9,6 +9,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -95,4 +99,40 @@ namespace MWClass { return std::string("Item Potion Down"); } + + bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + 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); + + info.effects = &ref->base->effects; + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index f9137766b1..8c2357fb2e 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index bfb1d29510..02dc1115d2 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -10,6 +10,9 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -105,4 +108,42 @@ namespace MWClass { return std::string("Item Probe Down"); } + + bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + /// \todo store remaining uses somewhere + + text += "\n" + store.gameSettings.search("sUses")->str + ": " + MWGui::ToolTips::toString(ref->base->data.uses); + text += "\n" + store.gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 543fa3f391..f8c13fa1ea 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 8bae71e194..0eb1f0cf2a 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -9,6 +9,9 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/world.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -95,4 +98,41 @@ namespace MWClass { return std::string("Item Repair Down"); } + + bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + std::string text; + + /// \todo store remaining uses somewhere + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + text += "\n" + store.gameSettings.search("sUses")->str + ": " + MWGui::ToolTips::toString(ref->base->data.uses); + text += "\n" + store.gameSettings.search("sQuality")->str + ": " + MWGui::ToolTips::toString(ref->base->data.quality); + 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); + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 446ab325da..1d9ebb8bfb 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 22745f82d5..fcfaebcb7a 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -10,6 +10,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/world.hpp" + +#include "../mwgui/window_manager.hpp" +#include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" @@ -245,4 +249,94 @@ namespace MWClass return std::string("Item Misc Down"); } + + bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return (ref->base->name != ""); + } + + MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + MWGui::ToolTipInfo info; + info.caption = ref->base->name; + info.icon = ref->base->icon; + + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string text; + + // weapon type & damage. arrows / bolts don't have his info. + if (ref->base->data.type < 12) + { + text += "\n" + store.gameSettings.search("sType")->str + " "; + + std::map > mapping; + mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded"); + mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded"); + mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded"); + mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded"); + mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); + mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded"); + mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded"); + mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded"); + mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded"); + mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", ""); + + std::string type = mapping[ref->base->data.type].first; + std::string oneOrTwoHanded = mapping[ref->base->data.type].second; + + text += store.gameSettings.search(type)->str + + ((oneOrTwoHanded != "") ? ", " + store.gameSettings.search(oneOrTwoHanded)->str : ""); + + // weapon damage + if (ref->base->data.type >= 9) + { + // marksman + text += "\n" + store.gameSettings.search("sAttack")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[1])); + } + else + { + // Chop + text += "\n" + store.gameSettings.search("sChop")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.chop[1])); + // Slash + text += "\n" + store.gameSettings.search("sSlash")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.slash[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.slash[1])); + // Thrust + text += "\n" + store.gameSettings.search("sThrust")->str + ": " + + MWGui::ToolTips::toString(static_cast(ref->base->data.thrust[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->base->data.thrust[1])); + } + } + + /// \todo store the current weapon health somewhere + if (ref->base->data.type < 11) // thrown weapons and arrows/bolts don't have health, only quantity + text += "\n" + store.gameSettings.search("sCondition")->str + ": " + MWGui::ToolTips::toString(ref->base->data.health); + + 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); + + info.enchant = ref->base->enchant; + + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { + text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); + } + + info.text = text; + + return info; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 204d327ade..9c5f43bd3f 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -22,6 +22,12 @@ namespace MWClass const MWWorld::Ptr& actor) const; ///< Generate action for activation + virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; ///< \return Item health data available? diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 24ee4ee7f6..ac41244d1c 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -54,6 +54,20 @@ namespace return lowerCase; } + bool stringCompareNoCase (std::string first, std::string second) + { + unsigned int i=0; + while ( (itolower(second[i])) return false; + ++i; + } + if (first.length() bool selectCompare (char comp, T1 value1, T2 value2) @@ -723,7 +737,11 @@ namespace MWDialogue } } } + + // sort again, because the previous sort was case-sensitive + keywordList.sort(stringCompareNoCase); win->setKeywords(keywordList); + mChoice = choice; } @@ -815,7 +833,7 @@ namespace MWDialogue { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); - mChoiceMap[question] = choice; + mChoiceMap[toLower(question)] = choice; mIsInChoice = true; } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index e9c15fab4a..cb15eaf15b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -25,13 +25,14 @@ BirthDialog::BirthDialog(WindowManager& parWindowManager) birthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); birthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); updateBirths(); @@ -46,21 +47,16 @@ void BirthDialog::setNextButtonShow(bool shown) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) - { - okButton->setCaption("Next"); - - // Adjust back button when next is shown - backButton->setCoord(MyGUI::IntCoord(375 - 18, 340, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(431 - 18, 340, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - backButton->setCoord(MyGUI::IntCoord(375, 340, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(431, 340, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + + okButton->setCoord(473 - okButtonWidth, 340, okButtonWidth, 23); + backButton->setCoord(473 - okButtonWidth - backButtonWidth - 6, 340, backButtonWidth, 23); } void BirthDialog::open() @@ -206,7 +202,7 @@ void BirthDialog::updateSpells() MyGUI::IntCoord spellCoord = coord; spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? - spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord); + spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); coord.top = spellCoord.top; ++i; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 75e534b42a..9f1fc5d2a5 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -26,14 +26,20 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan getWidget(classImage, "ClassImage"); getWidget(className, "ClassName"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + okButton->setCoord(315 - okButtonWidth, 219, okButtonWidth, 23); + backButton->setCoord(315 - okButtonWidth - backButtonWidth - 6, 219, backButtonWidth, 23); } void GenerateClassResultDialog::open() @@ -102,7 +108,6 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager) getWidget(classImage, "ClassImage"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); @@ -123,21 +128,16 @@ void PickClassDialog::setNextButtonShow(bool shown) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) - { - okButton->setCaption("Next"); - - // Adjust back button when next is shown - backButton->setCoord(MyGUI::IntCoord(382 - 18, 265, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(434 - 18, 265, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - backButton->setCoord(MyGUI::IntCoord(382, 265, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(434, 265, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + + okButton->setCoord(476 - okButtonWidth, 265, okButtonWidth, 23); + backButton->setCoord(476 - okButtonWidth - backButtonWidth - 6, 265, backButtonWidth, 23); } void PickClassDialog::open() @@ -423,9 +423,9 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(editName); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr descriptionButton; getWidget(descriptionButton, "DescriptionButton"); + descriptionButton->setCaption(mWindowManager.getGameSettingString("sCreateClassMenu1", "")); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); MyGUI::ButtonPtr backButton; @@ -507,32 +507,27 @@ std::vector CreateClassDialog::getMinorSkills() const void CreateClassDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr descriptionButton; - getWidget(descriptionButton, "DescriptionButton"); - MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. - if (shown) - { - okButton->setCaption("Next"); + MyGUI::ButtonPtr descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); - // Adjust back button when next is shown - descriptionButton->setCoord(MyGUI::IntCoord(207 - 18, 158, 143, 23)); - backButton->setCoord(MyGUI::IntCoord(356 - 18, 158, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(417 - 18, 158, 42 + 18, 23)); - } + if (shown) + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - descriptionButton->setCoord(MyGUI::IntCoord(207, 158, 143, 23)); - backButton->setCoord(MyGUI::IntCoord(356, 158, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(417, 158, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + int descriptionButtonWidth = descriptionButton->getTextSize().width + 24; + + okButton->setCoord(459 - okButtonWidth, 158, okButtonWidth, 23); + backButton->setCoord(459 - okButtonWidth - backButtonWidth - 6, 158, backButtonWidth, 23); + descriptionButton->setCoord(459 - okButtonWidth - backButtonWidth - descriptionButtonWidth - 12, 158, descriptionButtonWidth, 23); } void CreateClassDialog::open() @@ -679,11 +674,12 @@ SelectSpecializationDialog::SelectSpecializationDialog(WindowManager& parWindowM specialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); specializationId = ESM::Class::Combat; - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); + int buttonWidth = cancelButton->getTextSize().width + 24; + cancelButton->setCoord(216 - buttonWidth, 90, buttonWidth, 21); } // widget controls @@ -728,11 +724,12 @@ SelectAttributeDialog::SelectAttributeDialog(WindowManager& parWindowManager) attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); } - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); + int buttonWidth = cancelButton->getTextSize().width + 24; + cancelButton->setCoord(186 - buttonWidth, 180, buttonWidth, 21); } // widget controls @@ -817,11 +814,12 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) } } - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); + int buttonWidth = cancelButton->getTextSize().width + 24; + cancelButton->setCoord(447 - buttonWidth, 218, buttonWidth, 21); } // widget controls @@ -847,11 +845,12 @@ DescriptionDialog::DescriptionDialog(WindowManager& parWindowManager) getWidget(textEdit, "TextEdit"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); + int buttonWidth = okButton->getTextSize().width + 24; + okButton->setCoord(234 - buttonWidth, 214, buttonWidth, 24); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2386cf9a32..0238446ebe 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"); @@ -84,10 +84,18 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) UString key = history->getColorTextAt(cursorPosition); if(color == "#686EBA") MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(key); + if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); } } +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 61e8c124c5..5921ca57a2 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/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 0e9d57c3c2..e0c828fdc4 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -29,6 +29,9 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : getWidget(mButton, "WorldButton"); mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaption(mWindowManager.getGameSettingString("sWorld", "")); + int width = mButton->getTextSize().width + 24; + mButton->setCoord(mMainWidget->getSize().width - width - 22, mMainWidget->getSize().height - 64, width, 22); MyGUI::Button* eventbox; getWidget(eventbox, "EventBox"); @@ -97,7 +100,10 @@ void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) mGlobalMap->setVisible(mGlobal); mLocalMap->setVisible(!mGlobal); - mButton->setCaption( mGlobal ? "Local" : "World" ); + mButton->setCaption( mGlobal ? mWindowManager.getGameSettingString("sWorld", "") : + mWindowManager.getGameSettingString("sLocal", "")); + int width = mButton->getTextSize().width + 24; + mButton->setCoord(mMainWidget->getSize().width - width - 22, mMainWidget->getSize().height - 64, width, 22); } void MapWindow::onPinToggled() diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 880c0bc520..275759c9f7 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -69,13 +69,14 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); getWidget(spellPowerList, "SpellPowerList"); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); updateRaces(); @@ -91,21 +92,16 @@ void RaceDialog::setNextButtonShow(bool shown) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. if (shown) - { - okButton->setCaption("Next"); - - // Adjust back button when next is shown - backButton->setCoord(MyGUI::IntCoord(471 - 18, 397, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(532 - 18, 397, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - backButton->setCoord(MyGUI::IntCoord(471, 397, 53, 23)); - okButton->setCoord(MyGUI::IntCoord(532, 397, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + int backButtonWidth = backButton->getTextSize().width + 24; + + okButton->setCoord(574 - okButtonWidth, 397, okButtonWidth, 23); + backButton->setCoord(574 - okButtonWidth - backButtonWidth - 6, 397, backButtonWidth, 23); } void RaceDialog::open() diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index cb0d9969c6..7dfe514def 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -28,21 +28,25 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) getWidget(nameWidget, "NameText"); getWidget(button, "NameButton"); button->setCaption(mWindowManager.getGameSettingString("sName", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; getWidget(raceWidget, "RaceText"); getWidget(button, "RaceButton"); button->setCaption(mWindowManager.getGameSettingString("sRace", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; getWidget(classWidget, "ClassText"); getWidget(button, "ClassButton"); button->setCaption(mWindowManager.getGameSettingString("sClass", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; getWidget(birthSignWidget, "SignText"); getWidget(button, "SignButton"); button->setCaption(mWindowManager.getGameSettingString("sBirthSign", "")); + adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; // Setup dynamic stats @@ -86,14 +90,20 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ReviewDialog::onWindowResize); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); + backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); + + int backButtonWidth = backButton->getTextSize().width + 24; + int okButtonWidth = okButton->getTextSize().width + 24; + okButton->setCoord(502 - okButtonWidth, 372, okButtonWidth, 23); + backButton->setCoord(502 - okButtonWidth - backButtonWidth - 6, 372, backButtonWidth, 23); } void ReviewDialog::open() @@ -181,13 +191,14 @@ void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanic { float modified = value.getModified(), base = value.getBase(); std::string text = boost::lexical_cast(std::floor(modified)); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; + state = "decreased"; - setStyledText(widget, style, text); + widget->setCaption(text); + widget->_setWidgetState(state); } } @@ -210,17 +221,6 @@ void ReviewDialog::configureSkills(const std::vector& major, const std::vec } } -void ReviewDialog::setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value) -{ - widget->setCaption(value); - if (style == CS_Super) - widget->setTextColour(MyGUI::Colour(0, 1, 0)); - else if (style == CS_Sub) - widget->setTextColour(MyGUI::Colour(1, 0, 0)); - else - widget->setTextColour(MyGUI::Colour(1, 1, 1)); -} - void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); @@ -240,7 +240,7 @@ void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, M coord2.top += lineHeight; } -MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; MyGUI::TextBox* skillValueWidget; @@ -249,7 +249,8 @@ MyGUI::TextBox* ReviewDialog::addValueItem(const std::string text, const std::st skillNameWidget->setCaption(text); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); - setStyledText(skillValueWidget, style, value); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); skillWidgets.push_back(skillNameWidget); skillWidgets.push_back(skillValueWidget); @@ -295,12 +296,12 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId float base = stat.getBase(); float modified = stat.getModified(); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2); + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); skillWidgetMap[skillId] = widget; } } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 588c1b6b5d..76ca5a2d76 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -69,17 +69,10 @@ namespace MWGui void onBirthSignClicked(MyGUI::Widget* _sender); private: - enum ColorStyle - { - CS_Sub, - CS_Normal, - CS_Super - }; - void setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value); void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); void updateSkillArea(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 675e5141fa..b007fc1d40 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -72,6 +72,8 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) MyGUI::WindowPtr t = static_cast(mMainWidget); t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); + + setupToolTips(); } void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) @@ -109,17 +111,7 @@ void StatsWindow::setBar(const std::string& name, const std::string& tname, int void StatsWindow::setPlayerName(const std::string& playerName) { static_cast(mMainWidget)->setCaption(playerName); -} - -void StatsWindow::setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value) -{ - widget->setCaption(value); - if (style == CS_Super) - widget->setTextColour(MyGUI::Colour(0, 1, 0)); - else if (style == CS_Sub) - widget->setTextColour(MyGUI::Colour(1, 0, 0)); - else - widget->setTextColour(MyGUI::Colour(1, 1, 1)); + adjustWindowCaption(); } void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) @@ -138,12 +130,15 @@ void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& valueString << value.getModified(); setText (id, valueString.str()); + MyGUI::TextBox* box; + getWidget(box, id); + if (value.getModified()>value.getBase()) - setTextColor (id, 0, 1, 0); + box->_setWidgetState("increased"); else if (value.getModified()_setWidgetState("decreased"); else - setTextColor (id, 1, 1, 1); + box->_setWidgetState("normal"); break; } @@ -193,13 +188,14 @@ void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechani { float modified = value.getModified(), base = value.getBase(); std::string text = boost::lexical_cast(std::floor(modified)); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; + state = "decreased"; - setStyledText(widget, style, text); + widget->setCaption(text); + widget->_setWidgetState(state); } } @@ -251,15 +247,20 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My coord2.top += lineHeight; } -MyGUI::TextBox* StatsWindow::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); skillNameWidget->setCaption(text); + skillNameWidget->setUserString("ToolTipType", "Text"); + skillNameWidget->setUserString("ToolTipText", tooltip); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Default); - setStyledText(skillValueWidget, style, value); + skillValueWidget->setUserString("ToolTipType", "Text"); + skillValueWidget->setUserString("ToolTipText", tooltip); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); skillWidgets.push_back(skillNameWidget); skillWidgets.push_back(skillValueWidget); @@ -305,12 +306,13 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, float base = stat.getBase(); float modified = stat.getModified(); - ColorStyle style = CS_Normal; + std::string state = "normal"; if (modified > base) - style = CS_Super; + state = "increased"; else if (modified < base) - style = CS_Sub; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), style, coord1, coord2); + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), "", + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); skillWidgetMap[skillId] = widget; } } @@ -369,8 +371,12 @@ void StatsWindow::updateSkillArea() if (!skillWidgets.empty()) addSeparator(coord1, coord2); - addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), boost::lexical_cast(static_cast(reputation)), CS_Normal, coord1, coord2); - addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), boost::lexical_cast(static_cast(bounty)), CS_Normal, coord1, coord2); + addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), + mWindowManager.getGameSettingString("sSkillsMenuReputationHelp", ""), + boost::lexical_cast(static_cast(reputation)), "normal", coord1, coord2); + addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), + mWindowManager.getGameSettingString("sCrimeHelp", ""), + boost::lexical_cast(static_cast(bounty)), "normal", coord1, coord2); clientHeight = coord1.top; updateScroller(); @@ -386,3 +392,98 @@ void StatsWindow::onPinToggled() { mWindowManager.setHMSVisibility(!mPinned); } + +void StatsWindow::setupToolTips() +{ + + const ESMS::ESMStore &store = mWindowManager.getStore(); + MyGUI::Widget* widget; + + getWidget(widget, "Attrib1"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + getWidget(widget, "AttribVal1"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + + getWidget(widget, "Attrib2"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + getWidget(widget, "AttribVal2"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + + getWidget(widget, "Attrib3"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + getWidget(widget, "AttribVal3"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + + getWidget(widget, "Attrib4"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + getWidget(widget, "AttribVal4"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + + getWidget(widget, "Attrib5"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + getWidget(widget, "AttribVal5"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + + getWidget(widget, "Attrib6"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + getWidget(widget, "AttribVal6"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + + getWidget(widget, "Attrib7"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + getWidget(widget, "AttribVal7"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + + getWidget(widget, "Attrib8"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); + getWidget(widget, "AttribVal8"); + widget->setUserString("ToolTipType", "ImageCaptionText"); + widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); +} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index f2731e545c..ecbc82894e 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -43,20 +43,15 @@ namespace MWGui void updateSkillArea(); private: - enum ColorStyle - { - CS_Sub, - CS_Normal, - CS_Super - }; - void setStyledText(MyGUI::TextBox* widget, ColorStyle style, const std::string &value); void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); + void setupToolTips(); + void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onWindowResize(MyGUI::Window* window); diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 8ac07e7668..7d84a9b9fd 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -12,7 +12,6 @@ TextInputDialog::TextInputDialog(WindowManager& parWindowManager) getWidget(textEdit, "TextEdit"); textEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - // TODO: These buttons should be managed by a Dialog class MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); @@ -25,16 +24,15 @@ void TextInputDialog::setNextButtonShow(bool shown) { MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); + if (shown) - { - okButton->setCaption("Next"); - okButton->setCoord(MyGUI::IntCoord(264 - 18, 60, 42 + 18, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); else - { - okButton->setCaption("OK"); - okButton->setCoord(MyGUI::IntCoord(264, 60, 42, 23)); - } + okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + + int okButtonWidth = okButton->getTextSize().width + 24; + + okButton->setCoord(306 - okButtonWidth, 60, okButtonWidth, 23); } void TextInputDialog::setTextLabel(const std::string &label) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp new file mode 100644 index 0000000000..90b5baa679 --- /dev/null +++ b/apps/openmw/mwgui/tooltips.cpp @@ -0,0 +1,365 @@ +#include "tooltips.hpp" + +#include "window_manager.hpp" +#include "widgets.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" + +#include + +using namespace MWGui; +using namespace MyGUI; + +ToolTips::ToolTips(WindowManager* windowManager) : + Layout("openmw_tooltips.xml") + , mGameMode(true) + , mWindowManager(windowManager) + , mFullHelp(false) +{ + getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); + + mDynamicToolTipBox->setVisible(false); + + // turn off mouse focus so that getMouseFocusWidget returns the correct widget, + // even if the mouse is over the tooltip + mDynamicToolTipBox->setNeedMouseFocus(false); + mMainWidget->setNeedMouseFocus(false); +} + +void ToolTips::onFrame(float frameDuration) +{ + /// \todo Store a MWWorld::Ptr in the widget user data, retrieve it here and construct a tooltip dynamically + + /// \todo we are destroying/creating the tooltip widgets every frame here, + /// because the tooltip might change (e.g. when trap is activated) + /// is there maybe a better way (listener when the object changes)? + for (size_t i=0; igetChildCount(); ++i) + { + mDynamicToolTipBox->_destroyChildWidget(mDynamicToolTipBox->getChildAt(i)); + } + + const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + + if (!mGameMode) + { + Widget* focus = InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) + { + mDynamicToolTipBox->setVisible(false); + return; + } + + IntSize tooltipSize; + + std::string type = focus->getUserString("ToolTipType"); + std::string text = focus->getUserString("ToolTipText"); + + ToolTipInfo info; + + if (type == "") + { + mDynamicToolTipBox->setVisible(false); + return; + } + else if (type == "Text") + { + info.caption = text; + } + else if (type == "CaptionText") + { + std::string caption = focus->getUserString("ToolTipCaption"); + info.caption = caption; + info.text = text; + } + else if (type == "ImageCaptionText") + { + std::string caption = focus->getUserString("ToolTipCaption"); + std::string image = focus->getUserString("ToolTipImage"); + std::string sizeString = focus->getUserString("ToolTipImageSize"); + + info.text = text; + info.caption = caption; + info.icon = image; + } + tooltipSize = createToolTip(info); + + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + mDynamicToolTipBox->setVisible(true); + } + else + { + if (!mFocusObject.isEmpty()) + { + IntSize tooltipSize = getToolTipViaPtr(); + + // adjust tooltip size to fit its content, position it above the crosshair + /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) + setCoord(viewSize.width/2 - (tooltipSize.width)/2.f, + viewSize.height/2 - (tooltipSize.height) - 32, + tooltipSize.width, + tooltipSize.height); + } + else + mDynamicToolTipBox->setVisible(false); + } +} + +void ToolTips::enterGameMode() +{ + mGameMode = true; +} + +void ToolTips::enterGuiMode() +{ + mGameMode = false; +} + +void ToolTips::setFocusObject(const MWWorld::Ptr& focus) +{ + mFocusObject = focus; +} + +IntSize ToolTips::getToolTipViaPtr () +{ + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + IntSize tooltipSize; + + const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); + if (!object.hasToolTip(mFocusObject)) + { + mDynamicToolTipBox->setVisible(false); + } + else + { + mDynamicToolTipBox->setVisible(true); + + ToolTipInfo info = object.getToolTipInfo(mFocusObject); + tooltipSize = createToolTip(info); + } + + return tooltipSize; +} + +void ToolTips::findImageExtension(std::string& image) +{ + int len = image.size(); + if (len < 4) return; + + if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, image)) + { + // Change texture extension to .dds + image[len-3] = 'd'; + image[len-2] = 'd'; + image[len-1] = 's'; + } +} + +IntSize ToolTips::createToolTip(const ToolTipInfo& info) +{ + std::string caption = info.caption; + std::string image = info.icon; + int imageSize = (image != "") ? 32 : 0; + std::string text = info.text; + + // remove the first newline (easier this way) + 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); + + const IntPoint padding(8, 8); + + const int imageCaptionHPadding = 8; + const int imageCaptionVPadding = 4; + + std::string realImage = "icons\\" + image; + findImageExtension(realImage); + + EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); + captionWidget->setProperty("Static", "true"); + captionWidget->setCaption(caption); + IntSize captionSize = captionWidget->getTextSize(); + + int captionHeight = std::max(captionSize.height, imageSize); + + EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); + textWidget->setProperty("Static", "true"); + textWidget->setProperty("MultiLine", "true"); + textWidget->setProperty("WordWrap", "true"); + textWidget->setCaption(text); + textWidget->setTextAlign(Align::HCenter | Align::Top); + IntSize textSize = textWidget->getTextSize(); + + captionSize += IntSize(imageSize, 0); // adjust for image + IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), + ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); + + if (info.effects != 0) + { + Widget* effectArea = mDynamicToolTipBox->createWidget("", + IntCoord(0, totalSize.height, 300, 300-totalSize.height), + Align::Stretch, "ToolTipEffectArea"); + + IntCoord coord(0, 6, totalSize.width, 24); + + /** + * \todo + * the various potion effects should appear in the tooltip depending if the player + * has enough skill in alchemy to know about the effects of this potion. + */ + + Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget + ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); + effectsWidget->setWindowManager(mWindowManager); + effectsWidget->setEffectList(info.effects); + + std::vector effectItems; + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, Widgets::MWEffectList::EF_Potion); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + } + + if (info.enchant != "") + { + Widget* enchantArea = mDynamicToolTipBox->createWidget("", + IntCoord(0, totalSize.height, 300, 300-totalSize.height), + Align::Stretch, "ToolTipEnchantArea"); + + IntCoord coord(0, 6, totalSize.width, 24); + + Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget + ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); + enchantWidget->setWindowManager(mWindowManager); + enchantWidget->setEffectList(&enchant->effects); + + std::vector enchantEffectItems; + int flag = (enchant->data.type == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; + enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); + 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, + (captionHeight-captionSize.height)/2, + captionSize.width-imageSize, + captionSize.height); + + 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; +} + +std::string ToolTips::toString(const float value) +{ + std::ostringstream stream; + stream << std::setprecision(3) << value; + return stream.str(); +} + +std::string ToolTips::toString(const int value) +{ + std::ostringstream stream; + stream << value; + return stream.str(); +} + +std::string ToolTips::getValueString(const int value, const std::string& prefix) +{ + if (value == 0) + return ""; + else + return "\n" + prefix + ": " + toString(value); +} + +std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) +{ + if (text == "") + return ""; + else + return "\n" + prefix + ": " + text; +} + +void ToolTips::toggleFullHelp() +{ + mFullHelp = !mFullHelp; +} + +bool ToolTips::getFullHelp() const +{ + return mFullHelp; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp new file mode 100644 index 0000000000..fafe471a57 --- /dev/null +++ b/apps/openmw/mwgui/tooltips.hpp @@ -0,0 +1,76 @@ + +#ifndef MWGUI_TOOLTIPS_H +#define MWGUI_TOOLTIPS_H + +#include +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + class WindowManager; + + // Info about tooltip that is supplied by the MWWorld::Class object + struct ToolTipInfo + { + public: + ToolTipInfo() : + effects(0) + { + }; + + std::string caption; + std::string text; + std::string icon; + + // enchantment (for cloth, armor, weapons) + std::string enchant; + + // effects (for potions, ingredients) + const ESM::EffectList* effects; + }; + + class ToolTips : public OEngine::GUI::Layout + { + public: + ToolTips(WindowManager* windowManager); + + void onFrame(float frameDuration); + + void enterGameMode(); + void enterGuiMode(); + + void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) + bool getFullHelp() const; + + void setFocusObject(const MWWorld::Ptr& focus); + + static std::string getValueString(const int value, const std::string& prefix); + ///< @return "prefix: value" or "" if value is 0 + + static std::string getMiscString(const std::string& text, const std::string& prefix); + ///< @return "prefix: text" or "" if text is empty + + static std::string toString(const float value); + static std::string toString(const int value); + + private: + MyGUI::Widget* mDynamicToolTipBox; + + WindowManager* mWindowManager; + + MWWorld::Ptr mFocusObject; + + void findImageExtension(std::string& image); + + MyGUI::IntSize getToolTipViaPtr (); + ///< @return requested tooltip size + + MyGUI::IntSize createToolTip(const ToolTipInfo& info); + ///< @return requested tooltip size + + bool mGameMode; + + bool mFullHelp; + }; +} +#endif diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 74603aaf1c..2f5af64736 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -222,7 +222,7 @@ void MWSpell::setSpellId(const std::string &spellId) updateWidgets(); } -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) +void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags) { const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); @@ -234,9 +234,11 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); + effect->setFlags(flags); effect->setSpellEffect(*it); effects.push_back(effect); coord.top += effect->getHeight(); + coord.width = std::max(coord.width, effect->getRequestedWidth()); } } @@ -264,12 +266,82 @@ MWSpell::~MWSpell() { } +/* MWEffectList */ + +MWEffectList::MWEffectList() + : mWindowManager(nullptr) + , mEffectList(0) +{ +} + +void MWEffectList::setEffectList(const ESM::EffectList* list) +{ + mEffectList = list; + updateWidgets(); +} + +void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags) +{ + // 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 = mEffectList->list.end(); + int maxwidth = coord.width; + for (std::vector::const_iterator it = mEffectList->list.begin(); it != end; ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + effect->setWindowManager(mWindowManager); + effect->setFlags(flags); + effect->setSpellEffect(*it); + 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 MWEffectList::updateWidgets() +{ +} + +void MWEffectList::initialiseOverride() +{ + Base::initialiseOverride(); +} + +MWEffectList::~MWEffectList() +{ +} + /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() : mWindowManager(nullptr) , imageWidget(nullptr) , textWidget(nullptr) + , mRequestedWidth(0) + , mFlags(0) { } @@ -284,14 +356,32 @@ void MWSpellEffect::updateWidgets() if (!mWindowManager) return; + // lists effects that have no magnitude (e.g. invisiblity) + /// \todo this list is probably incomplete + std::vector effectsWithoutMagnitude; + effectsWithoutMagnitude.push_back("sEffectInvisibility"); + effectsWithoutMagnitude.push_back("sEffectStuntedMagicka"); + effectsWithoutMagnitude.push_back("sEffectParalyze"); + + // lists effects that have no duration (e.g. open lock) + /// \todo this list is probably incomplete + std::vector effectsWithoutDuration; + effectsWithoutDuration.push_back("sEffectOpen"); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); if (textWidget) { if (magicEffect) { - // TODO: Get name of effect from GMST - std::string spellLine = ""; + std::string pt = mWindowManager->getGameSettingString("spoint", ""); + std::string pts = mWindowManager->getGameSettingString("spoints", ""); + std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; + std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); + std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); + + std::string effectIDStr = effectIDToString(effect.effectID); + std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); if (effect.skill >= 0 && effect.skill < ESM::Skill::Length) { spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[effect.skill], ""); @@ -310,26 +400,42 @@ void MWSpellEffect::updateWidgets() }; spellLine += " " + mWindowManager->getGameSettingString(attributes[effect.attribute], ""); } - if (effect.magnMin >= 0 || effect.magnMax >= 0) + + bool hasMagnitude = (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effectIDStr) == effectsWithoutMagnitude.end()); + if ((effect.magnMin >= 0 || effect.magnMax >= 0) && hasMagnitude) { if (effect.magnMin == effect.magnMax) - spellLine += " " + boost::lexical_cast(effect.magnMin) + " pts"; + 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; } } - if (effect.duration >= 0) + + // constant effects have no duration and no target + if (!(mFlags & MWEffectList::EF_Constant)) { - spellLine += " for " + boost::lexical_cast(effect.duration) + " secs"; + bool hasDuration = (std::find(effectsWithoutDuration.begin(), effectsWithoutDuration.end(), effectIDStr) == effectsWithoutDuration.end()); + if (effect.duration >= 0 && hasDuration) + { + spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); + } + + // potions have no target + if (!(mFlags & MWEffectList::EF_Potion)) + { + std::string on = mWindowManager->getGameSettingString("sonword", ""); + if (effect.range == ESM::RT_Self) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + else if (effect.range == ESM::RT_Touch) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + else if (effect.range == ESM::RT_Target) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + } } - if (effect.range == ESM::RT_Self) - spellLine += " on Self"; - else if (effect.range == ESM::RT_Touch) - spellLine += " on Touch"; - else if (effect.range == ESM::RT_Target) - spellLine += " on Target"; + static_cast(textWidget)->setCaption(spellLine); + mRequestedWidth = textWidget->getTextSize().width + 24; } else static_cast(textWidget)->setCaption(""); @@ -342,6 +448,153 @@ void MWSpellEffect::updateWidgets() } } +std::string MWSpellEffect::effectIDToString(const short effectID) +{ + // Map effect ID to GMST name + // http://www.uesp.net/morrow/hints/mweffects.shtml + std::map names; + names[85] ="sEffectAbsorbAttribute"; + names[88] ="sEffectAbsorbFatigue"; + names[86] ="sEffectAbsorbHealth"; + names[87] ="sEffectAbsorbSpellPoints"; + names[89] ="sEffectAbsorbSkill"; + names[63] ="sEffectAlmsiviIntervention"; + names[47] ="sEffectBlind"; + names[123] ="sEffectBoundBattleAxe"; + names[129] ="sEffectBoundBoots"; + names[127] ="sEffectBoundCuirass"; + names[120] ="sEffectBoundDagger"; + names[131] ="sEffectBoundGloves"; + names[128] ="sEffectBoundHelm"; + names[125] ="sEffectBoundLongbow"; + names[121] ="sEffectBoundLongsword"; + names[122] ="sEffectBoundMace"; + names[130] ="sEffectBoundShield"; + names[124] ="sEffectBoundSpear"; + names[7] ="sEffectBurden"; + names[50] ="sEffectCalmCreature"; + names[49] ="sEffectCalmHumanoid"; + names[40] ="sEffectChameleon"; + names[44] ="sEffectCharm"; + names[118] ="sEffectCommandCreatures"; + names[119] ="sEffectCommandHumanoids"; + names[132] ="sEffectCorpus"; // NB this typo. (bethesda made it) + names[70] ="sEffectCureBlightDisease"; + names[69] ="sEffectCureCommonDisease"; + names[71] ="sEffectCureCorprusDisease"; + names[73] ="sEffectCureParalyzation"; + names[72] ="sEffectCurePoison"; + names[22] ="sEffectDamageAttribute"; + names[25] ="sEffectDamageFatigue"; + names[23] ="sEffectDamageHealth"; + names[24] ="sEffectDamageMagicka"; + names[26] ="sEffectDamageSkill"; + names[54] ="sEffectDemoralizeCreature"; + names[53] ="sEffectDemoralizeHumanoid"; + names[64] ="sEffectDetectAnimal"; + names[65] ="sEffectDetectEnchantment"; + names[66] ="sEffectDetectKey"; + names[38] ="sEffectDisintegrateArmor"; + names[37] ="sEffectDisintegrateWeapon"; + names[57] ="sEffectDispel"; + names[62] ="sEffectDivineIntervention"; + names[17] ="sEffectDrainAttribute"; + names[20] ="sEffectDrainFatigue"; + names[18] ="sEffectDrainHealth"; + names[19] ="sEffectDrainSpellpoints"; + names[21] ="sEffectDrainSkill"; + names[8] ="sEffectFeather"; + names[14] ="sEffectFireDamage"; + names[4] ="sEffectFireShield"; + names[117] ="sEffectFortifyAttackBonus"; + names[79] ="sEffectFortifyAttribute"; + names[82] ="sEffectFortifyFatigue"; + names[80] ="sEffectFortifyHealth"; + names[81] ="sEffectFortifySpellpoints"; + names[84] ="sEffectFortifyMagickaMultiplier"; + names[83] ="sEffectFortifySkill"; + names[52] ="sEffectFrenzyCreature"; + names[51] ="sEffectFrenzyHumanoid"; + names[16] ="sEffectFrostDamage"; + names[6] ="sEffectFrostShield"; + names[39] ="sEffectInvisibility"; + names[9] ="sEffectJump"; + names[10] ="sEffectLevitate"; + names[41] ="sEffectLight"; + names[5] ="sEffectLightningShield"; + names[12] ="sEffectLock"; + names[60] ="sEffectMark"; + names[43] ="sEffectNightEye"; + names[13] ="sEffectOpen"; + names[45] ="sEffectParalyze"; + names[27] ="sEffectPoison"; + names[56] ="sEffectRallyCreature"; + names[55] ="sEffectRallyHumanoid"; + names[61] ="sEffectRecall"; + names[68] ="sEffectReflect"; + names[100] ="sEffectRemoveCurse"; + names[95] ="sEffectResistBlightDisease"; + names[94] ="sEffectResistCommonDisease"; + names[96] ="sEffectResistCorprusDisease"; + names[90] ="sEffectResistFire"; + names[91] ="sEffectResistFrost"; + names[93] ="sEffectResistMagicka"; + names[98] ="sEffectResistNormalWeapons"; + names[99] ="sEffectResistParalysis"; + names[97] ="sEffectResistPoison"; + names[92] ="sEffectResistShock"; + names[74] ="sEffectRestoreAttribute"; + names[77] ="sEffectRestoreFatigue"; + names[75] ="sEffectRestoreHealth"; + names[76] ="sEffectRestoreSpellPoints"; + names[78] ="sEffectRestoreSkill"; + names[42] ="sEffectSanctuary"; + names[3] ="sEffectShield"; + names[15] ="sEffectShockDamage"; + names[46] ="sEffectSilence"; + names[11] ="sEffectSlowFall"; + names[58] ="sEffectSoultrap"; + names[48] ="sEffectSound"; + names[67] ="sEffectSpellAbsorption"; + names[136] ="sEffectStuntedMagicka"; + names[106] ="sEffectSummonAncestralGhost"; + names[110] ="sEffectSummonBonelord"; + names[108] ="sEffectSummonLeastBonewalker"; + names[134] ="sEffectSummonCenturionSphere"; + names[103] ="sEffectSummonClannfear"; + names[104] ="sEffectSummonDaedroth"; + names[105] ="sEffectSummonDremora"; + names[114] ="sEffectSummonFlameAtronach"; + names[115] ="sEffectSummonFrostAtronach"; + names[113] ="sEffectSummonGoldenSaint"; + names[109] ="sEffectSummonGreaterBonewalker"; + names[112] ="sEffectSummonHunger"; + names[102] ="sEffectSummonScamp"; + names[107] ="sEffectSummonSkeletalMinion"; + names[116] ="sEffectSummonStormAtronach"; + names[111] ="sEffectSummonWingedTwilight"; + names[135] ="sEffectSunDamage"; + names[1] ="sEffectSwiftSwim"; + names[59] ="sEffectTelekinesis"; + names[101] ="sEffectTurnUndead"; + names[133] ="sEffectVampirism"; + names[0] ="sEffectWaterBreathing"; + names[2] ="sEffectWaterWalking"; + names[33] ="sEffectWeaknesstoBlightDisease"; + names[32] ="sEffectWeaknesstoCommonDisease"; + names[34] ="sEffectWeaknesstoCorprusDisease"; + names[28] ="sEffectWeaknesstoFire"; + names[29] ="sEffectWeaknesstoFrost"; + names[31] ="sEffectWeaknesstoMagicka"; + names[36] ="sEffectWeaknesstoNormalWeapons"; + names[35] ="sEffectWeaknesstoPoison"; + names[30] ="sEffectWeaknesstoShock"; + + assert(names.find(effectID) != names.end() && "Unimplemented effect type"); + + return names[effectID]; +} + MWSpellEffect::~MWSpellEffect() { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index a7916285eb..c0e62533d8 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -119,14 +119,22 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); - 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 spell category, if this is 0, this means the spell effects are permanent and won't display e.g. duration + * @param various flags, see MWEffectList::EffectFlags + */ + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags); const std::string &getSpellId() const { return id; } protected: virtual ~MWSpell(); - virtual void initialiseOverride(); + virtual void initialiseOverride(); private: void updateWidgets(); @@ -137,6 +145,45 @@ namespace MWGui }; typedef MWSpell* MWSpellPtr; + class MYGUI_EXPORT MWEffectList : public Widget + { + MYGUI_RTTI_DERIVED( MWEffectList ); + public: + MWEffectList(); + + typedef MWMechanics::Stat EnchantmentValue; + + enum EffectFlags + { + EF_Potion = 0x01, // potions have no target (target is always the player) + EF_Constant = 0x02 // constant effect means that duration will not be displayed + }; + + void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } + void setEffectList(const ESM::EffectList* list); + + /** + * @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 various flags, see MWEffectList::EffectFlags + */ + void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags); + + protected: + virtual ~MWEffectList(); + + virtual void initialiseOverride(); + + private: + void updateWidgets(); + + WindowManager* mWindowManager; + const ESM::EffectList* mEffectList; + }; + typedef MWEffectList* MWEffectListPtr; + class MYGUI_EXPORT MWSpellEffect : public Widget { MYGUI_RTTI_DERIVED( MWSpellEffect ); @@ -147,9 +194,14 @@ namespace MWGui void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(SpellEffectValue value); + void setFlags(int flags) { mFlags = flags; } + + std::string effectIDToString(const short effectID); const SpellEffectValue &getSpellEffect() const { return effect; } + int getRequestedWidth() const { return mRequestedWidth; } + protected: virtual ~MWSpellEffect(); @@ -161,8 +213,10 @@ namespace MWGui WindowManager* mWindowManager; SpellEffectValue effect; + int mFlags; 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 0792b0fcb7..0f2df53e1a 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -7,6 +7,7 @@ #include "map_window.hpp" #include "stats_window.hpp" #include "messagebox.hpp" +#include "tooltips.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -32,6 +33,7 @@ WindowManager::WindowManager( , map(NULL) , menu(NULL) , stats(NULL) + , mToolTips(NULL) , mMessageBoxManager(NULL) , console(NULL) , mJournal(NULL) @@ -81,6 +83,7 @@ WindowManager::WindowManager( mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); dialogueWindow = new DialogueWindow(*this); + mToolTips = new ToolTips(this); // The HUD is always on hud->setVisible(true); @@ -101,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"); @@ -119,6 +123,7 @@ WindowManager::~WindowManager() delete stats; delete mJournal; delete dialogueWindow; + delete mToolTips; delete mCharGen; @@ -179,6 +184,11 @@ void WindowManager::updateVisible() // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + if (mode == GM_Game) + mToolTips->enterGameMode(); + else + mToolTips->enterGuiMode(); + switch(mode) { case GM_Game: // If in game mode, don't show anything. @@ -404,6 +414,7 @@ void WindowManager::onDialogueWindowBye() void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); + mToolTips->onFrame(frameDuration); } const ESMS::ESMStore& WindowManager::getStore() const @@ -419,7 +430,10 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) if (cell->cell->name != "") name = cell->cell->name; else - name = cell->cell->region; + { + const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().regions.search(cell->cell->region); + name = region->name; + } map->setCellName( name ); @@ -478,3 +492,18 @@ int WindowManager::toggleFps() Settings::Manager::setInt("fps", "HUD", showFPSLevel); return showFPSLevel; } + +void WindowManager::setFocusObject(const MWWorld::Ptr& focus) +{ + mToolTips->setFocusObject(focus); +} + +void WindowManager::toggleFullHelp() +{ + mToolTips->toggleFullHelp(); +} + +bool WindowManager::getFullHelp() const +{ + return mToolTips->getFullHelp(); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 6e446387e0..f96660715a 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -61,6 +61,7 @@ namespace MWGui class Console; class JournalWindow; class CharacterCreation; + class ToolTips; class TextInputDialog; class InfoBoxDialog; @@ -154,7 +155,11 @@ namespace MWGui void setPlayerPos(const float x, const float y); ///< set player position in map space void setPlayerDir(const float x, const float y); ///< set player view direction in map space + void setFocusObject(const MWWorld::Ptr& focus); + void toggleFogOfWar(); + void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) + bool getFullHelp() const; int toggleFps(); ///< toggle fps display @return resulting fps level @@ -192,6 +197,7 @@ namespace MWGui HUD *hud; MapWindow *map; MainMenu *menu; + ToolTips *mToolTips; StatsWindow *stats; MessageBoxManager *mMessageBoxManager; Console *console; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 86a845a279..5922086a01 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -365,7 +365,7 @@ void Objects::update(const float dt) // Light animation (pulse & flicker) it->time += dt; - const float phase = std::fmod(it->time, (32 * 2 * M_PI)) * 20; + const float phase = std::fmod(static_cast (it->time), (32 * 2 * M_PI)) * 20; float pulseConstant; // These formulas are just guesswork, but they work pretty well diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index bf5602f438..9a4ae7243c 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -66,7 +66,10 @@ void Shadows::recreate() if (split) { mPSSMSetup = new PSSMShadowCameraSetup(); - mPSSMSetup->setSplitPadding(5); + + // Make sure to keep this in sync with the camera's near clip distance! + mPSSMSetup->setSplitPadding(mRendering->getCamera()->getNearClipDistance()); + mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar); const Real adjustFactors[3] = {64, 64, 64}; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 11df70bbcc..9922cb21eb 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -144,5 +144,6 @@ op 0x200014d: ModDisposition op 0x200014e: ModDisposition, explicit reference op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference +op 0x2000151: ToggleFullHelp op 0x2000152: ToggleCompositors opcodes 0x2000153-0x3ffffff unused diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index a37595ea82..c4d9e9fabb 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -73,6 +73,16 @@ namespace MWScript } }; + class OpToggleFullHelp : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::Environment::get().getWindowManager()->toggleFullHelp(); + } + }; + const int opcodeEnableBirthMenu = 0x200000e; const int opcodeEnableClassMenu = 0x200000f; const int opcodeEnableNameMenu = 0x2000010; @@ -86,6 +96,7 @@ namespace MWScript const int opcodeShowRestMenu = 0x2000018; const int opcodeGetButtonPressed = 0x2000137; const int opcodeToggleFogOfWar = 0x2000145; + const int opcodeToggleFullHelp = 0x2000151; void registerExtensions (Compiler::Extensions& extensions) { @@ -94,7 +105,7 @@ namespace MWScript extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu); extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu); extensions.registerInstruction ("enablestatsreviewmenu", "", - opcodeEnableStatsReviewMenu); +opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu); extensions.registerInstruction ("enablemagicmenu", "", opcodeEnableMagicMenu); @@ -110,6 +121,9 @@ namespace MWScript extensions.registerInstruction ("togglefogofwar", "", opcodeToggleFogOfWar); extensions.registerInstruction ("tfow", "", opcodeToggleFogOfWar); + + extensions.registerInstruction ("togglefullhelp", "", opcodeToggleFullHelp); + extensions.registerInstruction ("tfh", "", opcodeToggleFullHelp); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -147,6 +161,8 @@ namespace MWScript interpreter.installSegment5 (opcodeGetButtonPressed, new OpGetButtonPressed); interpreter.installSegment5 (opcodeToggleFogOfWar, new OpToggleFogOfWar); + + interpreter.installSegment5 (opcodeToggleFullHelp, new OpToggleFullHelp); } } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c53ebcfd04..78ed5ca2e5 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -171,4 +171,14 @@ namespace MWWorld { throw std::runtime_error ("class does not have an down sound"); } + + MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) const + { + throw std::runtime_error ("class does not have a tool tip"); + } + + bool Class::hasToolTip (const Ptr& ptr) const + { + return false; + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 622d9eeaee..e69b8f2ac9 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -12,6 +12,7 @@ #include "physicssystem.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwgui/tooltips.hpp" namespace Ogre { @@ -85,6 +86,12 @@ namespace MWWorld ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exceoption) + virtual bool hasToolTip (const Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual MWGui::ToolTipInfo getToolTipInfo (const Ptr& ptr) const; + ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + virtual MWMechanics::NpcStats& getNpcStats (const Ptr& ptr) const; ///< Return NPC stats or throw an exception, if class does not have NPC stats /// (default implementation: throw an exceoption) diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 66eedcb845..3de14f158f 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -15,6 +15,7 @@ #include "../mwsound/soundmanager.hpp" +#include "../mwgui/window_manager.hpp" #include "ptr.hpp" #include "class.hpp" @@ -738,6 +739,17 @@ namespace MWWorld mWeatherManager->update (duration); + // inform the GUI about focused object + try + { + MWBase::Environment::get().getWindowManager()->setFocusObject(getPtrViaHandle(mFacedHandle)); + } + catch (std::runtime_error&) + { + MWWorld::Ptr null; + MWBase::Environment::get().getWindowManager()->setFocusObject(null); + } + if (!mRendering->occlusionQuerySupported()) { // cast a ray from player to sun to detect if the sun is visible diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index e3a7b9999c..49055d2ede 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -50,6 +50,7 @@ configure_file("${SDIR}/openmw_messagebox_layout.xml" "${DDIR}/openmw_messagebox configure_file("${SDIR}/openmw_interactive_messagebox_layout.xml" "${DDIR}/openmw_interactive_messagebox_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_journal_layout.xml" "${DDIR}/openmw_journal_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_journal_skin.xml" "${DDIR}/openmw_journal_skin.xml" COPYONLY) +configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 1c68930264..b88e994066 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -47,7 +47,6 @@ - @@ -59,11 +58,10 @@ - - - - - + + + + diff --git a/files/mygui/openmw_chargen_generate_class_result_layout.xml b/files/mygui/openmw_chargen_generate_class_result_layout.xml index 7ec926eb05..26ebe17e1f 100644 --- a/files/mygui/openmw_chargen_generate_class_result_layout.xml +++ b/files/mygui/openmw_chargen_generate_class_result_layout.xml @@ -1,27 +1,29 @@ - + - + + + - + - + - + diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window_layout.xml index 29a3b511ec..b0e437074c 100644 --- a/files/mygui/openmw_dialogue_window_layout.xml +++ b/files/mygui/openmw_dialogue_window_layout.xml @@ -16,7 +16,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window_skin.xml b/files/mygui/openmw_dialogue_window_skin.xml index ecdec8a5c0..31ce626be0 100644 --- a/files/mygui/openmw_dialogue_window_skin.xml +++ b/files/mygui/openmw_dialogue_window_skin.xml @@ -8,12 +8,12 @@ - - + + - + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index a86317d620..02fee4b179 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -13,7 +13,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/files/mygui/openmw_interactive_messagebox_layout.xml b/files/mygui/openmw_interactive_messagebox_layout.xml index 744f212276..b8a71c670d 100644 --- a/files/mygui/openmw_interactive_messagebox_layout.xml +++ b/files/mygui/openmw_interactive_messagebox_layout.xml @@ -5,7 +5,7 @@ - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 0ac8e03ba6..02075ad1a6 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -180,10 +180,14 @@ - - - - + + + + + + + + @@ -219,7 +223,7 @@ - <_BasisSkin type="MainSkin" offset = "0 0 0 0" align = "ALIGN_LEFT ALIGN_TOP"/> + diff --git a/files/mygui/openmw_messagebox_layout.xml b/files/mygui/openmw_messagebox_layout.xml index 81d1c0a57e..c99c00a49e 100644 --- a/files/mygui/openmw_messagebox_layout.xml +++ b/files/mygui/openmw_messagebox_layout.xml @@ -8,7 +8,7 @@ - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 6ae14c558b..36d97e1538 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -93,20 +93,25 @@ + + + + + - + - + - + diff --git a/files/mygui/openmw_text_input_layout.xml b/files/mygui/openmw_text_input_layout.xml index 6a7ad27f01..c8f76b2575 100644 --- a/files/mygui/openmw_text_input_layout.xml +++ b/files/mygui/openmw_text_input_layout.xml @@ -4,10 +4,10 @@ - + - + diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml new file mode 100644 index 0000000000..2d5a5da9f2 --- /dev/null +++ b/files/mygui/openmw_tooltips.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index 05a23e8aea..bda8935af2 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -85,7 +85,7 @@ namespace GUI // adjust the size of the window caption so that all text is visible // NOTE: this assumes that mMainWidget is of type Window. MyGUI::TextBox* box = static_cast(mMainWidget)->getCaptionWidget(); - box->setSize(box->getTextSize().width + 48, box->getSize().height); + box->setSize(box->getTextSize().width + 24, box->getSize().height); // in order to trigger alignment updates, we need to update the parent // mygui doesn't provide a proper way of doing this, so we are just changing size @@ -115,6 +115,13 @@ namespace GUI static_cast(pt)->setCaption(caption); } + void setState(const std::string& widget, const std::string& state) + { + MyGUI::Widget* pt; + getWidget(pt, widget); + pt->_setWidgetState(state); + } + void setTextColor(const std::string& name, float r, float g, float b) { MyGUI::Widget* pt; @@ -131,6 +138,13 @@ namespace GUI pt->setImageTexture(imgName); } + void adjustButtonSize(MyGUI::Button* button) + { + // adjust size of button to fit its text + MyGUI::IntSize size = button->getTextSize(); + button->setSize(size.width + 24, button->getSize().height); + } + protected: MyGUI::Widget* mMainWidget; diff --git a/readme.txt b/readme.txt index 52c4e11a24..53f4a4c59e 100644 --- a/readme.txt +++ b/readme.txt @@ -87,7 +87,6 @@ Allowed options: win1252 - Western European (Latin) alphabet, used by default - --report-focus [=arg(=1)] (=0) write name of focussed object to cout --fallback arg fallback values