Refactor Dialog and Computer GUI to use control binding

This commit is contained in:
Vsevolod Kremianskii 2021-06-13 10:14:07 +07:00
parent 9ee347f725
commit e2f6ee3b7a
6 changed files with 181 additions and 88 deletions

View file

@ -17,8 +17,6 @@
#include "computer.h" #include "computer.h"
#include "../../gui/control/listbox.h"
#include "../game.h" #include "../game.h"
#include "../gameidutil.h" #include "../gameidutil.h"
@ -33,13 +31,9 @@ namespace reone {
namespace game { namespace game {
static const char kControlTagMessage[] = "LB_MESSAGE";
static const char kControlTagReplies[] = "LB_REPLIES";
ComputerGUI::ComputerGUI(Game *game) : Conversation(game) { ComputerGUI::ComputerGUI(Game *game) : Conversation(game) {
_resRef = getResRef("computer"); _resRef = getResRef("computer");
_scaling = ScalingMode::Stretch; _scaling = ScalingMode::Stretch;
_repliesControlTag = kControlTagReplies;
if (isTSL(game->gameId())) { if (isTSL(game->gameId())) {
_resolutionX = 800; _resolutionX = 800;
@ -49,36 +43,79 @@ ComputerGUI::ComputerGUI(Game *game) : Conversation(game) {
void ComputerGUI::load() { void ComputerGUI::load() {
Conversation::load(); Conversation::load();
bindControls();
configureMessage(); configureMessage();
configureReplies(); configureReplies();
} }
void ComputerGUI::configureMessage() { void ComputerGUI::bindControls() {
auto &message = getControl<ListBox>(kControlTagMessage); _binding.lblCompSkill = getControlPtr<Label>("LBL_COMP_SKILL");
message.setProtoMatchContent(true); _binding.lblCompSkillVal = getControlPtr<Label>("LBL_COMP_SKILL_VAL");
_binding.lblCompSpikes = getControlPtr<Label>("LBL_COMP_SPIKES");
_binding.lblCompSpikesVal = getControlPtr<Label>("LBL_COMP_SPIKES_VAL");
_binding.lblRepSkill = getControlPtr<Label>("LBL_REP_SKILL");
_binding.lblRepSkillVal = getControlPtr<Label>("LBL_REP_SKILL_VAL");
_binding.lblRepUnits = getControlPtr<Label>("LBL_REP_UNITS");
_binding.lblRepUnitsVal = getControlPtr<Label>("LBL_REP_UNITS_VAL");
_binding.lbMessage = getControlPtr<ListBox>("LB_MESSAGE");
_binding.lbReplies = getControlPtr<ListBox>("LB_REPLIES");
Control &protoItem = message.protoItem(); if (isTSL(_game->gameId())) {
protoItem.setHilightColor(getHilightColor(_game->gameId())); _binding.lblBar1 = getControlPtr<Label>("LBL_BAR1");
protoItem.setTextColor(getBaseColor(_game->gameId())); _binding.lblBar2 = getControlPtr<Label>("LBL_BAR2");
_binding.lblBar3 = getControlPtr<Label>("LBL_BAR3");
_binding.lblBar4 = getControlPtr<Label>("LBL_BAR4");
_binding.lblBar5 = getControlPtr<Label>("LBL_BAR5");
_binding.lblBar6 = getControlPtr<Label>("LBL_BAR6");
} else {
_binding.lblCompSkillIcon = getControlPtr<Label>("LBL_COMP_SKILL_ICON");
_binding.lblCompSpikesIcon = getControlPtr<Label>("LBL_COMP_SPIKES_ICON");
_binding.lblRepSkillIcon = getControlPtr<Label>("LBL_REP_SKILL_ICON");
_binding.lblRepUnitsIcon = getControlPtr<Label>("LBL_REP_UNITS_ICON");
_binding.lblStatic1 = getControlPtr<Label>("LBL_STATIC1");
_binding.lblStatic2 = getControlPtr<Label>("LBL_STATIC2");
_binding.lblStatic3 = getControlPtr<Label>("LBL_STATIC3");
_binding.lblStatic4 = getControlPtr<Label>("LBL_STATIC4");
_binding.lblObscure = getControlPtr<Label>("LBL_OBSCURE");
}
}
void ComputerGUI::configureMessage() {
_binding.lbMessage->setProtoMatchContent(true);
_binding.lbMessage->protoItem().setHilightColor(getHilightColor(_game->gameId()));
_binding.lbMessage->protoItem().setTextColor(getBaseColor(_game->gameId()));
} }
void ComputerGUI::configureReplies() { void ComputerGUI::configureReplies() {
auto &replies = getControl<ListBox>(kControlTagReplies); _binding.lbReplies->setProtoMatchContent(true);
replies.setProtoMatchContent(true); _binding.lbReplies->protoItem().setHilightColor(getHilightColor(_game->gameId()));
_binding.lbReplies->protoItem().setTextColor(getBaseColor(_game->gameId()));
Control &protoItem = replies.protoItem();
protoItem.setHilightColor(getHilightColor(_game->gameId()));
protoItem.setTextColor(getBaseColor(_game->gameId()));
} }
void ComputerGUI::setMessage(string message) { void ComputerGUI::setMessage(string message) {
ListBox::Item item; ListBox::Item item;
item.text = message; item.text = move(message);
ListBox &listBox = getControl<ListBox>(kControlTagMessage); _binding.lbMessage->clearItems();
listBox.clearItems(); _binding.lbMessage->addItem(move(item));
listBox.addItem(move(item)); }
void ComputerGUI::setReplyLines(vector<string> lines) {
_binding.lbReplies->clearItems();
for (size_t i = 0; i < lines.size(); ++i) {
ListBox::Item item;
item.tag = to_string(i);
item.text = lines[i];
_binding.lbReplies->addItem(move(item));
}
}
void ComputerGUI::onListBoxItemClick(const string &control, const string &item) {
if (control == "LB_REPLIES") {
int replyIdx = stoi(item);
pickReply(replyIdx);
}
} }
} // namespace game } // namespace game

View file

@ -17,6 +17,9 @@
#pragma once #pragma once
#include "../../gui/control/label.h"
#include "../../gui/control/listbox.h"
#include "conversation.h" #include "conversation.h"
namespace reone { namespace reone {
@ -30,10 +33,48 @@ public:
void load() override; void load() override;
private: private:
void setMessage(std::string message) override; struct Binding {
std::shared_ptr<gui::Label> lblCompSkill;
std::shared_ptr<gui::Label> lblCompSkillVal;
std::shared_ptr<gui::Label> lblCompSpikes;
std::shared_ptr<gui::Label> lblCompSpikesVal;
std::shared_ptr<gui::Label> lblRepSkill;
std::shared_ptr<gui::Label> lblRepSkillVal;
std::shared_ptr<gui::Label> lblRepUnits;
std::shared_ptr<gui::Label> lblRepUnitsVal;
std::shared_ptr<gui::ListBox> lbMessage;
std::shared_ptr<gui::ListBox> lbReplies;
// KotOR only
std::shared_ptr<gui::Label> lblCompSkillIcon;
std::shared_ptr<gui::Label> lblCompSpikesIcon;
std::shared_ptr<gui::Label> lblRepSkillIcon;
std::shared_ptr<gui::Label> lblRepUnitsIcon;
std::shared_ptr<gui::Label> lblStatic1;
std::shared_ptr<gui::Label> lblStatic2;
std::shared_ptr<gui::Label> lblStatic3;
std::shared_ptr<gui::Label> lblStatic4;
std::shared_ptr<gui::Label> lblObscure;
// END KotOR only
// TSL only
std::shared_ptr<gui::Label> lblBar1;
std::shared_ptr<gui::Label> lblBar2;
std::shared_ptr<gui::Label> lblBar3;
std::shared_ptr<gui::Label> lblBar4;
std::shared_ptr<gui::Label> lblBar5;
std::shared_ptr<gui::Label> lblBar6;
// END TSL only
} _binding;
void bindControls();
void configureMessage(); void configureMessage();
void configureReplies(); void configureReplies();
void setMessage(std::string message) override;
void setReplyLines(std::vector<std::string> lines) override;
void onListBoxItemClick(const std::string &control, const std::string &item) override;
}; };
} // namespace game } // namespace game

View file

@ -216,24 +216,13 @@ static string getReplyText(const Dialog::EntryReply &reply, int index) {
} }
void Conversation::refreshReplies() { void Conversation::refreshReplies() {
ListBox &listBox = getControl<ListBox>(_repliesControlTag); vector<string> lines;
listBox.clearItems(); if (!_autoPickFirstReply) {
for (size_t i = 0; i < _replies.size(); ++i) {
if (_autoPickFirstReply) return; lines.push_back(getReplyText(*_replies[i], static_cast<int>(i)));
}
for (size_t i = 0; i < _replies.size(); ++i) {
ListBox::Item item;
item.tag = to_string(i);
item.text = getReplyText(*_replies[i], static_cast<int>(i));
listBox.addItem(move(item));
}
}
void Conversation::onListBoxItemClick(const string &control, const string &item) {
if (control == _repliesControlTag) {
int replyIdx = stoi(item);
pickReply(replyIdx);
} }
setReplyLines(move(lines));
} }
void Conversation::pickReply(int index) { void Conversation::pickReply(int index) {

View file

@ -67,8 +67,6 @@ public:
void resume(); void resume();
protected: protected:
std::string _repliesControlTag;
std::shared_ptr<Dialog> _dialog; std::shared_ptr<Dialog> _dialog;
std::shared_ptr<SpatialObject> _owner; std::shared_ptr<SpatialObject> _owner;
std::shared_ptr<graphics::Model> _cameraModel; std::shared_ptr<graphics::Model> _cameraModel;
@ -77,17 +75,21 @@ protected:
bool _entryEnded { false }; bool _entryEnded { false };
bool _paused { false }; bool _paused { false };
/**
* @param index index of the entry in the DLG file
* @param start true if this is a starting entry, false otherwise
*/
virtual void loadEntry(int index, bool start = false);
void pickReply(int index);
virtual void setReplyLines(std::vector<std::string> lines) = 0;
virtual void onStart(); virtual void onStart();
virtual void onFinish(); virtual void onFinish();
virtual void onLoadEntry(); virtual void onLoadEntry();
virtual void onEntryEnded(); virtual void onEntryEnded();
/**
* @param index index of the entry in the DLG file
* @param start true if this is a starting entry, false otherwise
*/
virtual void loadEntry(int index, bool start = false);
private: private:
std::shared_ptr<audio::SoundHandle> _currentVoice; std::shared_ptr<audio::SoundHandle> _currentVoice;
Timer _endEntryTimer; Timer _endEntryTimer;
@ -95,8 +97,6 @@ private:
std::vector<const Dialog::EntryReply *> _replies; std::vector<const Dialog::EntryReply *> _replies;
bool _autoPickFirstReply { false }; bool _autoPickFirstReply { false };
void onListBoxItemClick(const std::string &control, const std::string &item) override;
void loadConversationBackground(); void loadConversationBackground();
void loadCameraModel(); void loadCameraModel();
void loadStartEntry(); void loadStartEntry();
@ -106,11 +106,6 @@ private:
bool isSkippableEntry() const; bool isSkippableEntry() const;
/**
* Replaces text in the message control.
*/
virtual void setMessage(std::string message) = 0;
/** /**
* Recreates items in the replies list box. * Recreates items in the replies list box.
*/ */
@ -118,7 +113,6 @@ private:
void finish(); void finish();
void endCurrentEntry(); void endCurrentEntry();
void pickReply(int index);
/** /**
* @return index of the first active entry/reply from the specified list, -1 otherwise * @return index of the first active entry/reply from the specified list, -1 otherwise
@ -132,6 +126,11 @@ private:
*/ */
bool evaluateCondition(const std::string &scriptResRef); bool evaluateCondition(const std::string &scriptResRef);
/**
* Replaces text in the message control.
*/
virtual void setMessage(std::string message) = 0;
// Event handlers // Event handlers
bool handleMouseButtonDown(const SDL_MouseButtonEvent &event); bool handleMouseButtonDown(const SDL_MouseButtonEvent &event);

View file

@ -22,7 +22,6 @@
#include "../../audio/soundhandle.h" #include "../../audio/soundhandle.h"
#include "../../common/log.h" #include "../../common/log.h"
#include "../../common/random.h" #include "../../common/random.h"
#include "../../gui/control/listbox.h"
#include "../../gui/control/panel.h" #include "../../gui/control/panel.h"
#include "../../graphics/model/models.h" #include "../../graphics/model/models.h"
#include "../../resource/resources.h" #include "../../resource/resources.h"
@ -50,9 +49,6 @@ namespace game {
static const char kControlTagTopFrame[] = "TOP"; static const char kControlTagTopFrame[] = "TOP";
static const char kControlTagBottomFrame[] = "BOTTOM"; static const char kControlTagBottomFrame[] = "BOTTOM";
static const char kControlTagMessage[] = "LBL_MESSAGE";
static const char kControlTagReplies[] = "LB_REPLIES";
static const char kObjectTagOwner[] = "owner"; static const char kObjectTagOwner[] = "owner";
static const unordered_map<string, AnimationType> g_animTypeByName { static const unordered_map<string, AnimationType> g_animTypeByName {
@ -92,20 +88,24 @@ static const unordered_map<string, AnimationType> g_animTypeByName {
DialogGUI::DialogGUI(Game *game) : Conversation(game) { DialogGUI::DialogGUI(Game *game) : Conversation(game) {
_resRef = getResRef("dialog"); _resRef = getResRef("dialog");
_scaling = ScalingMode::Stretch; _scaling = ScalingMode::Stretch;
_repliesControlTag = kControlTagReplies;
} }
void DialogGUI::load() { void DialogGUI::load() {
Conversation::load(); Conversation::load();
bindControls();
configureMessage(); configureMessage();
configureReplies(); configureReplies();
loadFrames(); loadFrames();
} }
void DialogGUI::bindControls() {
_binding.lblMessage = getControlPtr<Label>("LBL_MESSAGE");
_binding.lbReplies = getControlPtr<ListBox>("LB_REPLIES");
}
void DialogGUI::loadFrames() { void DialogGUI::loadFrames() {
int rootTop = _rootControl->extent().top; int rootTop = _rootControl->extent().top;
int messageHeight = getControl(kControlTagMessage).extent().height; int messageHeight = _binding.lblMessage->extent().height;
addFrame(kControlTagTopFrame, -rootTop, messageHeight); addFrame(kControlTagTopFrame, -rootTop, messageHeight);
addFrame(kControlTagBottomFrame, 0, _options.height - rootTop); addFrame(kControlTagBottomFrame, 0, _options.height - rootTop);
@ -128,18 +128,14 @@ void DialogGUI::addFrame(string tag, int top, int height) {
} }
void DialogGUI::configureMessage() { void DialogGUI::configureMessage() {
auto &message = getControl(kControlTagMessage); _binding.lblMessage->setExtentTop(-_rootControl->extent().top);
message.setExtentTop(-_rootControl->extent().top); _binding.lblMessage->setTextColor(getBaseColor(_game->gameId()));
message.setTextColor(getBaseColor(_game->gameId()));
} }
void DialogGUI::configureReplies() { void DialogGUI::configureReplies() {
auto &replies = getControl<ListBox>(kControlTagReplies); _binding.lbReplies->setProtoMatchContent(true);
replies.setProtoMatchContent(true); _binding.lbReplies->protoItem().setHilightColor(getHilightColor(_game->gameId()));
_binding.lbReplies->protoItem().setTextColor(getBaseColor(_game->gameId()));
Control &protoItem = replies.protoItem();
protoItem.setHilightColor(getHilightColor(_game->gameId()));
protoItem.setTextColor(getBaseColor(_game->gameId()));
} }
void DialogGUI::onStart() { void DialogGUI::onStart() {
@ -188,7 +184,8 @@ void DialogGUI::onLoadEntry() {
updateCamera(); updateCamera();
updateParticipantAnimations(); updateParticipantAnimations();
repositionMessage(); repositionMessage();
hideControl(kControlTagReplies);
_binding.lbReplies->setVisible(false);
} }
void DialogGUI::loadCurrentSpeaker() { void DialogGUI::loadCurrentSpeaker() {
@ -319,8 +316,7 @@ AnimationType DialogGUI::getStuntAnimationType(int ordinal) const {
} }
void DialogGUI::repositionMessage() { void DialogGUI::repositionMessage() {
Control &message = getControl(kControlTagMessage); Control::Text text(_binding.lblMessage->text());
Control::Text text(message.text());
int top; int top;
if (_entryEnded) { if (_entryEnded) {
@ -328,11 +324,11 @@ void DialogGUI::repositionMessage() {
top = -_rootControl->extent().top; top = -_rootControl->extent().top;
} else { } else {
text.align = Control::TextAlign::CenterTop; text.align = Control::TextAlign::CenterTop;
top = getControl(kControlTagReplies).extent().top; top = _binding.lbReplies->extent().top;
} }
message.setText(move(text)); _binding.lblMessage->setText(move(text));
message.setExtentTop(top); _binding.lblMessage->setExtentTop(top);
} }
void DialogGUI::onFinish() { void DialogGUI::onFinish() {
@ -354,13 +350,25 @@ void DialogGUI::releaseStuntParticipants() {
} }
void DialogGUI::onEntryEnded() { void DialogGUI::onEntryEnded() {
showControl(kControlTagReplies); _binding.lbReplies->setVisible(true);
updateCamera(); updateCamera();
repositionMessage(); repositionMessage();
} }
void DialogGUI::setMessage(string message) { void DialogGUI::setMessage(string message) {
setControlText(kControlTagMessage, message); _binding.lblMessage->setTextMessage(message);
}
void DialogGUI::setReplyLines(vector<string> lines) {
_binding.lbReplies->clearItems();
for (size_t i = 0; i < lines.size(); ++i) {
ListBox::Item item;
item.tag = to_string(i);
item.text = lines[i];
_binding.lbReplies->addItem(move(item));
}
} }
void DialogGUI::update(float dt) { void DialogGUI::update(float dt) {
@ -373,6 +381,13 @@ void DialogGUI::update(float dt) {
} }
} }
void DialogGUI::onListBoxItemClick(const string &control, const string &item) {
if (control == "LB_REPLIES") {
int replyIdx = stoi(item);
pickReply(replyIdx);
}
}
} // namespace game } // namespace game
} // namespace reone } // namespace reone

View file

@ -17,6 +17,9 @@
#pragma once #pragma once
#include "../../gui/control/label.h"
#include "../../gui/control/listbox.h"
#include "../camera/dialogcamera.h" #include "../camera/dialogcamera.h"
#include "../object/creature.h" #include "../object/creature.h"
@ -39,16 +42,15 @@ private:
std::shared_ptr<Creature> creature; std::shared_ptr<Creature> creature;
}; };
struct Binding {
std::shared_ptr<gui::Label> lblMessage;
std::shared_ptr<gui::ListBox> lbReplies;
} _binding;
std::shared_ptr<SpatialObject> _currentSpeaker; std::shared_ptr<SpatialObject> _currentSpeaker;
std::map<std::string, Participant> _participantByTag; std::map<std::string, Participant> _participantByTag;
void onStart() override; void bindControls();
void onFinish() override;
void onLoadEntry() override;
void onEntryEnded() override;
void setMessage(std::string message) override;
void addFrame(std::string tag, int top, int height); void addFrame(std::string tag, int top, int height);
void configureMessage(); void configureMessage();
void configureReplies(); void configureReplies();
@ -62,6 +64,16 @@ private:
std::string getStuntAnimationName(int ordinal) const; std::string getStuntAnimationName(int ordinal) const;
AnimationType getStuntAnimationType(int ordinal) const; AnimationType getStuntAnimationType(int ordinal) const;
void setMessage(std::string message) override;
void setReplyLines(std::vector<std::string> lines) override;
void onStart() override;
void onFinish() override;
void onLoadEntry() override;
void onEntryEnded() override;
void onListBoxItemClick(const std::string &control, const std::string &item) override;
// Loading // Loading
void loadFrames(); void loadFrames();