1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-03 20:49:41 +00:00

reworked journal to match bethesda's implemenation

This commit is contained in:
Nathan Jeffords 2013-01-27 12:16:46 -08:00
parent f02a53b121
commit 718af692c9
6 changed files with 424 additions and 173 deletions

View file

@ -1,174 +1,175 @@
#include "journalwindow.hpp" #include "journalwindow.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "list.hpp"
#include <sstream> #include <sstream>
#include <set> #include <set>
#include <stack>
#include <string> #include <string>
#include <utility> #include <utility>
#include "boost/lexical_cast.hpp"
#include "bookpage.hpp"
#include "windowbase.hpp" #include "windowbase.hpp"
#include "imagebutton.hpp" #include "imagebutton.hpp"
#include "journalviewmodel.hpp"
#include "journalbooks.hpp"
using namespace MyGUI;
using namespace MWGui; using namespace MWGui;
namespace namespace
{ {
struct book #define CONTROL_ID(name) \
static char const name [] = #name;
CONTROL_ID(OptionsOverlay)
CONTROL_ID(OptionsBTN)
CONTROL_ID(PrevPageBTN);
CONTROL_ID(NextPageBTN);
CONTROL_ID(CloseBTN);
CONTROL_ID(JournalBTN);
CONTROL_ID(TopicsBTN);
CONTROL_ID(QuestsBTN);
CONTROL_ID(CancelBTN);
CONTROL_ID(ShowAllBTN);
CONTROL_ID(ShowActiveBTN);
CONTROL_ID(PageOneNum)
CONTROL_ID(PageTwoNum)
CONTROL_ID(TopicsList);
CONTROL_ID(TopicsPage);
CONTROL_ID(QuestsList);
CONTROL_ID(QuestsPage);
CONTROL_ID(LeftBookPage);
CONTROL_ID(RightBookPage);
CONTROL_ID(LeftTopicIndex);
CONTROL_ID(RightTopicIndex);
struct JournalWindow : WindowBase, JournalBooks, IJournalWindow
{ {
int endLine; struct display_state
std::list<std::string> pages; {
int mPage;
book mBook;
}; };
}
book formatText(std::string text,book mBook,int maxLine, int lineSize) typedef std::stack <display_state> display_state_stack;
{
//stringList.push_back("");
int cLineSize = 0; display_state_stack mStates;
int cLine = mBook.endLine +1; book mTopicIndexBook;
std::string cString; bool mQuestMode;
bool mAllQuests;
if(mBook.pages.empty()) template <typename widget_type>
widget_type * getWidget (char const * name)
{ {
cString = ""; widget_type * widget;
cLine = 0; WindowBase::getWidget (widget, name);
} return widget;
else
{
cString = mBook.pages.back() + std::string("\n");
mBook.pages.pop_back();
} }
//std::string::iterator wordBegin = text.begin(); template <typename value_type>
//std::string::iterator wordEnd; void setText (char const * name, value_type const & value)
{
getWidget <TextBox> (name) ->
setCaption (boost::lexical_cast <std::string> (value));
}
std::string cText = text; void setVisible (char const * name, bool visible)
{
getWidget <Widget> (name) ->
setVisible (visible);
}
while(cText.length() != 0) void adviseButtonClick (char const * name, void (JournalWindow::*Handler) (Widget* _sender))
{ {
size_t firstSpace = cText.find_first_of(' '); getWidget <MWGui::ImageButton> (name) ->
if(firstSpace == std::string::npos) eventMouseButtonClick += newDelegate(this, Handler);
{
cString = cString + cText;
mBook.pages.push_back(cString);
//TODO:finnish this
break;
} }
if(static_cast<int> (firstSpace) + cLineSize <= lineSize)
{
cLineSize = firstSpace + cLineSize;
cString = cString + cText.substr(0,firstSpace +1);
}
else
{
cLineSize = firstSpace;
if(cLine +1 <= maxLine)
{
cLine = cLine + 1;
cString = cString + std::string("\n") + cText.substr(0,firstSpace +1);
}
else
{
cLine = 0;
mBook.pages.push_back(cString);
cString = cText.substr(0,firstSpace +1);
}
}
//std::cout << cText << "\n";
//std::cout << cText.length();
cText = cText.substr(firstSpace +1,cText.length() - firstSpace -1);
}
mBook.endLine = cLine;
return mBook;
//std::string
}
namespace MWGui::IBookPage* getPage (char const * name)
{
struct JournalWindow : WindowBase, IJournalWindow
{ {
MyGUI::EditPtr mLeftTextWidget; return getWidget <MWGui::IBookPage> (name);
MyGUI::EditPtr mRightTextWidget; }
MWGui::ImageButton* mPrevBtn;
MWGui::ImageButton* mNextBtn;
std::vector<std::string> mLeftPages;
std::vector<std::string> mRightPages;
int mPageNumber; //store the number of the current left page
JournalWindow () JournalWindow (IJournalViewModel::ptr Model)
: WindowBase("openmw_journal.layout") : WindowBase("openmw_journal.layout"), JournalBooks (Model)
, mPageNumber(0)
{ {
mMainWidget->setVisible(false); mMainWidget->setVisible(false);
//setCoord(0,0,498, 342);
center(); center();
getWidget(mLeftTextWidget, "LeftText"); adviseButtonClick (OptionsBTN, &JournalWindow::notifyOptions );
getWidget(mRightTextWidget, "RightText"); adviseButtonClick (PrevPageBTN, &JournalWindow::notifyPrevPage );
getWidget(mPrevBtn, "PrevPageBTN"); adviseButtonClick (NextPageBTN, &JournalWindow::notifyNextPage );
mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyPrevPage); adviseButtonClick (CloseBTN, &JournalWindow::notifyClose );
getWidget(mNextBtn, "NextPageBTN"); adviseButtonClick (JournalBTN, &JournalWindow::notifyJournal );
mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyNextPage);
adviseButtonClick (TopicsBTN, &JournalWindow::notifyTopics );
adviseButtonClick (QuestsBTN, &JournalWindow::notifyQuests );
adviseButtonClick (CancelBTN, &JournalWindow::notifyCancel );
adviseButtonClick (ShowAllBTN, &JournalWindow::notifyShowAll );
adviseButtonClick (ShowActiveBTN, &JournalWindow::notifyShowActive);
mLeftTextWidget->setEditReadOnly(true); {
mRightTextWidget->setEditReadOnly(true); auto callback = std::bind (&JournalWindow::notifyTopicClicked, this, std::placeholders::_1);
mRightTextWidget->setEditStatic(true);
mLeftTextWidget->setEditStatic(true); getPage (TopicsPage)->adviseLinkClicked (callback);
getPage (LeftBookPage)->adviseLinkClicked (callback);
getPage (RightBookPage)->adviseLinkClicked (callback);
} }
void close()
{ {
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); auto callback = std::bind (&JournalWindow::notifyIndexLinkClicked, this, std::placeholders::_1);
getPage (LeftTopicIndex)->adviseLinkClicked (callback);
getPage (RightTopicIndex)->adviseLinkClicked (callback);
}
{
auto callback = std::bind (&JournalWindow::notifyQuestClicked, this, std::placeholders::_1);
getPage (QuestsPage)->adviseLinkClicked (callback);
}
mQuestMode = false;
mAllQuests = false;
} }
void open() void open()
{ {
mPageNumber = 0; Model->load ();
setBookMode ();
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end())
{
book journal;
journal.endLine = 0;
for(std::deque<MWDialogue::StampedJournalEntry>::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) book journalBook;
{ if (Model->is_empty ())
std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); journalBook = createEmptyJournalBook ();
journal = formatText(a,journal,10,17);
journal.endLine = journal.endLine +1;
journal.pages.back() = journal.pages.back() + std::string("\n");
}
//std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore());
//std::list<std::string> journal = formatText(a,10,20,1);
bool left = true;
for(std::list<std::string>::iterator it = journal.pages.begin(); it != journal.pages.end();++it)
{
if(left)
{
mLeftPages.push_back(*it);
}
else else
{ journalBook = createJournalBook ();
mRightPages.push_back(*it);
}
left = !left;
}
if(!left) mRightPages.push_back("");
mPageNumber = mLeftPages.size()-1; pushBook (journalBook, 0);
displayLeftText(mLeftPages[mPageNumber]); }
displayRightText(mRightPages[mPageNumber]);
} void close()
else
{ {
//std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); Model->unload ();
}
getPage (LeftBookPage)->showPage (book (), 0);
getPage (RightBookPage)->showPage (book (), 0);
decltype (mStates) clr;
mStates.swap (clr);
mTopicIndexBook.reset ();
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
} }
void setVisible (bool newValue) void setVisible (bool newValue)
@ -176,46 +177,246 @@ namespace
WindowBase::setVisible (newValue); WindowBase::setVisible (newValue);
} }
void setBookMode ()
void displayLeftText(std::string text)
{ {
mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); setVisible (OptionsBTN, true);
mLeftTextWidget->addText(text); setVisible (OptionsOverlay, false);
updateShowingPages ();
updateCloseJournalButton ();
} }
void displayRightText(std::string text) void setOptionsMode ()
{ {
mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); setVisible (OptionsBTN, false);
mRightTextWidget->addText(text); setVisible (OptionsOverlay, true);
setVisible (PrevPageBTN, false);
setVisible (NextPageBTN, false);
setVisible (CloseBTN, false);
setVisible (JournalBTN, false);
setVisible (TopicsList, false);
setVisible (QuestsList, mQuestMode);
setVisible (LeftTopicIndex, !mQuestMode);
setVisible (RightTopicIndex, !mQuestMode);
setVisible (ShowAllBTN, mQuestMode && !mAllQuests);
setVisible (ShowActiveBTN, mQuestMode && mAllQuests);
//TODO: figure out how to make "options" page overlay book page
// correctly, so that text may show underneath
getPage (RightBookPage)->showPage (book (), 0);
} }
void pushBook (book Book, int Page)
void notifyNextPage(MyGUI::Widget* _sender)
{ {
if(mPageNumber < int(mLeftPages.size())-1) display_state bs;
bs.mPage = Page;
bs.mBook = Book;
mStates.push (bs);
updateShowingPages ();
updateCloseJournalButton ();
}
void replaceBook (book Book, int Page)
{ {
std::string nextSound = "book page2"; assert (!mStates.empty ());
MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); mStates.top ().mBook = Book;
mPageNumber = mPageNumber + 1; mStates.top ().mPage = Page;
displayLeftText(mLeftPages[mPageNumber]); updateShowingPages ();
displayRightText(mRightPages[mPageNumber]); }
void popBook ()
{
mStates.pop ();
updateShowingPages ();
updateCloseJournalButton ();
}
void updateCloseJournalButton ()
{
setVisible (CloseBTN, mStates.size () < 2);
setVisible (JournalBTN, mStates.size () >= 2);
}
void updateShowingPages ()
{
book Book;
int Page;
int relPages;
if (!mStates.empty ())
{
Book = mStates.top ().mBook;
Page = mStates.top ().mPage;
relPages = Book->pageCount () - Page;
}
else
{
Page = 0;
relPages = 0;
}
setVisible (PrevPageBTN, Page > 0);
setVisible (NextPageBTN, relPages > 2);
setVisible (PageOneNum, relPages > 0);
setVisible (PageTwoNum, relPages > 1);
getPage (LeftBookPage)->showPage ((relPages > 0) ? Book : book (), Page+0);
getPage (RightBookPage)->showPage ((relPages > 0) ? Book : book (), Page+1);
setText (PageOneNum, Page + 1);
setText (PageTwoNum, Page + 2);
}
void notifyTopicClicked (intptr_t linkId)
{
auto topicBook = createTopicBook (linkId);
if (mStates.size () > 1)
replaceBook (topicBook, 0);
else
pushBook (topicBook, 0);
setVisible (OptionsOverlay, false);
setVisible (OptionsBTN, true);
setVisible (JournalBTN, true);
}
void notifyQuestClicked (intptr_t questId)
{
auto Book = createQuestBook (questId);
if (mStates.size () > 1)
replaceBook (Book, 0);
else
pushBook (Book, 0);
setVisible (OptionsOverlay, false);
setVisible (OptionsBTN, true);
setVisible (JournalBTN, true);
}
void notifyOptions(Widget* _sender)
{
setOptionsMode ();
if (!mTopicIndexBook)
mTopicIndexBook = createTopicIndexBook ();
getPage (LeftTopicIndex)->showPage (mTopicIndexBook, 0);
getPage (RightTopicIndex)->showPage (mTopicIndexBook, 1);
}
void notifyJournal(Widget* _sender)
{
assert (mStates.size () > 1);
popBook ();
}
void showList (char const * ListId, char const * PageId, book book)
{
auto size = book->getSize ();
getPage (PageId)->showPage (book, 0);
getWidget <ScrollView> (ListId)->setCanvasSize (size.first, size.second);
}
void notifyIndexLinkClicked (ITypesetBook::interactive_id character)
{
setVisible (LeftTopicIndex, false);
setVisible (RightTopicIndex, false);
setVisible (TopicsList, true);
showList (TopicsList, TopicsPage, createTopicIndexBook ((char)character));
}
void notifyTopics(Widget* _sender)
{
mQuestMode = false;
setVisible (LeftTopicIndex, true);
setVisible (RightTopicIndex, true);
setVisible (TopicsList, false);
setVisible (QuestsList, false);
setVisible (ShowAllBTN, false);
setVisible (ShowActiveBTN, false);
}
void notifyQuests(Widget* _sender)
{
mQuestMode = true;
setVisible (LeftTopicIndex, false);
setVisible (RightTopicIndex, false);
setVisible (TopicsList, false);
setVisible (QuestsList, true);
setVisible (ShowAllBTN, !mAllQuests);
setVisible (ShowActiveBTN, mAllQuests);
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
}
void notifyShowAll(Widget* _sender)
{
mAllQuests = true;
setVisible (ShowAllBTN, !mAllQuests);
setVisible (ShowActiveBTN, mAllQuests);
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
}
void notifyShowActive(Widget* _sender)
{
mAllQuests = false;
setVisible (ShowAllBTN, !mAllQuests);
setVisible (ShowActiveBTN, mAllQuests);
showList (QuestsList, QuestsPage, createQuestIndexBook (!mAllQuests));
}
void notifyCancel(Widget* _sender)
{
setBookMode ();
}
void notifyClose(Widget* _sender)
{
MWBase::Environment::get().getWindowManager ()->popGuiMode ();
}
void notifyNextPage(Widget* _sender)
{
if (!mStates.empty ())
{
auto & Page = mStates.top ().mPage;
auto Book = mStates.top ().mBook;
if (Page < Book->pageCount () - 2)
{
Page += 2;
updateShowingPages ();
}
} }
} }
void notifyPrevPage(MyGUI::Widget* _sender) void notifyPrevPage(Widget* _sender)
{ {
if(mPageNumber > 0) if (!mStates.empty ())
{ {
std::string prevSound = "book page"; auto & Page = mStates.top ().mPage;
MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0);
mPageNumber = mPageNumber - 1; if(Page > 0)
displayLeftText(mLeftPages[mPageNumber]); {
displayRightText(mRightPages[mPageNumber]); Page -= 2;
updateShowingPages ();
}
} }
} }
}; };
} }
// glue the implementation to the interface // glue the implementation to the interface
IJournalWindow * MWGui::IJournalWindow::create () { return new JournalWindow (); } IJournalWindow * MWGui::IJournalWindow::create (IJournalViewModel::ptr Model)
{
return new JournalWindow (Model);
}

