mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-05 15:55:45 +00:00
Dialogue history rewrite WIP
This commit is contained in:
parent
6cd28d1156
commit
78e6dab9d2
@ -32,6 +32,7 @@ add_openmw_dir (mwgui
|
||||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
|
||||
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
|
||||
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
||||
keywordsearch
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
@ -41,7 +41,7 @@ namespace MWBase
|
||||
//calbacks for the GUI
|
||||
virtual void keywordSelected (const std::string& keyword) = 0;
|
||||
virtual void goodbyeSelected() = 0;
|
||||
virtual void questionAnswered (const std::string& answer) = 0;
|
||||
virtual void questionAnswered (int answer) = 0;
|
||||
|
||||
virtual bool checkServiceRefused () = 0;
|
||||
|
||||
|
@ -161,7 +161,7 @@ namespace MWDialogue
|
||||
parseText (info->mResponse);
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
executeScript (info->mResultScript);
|
||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||
mLastDialogue = *info;
|
||||
@ -263,6 +263,7 @@ namespace MWDialogue
|
||||
|
||||
parseText (info->mResponse);
|
||||
|
||||
std::string title;
|
||||
if (dialogue.mType==ESM::Dialogue::Persuasion)
|
||||
{
|
||||
std::string modifiedTopic = "s" + topic;
|
||||
@ -272,13 +273,13 @@ namespace MWDialogue
|
||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
win->addTitle (gmsts.find (modifiedTopic)->getString());
|
||||
title = gmsts.find (modifiedTopic)->getString();
|
||||
}
|
||||
else
|
||||
win->addTitle (topic);
|
||||
title = topic;
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title);
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
@ -289,9 +290,7 @@ namespace MWDialogue
|
||||
else
|
||||
{
|
||||
// no response found, print a fallback text
|
||||
win->addTitle (topic);
|
||||
win->addText ("…");
|
||||
|
||||
win->addResponse ("…", topic);
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,53 +423,42 @@ namespace MWDialogue
|
||||
mTemporaryDispositionChange = 0;
|
||||
}
|
||||
|
||||
void DialogueManager::questionAnswered (const std::string& answer)
|
||||
void DialogueManager::questionAnswered (int answer)
|
||||
{
|
||||
mChoice = answer;
|
||||
|
||||
if (mChoiceMap.find(answer) != mChoiceMap.end())
|
||||
if (mDialogueMap.find(mLastTopic) != mDialogueMap.end())
|
||||
{
|
||||
mChoice = mChoiceMap[answer];
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
if (mDialogueMap.find(mLastTopic) != mDialogueMap.end())
|
||||
if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic
|
||||
|| mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting)
|
||||
{
|
||||
Filter filter (mActor, mChoice, mTalkedTo);
|
||||
|
||||
if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic
|
||||
|| mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting)
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true))
|
||||
{
|
||||
if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true))
|
||||
{
|
||||
std::string text = info->mResponse;
|
||||
parseText (text);
|
||||
std::string text = info->mResponse;
|
||||
parseText (text);
|
||||
|
||||
mChoiceMap.clear();
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices();
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
executeScript (info->mResultScript);
|
||||
mLastDialogue = *info;
|
||||
}
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
executeScript (info->mResultScript);
|
||||
mLastDialogue = *info;
|
||||
}
|
||||
}
|
||||
|
||||
updateTopics();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogueManager::printError (const std::string& error)
|
||||
{
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->addText(error);
|
||||
updateTopics();
|
||||
}
|
||||
|
||||
void DialogueManager::askQuestion (const std::string& question, int choice)
|
||||
{
|
||||
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
|
||||
win->askQuestion(question);
|
||||
mChoiceMap[Misc::StringUtils::lowerCase(question)] = choice;
|
||||
win->addChoice(question, choice);
|
||||
mIsInChoice = true;
|
||||
}
|
||||
|
||||
@ -551,10 +539,10 @@ namespace MWDialogue
|
||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
win->addTitle (gmsts.find ("sServiceRefusal")->getString());
|
||||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext),
|
||||
gmsts.find ("sServiceRefusal")->getString());
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
return true;
|
||||
@ -565,9 +553,7 @@ namespace MWDialogue
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
|
||||
{
|
||||
std::vector<HyperTextToken> result;
|
||||
|
||||
MyGUI::UString utext(text);
|
||||
|
||||
size_t pos_begin, pos_end, iteration_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
|
@ -30,7 +30,6 @@ namespace MWDialogue
|
||||
bool mTalkedTo;
|
||||
|
||||
int mChoice;
|
||||
std::map<std::string, int> mChoiceMap;
|
||||
std::string mLastTopic;
|
||||
ESM::DialInfo mLastDialogue;
|
||||
bool mIsInChoice;
|
||||
@ -46,8 +45,6 @@ namespace MWDialogue
|
||||
bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code);
|
||||
void executeScript (const std::string& script);
|
||||
|
||||
void printError (const std::string& error);
|
||||
|
||||
void executeTopic (const std::string& topic, bool randomResponse=false);
|
||||
|
||||
public:
|
||||
@ -72,7 +69,7 @@ namespace MWDialogue
|
||||
//calbacks for the GUI
|
||||
virtual void keywordSelected (const std::string& keyword);
|
||||
virtual void goodbyeSelected();
|
||||
virtual void questionAnswered (const std::string& answer);
|
||||
virtual void questionAnswered (int answer);
|
||||
|
||||
virtual void persuade (int type);
|
||||
virtual int getTemporaryDispositionChange () const;
|
||||
|
@ -120,7 +120,7 @@ struct MWGui::TypesetBookImpl : TypesetBook
|
||||
|
||||
size_t pageCount () const { return mPages.size (); }
|
||||
|
||||
std::pair <int, int> getSize () const
|
||||
std::pair <unsigned int, unsigned int> getSize () const
|
||||
{
|
||||
return std::make_pair (mRect.width (), mRect.height ());
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace MWGui
|
||||
/// it is the largest distance from the left edge to the
|
||||
/// right edge. The second integer is the height of all
|
||||
/// text combined prior to pagination.
|
||||
virtual std::pair <int, int> getSize () const = 0;
|
||||
virtual std::pair <unsigned int, unsigned int> getSize () const = 0;
|
||||
};
|
||||
|
||||
/// A factory class for creating a typeset book instance.
|
||||
|
@ -18,29 +18,18 @@
|
||||
#include "spellbuyingwindow.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "travelwindow.hpp"
|
||||
#include "bookpage.hpp"
|
||||
|
||||
/**
|
||||
*Copied from the internet.
|
||||
*/
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::string lower_string(const std::string& str)
|
||||
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
|
||||
{
|
||||
std::string lowerCase = Misc::StringUtils::lowerCase (str);
|
||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
point begin = reinterpret_cast <point> (text);
|
||||
|
||||
std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos)
|
||||
{
|
||||
return lower_string(str).find(lower_string(substr),pos);
|
||||
}
|
||||
|
||||
bool sortByLength (const std::string& left, const std::string& right)
|
||||
{
|
||||
return left.size() > right.size();
|
||||
return MWGui::BookTypesetter::Utf8Span (begin, begin + strlen (text));
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +105,103 @@ namespace MWGui
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
Response::Response(const std::string &text, const std::string &title)
|
||||
: mTitle(title)
|
||||
{
|
||||
mText = text;
|
||||
}
|
||||
|
||||
void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks)
|
||||
{
|
||||
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour::White);
|
||||
BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::Green);
|
||||
typesetter->sectionBreak(9);
|
||||
if (mTitle != "")
|
||||
typesetter->write(title, to_utf8_span(mTitle.c_str()));
|
||||
typesetter->sectionBreak(9);
|
||||
|
||||
typedef std::pair<size_t, size_t> Range;
|
||||
std::map<Range, intptr_t> hyperLinks;
|
||||
|
||||
size_t pos_begin, pos_end, iteration_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
pos_begin = mText.find('@', iteration_pos);
|
||||
if (pos_begin != std::string::npos)
|
||||
pos_end = mText.find('#', pos_begin);
|
||||
|
||||
if (pos_begin != std::string::npos && pos_end != std::string::npos)
|
||||
{
|
||||
std::string link = mText.substr(pos_begin + 1, pos_end - pos_begin - 1);
|
||||
const char specialPseudoAsteriskCharacter = 127;
|
||||
std::replace(link.begin(), link.end(), specialPseudoAsteriskCharacter, '*');
|
||||
std::string topicName = MWBase::Environment::get().getWindowManager()->
|
||||
getTranslationDataStorage().topicStandardForm(link);
|
||||
|
||||
std::string displayName = link;
|
||||
MWDialogue::RemovePseudoAsterisks(displayName);
|
||||
|
||||
mText.replace(pos_begin, pos_end+1, displayName);
|
||||
|
||||
assert(topicLinks.find(topicName) != topicLinks.end());
|
||||
hyperLinks[std::make_pair(pos_begin, pos_begin+displayName.size())] = intptr_t(topicLinks[topicName]);
|
||||
}
|
||||
}
|
||||
|
||||
typesetter->addContent(to_utf8_span(mText.c_str()));
|
||||
|
||||
for (std::map<Range, intptr_t>::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it)
|
||||
{
|
||||
intptr_t topicId = it->second;
|
||||
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour::Green);
|
||||
const MyGUI::Colour linkHot (0.40f, 0.40f, 0.80f);
|
||||
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
||||
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
||||
style = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId);
|
||||
typesetter->write(style, it->first.first, it->first.second);
|
||||
}
|
||||
|
||||
std::string::const_iterator i = mText.begin ();
|
||||
KeywordSearchT::Match match;
|
||||
while (i != mText.end () && keywordSearch->search (i, mText.end (), match))
|
||||
{
|
||||
if (i != match.mBeg)
|
||||
addTopicLink (typesetter, 0, i - mText.begin (), match.mBeg - mText.begin ());
|
||||
|
||||
addTopicLink (typesetter, match.mValue, match.mBeg - mText.begin (), match.mEnd - mText.begin ());
|
||||
|
||||
i = match.mEnd;
|
||||
}
|
||||
|
||||
if (i != mText.end ())
|
||||
addTopicLink (typesetter, 0, i - mText.begin (), mText.size ());
|
||||
}
|
||||
|
||||
void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end)
|
||||
{
|
||||
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour::Green);
|
||||
const MyGUI::Colour linkHot (0.40f, 0.40f, 0.80f);
|
||||
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
||||
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
||||
if (topicId)
|
||||
style = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId);
|
||||
typesetter->write (style, begin, end);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
void Choice::activated()
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId);
|
||||
}
|
||||
|
||||
void Topic::activated()
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
DialogueWindow::DialogueWindow()
|
||||
: WindowBase("openmw_dialogue_window.layout")
|
||||
, mPersuasionDialog()
|
||||
@ -129,15 +215,6 @@ namespace MWGui
|
||||
|
||||
//History view
|
||||
getWidget(mHistory, "History");
|
||||
mHistory->setOverflowToTheLeft(true);
|
||||
mHistory->setMaxTextLength(1000000);
|
||||
MyGUI::Widget* eventbox;
|
||||
|
||||
//An EditBox cannot receive mouse click events, so we use an
|
||||
//invisible widget on top of the editbox to receive them
|
||||
getWidget(eventbox, "EventBox");
|
||||
eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked);
|
||||
eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel);
|
||||
|
||||
//Topics list
|
||||
getWidget(mTopicsList, "TopicsList");
|
||||
@ -149,12 +226,20 @@ namespace MWGui
|
||||
|
||||
getWidget(mDispositionBar, "Disposition");
|
||||
getWidget(mDispositionText,"DispositionText");
|
||||
getWidget(mScrollBar, "VScroll");
|
||||
|
||||
mScrollBar->eventScrollChangePosition += MyGUI::newDelegate(this, &DialogueWindow::onScrollbarMoved);
|
||||
mHistory->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel);
|
||||
|
||||
BookPage::ClickCallback callback = boost::bind (&DialogueWindow::notifyLinkClicked, this, _1);
|
||||
mHistory->adviseLinkClicked(callback);
|
||||
|
||||
static_cast<MyGUI::Window*>(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize);
|
||||
}
|
||||
|
||||
void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
/*
|
||||
MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText();
|
||||
if(t == NULL)
|
||||
return;
|
||||
@ -198,19 +283,22 @@ namespace MWGui
|
||||
if(color == "#572D21")
|
||||
MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void DialogueWindow::onWindowResize(MyGUI::Window* _sender)
|
||||
{
|
||||
mTopicsList->adjustSize();
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||
{
|
||||
if (mHistory->getVScrollPosition() - _rel*0.3 < 0)
|
||||
mHistory->setVScrollPosition(0);
|
||||
else
|
||||
mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3);
|
||||
if (!mScrollBar->getVisible())
|
||||
return;
|
||||
mScrollBar->setScrollPosition(std::min(static_cast<int>(mScrollBar->getScrollRange()-1),
|
||||
std::max(0, static_cast<int>(mScrollBar->getScrollPosition() - _rel*0.3))));
|
||||
onScrollbarMoved(mScrollBar, mScrollBar->getScrollPosition());
|
||||
}
|
||||
|
||||
void DialogueWindow::onByeClicked(MyGUI::Widget* _sender)
|
||||
@ -231,7 +319,7 @@ namespace MWGui
|
||||
}
|
||||
|
||||
if (id >= separatorPos)
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic));
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(topic));
|
||||
else
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
@ -296,13 +384,25 @@ namespace MWGui
|
||||
|
||||
mTopicsList->clear();
|
||||
mHyperLinks.clear();
|
||||
mHistory->setCaption("");
|
||||
|
||||
for (std::vector<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it)
|
||||
delete (*it);
|
||||
mHistoryContents.clear();
|
||||
|
||||
for (std::vector<Link*>::iterator it = mLinks.begin(); it != mLinks.end(); ++it)
|
||||
delete (*it);
|
||||
mLinks.clear();
|
||||
|
||||
updateOptions();
|
||||
}
|
||||
|
||||
void DialogueWindow::setKeywords(std::list<std::string> keyWords)
|
||||
{
|
||||
mTopicsList->clear();
|
||||
for (std::map<std::string, Link*>::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it)
|
||||
delete it->second;
|
||||
mTopicLinks.clear();
|
||||
mKeywordSearch.clear();
|
||||
|
||||
bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty()
|
||||
&& mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion");
|
||||
@ -346,46 +446,15 @@ namespace MWGui
|
||||
for(std::list<std::string>::iterator it = keyWords.begin(); it != keyWords.end(); ++it)
|
||||
{
|
||||
mTopicsList->addItem(*it);
|
||||
|
||||
Topic* t = new Topic(*it);
|
||||
mTopicLinks[*it] = t;
|
||||
|
||||
mKeywordSearch.seed(*it, intptr_t(t));
|
||||
}
|
||||
mTopicsList->adjustSize();
|
||||
}
|
||||
|
||||
void DialogueWindow::removeKeyword(std::string keyWord)
|
||||
{
|
||||
if(mTopicsList->hasItem(keyWord))
|
||||
{
|
||||
mTopicsList->removeItem(keyWord);
|
||||
}
|
||||
mTopicsList->adjustSize();
|
||||
}
|
||||
|
||||
void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = find_str_ci(str,keyword, pos)) != std::string::npos)
|
||||
{
|
||||
// do not add color if this portion of text is already colored.
|
||||
{
|
||||
MyGUI::TextIterator iterator (str);
|
||||
MyGUI::UString colour;
|
||||
while(iterator.moveNext())
|
||||
{
|
||||
size_t iteratorPos = iterator.getPosition();
|
||||
iterator.getTagColour(colour);
|
||||
if (iteratorPos == pos)
|
||||
break;
|
||||
}
|
||||
|
||||
if (colour == color1)
|
||||
return;
|
||||
}
|
||||
|
||||
str.insert(pos,color1);
|
||||
pos += color1.length();
|
||||
pos += keyword.length();
|
||||
str.insert(pos,color2);
|
||||
pos+= color2.length();
|
||||
}
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
std::string DialogueWindow::parseText(const std::string& text)
|
||||
@ -410,18 +479,19 @@ namespace MWGui
|
||||
separatorReached = true;
|
||||
}
|
||||
|
||||
// sort by length to make sure longer topics are replaced first
|
||||
std::sort(topics.begin(), topics.end(), sortByLength);
|
||||
|
||||
std::vector<MWDialogue::HyperTextToken> hypertext = MWDialogue::ParseHyperText(text);
|
||||
|
||||
/*
|
||||
size_t historySize = 0;
|
||||
if(mHistory->getClient()->getSubWidgetText() != NULL)
|
||||
{
|
||||
historySize = mHistory->getOnlyText().size();
|
||||
}
|
||||
*/
|
||||
|
||||
std::string result;
|
||||
|
||||
/*
|
||||
size_t hypertextPos = 0;
|
||||
for (size_t i = 0; i < hypertext.size(); ++i)
|
||||
{
|
||||
@ -461,38 +531,115 @@ namespace MWGui
|
||||
|
||||
hypertextPos += MyGUI::UString(hypertext[i].mText).length();
|
||||
}
|
||||
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
void DialogueWindow::addText(std::string text)
|
||||
void DialogueWindow::updateHistory(bool scrollbar)
|
||||
{
|
||||
mHistory->addDialogText("#B29154"+parseText(text)+"#B29154");
|
||||
if (!scrollbar && mScrollBar->getVisible())
|
||||
{
|
||||
mHistory->setSize(mHistory->getSize()+MyGUI::IntSize(mScrollBar->getWidth(),0));
|
||||
mScrollBar->setVisible(false);
|
||||
}
|
||||
if (scrollbar && !mScrollBar->getVisible())
|
||||
{
|
||||
mHistory->setSize(mHistory->getSize()-MyGUI::IntSize(mScrollBar->getWidth(),0));
|
||||
mScrollBar->setVisible(true);
|
||||
}
|
||||
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (mHistory->getWidth(), std::numeric_limits<int>().max());
|
||||
|
||||
for (std::vector<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it)
|
||||
(*it)->write(typesetter, &mKeywordSearch, mTopicLinks);
|
||||
|
||||
|
||||
BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::White);
|
||||
|
||||
// choices
|
||||
for (std::map<std::string, int>::iterator it = mChoices.begin(); it != mChoices.end(); ++it)
|
||||
{
|
||||
Choice* link = new Choice(it->second);
|
||||
mLinks.push_back(link);
|
||||
|
||||
typesetter->lineBreak();
|
||||
const MyGUI::Colour linkHot (0.40f, 0.40f, 0.80f);
|
||||
const MyGUI::Colour linkNormal (0.20f, 0.20f, 0.60f);
|
||||
const MyGUI::Colour linkActive (0.50f, 0.50f, 1.00f);
|
||||
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, linkNormal, linkHot, linkActive,
|
||||
TypesetBook::InteractiveId(link));
|
||||
typesetter->write(questionStyle, to_utf8_span(it->first.c_str()));
|
||||
}
|
||||
|
||||
TypesetBook::Ptr book = typesetter->complete();
|
||||
mHistory->showPage(book, 0);
|
||||
size_t viewHeight = mHistory->getParent()->getHeight();
|
||||
if (!scrollbar && book->getSize().second > viewHeight)
|
||||
updateHistory(true);
|
||||
else if (scrollbar)
|
||||
{
|
||||
mHistory->setSize(MyGUI::IntSize(mHistory->getWidth(), book->getSize().second));
|
||||
size_t range = book->getSize().second - viewHeight;
|
||||
mScrollBar->setScrollRange(range);
|
||||
mScrollBar->setScrollPosition(range-1);
|
||||
onScrollbarMoved(mScrollBar, range-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no scrollbar
|
||||
onScrollbarMoved(mScrollBar, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogueWindow::notifyLinkClicked (TypesetBook::InteractiveId link)
|
||||
{
|
||||
reinterpret_cast<Link*>(link)->activated();
|
||||
}
|
||||
|
||||
void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos)
|
||||
{
|
||||
mHistory->setPosition(0,-pos);
|
||||
}
|
||||
|
||||
void DialogueWindow::addResponse(const std::string &text, const std::string &title)
|
||||
{
|
||||
// This is called from the dialogue manager, so text is
|
||||
// case-smashed - thus we have to retrieve the correct case
|
||||
// of the title through the topic list.
|
||||
std::string realTitle = title;
|
||||
if (realTitle != "")
|
||||
{
|
||||
for (size_t i=0; i<mTopicsList->getItemCount(); ++i)
|
||||
{
|
||||
std::string item = mTopicsList->getItemNameAt(i);
|
||||
if (Misc::StringUtils::lowerCase(item) == title)
|
||||
{
|
||||
realTitle = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mHistoryContents.push_back(new Response(text, realTitle));
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::addMessageBox(const std::string& text)
|
||||
{
|
||||
mHistory->addDialogText("\n#FFFFFF"+text+"#B29154");
|
||||
//mHistoryContents.push_back(new Message(text));
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::addTitle(std::string text)
|
||||
void DialogueWindow::addChoice(const std::string& choice, int id)
|
||||
{
|
||||
// This is called from the dialogue manager, so text is
|
||||
// case-smashed - thus we have to retrieve the correct case
|
||||
// of the text through the topic list.
|
||||
for (size_t i=0; i<mTopicsList->getItemCount(); ++i)
|
||||
{
|
||||
std::string item = mTopicsList->getItemNameAt(i);
|
||||
if (lower_string(item) == text)
|
||||
text = item;
|
||||
}
|
||||
|
||||
mHistory->addDialogHeading(text);
|
||||
mChoices[choice] = id;
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::askQuestion(std::string question)
|
||||
void DialogueWindow::clearChoices()
|
||||
{
|
||||
mHistory->addDialogText("#572D21"+question+"#B29154"+" ");
|
||||
mChoices.clear();
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
void DialogueWindow::updateOptions()
|
||||
@ -500,7 +647,6 @@ namespace MWGui
|
||||
//Clear the list of topics
|
||||
mTopicsList->clear();
|
||||
mHyperLinks.clear();
|
||||
mHistory->eraseText(0, mHistory->getTextLength());
|
||||
|
||||
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
||||
{
|
||||
@ -513,7 +659,7 @@ namespace MWGui
|
||||
|
||||
void DialogueWindow::goodbye()
|
||||
{
|
||||
mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->getString());
|
||||
//mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->getString());
|
||||
mTopicsList->setEnabled(false);
|
||||
mEnabled = false;
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include "windowbase.hpp"
|
||||
#include "referenceinterface.hpp"
|
||||
|
||||
#include "bookpage.hpp"
|
||||
|
||||
#include "keywordsearch.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
@ -21,7 +25,8 @@ namespace MWGui
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class DialogueHistory;
|
||||
class DialogueHistoryViewModel;
|
||||
class BookPage;
|
||||
|
||||
class PersuasionDialog : public WindowModal
|
||||
{
|
||||
@ -44,6 +49,55 @@ namespace MWGui
|
||||
void onPersuade (MyGUI::Widget* sender);
|
||||
};
|
||||
|
||||
|
||||
struct Link
|
||||
{
|
||||
virtual ~Link() {}
|
||||
virtual void activated () = 0;
|
||||
};
|
||||
|
||||
struct Topic : Link
|
||||
{
|
||||
Topic(const std::string& id) : mTopicId(id) {}
|
||||
std::string mTopicId;
|
||||
virtual void activated ();
|
||||
};
|
||||
|
||||
struct Choice : Link
|
||||
{
|
||||
Choice(int id) : mChoiceId(id) {}
|
||||
int mChoiceId;
|
||||
virtual void activated ();
|
||||
};
|
||||
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
struct DialogueText
|
||||
{
|
||||
virtual ~DialogueText() {}
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) = 0;
|
||||
std::string mText;
|
||||
};
|
||||
|
||||
struct Response : DialogueText
|
||||
{
|
||||
Response(const std::string& text, const std::string& title = "");
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks);
|
||||
void addTopicLink (BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end);
|
||||
std::string mTitle;
|
||||
};
|
||||
|
||||
struct Message : DialogueText
|
||||
{
|
||||
Message(const std::string& text);
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks);
|
||||
};
|
||||
|
||||
struct Goodbye : DialogueText
|
||||
{
|
||||
virtual void write (BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks);
|
||||
};
|
||||
|
||||
class DialogueWindow: public WindowBase, public ReferenceInterface
|
||||
{
|
||||
public:
|
||||
@ -52,19 +106,19 @@ namespace MWGui
|
||||
// Events
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
|
||||
/** Event : Dialog finished, OK button clicked.\n
|
||||
signature : void method()\n
|
||||
*/
|
||||
EventHandle_Void eventBye;
|
||||
void notifyLinkClicked (TypesetBook::InteractiveId link);
|
||||
|
||||
void startDialogue(MWWorld::Ptr actor, std::string npcName);
|
||||
void stopDialogue();
|
||||
void setKeywords(std::list<std::string> keyWord);
|
||||
void removeKeyword(std::string keyWord);
|
||||
void addText(std::string text);
|
||||
|
||||
void addResponse (const std::string& text, const std::string& title="");
|
||||
|
||||
void addMessageBox(const std::string& text);
|
||||
void addTitle(std::string text);
|
||||
void askQuestion(std::string question);
|
||||
|
||||
void addChoice(const std::string& choice, int id);
|
||||
void clearChoices();
|
||||
|
||||
void goodbye();
|
||||
void onFrame();
|
||||
|
||||
@ -89,6 +143,10 @@ namespace MWGui
|
||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||
void onWindowResize(MyGUI::Window* _sender);
|
||||
|
||||
void onScrollbarMoved (MyGUI::ScrollBar* sender, size_t pos);
|
||||
|
||||
void updateHistory(bool scrollbar=false);
|
||||
|
||||
virtual void onReferenceUnavailable();
|
||||
|
||||
struct HyperLink
|
||||
@ -108,11 +166,22 @@ namespace MWGui
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
DialogueHistory* mHistory;
|
||||
std::vector<DialogueText*> mHistoryContents;
|
||||
std::map<std::string, int> mChoices;
|
||||
|
||||
std::vector<Link*> mLinks;
|
||||
std::map<std::string, Link*> mTopicLinks;
|
||||
|
||||
KeywordSearchT mKeywordSearch;
|
||||
|
||||
BookPage* mHistory;
|
||||
Widgets::MWList* mTopicsList;
|
||||
MyGUI::ScrollBar* mScrollBar;
|
||||
MyGUI::ProgressPtr mDispositionBar;
|
||||
MyGUI::EditBox* mDispositionText;
|
||||
|
||||
std::stringstream mText;
|
||||
|
||||
PersuasionDialog mPersuasionDialog;
|
||||
|
||||
std::map<size_t, HyperLink> mHyperLinks;
|
||||
|
@ -1,78 +1,11 @@
|
||||
#include "dialoguehistory.hpp"
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "widgets.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos)
|
||||
{
|
||||
MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour());
|
||||
MyGUI::TextIterator iterator(getCaption());
|
||||
while(iterator.moveNext())
|
||||
{
|
||||
size_t pos = iterator.getPosition();
|
||||
iterator.getTagColour(colour);
|
||||
if (pos < _pos)
|
||||
continue;
|
||||
else if (pos == _pos)
|
||||
break;
|
||||
}
|
||||
return colour;
|
||||
}
|
||||
|
||||
MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos)
|
||||
{
|
||||
bool breakOnNext = false;
|
||||
MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour());
|
||||
MyGUI::UString colour2 = colour;
|
||||
MyGUI::TextIterator iterator(getCaption());
|
||||
MyGUI::TextIterator col_start = iterator;
|
||||
while(iterator.moveNext())
|
||||
{
|
||||
size_t pos = iterator.getPosition();
|
||||
iterator.getTagColour(colour);
|
||||
if(colour != colour2)
|
||||
{
|
||||
if(breakOnNext)
|
||||
{
|
||||
return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition());
|
||||
}
|
||||
col_start = iterator;
|
||||
colour2 = colour;
|
||||
}
|
||||
if (pos < _pos)
|
||||
continue;
|
||||
else if (pos == _pos)
|
||||
{
|
||||
breakOnNext = true;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void DialogueHistory::addDialogHeading(const MyGUI::UString& parText)
|
||||
{
|
||||
MyGUI::UString head("\n#D8C09A");
|
||||
head.append(parText);
|
||||
head.append("#B29154\n");
|
||||
addText(head);
|
||||
}
|
||||
|
||||
void DialogueHistory::addDialogText(const MyGUI::UString& parText)
|
||||
{
|
||||
addText(parText);
|
||||
addText("\n");
|
||||
}
|
||||
DialogueHistoryViewModel::DialogueHistoryViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,23 @@
|
||||
#ifndef MWGUI_DIALOGE_HISTORY_H
|
||||
#define MWGUI_DIALOGE_HISTORY_H
|
||||
|
||||
#include <openengine/gui/layout.hpp>
|
||||
#include "keywordsearch.hpp"
|
||||
|
||||
#include <platform/stdint.h>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class DialogueHistory : public MyGUI::EditBox
|
||||
class DialogueHistoryViewModel
|
||||
{
|
||||
MYGUI_RTTI_DERIVED( DialogueHistory )
|
||||
public:
|
||||
Widget* getClient() { return mClient; }
|
||||
MyGUI::UString getColorAtPos(size_t _pos);
|
||||
MyGUI::UString getColorTextAt(size_t _pos);
|
||||
void addDialogHeading(const MyGUI::UString& parText);
|
||||
void addDialogText(const MyGUI::UString& parText);
|
||||
public:
|
||||
DialogueHistoryViewModel();
|
||||
|
||||
private:
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
mutable bool mKeywordSearchLoaded;
|
||||
mutable KeywordSearchT mKeywordSearch;
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -1,17 +1,20 @@
|
||||
#include "journalviewmodel.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include <MyGUI_LanguageManager.h>
|
||||
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
|
||||
#include <MyGUI_LanguageManager.h>
|
||||
#include "keywordsearch.hpp"
|
||||
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
@ -19,143 +22,12 @@ namespace MWGui { struct JournalViewModelImpl; }
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month);
|
||||
|
||||
template <typename string_t, typename value_t>
|
||||
class KeywordSearch
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename string_t::const_iterator Point;
|
||||
|
||||
struct Match
|
||||
{
|
||||
Point mBeg;
|
||||
Point mEnd;
|
||||
value_t mValue;
|
||||
};
|
||||
|
||||
void seed (string_t keyword, value_t value)
|
||||
{
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
mRoot.mChildren.clear ();
|
||||
mRoot.mKeyword.clear ();
|
||||
}
|
||||
|
||||
bool search (Point beg, Point end, Match & match)
|
||||
{
|
||||
for (Point i = beg; i != end; ++i)
|
||||
{
|
||||
// check first character
|
||||
typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale));
|
||||
|
||||
// no match, on to next character
|
||||
if (candidate == mRoot.mChildren.end ())
|
||||
continue;
|
||||
|
||||
// see how far the match goes
|
||||
Point j = i;
|
||||
|
||||
while ((j + 1) != end)
|
||||
{
|
||||
typename Entry::childen_t::iterator next = candidate->second.mChildren.find (std::tolower (*++j, mLocale));
|
||||
|
||||
if (next == candidate->second.mChildren.end ())
|
||||
break;
|
||||
|
||||
candidate = next;
|
||||
}
|
||||
|
||||
// didn't match enough to disambiguate, on to next character
|
||||
if (!candidate->second.mKeyword.size ())
|
||||
continue;
|
||||
|
||||
// match the rest of the keyword
|
||||
typename string_t::const_iterator t = candidate->second.mKeyword.begin () + (j - i);
|
||||
|
||||
while (j != end && t != candidate->second.mKeyword.end ())
|
||||
{
|
||||
if (std::tolower (*j, mLocale) != std::tolower (*t, mLocale))
|
||||
break;
|
||||
|
||||
++j, ++t;
|
||||
}
|
||||
|
||||
// didn't match full keyword, on to next character
|
||||
if (t != candidate->second.mKeyword.end ())
|
||||
continue;
|
||||
|
||||
// we did it, report the good news
|
||||
match.mValue = candidate->second.mValue;
|
||||
match.mBeg = i;
|
||||
match.mEnd = j;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// no match in range, report the bad news
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Entry
|
||||
{
|
||||
typedef std::map <wchar_t, Entry> childen_t;
|
||||
|
||||
string_t mKeyword;
|
||||
value_t mValue;
|
||||
childen_t mChildren;
|
||||
};
|
||||
|
||||
void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry)
|
||||
{
|
||||
int ch = tolower (keyword.at (depth), mLocale);
|
||||
|
||||
typename Entry::childen_t::iterator j = entry.mChildren.find (ch);
|
||||
|
||||
if (j == entry.mChildren.end ())
|
||||
{
|
||||
entry.mChildren [ch].mValue = /*std::move*/ (value);
|
||||
entry.mChildren [ch].mKeyword = /*std::move*/ (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j->second.mKeyword.size () > 0)
|
||||
{
|
||||
if (keyword == j->second.mKeyword)
|
||||
throw std::runtime_error ("duplicate keyword inserted");
|
||||
|
||||
value_t pushValue = /*std::move*/ (j->second.mValue);
|
||||
string_t pushKeyword = /*std::move*/ (j->second.mKeyword);
|
||||
|
||||
j->second.mKeyword.clear ();
|
||||
|
||||
if (depth >= pushKeyword.size ())
|
||||
throw std::runtime_error ("unexpected");
|
||||
|
||||
if (depth+1 < pushKeyword.size())
|
||||
seed_impl (/*std::move*/ (pushKeyword), /*std::move*/ (pushValue), depth+1, j->second);
|
||||
}
|
||||
|
||||
if (depth+1 < keyword.size())
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), depth+1, j->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entry mRoot;
|
||||
std::locale mLocale;
|
||||
};
|
||||
|
||||
struct MWGui::JournalViewModelImpl : JournalViewModel
|
||||
{
|
||||
typedef KeywordSearch <std::string, intptr_t> keyword_search_t;
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
mutable bool mKeywordSearchLoaded;
|
||||
mutable keyword_search_t mKeywordSearch;
|
||||
mutable KeywordSearchT mKeywordSearch;
|
||||
|
||||
std::locale mLocale;
|
||||
|
||||
@ -253,7 +125,7 @@ struct MWGui::JournalViewModelImpl : JournalViewModel
|
||||
|
||||
std::string::const_iterator i = utf8text.begin ();
|
||||
|
||||
keyword_search_t::Match match;
|
||||
KeywordSearchT::Match match;
|
||||
|
||||
while (i != utf8text.end () && mModel->mKeywordSearch.search (i, utf8text.end (), match))
|
||||
{
|
||||
@ -300,8 +172,8 @@ struct MWGui::JournalViewModelImpl : JournalViewModel
|
||||
|
||||
mutable std::string timestamp_buffer;
|
||||
|
||||
JournalEntryImpl (JournalViewModelImpl const * Model, iterator_t itr) :
|
||||
BaseEntry <iterator_t, JournalEntry> (Model, itr)
|
||||
JournalEntryImpl (JournalViewModelImpl const * model, iterator_t itr) :
|
||||
BaseEntry <iterator_t, JournalEntry> (model, itr)
|
||||
{}
|
||||
|
||||
std::string getText () const
|
||||
|
@ -152,6 +152,10 @@ namespace
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
|
||||
|
||||
/// \todo Wiping the whole book layout each time the journal is opened is probably too costly for a large journal (eg 300+ pages).
|
||||
/// There should be a way to keep the existing layout and append new entries to the end of it.
|
||||
/// However, that still leaves the problem of having to add links to previously unknown, but now known topics, so
|
||||
/// we maybe need to find another way to speed things up.
|
||||
Book journalBook;
|
||||
if (mModel->isEmpty ())
|
||||
journalBook = createEmptyJournalBook ();
|
||||
|
0
apps/openmw/mwgui/keywordsearch.cpp
Normal file
0
apps/openmw/mwgui/keywordsearch.cpp
Normal file
139
apps/openmw/mwgui/keywordsearch.hpp
Normal file
139
apps/openmw/mwgui/keywordsearch.hpp
Normal file
@ -0,0 +1,139 @@
|
||||
#ifndef MWGUI_KEYWORDSEARCH_H
|
||||
#define MWGUI_KEYWORDSEARCH_H
|
||||
|
||||
#include <map>
|
||||
#include <locale>
|
||||
#include <stdexcept>
|
||||
|
||||
template <typename string_t, typename value_t>
|
||||
class KeywordSearch
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename string_t::const_iterator Point;
|
||||
|
||||
struct Match
|
||||
{
|
||||
Point mBeg;
|
||||
Point mEnd;
|
||||
value_t mValue;
|
||||
};
|
||||
|
||||
void seed (string_t keyword, value_t value)
|
||||
{
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
mRoot.mChildren.clear ();
|
||||
mRoot.mKeyword.clear ();
|
||||
}
|
||||
|
||||
bool search (Point beg, Point end, Match & match)
|
||||
{
|
||||
for (Point i = beg; i != end; ++i)
|
||||
{
|
||||
// check first character
|
||||
typename Entry::childen_t::iterator candidate = mRoot.mChildren.find (std::tolower (*i, mLocale));
|
||||
|
||||
// no match, on to next character
|
||||
if (candidate == mRoot.mChildren.end ())
|
||||
continue;
|
||||
|
||||
// see how far the match goes
|
||||
Point j = i;
|
||||
|
||||
while ((j + 1) != end)
|
||||
{
|
||||
typename Entry::childen_t::iterator next = candidate->second.mChildren.find (std::tolower (*++j, mLocale));
|
||||
|
||||
if (next == candidate->second.mChildren.end ())
|
||||
break;
|
||||
|
||||
candidate = next;
|
||||
}
|
||||
|
||||
// didn't match enough to disambiguate, on to next character
|
||||
if (!candidate->second.mKeyword.size ())
|
||||
continue;
|
||||
|
||||
// match the rest of the keyword
|
||||
typename string_t::const_iterator t = candidate->second.mKeyword.begin () + (j - i);
|
||||
|
||||
while (j != end && t != candidate->second.mKeyword.end ())
|
||||
{
|
||||
if (std::tolower (*j, mLocale) != std::tolower (*t, mLocale))
|
||||
break;
|
||||
|
||||
++j, ++t;
|
||||
}
|
||||
|
||||
// didn't match full keyword, on to next character
|
||||
if (t != candidate->second.mKeyword.end ())
|
||||
continue;
|
||||
|
||||
// we did it, report the good news
|
||||
match.mValue = candidate->second.mValue;
|
||||
match.mBeg = i;
|
||||
match.mEnd = j;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// no match in range, report the bad news
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Entry
|
||||
{
|
||||
typedef std::map <wchar_t, Entry> childen_t;
|
||||
|
||||
string_t mKeyword;
|
||||
value_t mValue;
|
||||
childen_t mChildren;
|
||||
};
|
||||
|
||||
void seed_impl (string_t keyword, value_t value, size_t depth, Entry & entry)
|
||||
{
|
||||
int ch = tolower (keyword.at (depth), mLocale);
|
||||
|
||||
typename Entry::childen_t::iterator j = entry.mChildren.find (ch);
|
||||
|
||||
if (j == entry.mChildren.end ())
|
||||
{
|
||||
entry.mChildren [ch].mValue = /*std::move*/ (value);
|
||||
entry.mChildren [ch].mKeyword = /*std::move*/ (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j->second.mKeyword.size () > 0)
|
||||
{
|
||||
if (keyword == j->second.mKeyword)
|
||||
throw std::runtime_error ("duplicate keyword inserted");
|
||||
|
||||
value_t pushValue = /*std::move*/ (j->second.mValue);
|
||||
string_t pushKeyword = /*std::move*/ (j->second.mKeyword);
|
||||
|
||||
j->second.mKeyword.clear ();
|
||||
|
||||
if (depth >= pushKeyword.size ())
|
||||
throw std::runtime_error ("unexpected");
|
||||
|
||||
if (depth+1 < pushKeyword.size())
|
||||
seed_impl (/*std::move*/ (pushKeyword), /*std::move*/ (pushValue), depth+1, j->second);
|
||||
}
|
||||
|
||||
if (depth+1 < keyword.size())
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), depth+1, j->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entry mRoot;
|
||||
std::locale mLocale;
|
||||
};
|
||||
|
||||
#endif
|
@ -108,7 +108,6 @@ namespace MWGui
|
||||
mGui = mGuiManager->getGui();
|
||||
|
||||
//Register own widgets with MyGUI
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<DialogueHistory>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSkill>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWAttribute>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSpell>("Widget");
|
||||
|
@ -23,7 +23,6 @@ namespace Interpreter{
|
||||
}
|
||||
|
||||
std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context){
|
||||
|
||||
unsigned int start = 0;
|
||||
std::ostringstream retval;
|
||||
for(unsigned int i = 0; i < text.length(); i++){
|
||||
|
@ -5,14 +5,13 @@
|
||||
|
||||
<Widget type="Widget" skin="MW_Box" position="8 8 415 381" align="Stretch" name = "Client"/>
|
||||
|
||||
<!-- The Dialogue history -->
|
||||
<Widget type="DialogueHistory" skin="MW_TextBoxEdit" position="13 13 405 371" name="History" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH">
|
||||
<Property key="Static" value="true"/>
|
||||
<Property key="WordWrap" value="true"/>
|
||||
<Property key="MultiLine" value="1" />
|
||||
<Property key="VisibleVScroll" value="1" />
|
||||
<!-- box for receiving mouse events -->
|
||||
<Widget type="Widget" skin="" position="0 0 400 375" name="EventBox" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH"/>
|
||||
<Widget type="Widget" position="13 13 391 371" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH">
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="0 0 391 371" name="History" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH">
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ScrollBar" skin="MW_VScroll" position="404 13 14 371" align="ALIGN_RIGHT ALIGN_VSTRETCH" name="VScroll">
|
||||
<Property key="Visible" value="false"/>
|
||||
</Widget>
|
||||
|
||||
<!-- The disposition bar-->
|
||||
|
Loading…
Reference in New Issue
Block a user