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.
deque
scrawl 11 years ago
parent 577ed3943b
commit bbc5b125ab

@ -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,20 +268,29 @@ 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 (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
for (std::vector<MWDialogue::Quest const*>::iterator questIt = quests.begin(); questIt != quests.end(); ++questIt)
{
if (i->mInfoId == j->mInfoId)
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, i));
MWDialogue::Quest const* quest = *questIt;
for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
{
if (i->mInfoId == j->mInfoId)
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, 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…
Cancel
Save