Implemented the Class Choice dialog which allows the player to choose between three ways to define a class.

Added a generic infobox dialog which displays some text and a set of buttons (vertical only for now), this is used for the Class Choice dialogs and the dialogs which shows various questions the player must choose from. The questions are currently hardcoded.
Added more gui states to handle the extra class dialogs (Generate, Pick or Create).
actorid
Jan Borsodi 14 years ago
parent efd9def3a8
commit b364d47b0b

@ -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<MyGUI::ButtonPtr>::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<MyGUI::Button>("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<MyGUI::ButtonPtr>::const_iterator end = buttons.end();
int i = 0;
for (std::vector<MyGUI::ButtonPtr>::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 */

@ -23,6 +23,58 @@ namespace MWGui
{
using namespace MyGUI;
class InfoBoxDialog : public OEngine::GUI::Layout
{
public:
InfoBoxDialog(MWWorld::Environment& environment);
typedef std::vector<std::string> ButtonList;
void setText(const std::string &str);
std::string getText() const;
void setButtons(ButtonList &buttons);
void update();
int getChosenButton() const;
// Events
typedef delegates::CDelegate2<MyGUI::WidgetPtr, int> 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<MyGUI::ButtonPtr> 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:

@ -23,6 +23,9 @@ namespace MWGui
GM_Race,
GM_Birth,
GM_Class,
GM_ClassGenerate,
GM_ClassPick,
GM_ClassCreate,
GM_Review
};

@ -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<Step, 2> 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()

@ -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();

@ -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)

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 545 265" name="_Main">
<!-- Edit box -->
<Widget type="Widget" skin="MW_Box" position="14 14 516 70" name="TextBox" align="ALIGN_TOP ALIGN_HCENTER">
<Widget type="StaticText" skin="SandText" position="4 4 508 62" name="Text" align="ALIGN_TOP ALIGN_HCENTER">
<Property key="Edit_WordWrap" value="1" />
</Widget>
</Widget>
<!-- Button bar, buttons are created as children -->
<Widget type="Widget" skin="" position="72 98 400 150" name="ButtonBar" align="ALIGN_TOP ALIGN_HCENTER" />
</Widget>
</MyGUI>
Loading…
Cancel
Save