View file

@ -1,14 +1,18 @@
#ifndef MWGUI_JOURNAL_H #ifndef MWGUI_JOURNAL_H
#define MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H
#include <memory>
namespace MWBase { class WindowManager; } namespace MWBase { class WindowManager; }
namespace MWGui namespace MWGui
{ {
struct IJournalViewModel;
struct IJournalWindow struct IJournalWindow
{ {
/// construct a new instance of the one JournalWindow implementation /// construct a new instance of the one JournalWindow implementation
static IJournalWindow * create (); static IJournalWindow * create (std::shared_ptr <IJournalViewModel> Model);
/// destroy this instance of the JournalWindow implementation /// destroy this instance of the JournalWindow implementation
virtual ~IJournalWindow () {}; virtual ~IJournalWindow () {};

View file

@ -7,6 +7,7 @@
#include "console.hpp" #include "console.hpp"
#include "journalwindow.hpp" #include "journalwindow.hpp"
#include "journalviewmodel.hpp"
#include "charactercreation.hpp" #include "charactercreation.hpp"
#include "dialogue.hpp" #include "dialogue.hpp"
#include "dialoguehistory.hpp" #include "dialoguehistory.hpp"
@ -147,7 +148,7 @@ namespace MWGui
mMap = new MapWindow(cacheDir); mMap = new MapWindow(cacheDir);
mStatsWindow = new StatsWindow(); mStatsWindow = new StatsWindow();
mConsole = new Console(w,h, consoleOnlyScripts); mConsole = new Console(w,h, consoleOnlyScripts);
mJournal = IJournalWindow::create(); mJournal = IJournalWindow::create(IJournalViewModel::create ());
mMessageBoxManager = new MessageBoxManager(); mMessageBoxManager = new MessageBoxManager();
mInventoryWindow = new InventoryWindow(mDragAndDrop); mInventoryWindow = new InventoryWindow(mDragAndDrop);
mTradeWindow = new TradeWindow(); mTradeWindow = new TradeWindow();

View file

@ -22,6 +22,26 @@
</Codes> </Codes>
</Resource> </Resource>
<Resource type="ResourceTrueTypeFont" name="EB Garamond 24">
<Property key="Source" value="EBGaramond-Regular.ttf"/>
<Property key="Size" value="24"/>
<Property key="Resolution" value="72"/>
<Property key="Antialias" value="false"/>
<Property key="TabWidth" value="8"/>
<Property key="OffsetHeight" value="0"/>
<Codes>
<Code range="33 126"/>
<Code range="192 382"/> <!-- Central and Eastern European languages glyphs -->
<Code range="1025 1105"/>
<Code range="8470"/>
<Code range="8211"/> <!-- Minus -->
<Code range="8216 8217"/> <!-- Single quotes -->
<Code range="8220 8221"/> <!-- Right and Left Double Quotation mark -->
<Code hide="128"/>
<Code hide="1026 1039"/>
<Code hide="1104"/>
</Codes>
</Resource>
<Resource type="ResourceTrueTypeFont" name="Daedric"> <Resource type="ResourceTrueTypeFont" name="Daedric">
<!--<Property key="Source" value="Oblivion/Oblivion Worn.ttf"/>--> <!--<Property key="Source" value="Oblivion/Oblivion Worn.ttf"/>-->
<Property key="Source" value="Oblivion/Oblivion.ttf"/> <Property key="Source" value="Oblivion/Oblivion.ttf"/>

View file

@ -47,8 +47,8 @@
<!-- text pages --> <!-- text pages -->
<Widget type="EditBox" skin="MW_BookPage" position="30 22 240 300" name="LeftText"/> <Widget type="BookPage" skin="MW_BookPage" position="30 22 240 300" name="LeftBookPage"/>
<Widget type="EditBox" skin="MW_BookPage" position="300 22 240 300" name="RightText"/> <Widget type="BookPage" skin="MW_BookPage" position="300 22 240 300" name="RightBookPage"/>
<!-- options overlay --> <!-- options overlay -->
@ -59,6 +59,33 @@
<Property key="ImageTexture" value="textures\tx_menubook_bookmark.dds"/> <Property key="ImageTexture" value="textures\tx_menubook_bookmark.dds"/>
<Property key="ImageCoord" value="0 0 164 256"/> <Property key="ImageCoord" value="0 0 164 256"/>
<Widget type="BookPage" skin="MW_BookPage" position="20 15 92 250" name="LeftTopicIndex"/>
<Widget type="BookPage" skin="MW_BookPage" position="112 15 92 250" name="RightTopicIndex"/>
<Widget type="ScrollView" skin="MW_ScrollView" position="20 15 184 245" name="TopicsList" align="Right VStretch">
<Property key="CanvasAlign" value="Left Top"/>
<Widget type="BookPage" skin="MW_BookPage" position="0 0 30000 30000" name="TopicsPage"/>
</Widget>
<Widget type="ScrollView" skin="MW_ScrollView" position="20 35 184 245" 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>
<Widget type="ImageButton" skin="ImageBox" position="62 15 100 20" Align="Top|Left" name="ShowActiveBTN">
<Property key="ImageCoord" value="0 0 100 20"/>
<Property key="ImageHighlighted" value="textures\tx_menubook_quests_active_over.dds"/>
<Property key="ImageNormal" value="textures\tx_menubook_quests_active_idle.dds"/>
<Property key="ImagePushed" value="textures\tx_menubook_quests_active_pressed.dds"/>
</Widget>
<Widget type="ImageButton" skin="ImageBox" position="76 15 72 20" Align="Top|Left" name="ShowAllBTN">
<Property key="ImageCoord" value="0 0 72 20"/>
<Property key="ImageHighlighted" value="textures\tx_menubook_quests_all_over.dds"/>
<Property key="ImageNormal" value="textures\tx_menubook_quests_all_idle.dds"/>
<Property key="ImagePushed" value="textures\tx_menubook_quests_all_pressed.dds"/>
</Widget>
<Widget type="ImageButton" skin="ImageBox" position="40 265 56 32" Align="Top|Left" name="TopicsBTN"> <Widget type="ImageButton" skin="ImageBox" position="40 265 56 32" Align="Top|Left" name="TopicsBTN">
<Property key="ImageCoord" value="0 0 56 32"/> <Property key="ImageCoord" value="0 0 56 32"/>
<Property key="ImageHighlighted" value="textures\tx_menubook_topics_over.dds"/> <Property key="ImageHighlighted" value="textures\tx_menubook_topics_over.dds"/>

View file

@ -10,8 +10,6 @@
</Skin> </Skin>
<Skin name="MW_BookPage" size="0 0 50 50"> <Skin name="MW_BookPage" size="0 0 50 50">
<Property key="WordWrap" value = "true" /> <BasisSkin type="PageDisplay"/>
<Child type="TextBox" skin="MW_BookClient" offset="0 0 35 10" align = "ALIGN_STRETCH" name = "Client"/>
<!--Child type="ScrollBar" skin="VScroll" offset = "35 0 15 50" align = "Right VStretch" name = "VScroll"/-->
</Skin> </Skin>
</MyGUI> </MyGUI>