forked from teamnwah/openmw-tes3coop
Rewrite journal GUI quest index
- Use quest names as identifiers, not quest IDs. This ensures that quests with different IDs, but the same name (e.g. A2_4_MiloCaiusGone and A2_4_MiloGone) are merged properly, as they should. - Switch display from BookPage to MWList. Handles word-wrapping and scrolling properly. - Fixes a bug where the quest index would not be updated when opened.
This commit is contained in:
parent
577ed3943b
commit
bbc5b125ab
10 changed files with 111 additions and 67 deletions
|
@ -148,22 +148,6 @@ namespace
|
|||
mTypesetter->lineBreak ();
|
||||
}
|
||||
};
|
||||
|
||||
struct AddQuestLink : AddContent
|
||||
{
|
||||
AddQuestLink (MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style) :
|
||||
AddContent (typesetter, style)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (MWGui::JournalViewModel::QuestId id, MWGui::JournalViewModel::Utf8Span name)
|
||||
{
|
||||
MWGui::BookTypesetter::Style* style = mTypesetter->createHotStyle (mBodyStyle, MyGUI::Colour::Black, linkHot, linkActive, id);
|
||||
|
||||
mTypesetter->write (style, name);
|
||||
mTypesetter->lineBreak ();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
|
@ -206,7 +190,7 @@ book JournalBooks::createJournalBook ()
|
|||
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true));
|
||||
mModel->visitJournalEntries ("", AddJournalEntry (typesetter, body, header, true));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
@ -227,16 +211,17 @@ book JournalBooks::createTopicBook (uintptr_t topicId)
|
|||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createQuestBook (uintptr_t questId)
|
||||
book JournalBooks::createQuestBook (const std::string& questName)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitQuestName (questId, AddQuestName (typesetter, header));
|
||||
AddQuestName addName (typesetter, header);
|
||||
addName(to_utf8_span(questName.c_str()));
|
||||
|
||||
mModel->visitJournalEntries (questId, AddJournalEntry (typesetter, body, header, false));
|
||||
mModel->visitJournalEntries (questName, AddJournalEntry (typesetter, body, header, false));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
@ -279,16 +264,6 @@ book JournalBooks::createTopicIndexBook (char character)
|
|||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
book JournalBooks::createQuestIndexBook (bool activeOnly)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
|
||||
BookTypesetter::Style* base = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
BookTypesetter::Ptr JournalBooks::createTypesetter ()
|
||||
{
|
||||
//TODO: determine page size from layout...
|
||||
|
|
|
@ -18,10 +18,9 @@ namespace MWGui
|
|||
Book createEmptyJournalBook ();
|
||||
Book createJournalBook ();
|
||||
Book createTopicBook (uintptr_t topicId);
|
||||
Book createQuestBook (uintptr_t questId);
|
||||
Book createQuestBook (const std::string& questName);
|
||||
Book createTopicIndexBook ();
|
||||
Book createTopicIndexBook (char character);
|
||||
Book createQuestIndexBook (bool showAll);
|
||||
|
||||
private:
|
||||
BookTypesetter::Ptr createTypesetter ();
|
||||
|
|
|
@ -195,10 +195,12 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
};
|
||||
|
||||
void visitQuestNames (bool active_only, boost::function <void (QuestId, Utf8Span)> visitor) const
|
||||
void visitQuestNames (bool active_only, boost::function <void (const std::string&)> visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get ().getJournal ();
|
||||
|
||||
std::set<std::string> visitedQuests;
|
||||
|
||||
for (MWBase::Journal::TQuestIter i = journal->questBegin (); i != journal->questEnd (); ++i)
|
||||
{
|
||||
if (active_only && i->second.isFinished ())
|
||||
|
@ -209,7 +211,15 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
// Note that even with Tribunal, some quests still don't have quest names. I'm assuming those are not supposed
|
||||
// to appear in the quest book.
|
||||
if (!quest.getName().empty())
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
|
||||
{
|
||||
// Don't list the same quest name twice
|
||||
if (visitedQuests.find(quest.getName()) != visitedQuests.end())
|
||||
continue;
|
||||
|
||||
visitor (quest.getName());
|
||||
|
||||
visitedQuests.insert(quest.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,16 +268,24 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
}
|
||||
};
|
||||
|
||||
void visitJournalEntries (QuestId questId, boost::function <void (JournalEntry const &)> visitor) const
|
||||
void visitJournalEntries (const std::string& questName, boost::function <void (JournalEntry const &)> visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get().getJournal();
|
||||
|
||||
if (questId != 0)
|
||||
if (!questName.empty())
|
||||
{
|
||||
MWDialogue::Quest const * quest = reinterpret_cast <MWDialogue::Quest const *> (questId);
|
||||
std::vector<MWDialogue::Quest const*> quests;
|
||||
for (MWBase::Journal::TQuestIter questIt = journal->questBegin(); questIt != journal->questEnd(); ++questIt)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(questIt->second.getName(), questName))
|
||||
quests.push_back(&questIt->second);
|
||||
}
|
||||
|
||||
for(MWBase::Journal::TEntryIter i = journal->begin(); i != journal->end (); ++i)
|
||||
{
|
||||
for (std::vector<MWDialogue::Quest const*>::iterator questIt = quests.begin(); questIt != quests.end(); ++questIt)
|
||||
{
|
||||
MWDialogue::Quest const* quest = *questIt;
|
||||
for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
|
||||
{
|
||||
if (i->mInfoId == j->mInfoId)
|
||||
|
@ -275,6 +293,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(MWBase::Journal::TEntryIter i = journal->begin(); i != journal->end (); ++i)
|
||||
|
|
|
@ -70,11 +70,12 @@ namespace MWGui
|
|||
/// provides access to the name of the quest with the specified identifier
|
||||
virtual void visitQuestName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const = 0;
|
||||
|
||||
/// walks the active and optionally completed, quests providing the quest id and name
|
||||
virtual void visitQuestNames (bool active_only, boost::function <void (QuestId, Utf8Span)> visitor) const = 0;
|
||||
/// walks the active and optionally completed, quests providing the name
|
||||
virtual void visitQuestNames (bool active_only, boost::function <void (const std::string&)> visitor) const = 0;
|
||||
|
||||
/// walks over the journal entries related to the specified quest identified by its id
|
||||
virtual void visitJournalEntries (QuestId questId, boost::function <void (JournalEntry const &)> visitor) const = 0;
|
||||
/// walks over the journal entries related to all quests with the given name
|
||||
/// If \a questName is empty, simply visits all journal entries
|
||||
virtual void visitJournalEntries (const std::string& questName, boost::function <void (JournalEntry const &)> visitor) const = 0;
|
||||
|
||||
/// provides the name of the topic specified by its id
|
||||
virtual void visitTopicName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const = 0;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "imagebutton.hpp"
|
||||
#include "journalviewmodel.hpp"
|
||||
#include "journalbooks.hpp"
|
||||
#include "list.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -38,7 +39,6 @@ namespace
|
|||
static char const TopicsList [] = "TopicsList";
|
||||
static char const TopicsPage [] = "TopicsPage";
|
||||
static char const QuestsList [] = "QuestsList";
|
||||
static char const QuestsPage [] = "QuestsPage";
|
||||
static char const LeftBookPage [] = "LeftBookPage";
|
||||
static char const RightBookPage [] = "RightBookPage";
|
||||
static char const LeftTopicIndex [] = "LeftTopicIndex";
|
||||
|
@ -110,6 +110,9 @@ namespace
|
|||
adviseButtonClick (ShowAllBTN, &JournalWindowImpl::notifyShowAll );
|
||||
adviseButtonClick (ShowActiveBTN, &JournalWindowImpl::notifyShowActive);
|
||||
|
||||
MWGui::Widgets::MWList* list = getWidget<MWGui::Widgets::MWList>(QuestsList);
|
||||
list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked);
|
||||
|
||||
{
|
||||
MWGui::BookPage::ClickCallback callback;
|
||||
|
||||
|
@ -129,14 +132,6 @@ namespace
|
|||
getPage (RightTopicIndex)->adviseLinkClicked (callback);
|
||||
}
|
||||
|
||||
{
|
||||
MWGui::BookPage::ClickCallback callback;
|
||||
|
||||
callback = boost::bind (&JournalWindowImpl::notifyQuestClicked, this, _1);
|
||||
|
||||
getPage (QuestsPage)->adviseLinkClicked (callback);
|
||||
}
|
||||
|
||||
adjustButton(OptionsBTN, true);
|
||||
adjustButton(PrevPageBTN);
|
||||
adjustButton(NextPageBTN);
|
||||
|
@ -271,6 +266,10 @@ namespace
|
|||
//TODO: figure out how to make "options" page overlay book page
|
||||
// correctly, so that text may show underneath
|
||||
getPage (RightBookPage)->showPage (Book (), 0);
|
||||
|
||||
// If in quest mode, ensure the quest list is updated
|
||||
if (mQuestMode)
|
||||
notifyQuests(getWidget<MyGUI::Widget>(QuestsList));
|
||||
}
|
||||
|
||||
void pushBook (Book book, unsigned int page)
|
||||
|
@ -349,9 +348,9 @@ namespace
|
|||
setVisible (JournalBTN, true);
|
||||
}
|
||||
|
||||
void notifyQuestClicked (intptr_t questId)
|
||||
void notifyQuestClicked (const std::string& name, int id)
|
||||
{
|
||||
Book book = createQuestBook (questId);
|
||||
Book book = createQuestBook (name);
|
||||
|
||||
if (mStates.size () > 1)
|
||||
replaceBook (book, 0);
|
||||
|
@ -409,9 +408,21 @@ namespace
|
|||
setVisible (ShowActiveBTN, false);
|
||||
}
|
||||
|
||||
struct AddQuestNamesToList
|
||||
{
|
||||
AddQuestNamesToList(MWGui::Widgets::MWList* list) : mList(list) {}
|
||||
|
||||
MWGui::Widgets::MWList* mList;
|
||||
void operator () (const std::string& name)
|
||||
{
|
||||
mList->addItem(name);
|
||||
}
|
||||
};
|
||||
|
||||
void notifyQuests(MyGUI::Widget* _sender)
|
||||
{
|
||||
mQuestMode = true;
|
||||
|
||||
setVisible (LeftTopicIndex, false);
|
||||
setVisible (RightTopicIndex, false);
|
||||
setVisible (TopicsList, false);
|
||||
|
@ -419,23 +430,26 @@ namespace
|
|||
setVisible (ShowAllBTN, !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mAllQuests);
|
||||
|
||||
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
|
||||
MWGui::Widgets::MWList* list = getWidget<MWGui::Widgets::MWList>(QuestsList);
|
||||
list->clear();
|
||||
|
||||
AddQuestNamesToList add(list);
|
||||
|
||||
mModel->visitQuestNames(!mAllQuests, add);
|
||||
|
||||
list->adjustSize();
|
||||
}
|
||||
|
||||
void notifyShowAll(MyGUI::Widget* _sender)
|
||||
{
|
||||
mAllQuests = true;
|
||||
setVisible (ShowAllBTN, !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mAllQuests);
|
||||
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
|
||||
notifyQuests(_sender);
|
||||
}
|
||||
|
||||
void notifyShowActive(MyGUI::Widget* _sender)
|
||||
{
|
||||
mAllQuests = false;
|
||||
setVisible (ShowAllBTN, !mAllQuests);
|
||||
setVisible (ShowActiveBTN, mAllQuests);
|
||||
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
|
||||
notifyQuests(_sender);
|
||||
}
|
||||
|
||||
void notifyCancel(MyGUI::Widget* _sender)
|
||||
|
|
|
@ -65,8 +65,10 @@ namespace MWGui
|
|||
{
|
||||
if (*it != "")
|
||||
{
|
||||
if (mListItemSkin.empty())
|
||||
throw std::runtime_error("MWList needs a ListItemSkin property");
|
||||
MyGUI::Button* button = mScrollView->createWidget<MyGUI::Button>(
|
||||
"MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24),
|
||||
mListItemSkin, MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24),
|
||||
MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it));
|
||||
button->setCaption((*it));
|
||||
button->getSubWidgetText()->setWordWrap(true);
|
||||
|
@ -102,6 +104,14 @@ namespace MWGui
|
|||
mScrollView->setViewOffset(MyGUI::IntPoint(0, -viewPosition));
|
||||
}
|
||||
|
||||
void MWList::setPropertyOverride(const std::string &_key, const std::string &_value)
|
||||
{
|
||||
if (_key == "ListItemSkin")
|
||||
mListItemSkin = _value;
|
||||
else
|
||||
Base::setPropertyOverride(_key, _value);
|
||||
}
|
||||
|
||||
bool MWList::hasItem(const std::string& name)
|
||||
{
|
||||
return (std::find(mItems.begin(), mItems.end(), name) != mItems.end());
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace MWGui
|
|||
|
||||
/**
|
||||
* Event: Item selected with the mouse.
|
||||
* signature: void method(std::string itemName)
|
||||
* signature: void method(std::string itemName, int index)
|
||||
*/
|
||||
EventHandle_StringInt eventItemSelected;
|
||||
|
||||
|
@ -49,6 +49,8 @@ namespace MWGui
|
|||
MyGUI::Widget* getItemWidget(const std::string& name);
|
||||
///< get widget for an item name, useful to set up tooltip
|
||||
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
|
||||
protected:
|
||||
void initialiseOverride();
|
||||
|
||||
|
@ -60,6 +62,7 @@ namespace MWGui
|
|||
private:
|
||||
MyGUI::ScrollView* mScrollView;
|
||||
MyGUI::Widget* mClient;
|
||||
std::string mListItemSkin;
|
||||
|
||||
std::vector<std::string> mItems;
|
||||
|
||||
|
|
|
@ -82,9 +82,7 @@
|
|||
<Widget type="BookPage" skin="MW_BookPage" position="0 0 30000 30000" name="TopicsPage"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="20 35 184 225" name="QuestsList" align="Right VStretch">
|
||||
<Property key="CanvasAlign" value="Left Top"/>
|
||||
<Widget type="BookPage" skin="MW_BookPage" position="0 0 30000 30000" name="QuestsPage"/>
|
||||
<Widget type="MWList" skin="MW_QuestList" position="8 35 208 225" name="QuestsList" align="Right VStretch">
|
||||
</Widget>
|
||||
|
||||
<Widget type="ImageButton" skin="ImageBox" position="20 265 56 32" Align="Top|Left" name="TopicsBTN">
|
||||
|
|
|
@ -12,4 +12,28 @@
|
|||
<Skin name="MW_BookPage" size="0 0 50 50">
|
||||
<BasisSkin type="PageDisplay"/>
|
||||
</Skin>
|
||||
|
||||
<Skin name="MW_QuestList" size="516 516" align="Left Top">
|
||||
|
||||
<Property key="ListItemSkin" value="MW_QuestLink"/>
|
||||
|
||||
<Child type="Widget" skin="" offset="3 3 510 510" align="Top Left Stretch" name="Client"/>
|
||||
|
||||
</Skin>
|
||||
|
||||
<Skin name="MW_QuestLink" size="5 5">
|
||||
<Property key="FontName" value="Default"/>
|
||||
<Property key="TextAlign" value="Left VCenter"/>
|
||||
|
||||
<BasisSkin type="SimpleText" offset="2 0 1 5" align="Stretch">
|
||||
<State name="disabled" colour="0 0 0" shift="0"/>
|
||||
<State name="normal" colour="0 0 0" shift="0"/>
|
||||
<State name="highlighted" colour="0.4 0.4 0.8" shift="0"/>
|
||||
<State name="pushed" colour="0.5 0.5 1" shift="0"/>
|
||||
<State name="disabled_checked" colour="0 0 0" shift="0"/>
|
||||
<State name="normal_checked" colour="0 0 0" shift="0"/>
|
||||
<State name="highlighted_checked" colour="0.4 0.4 0.8" shift="0"/>
|
||||
<State name="pushed_checked" colour="0.5 0.5 1" shift="0"/>
|
||||
</BasisSkin>
|
||||
</Skin>
|
||||
</MyGUI>
|
||||
|
|
|
@ -157,6 +157,7 @@
|
|||
</Skin>
|
||||
|
||||
<Skin name="MW_SimpleList" size="516 516" align="Left Top">
|
||||
<Property key="ListItemSkin" value="MW_ListLine"/>
|
||||
|
||||
<Child type="Widget" skin="MW_Box" offset="0 0 516 516" align="Stretch"/>
|
||||
|
||||
|
|
Loading…
Reference in a new issue