diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 3f5bc73de..ec792daa4 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -224,6 +224,146 @@ void PickClassDialog::updateStats() classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); } +/* InfoBoxDialog */ + +void fitToText(MyGUI::StaticTextPtr widget) +{ + MyGUI::IntCoord inner = widget->getTextRegion(); + MyGUI::IntCoord outer = widget->getCoord(); + MyGUI::IntSize size = widget->getTextSize(); + size.width += outer.width - inner.width; + size.height += outer.height - inner.height; + widget->setSize(size); +} + +void layoutVertically(MyGUI::WidgetPtr widget, int margin) +{ + size_t count = widget->getChildCount(); + int pos = 0; + pos += margin; + int width = 0; + for (unsigned i = 0; i < count; ++i) + { + MyGUI::WidgetPtr child = widget->getChildAt(i); + if (!child->isVisible()) + continue; + + child->setPosition(child->getLeft(), pos); + width = std::max(width, child->getWidth()); + pos += child->getHeight() + margin; + } + width += margin*2; + widget->setSize(width, pos); +} + +InfoBoxDialog::InfoBoxDialog(MWWorld::Environment& environment) + : Layout("openmw_infobox_layout.xml") + , environment(environment) + , currentButton(-1) +{ + getWidget(textBox, "TextBox"); + getWidget(text, "Text"); + text->getSubWidgetText()->setWordWrap(true); + getWidget(buttonBar, "ButtonBar"); + + center(); +} + +void InfoBoxDialog::setText(const std::string &str) +{ + text->setCaption(str); + textBox->setVisible(!str.empty()); + fitToText(text); +} + +std::string InfoBoxDialog::getText() const +{ + return text->getCaption(); +} + +void InfoBoxDialog::setButtons(ButtonList &buttons) +{ + for (std::vector::iterator it = this->buttons.begin(); it != this->buttons.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + this->buttons.clear(); + currentButton = -1; + + // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget + MyGUI::ButtonPtr button; + MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, buttonBar->getWidth(), 10); + ButtonList::const_iterator end = buttons.end(); + for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + { + const std::string &text = *it; + button = buttonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); + button->getSubWidgetText()->setWordWrap(true); + button->setCaption(text); + fitToText(button); + button->eventMouseButtonClick = MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); + coord.top += button->getHeight(); + this->buttons.push_back(button); + } +} + +void InfoBoxDialog::update() +{ + // Fix layout + layoutVertically(textBox, 4); + layoutVertically(buttonBar, 6); + layoutVertically(mMainWidget, 4 + 6); + + center(); +} + +int InfoBoxDialog::getChosenButton() const +{ + return currentButton; +} + +void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) +{ + std::vector::const_iterator end = buttons.end(); + int i = 0; + for (std::vector::const_iterator it = buttons.begin(); it != end; ++it) + { + if (*it == _sender) + { + currentButton = i; + eventButtonSelected(_sender, i); + return; + } + ++i; + } +} + +void InfoBoxDialog::center() +{ + // Centre dialog + MyGUI::IntSize gameWindowSize = environment.mWindowManager->getGui()->getViewSize(); + MyGUI::IntCoord coord = mMainWidget->getCoord(); + coord.left = (gameWindowSize.width - coord.width)/2; + coord.top = (gameWindowSize.height - coord.height)/2; + mMainWidget->setCoord(coord); +} + +/* ClassChoiceDialog */ + +ClassChoiceDialog::ClassChoiceDialog(MWWorld::Environment& environment) + : InfoBoxDialog(environment) +{ + WindowManager *mw = environment.mWindowManager; + setText(""); + ButtonList buttons; + buttons.push_back(mw->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(mw->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(mw->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(mw->getGameSettingString("sBack", "")); + setButtons(buttons); + + update(); +} /* CreateClassDialog */ diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 15547e594..38457b7e3 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -23,6 +23,58 @@ namespace MWGui { using namespace MyGUI; + class InfoBoxDialog : public OEngine::GUI::Layout + { + public: + InfoBoxDialog(MWWorld::Environment& environment); + + typedef std::vector ButtonList; + + void setText(const std::string &str); + std::string getText() const; + void setButtons(ButtonList &buttons); + + void update(); + int getChosenButton() const; + + // Events + typedef delegates::CDelegate2 EventHandle_WidgetInt; + + /** Event : Button was clicked.\n + signature : void method(MyGUI::WidgetPtr widget, int index)\n + */ + EventHandle_WidgetInt eventButtonSelected; + + protected: + void onButtonClicked(MyGUI::WidgetPtr _sender); + + private: + void center(); + + MWWorld::Environment& environment; + + int currentButton; + MyGUI::WidgetPtr textBox; + MyGUI::StaticTextPtr text; + MyGUI::WidgetPtr buttonBar; + std::vector buttons; + }; + + // Lets the player choose between 3 ways of creating a class + class ClassChoiceDialog : public InfoBoxDialog + { + public: + // Corresponds to the buttons that can be clicked + enum ClassChoice + { + Class_Generate = 0, + Class_Pick = 1, + Class_Create = 2, + Class_Back = 3 + }; + ClassChoiceDialog(MWWorld::Environment& environment); + }; + class PickClassDialog : public OEngine::GUI::Layout { public: diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index b18dd9f95..313b097cf 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -23,6 +23,9 @@ namespace MWGui GM_Race, GM_Birth, GM_Class, + GM_ClassGenerate, + GM_ClassPick, + GM_ClassCreate, GM_Review }; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 3073dcc08..7c4e16bf7 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -21,6 +21,8 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment : environment(environment) , nameDialog(nullptr) , raceDialog(nullptr) + , classChoiceDialog(nullptr) + , generateClassQuestionDialog(nullptr) , pickClassDialog(nullptr) , birthSignDialog(nullptr) , nameChosen(false) @@ -67,6 +69,8 @@ WindowManager::~WindowManager() delete nameDialog; delete raceDialog; + delete classChoiceDialog; + delete generateClassQuestionDialog; delete pickClassDialog; delete birthSignDialog; } @@ -129,6 +133,22 @@ void WindowManager::updateVisible() } if (mode == GM_Class) + { + if (classChoiceDialog) + delete classChoiceDialog; + classChoiceDialog = new ClassChoiceDialog(environment); + classChoiceDialog->eventButtonSelected = MyGUI::newDelegate(this, &WindowManager::onClassChoice); + return; + } + + if (mode == GM_ClassGenerate) + { + generateClassStep = 0; + showClassQuestionDialog(); + return; + } + + if (mode == GM_ClassPick) { if (!pickClassDialog) pickClassDialog = new PickClassDialog(environment, gui->getViewSize()); @@ -139,6 +159,13 @@ void WindowManager::updateVisible() return; } + if (mode == GM_ClassCreate) + { + CreateClassDialog *ccd = new CreateClassDialog(environment, gui->getViewSize()); + ccd->open(); + return; + } + if (mode == GM_Birth) { if (!birthSignDialog) @@ -317,6 +344,88 @@ void WindowManager::onRaceDialogBack() environment.mInputManager->setGuiMode(GM_Name); } +void WindowManager::onClassChoice(MyGUI::WidgetPtr, int _index) +{ + classChoiceDialog->setVisible(false); +// classChoiceDialog = nullptr; + + if (_index == ClassChoiceDialog::Class_Generate) + { + environment.mInputManager->setGuiMode(GM_ClassGenerate); + } + else if (_index == ClassChoiceDialog::Class_Pick) + { + environment.mInputManager->setGuiMode(GM_ClassPick); + } + else if (_index == ClassChoiceDialog::Class_Create) + { + environment.mInputManager->setGuiMode(GM_ClassCreate); + } + else if (_index == ClassChoiceDialog::Class_Back) + { + environment.mInputManager->setGuiMode(GM_Race); + } +} + +void WindowManager::showClassQuestionDialog() +{ + if (!generateClassQuestionDialog) + generateClassQuestionDialog = new InfoBoxDialog(environment); + + struct Step + { + const char* text; + const char* buttons[3]; + }; + static boost::array steps = { { + {"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.", + {"Use herbs from your pack to put it to sleep?", + "Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before?", + "Draw your dagger, mercifully endings its life with a single thrust?"} + }, + {"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.", + {"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?", + "Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?", + "Decide to put the extra money to good use and purchase items that would help your family?"} + }, + } }; + + if (generateClassStep > steps.size()) + { + environment.mInputManager->setGuiMode(GM_Class); + return; + } + if (generateClassStep == steps.size()) + { + // TODO: Show selected class + environment.mInputManager->setGuiMode(GM_Review); + return; + } + + InfoBoxDialog::ButtonList buttons; + generateClassQuestionDialog->setText(steps[generateClassStep].text); + buttons.push_back(steps[generateClassStep].buttons[0]); + buttons.push_back(steps[generateClassStep].buttons[1]); + buttons.push_back(steps[generateClassStep].buttons[2]); + generateClassQuestionDialog->setButtons(buttons); + generateClassQuestionDialog->update(); + generateClassQuestionDialog->eventButtonSelected = MyGUI::newDelegate(this, &WindowManager::onClassQuestionChosen); + generateClassQuestionDialog->setVisible(true); +} + +void WindowManager::onClassQuestionChosen(MyGUI::Widget* _sender, int _index) +{ + generateClassQuestionDialog->setVisible(false); + if (_index < 0 || _index >= 3) + { + environment.mInputManager->setGuiMode(GM_Class); + return; + } + + ++generateClassStep; + showClassQuestionDialog(); +} + void WindowManager::onPickClassDialogDone() { pickClassDialog->eventDone = MWGui::PickClassDialog::EventHandle_Void(); @@ -349,7 +458,7 @@ void WindowManager::onPickClassDialogBack() updateCharacterGeneration(); - environment.mInputManager->setGuiMode(GM_Race); + environment.mInputManager->setGuiMode(GM_Class); } void WindowManager::onBirthSignDialogDone() diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 80c70f608..a0810e091 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -20,6 +20,7 @@ namespace MyGUI { class Gui; + class Widget; } namespace Compiler @@ -42,7 +43,9 @@ namespace MWGui class Console; class TextInputDialog; + class InfoBoxDialog; class RaceDialog; + class ClassChoiceDialog; class PickClassDialog; class BirthDialog; @@ -61,6 +64,8 @@ namespace MWGui // Character creation TextInputDialog *nameDialog; RaceDialog *raceDialog; + ClassChoiceDialog *classChoiceDialog; + InfoBoxDialog *generateClassQuestionDialog; PickClassDialog *pickClassDialog; BirthDialog *birthSignDialog; @@ -72,6 +77,9 @@ namespace MWGui bool reviewNext; ///< If true then any click on Next will cause the summary to be shown + // Keeps track of current step in Generate Class dialogs + unsigned generateClassStep; + MyGUI::Gui *gui; // Current gui mode @@ -189,6 +197,13 @@ namespace MWGui void onRaceDialogDone(); void onRaceDialogBack(); + // Character generation: Choose class process + void onClassChoice(MyGUI::Widget* _sender, int _index); + + // Character generation: Generate Class + void showClassQuestionDialog(); + void onClassQuestionChosen(MyGUI::Widget* _sender, int _index); + // Character generation: Pick Class dialog void onPickClassDialogDone(); void onPickClassDialogBack(); diff --git a/extern/mygui_3.0.1/CMakeLists.txt b/extern/mygui_3.0.1/CMakeLists.txt index e982df3ff..a02b02f1b 100644 --- a/extern/mygui_3.0.1/CMakeLists.txt +++ b/extern/mygui_3.0.1/CMakeLists.txt @@ -42,6 +42,7 @@ configure_file("${SDIR}/openmw_hud_box.skin.xml" "${DDIR}/openmw_hud_box.skin.xm configure_file("${SDIR}/openmw_hud_energybar.skin.xml" "${DDIR}/openmw_hud_energybar.skin.xml" COPYONLY) configure_file("${SDIR}/openmw_hud_layout.xml" "${DDIR}/openmw_hud_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_text_input_layout.xml" "${DDIR}/openmw_text_input_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_infobox_layout.xml" "${DDIR}/openmw_infobox_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_chargen_race_layout.xml" "${DDIR}/openmw_chargen_race_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_chargen_class_layout.xml" "${DDIR}/openmw_chargen_class_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_chargen_create_class_layout.xml" "${DDIR}/openmw_chargen_create_class_layout.xml" COPYONLY) diff --git a/extern/mygui_3.0.1/openmw_resources/openmw_infobox_layout.xml b/extern/mygui_3.0.1/openmw_resources/openmw_infobox_layout.xml new file mode 100644 index 000000000..63725a5c3 --- /dev/null +++ b/extern/mygui_3.0.1/openmw_resources/openmw_infobox_layout.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + +