mirror of
https://github.com/OpenMW/openmw.git
synced 2025-11-28 15:34:29 +00:00
Reduce type conversions in books
This commit is contained in:
parent
5308e22f6d
commit
b15ae08a07
9 changed files with 303 additions and 342 deletions
|
|
@ -113,10 +113,7 @@ namespace MWGui
|
||||||
|
|
||||||
struct TypesetBookImpl : TypesetBook
|
struct TypesetBookImpl : TypesetBook
|
||||||
{
|
{
|
||||||
typedef std::vector<uint8_t> Content;
|
typedef std::pair<Utf8Stream::Point, Utf8Stream::Point> Range;
|
||||||
typedef std::list<Content> Contents;
|
|
||||||
typedef Utf8Stream::Point Utf8Point;
|
|
||||||
typedef std::pair<Utf8Point, Utf8Point> Range;
|
|
||||||
|
|
||||||
struct StyleImpl : BookTypesetter::Style
|
struct StyleImpl : BookTypesetter::Style
|
||||||
{
|
{
|
||||||
|
|
@ -127,29 +124,28 @@ namespace MWGui
|
||||||
InteractiveId mInteractiveId;
|
InteractiveId mInteractiveId;
|
||||||
|
|
||||||
bool match(MyGUI::IFont* tstFont, const MyGUI::Colour& tstHotColour, const MyGUI::Colour& tstActiveColour,
|
bool match(MyGUI::IFont* tstFont, const MyGUI::Colour& tstHotColour, const MyGUI::Colour& tstActiveColour,
|
||||||
const MyGUI::Colour& tstNormalColour, intptr_t tstInteractiveId)
|
const MyGUI::Colour& tstNormalColour, InteractiveId tstInteractiveId) const
|
||||||
{
|
{
|
||||||
return (mFont == tstFont)
|
return (mFont == tstFont)
|
||||||
&& partal_match(tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId);
|
&& partialMatch(tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(std::string_view tstFont, const MyGUI::Colour& tstHotColour,
|
bool match(std::string_view tstFont, const MyGUI::Colour& tstHotColour,
|
||||||
const MyGUI::Colour& tstActiveColour, const MyGUI::Colour& tstNormalColour, intptr_t tstInteractiveId)
|
const MyGUI::Colour& tstActiveColour, const MyGUI::Colour& tstNormalColour,
|
||||||
|
InteractiveId tstInteractiveId) const
|
||||||
{
|
{
|
||||||
return (mFont->getResourceName() == tstFont)
|
return (mFont->getResourceName() == tstFont)
|
||||||
&& partal_match(tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId);
|
&& partialMatch(tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool partal_match(const MyGUI::Colour& tstHotColour, const MyGUI::Colour& tstActiveColour,
|
bool partialMatch(const MyGUI::Colour& tstHotColour, const MyGUI::Colour& tstActiveColour,
|
||||||
const MyGUI::Colour& tstNormalColour, intptr_t tstInteractiveId)
|
const MyGUI::Colour& tstNormalColour, InteractiveId tstInteractiveId) const
|
||||||
{
|
{
|
||||||
return (mHotColour == tstHotColour) && (mActiveColour == tstActiveColour)
|
return (mHotColour == tstHotColour) && (mActiveColour == tstActiveColour)
|
||||||
&& (mNormalColour == tstNormalColour) && (mInteractiveId == tstInteractiveId);
|
&& (mNormalColour == tstNormalColour) && (mInteractiveId == tstInteractiveId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list<StyleImpl> Styles;
|
|
||||||
|
|
||||||
struct Run
|
struct Run
|
||||||
{
|
{
|
||||||
StyleImpl* mStyle;
|
StyleImpl* mStyle;
|
||||||
|
|
@ -158,19 +154,15 @@ namespace MWGui
|
||||||
int mPrintableChars;
|
int mPrintableChars;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Run> Runs;
|
|
||||||
|
|
||||||
struct Line
|
struct Line
|
||||||
{
|
{
|
||||||
Runs mRuns;
|
std::vector<Run> mRuns;
|
||||||
MyGUI::IntRect mRect;
|
MyGUI::IntRect mRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Line> Lines;
|
|
||||||
|
|
||||||
struct Section
|
struct Section
|
||||||
{
|
{
|
||||||
Lines mLines;
|
std::vector<Line> mLines;
|
||||||
MyGUI::IntRect mRect;
|
MyGUI::IntRect mRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -180,12 +172,10 @@ namespace MWGui
|
||||||
// A page is basically a "window" into a portion of the source text, similar to a ScrollView.
|
// A page is basically a "window" into a portion of the source text, similar to a ScrollView.
|
||||||
typedef std::pair<int, int> Page;
|
typedef std::pair<int, int> Page;
|
||||||
|
|
||||||
typedef std::vector<Page> Pages;
|
std::vector<Page> mPages;
|
||||||
|
|
||||||
Pages mPages;
|
|
||||||
Sections mSections;
|
Sections mSections;
|
||||||
Contents mContents;
|
std::list<Content> mContents;
|
||||||
Styles mStyles;
|
std::list<StyleImpl> mStyles;
|
||||||
MyGUI::IntRect mRect;
|
MyGUI::IntRect mRect;
|
||||||
|
|
||||||
void setColour(size_t section, size_t line, size_t run, const MyGUI::Colour& colour) const override
|
void setColour(size_t section, size_t line, size_t run, const MyGUI::Colour& colour) const override
|
||||||
|
|
@ -202,14 +192,14 @@ namespace MWGui
|
||||||
|
|
||||||
virtual ~TypesetBookImpl() = default;
|
virtual ~TypesetBookImpl() = default;
|
||||||
|
|
||||||
Range addContent(const BookTypesetter::Utf8Span& text)
|
Range addContent(std::string_view text)
|
||||||
{
|
{
|
||||||
Contents::iterator i = mContents.insert(mContents.end(), Content(text.first, text.second));
|
Content& content = mContents.emplace_back(text.begin(), text.end());
|
||||||
|
|
||||||
if (i->empty())
|
if (content.empty())
|
||||||
return Range(Utf8Point(nullptr), Utf8Point(nullptr));
|
return Range(nullptr, nullptr);
|
||||||
|
|
||||||
return Range(i->data(), i->data() + i->size());
|
return Range(content.data(), content.data() + content.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pageCount() const override { return mPages.size(); }
|
size_t pageCount() const override { return mPages.size(); }
|
||||||
|
|
@ -222,19 +212,19 @@ namespace MWGui
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
void visitRuns(int top, int bottom, MyGUI::IFont* font, Visitor const& visitor) const
|
void visitRuns(int top, int bottom, MyGUI::IFont* font, Visitor const& visitor) const
|
||||||
{
|
{
|
||||||
for (Sections::const_iterator i = mSections.begin(); i != mSections.end(); ++i)
|
for (const Section& section : mSections)
|
||||||
{
|
{
|
||||||
if (top >= mRect.bottom || bottom <= i->mRect.top)
|
if (top >= mRect.bottom || bottom <= section.mRect.top)
|
||||||
continue;
|
continue;
|
||||||
|
for (const Line& line : section.mLines)
|
||||||
for (Lines::const_iterator j = i->mLines.begin(); j != i->mLines.end(); ++j)
|
|
||||||
{
|
{
|
||||||
if (top >= j->mRect.bottom || bottom <= j->mRect.top)
|
if (top >= line.mRect.bottom || bottom <= line.mRect.top)
|
||||||
continue;
|
continue;
|
||||||
|
for (const Run& run : line.mRuns)
|
||||||
for (Runs::const_iterator k = j->mRuns.begin(); k != j->mRuns.end(); ++k)
|
{
|
||||||
if (!font || k->mStyle->mFont == font)
|
if (!font || run.mStyle->mFont == font)
|
||||||
visitor(*i, *j, *k);
|
visitor(section, line, run);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -275,26 +265,26 @@ namespace MWGui
|
||||||
|
|
||||||
StyleImpl* hitTest(int left, int top) const
|
StyleImpl* hitTest(int left, int top) const
|
||||||
{
|
{
|
||||||
for (Sections::const_iterator i = mSections.begin(); i != mSections.end(); ++i)
|
for (const Section& section : mSections)
|
||||||
{
|
{
|
||||||
if (top < i->mRect.top || top >= i->mRect.bottom)
|
if (top < section.mRect.top || top >= section.mRect.bottom)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int left1 = left - i->mRect.left;
|
int left1 = left - section.mRect.left;
|
||||||
|
|
||||||
for (Lines::const_iterator j = i->mLines.begin(); j != i->mLines.end(); ++j)
|
for (const Line& line : section.mLines)
|
||||||
{
|
{
|
||||||
if (top < j->mRect.top || top >= j->mRect.bottom)
|
if (top < line.mRect.top || top >= line.mRect.bottom)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int left2 = left1 - j->mRect.left;
|
int left2 = left1 - line.mRect.left;
|
||||||
|
|
||||||
for (Runs::const_iterator k = j->mRuns.begin(); k != j->mRuns.end(); ++k)
|
for (const Run& run : line.mRuns)
|
||||||
{
|
{
|
||||||
if (left2 < k->mLeft || left2 >= k->mRight)
|
if (left2 < run.mLeft || left2 >= run.mRight)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return k->mStyle;
|
return run.mStyle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,9 +294,9 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::IFont* affectedFont(StyleImpl* style)
|
MyGUI::IFont* affectedFont(StyleImpl* style)
|
||||||
{
|
{
|
||||||
for (Styles::iterator i = mStyles.begin(); i != mStyles.end(); ++i)
|
for (const StyleImpl& s : mStyles)
|
||||||
if (&*i == style)
|
if (&s == style)
|
||||||
return i->mFont;
|
return s.mFont;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,14 +321,10 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TypesetBookImpl Book;
|
|
||||||
typedef std::shared_ptr<Book> BookPtr;
|
|
||||||
typedef std::vector<PartialText>::const_iterator PartialTextConstIterator;
|
|
||||||
|
|
||||||
int mPageWidth;
|
int mPageWidth;
|
||||||
int mPageHeight;
|
int mPageHeight;
|
||||||
|
|
||||||
BookPtr mBook;
|
std::shared_ptr<TypesetBookImpl> mBook;
|
||||||
Section* mSection;
|
Section* mSection;
|
||||||
Line* mLine;
|
Line* mLine;
|
||||||
Run* mRun;
|
Run* mRun;
|
||||||
|
|
@ -347,7 +333,7 @@ namespace MWGui
|
||||||
std::vector<PartialText> mPartialWhitespace;
|
std::vector<PartialText> mPartialWhitespace;
|
||||||
std::vector<PartialText> mPartialWord;
|
std::vector<PartialText> mPartialWord;
|
||||||
|
|
||||||
Book::Content const* mCurrentContent;
|
TypesetBookImpl::Content const* mCurrentContent;
|
||||||
Alignment mCurrentAlignment;
|
Alignment mCurrentAlignment;
|
||||||
|
|
||||||
Typesetter(int width, int height)
|
Typesetter(int width, int height)
|
||||||
|
|
@ -359,12 +345,12 @@ namespace MWGui
|
||||||
, mCurrentContent(nullptr)
|
, mCurrentContent(nullptr)
|
||||||
, mCurrentAlignment(AlignLeft)
|
, mCurrentAlignment(AlignLeft)
|
||||||
{
|
{
|
||||||
mBook = std::make_shared<Book>();
|
mBook = std::make_shared<TypesetBookImpl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Typesetter() = default;
|
virtual ~Typesetter() = default;
|
||||||
|
|
||||||
Style* createStyle(const std::string& fontName, const Colour& fontColour, bool useBookFont) override
|
Style* createStyle(const std::string& fontName, const MyGUI::Colour& fontColour, bool useBookFont) override
|
||||||
{
|
{
|
||||||
std::string fullFontName;
|
std::string fullFontName;
|
||||||
if (fontName.empty())
|
if (fontName.empty())
|
||||||
|
|
@ -375,9 +361,9 @@ namespace MWGui
|
||||||
if (useBookFont)
|
if (useBookFont)
|
||||||
fullFontName = "Journalbook " + fullFontName;
|
fullFontName = "Journalbook " + fullFontName;
|
||||||
|
|
||||||
for (Styles::iterator i = mBook->mStyles.begin(); i != mBook->mStyles.end(); ++i)
|
for (StyleImpl& style : mBook->mStyles)
|
||||||
if (i->match(fullFontName, fontColour, fontColour, fontColour, 0))
|
if (style.match(fullFontName, fontColour, fontColour, fontColour, 0))
|
||||||
return &*i;
|
return &style;
|
||||||
|
|
||||||
MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(fullFontName);
|
MyGUI::IFont* font = MyGUI::FontManager::getInstance().getByName(fullFontName);
|
||||||
if (!font)
|
if (!font)
|
||||||
|
|
@ -393,15 +379,15 @@ namespace MWGui
|
||||||
return &style;
|
return &style;
|
||||||
}
|
}
|
||||||
|
|
||||||
Style* createHotStyle(Style* baseStyle, const Colour& normalColour, const Colour& hoverColour,
|
Style* createHotStyle(Style* baseStyle, const MyGUI::Colour& normalColour, const MyGUI::Colour& hoverColour,
|
||||||
const Colour& activeColour, InteractiveId id, bool unique) override
|
const MyGUI::Colour& activeColour, InteractiveId id, bool unique) override
|
||||||
{
|
{
|
||||||
StyleImpl* const baseStyleImpl = static_cast<StyleImpl*>(baseStyle);
|
StyleImpl* const baseStyleImpl = static_cast<StyleImpl*>(baseStyle);
|
||||||
|
|
||||||
if (!unique)
|
if (!unique)
|
||||||
for (Styles::iterator i = mBook->mStyles.begin(); i != mBook->mStyles.end(); ++i)
|
for (StyleImpl& style : mBook->mStyles)
|
||||||
if (i->match(baseStyleImpl->mFont, hoverColour, activeColour, normalColour, id))
|
if (style.match(baseStyleImpl->mFont, hoverColour, activeColour, normalColour, id))
|
||||||
return &*i;
|
return &style;
|
||||||
|
|
||||||
StyleImpl& style = *mBook->mStyles.insert(mBook->mStyles.end(), StyleImpl());
|
StyleImpl& style = *mBook->mStyles.insert(mBook->mStyles.end(), StyleImpl());
|
||||||
|
|
||||||
|
|
@ -414,30 +400,30 @@ namespace MWGui
|
||||||
return &style;
|
return &style;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(Style* style, Utf8Span text) override
|
void write(Style* style, std::string_view text) override
|
||||||
{
|
{
|
||||||
Range range = mBook->addContent(text);
|
Range range = mBook->addContent(text);
|
||||||
|
|
||||||
writeImpl(static_cast<StyleImpl*>(style), range.first, range.second);
|
writeImpl(static_cast<StyleImpl*>(style), Utf8Stream(range.first, range.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t addContent(Utf8Span text, bool select) override
|
const Content* addContent(std::string_view text, bool select) override
|
||||||
{
|
{
|
||||||
add_partial_text();
|
add_partial_text();
|
||||||
|
|
||||||
Contents::iterator i = mBook->mContents.insert(mBook->mContents.end(), Content(text.first, text.second));
|
Content& content = mBook->mContents.emplace_back(text.begin(), text.end());
|
||||||
|
|
||||||
if (select)
|
if (select)
|
||||||
mCurrentContent = &(*i);
|
mCurrentContent = &content;
|
||||||
|
|
||||||
return reinterpret_cast<intptr_t>(&(*i));
|
return &content;
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectContent(intptr_t contentHandle) override
|
void selectContent(const Content* contentHandle) override
|
||||||
{
|
{
|
||||||
add_partial_text();
|
add_partial_text();
|
||||||
|
|
||||||
mCurrentContent = reinterpret_cast<Content const*>(contentHandle);
|
mCurrentContent = contentHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(Style* style, size_t begin, size_t end) override
|
void write(Style* style, size_t begin, size_t end) override
|
||||||
|
|
@ -446,10 +432,10 @@ namespace MWGui
|
||||||
assert(end <= mCurrentContent->size());
|
assert(end <= mCurrentContent->size());
|
||||||
assert(begin <= mCurrentContent->size());
|
assert(begin <= mCurrentContent->size());
|
||||||
|
|
||||||
const Utf8Point contentBegin = mCurrentContent->data() + begin;
|
const Utf8Stream::Point contentBegin = mCurrentContent->data() + begin;
|
||||||
const Utf8Point contentEnd = mCurrentContent->data() + end;
|
const Utf8Stream::Point contentEnd = mCurrentContent->data() + end;
|
||||||
|
|
||||||
writeImpl(static_cast<StyleImpl*>(style), contentBegin, contentEnd);
|
writeImpl(static_cast<StyleImpl*>(style), Utf8Stream(contentBegin, contentEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lineBreak(float margin) override
|
void lineBreak(float margin) override
|
||||||
|
|
@ -486,7 +472,7 @@ namespace MWGui
|
||||||
mCurrentAlignment = sectionAlignment;
|
mCurrentAlignment = sectionAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypesetBook::Ptr complete() override
|
std::shared_ptr<TypesetBook> complete() override
|
||||||
{
|
{
|
||||||
int curPageStart = 0;
|
int curPageStart = 0;
|
||||||
int curPageStop = 0;
|
int curPageStop = 0;
|
||||||
|
|
@ -497,26 +483,26 @@ namespace MWGui
|
||||||
for (Sections::iterator i = mBook->mSections.begin(); i != mBook->mSections.end(); ++i, ++sa)
|
for (Sections::iterator i = mBook->mSections.begin(); i != mBook->mSections.end(); ++i, ++sa)
|
||||||
{
|
{
|
||||||
// apply alignment to individual lines...
|
// apply alignment to individual lines...
|
||||||
for (Lines::iterator j = i->mLines.begin(); j != i->mLines.end(); ++j)
|
for (Line& line : i->mLines)
|
||||||
{
|
{
|
||||||
int width = j->mRect.width();
|
int width = line.mRect.width();
|
||||||
int excess = mPageWidth - width;
|
int excess = mPageWidth - width;
|
||||||
|
|
||||||
switch (*sa)
|
switch (*sa)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case AlignLeft:
|
case AlignLeft:
|
||||||
j->mRect.left = 0;
|
line.mRect.left = 0;
|
||||||
break;
|
break;
|
||||||
case AlignCenter:
|
case AlignCenter:
|
||||||
j->mRect.left = excess / 2;
|
line.mRect.left = excess / 2;
|
||||||
break;
|
break;
|
||||||
case AlignRight:
|
case AlignRight:
|
||||||
j->mRect.left = excess;
|
line.mRect.left = excess;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
j->mRect.right = j->mRect.left + width;
|
line.mRect.right = line.mRect.left + width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curPageStop == curPageStart)
|
if (curPageStop == curPageStart)
|
||||||
|
|
@ -541,7 +527,7 @@ namespace MWGui
|
||||||
// one.
|
// one.
|
||||||
assert(curPageStart != curPageStop);
|
assert(curPageStart != curPageStop);
|
||||||
|
|
||||||
mBook->mPages.push_back(Page(curPageStart, curPageStop));
|
mBook->mPages.emplace_back(curPageStart, curPageStop);
|
||||||
|
|
||||||
curPageStart = i->mRect.top;
|
curPageStart = i->mRect.top;
|
||||||
curPageStop = i->mRect.bottom;
|
curPageStop = i->mRect.bottom;
|
||||||
|
|
@ -553,7 +539,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// The section won't completely fit on the current page. Finish the current page and start a new
|
// The section won't completely fit on the current page. Finish the current page and start a new
|
||||||
// one.
|
// one.
|
||||||
mBook->mPages.push_back(Page(curPageStart, curPageStop));
|
mBook->mPages.emplace_back(curPageStart, curPageStop);
|
||||||
|
|
||||||
curPageStart = i->mRect.top;
|
curPageStart = i->mRect.top;
|
||||||
curPageStop = i->mRect.bottom;
|
curPageStop = i->mRect.bottom;
|
||||||
|
|
@ -564,16 +550,16 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// Adjust to the top of the first line that does not fit on the current page anymore
|
// Adjust to the top of the first line that does not fit on the current page anymore
|
||||||
int splitPos = curPageStop;
|
int splitPos = curPageStop;
|
||||||
for (Lines::iterator j = i->mLines.begin(); j != i->mLines.end(); ++j)
|
for (const Line& line : i->mLines)
|
||||||
{
|
{
|
||||||
if (j->mRect.bottom > curPageStart + mPageHeight)
|
if (line.mRect.bottom > curPageStart + mPageHeight)
|
||||||
{
|
{
|
||||||
splitPos = j->mRect.top;
|
splitPos = line.mRect.top;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mBook->mPages.push_back(Page(curPageStart, splitPos));
|
mBook->mPages.emplace_back(curPageStart, splitPos);
|
||||||
curPageStart = splitPos;
|
curPageStart = splitPos;
|
||||||
curPageStop = splitPos;
|
curPageStop = splitPos;
|
||||||
|
|
||||||
|
|
@ -584,15 +570,13 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curPageStart != curPageStop)
|
if (curPageStart != curPageStop)
|
||||||
mBook->mPages.push_back(Page(curPageStart, curPageStop));
|
mBook->mPages.emplace_back(curPageStart, curPageStop);
|
||||||
|
|
||||||
return mBook;
|
return mBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeImpl(StyleImpl* style, Utf8Stream::Point begin, Utf8Stream::Point end)
|
void writeImpl(StyleImpl* style, Utf8Stream&& stream)
|
||||||
{
|
{
|
||||||
Utf8Stream stream(begin, end);
|
|
||||||
|
|
||||||
while (!stream.eof())
|
while (!stream.eof())
|
||||||
{
|
{
|
||||||
if (ucsLineBreak(stream.peek()))
|
if (ucsLineBreak(stream.peek()))
|
||||||
|
|
@ -651,10 +635,10 @@ namespace MWGui
|
||||||
int spaceWidth = 0;
|
int spaceWidth = 0;
|
||||||
int wordWidth = 0;
|
int wordWidth = 0;
|
||||||
|
|
||||||
for (PartialTextConstIterator i = mPartialWhitespace.begin(); i != mPartialWhitespace.end(); ++i)
|
for (const PartialText& partialText : mPartialWhitespace)
|
||||||
spaceWidth += i->mWidth;
|
spaceWidth += partialText.mWidth;
|
||||||
for (PartialTextConstIterator i = mPartialWord.begin(); i != mPartialWord.end(); ++i)
|
for (const PartialText& partialText : mPartialWord)
|
||||||
wordWidth += i->mWidth;
|
wordWidth += partialText.mWidth;
|
||||||
|
|
||||||
int left = mLine ? mLine->mRect.right : 0;
|
int left = mLine ? mLine->mRect.right : 0;
|
||||||
|
|
||||||
|
|
@ -666,21 +650,23 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (PartialTextConstIterator i = mPartialWhitespace.begin(); i != mPartialWhitespace.end(); ++i)
|
for (const PartialText& partialText : mPartialWhitespace)
|
||||||
{
|
{
|
||||||
int top = mLine ? mLine->mRect.top : mBook->mRect.bottom;
|
int top = mLine ? mLine->mRect.top : mBook->mRect.bottom;
|
||||||
|
|
||||||
appendRun(i->mStyle, i->mBegin, i->mEnd, 0, left + i->mWidth, top + fontHeight);
|
appendRun(partialText.mStyle, partialText.mBegin, partialText.mEnd, 0, left + partialText.mWidth,
|
||||||
|
top + fontHeight);
|
||||||
|
|
||||||
left = mLine->mRect.right;
|
left = mLine->mRect.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PartialTextConstIterator i = mPartialWord.begin(); i != mPartialWord.end(); ++i)
|
for (const PartialText& partialText : mPartialWord)
|
||||||
{
|
{
|
||||||
int top = mLine ? mLine->mRect.top : mBook->mRect.bottom;
|
int top = mLine ? mLine->mRect.top : mBook->mRect.bottom;
|
||||||
const int numChars = static_cast<int>(i->mEnd - i->mBegin);
|
const int numChars = static_cast<int>(partialText.mEnd - partialText.mBegin);
|
||||||
appendRun(i->mStyle, i->mBegin, i->mEnd, numChars, left + i->mWidth, top + fontHeight);
|
appendRun(partialText.mStyle, partialText.mBegin, partialText.mEnd, numChars, left + partialText.mWidth,
|
||||||
|
top + fontHeight);
|
||||||
|
|
||||||
left = mLine->mRect.right;
|
left = mLine->mRect.right;
|
||||||
}
|
}
|
||||||
|
|
@ -747,7 +733,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BookTypesetter::Ptr BookTypesetter::create(int pageWidth, int pageHeight)
|
std::shared_ptr<BookTypesetter> BookTypesetter::create(int pageWidth, int pageHeight)
|
||||||
{
|
{
|
||||||
return std::make_shared<TypesetBookImpl::Typesetter>(pageWidth, pageHeight);
|
return std::make_shared<TypesetBookImpl::Typesetter>(pageWidth, pageHeight);
|
||||||
}
|
}
|
||||||
|
|
@ -932,17 +918,12 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MYGUI_RTTI_DERIVED(PageDisplay)
|
MYGUI_RTTI_DERIVED(PageDisplay)
|
||||||
protected:
|
protected:
|
||||||
typedef TypesetBookImpl::Section Section;
|
|
||||||
typedef TypesetBookImpl::Line Line;
|
|
||||||
typedef TypesetBookImpl::Run Run;
|
|
||||||
bool mIsPageReset;
|
bool mIsPageReset;
|
||||||
size_t mPage;
|
size_t mPage;
|
||||||
|
|
||||||
struct TextFormat : ISubWidget
|
struct TextFormat : ISubWidget
|
||||||
{
|
{
|
||||||
typedef MyGUI::IFont* Id;
|
MyGUI::IFont* mFont;
|
||||||
|
|
||||||
Id mFont;
|
|
||||||
int mCountVertex;
|
int mCountVertex;
|
||||||
MyGUI::ITexture* mTexture;
|
MyGUI::ITexture* mTexture;
|
||||||
MyGUI::RenderItem* mRenderItem;
|
MyGUI::RenderItem* mRenderItem;
|
||||||
|
|
@ -1017,16 +998,15 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef TypesetBookImpl::StyleImpl Style;
|
typedef std::map<MyGUI::IFont*, std::unique_ptr<TextFormat>> ActiveTextFormats;
|
||||||
typedef std::map<TextFormat::Id, std::unique_ptr<TextFormat>> ActiveTextFormats;
|
|
||||||
|
|
||||||
int mViewTop;
|
int mViewTop;
|
||||||
int mViewBottom;
|
int mViewBottom;
|
||||||
|
|
||||||
Style* mFocusItem;
|
TypesetBookImpl::StyleImpl* mFocusItem;
|
||||||
bool mItemActive;
|
bool mItemActive;
|
||||||
MyGUI::MouseButton mLastDown;
|
MyGUI::MouseButton mLastDown;
|
||||||
std::function<void(intptr_t)> mLinkClicked;
|
std::function<void(TypesetBook::InteractiveId)> mLinkClicked;
|
||||||
|
|
||||||
std::shared_ptr<TypesetBookImpl> mBook;
|
std::shared_ptr<TypesetBookImpl> mBook;
|
||||||
|
|
||||||
|
|
@ -1072,7 +1052,7 @@ namespace MWGui
|
||||||
|
|
||||||
void onMouseMove(int left, int top)
|
void onMouseMove(int left, int top)
|
||||||
{
|
{
|
||||||
Style* hit = nullptr;
|
TypesetBookImpl::StyleImpl* hit = nullptr;
|
||||||
if (auto pos = getAdjustedPos(left, top, true))
|
if (auto pos = getAdjustedPos(left, top, true))
|
||||||
if (pos->top <= mViewBottom)
|
if (pos->top <= mViewBottom)
|
||||||
hit = mBook->hitTestWithMargin(pos->left, pos->top);
|
hit = mBook->hitTestWithMargin(pos->left, pos->top);
|
||||||
|
|
@ -1123,7 +1103,8 @@ namespace MWGui
|
||||||
|
|
||||||
if (pos && mLastDown == id)
|
if (pos && mLastDown == id)
|
||||||
{
|
{
|
||||||
Style* item = pos->top <= mViewBottom ? mBook->hitTestWithMargin(pos->left, pos->top) : nullptr;
|
TypesetBookImpl::StyleImpl* item
|
||||||
|
= pos->top <= mViewBottom ? mBook->hitTestWithMargin(pos->left, pos->top) : nullptr;
|
||||||
|
|
||||||
bool clicked = mFocusItem == item;
|
bool clicked = mFocusItem == item;
|
||||||
|
|
||||||
|
|
@ -1138,7 +1119,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void showPage(TypesetBook::Ptr book, size_t newPage)
|
void showPage(std::shared_ptr<TypesetBook> book, size_t newPage)
|
||||||
{
|
{
|
||||||
std::shared_ptr<TypesetBookImpl> newBook = std::dynamic_pointer_cast<TypesetBookImpl>(book);
|
std::shared_ptr<TypesetBookImpl> newBook = std::dynamic_pointer_cast<TypesetBookImpl>(book);
|
||||||
|
|
||||||
|
|
@ -1212,7 +1193,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(Section const& section, Line const& line, Run const& run) const
|
void operator()(const TypesetBookImpl::Section& section, const TypesetBookImpl::Line& line,
|
||||||
|
const TypesetBookImpl::Run& run) const
|
||||||
{
|
{
|
||||||
MyGUI::IFont* const font = run.mStyle->mFont;
|
MyGUI::IFont* const font = run.mStyle->mFont;
|
||||||
|
|
||||||
|
|
@ -1281,7 +1263,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(Section const& section, Line const& line, Run const& run) const
|
void operator()(const TypesetBookImpl::Section& section, const TypesetBookImpl::Line& line,
|
||||||
|
const TypesetBookImpl::Run& run) const
|
||||||
{
|
{
|
||||||
bool isActive = run.mStyle->mInteractiveId && (run.mStyle == mPageDisplay->mFocusItem);
|
bool isActive = run.mStyle->mInteractiveId && (run.mStyle == mPageDisplay->mFocusItem);
|
||||||
|
|
||||||
|
|
@ -1374,14 +1357,20 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void showPage(TypesetBook::Ptr book, size_t page) override { mPageDisplay->showPage(std::move(book), page); }
|
void showPage(std::shared_ptr<TypesetBook> book, size_t page) override
|
||||||
|
{
|
||||||
|
mPageDisplay->showPage(std::move(book), page);
|
||||||
|
}
|
||||||
|
|
||||||
void adviseLinkClicked(std::function<void(InteractiveId)> linkClicked) override
|
void adviseLinkClicked(std::function<void(TypesetBook::InteractiveId)> linkClicked) override
|
||||||
{
|
{
|
||||||
mPageDisplay->mLinkClicked = std::move(linkClicked);
|
mPageDisplay->mLinkClicked = std::move(linkClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unadviseLinkClicked() override { mPageDisplay->mLinkClicked = std::function<void(InteractiveId)>(); }
|
void unadviseLinkClicked() override
|
||||||
|
{
|
||||||
|
mPageDisplay->mLinkClicked = std::function<void(TypesetBook::InteractiveId)>();
|
||||||
|
}
|
||||||
|
|
||||||
void setFocusItem(BookTypesetter::Style* itemStyle) override
|
void setFocusItem(BookTypesetter::Style* itemStyle) override
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <components/settings/values.hpp>
|
#include <components/settings/values.hpp>
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ namespace MWGui
|
||||||
/// the book page widget.
|
/// the book page widget.
|
||||||
struct TypesetBook
|
struct TypesetBook
|
||||||
{
|
{
|
||||||
typedef std::shared_ptr<TypesetBook> Ptr;
|
using Content = std::vector<uint8_t>;
|
||||||
typedef intptr_t InteractiveId;
|
typedef intptr_t InteractiveId;
|
||||||
|
|
||||||
/// Returns the number of pages in the document.
|
/// Returns the number of pages in the document.
|
||||||
|
|
@ -40,12 +41,6 @@ namespace MWGui
|
||||||
/// A factory class for creating a typeset book instance.
|
/// A factory class for creating a typeset book instance.
|
||||||
struct BookTypesetter
|
struct BookTypesetter
|
||||||
{
|
{
|
||||||
typedef std::shared_ptr<BookTypesetter> Ptr;
|
|
||||||
typedef TypesetBook::InteractiveId InteractiveId;
|
|
||||||
typedef MyGUI::Colour Colour;
|
|
||||||
typedef uint8_t const* Utf8Point;
|
|
||||||
typedef std::pair<Utf8Point, Utf8Point> Utf8Span;
|
|
||||||
|
|
||||||
virtual ~BookTypesetter() = default;
|
virtual ~BookTypesetter() = default;
|
||||||
|
|
||||||
enum Alignment
|
enum Alignment
|
||||||
|
|
@ -62,16 +57,18 @@ namespace MWGui
|
||||||
struct Style;
|
struct Style;
|
||||||
|
|
||||||
/// A factory function for creating the default implementation of a book typesetter
|
/// A factory function for creating the default implementation of a book typesetter
|
||||||
static Ptr create(int pageWidth, int pageHeight);
|
static std::shared_ptr<BookTypesetter> create(int pageWidth, int pageHeight);
|
||||||
|
|
||||||
/// Create a simple text style consisting of a font and a text color.
|
/// Create a simple text style consisting of a font and a text color.
|
||||||
virtual Style* createStyle(const std::string& fontName, const Colour& colour, bool useBookFont = true) = 0;
|
virtual Style* createStyle(const std::string& fontName, const MyGUI::Colour& colour, bool useBookFont = true)
|
||||||
|
= 0;
|
||||||
|
|
||||||
/// Create a hyper-link style with a user-defined identifier based on an
|
/// Create a hyper-link style with a user-defined identifier based on an
|
||||||
/// existing style. The unique flag forces a new instance of this style
|
/// existing style. The unique flag forces a new instance of this style
|
||||||
/// to be created even if an existing instance is present.
|
/// to be created even if an existing instance is present.
|
||||||
virtual Style* createHotStyle(Style* baseStyle, const Colour& normalColour, const Colour& hoverColour,
|
virtual Style* createHotStyle(Style* baseStyle, const MyGUI::Colour& normalColour,
|
||||||
const Colour& activeColour, InteractiveId id, bool unique = true)
|
const MyGUI::Colour& hoverColour, const MyGUI::Colour& activeColour, TypesetBook::InteractiveId id,
|
||||||
|
bool unique = true)
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
/// Insert a line break into the document. Newline characters in the input
|
/// Insert a line break into the document. Newline characters in the input
|
||||||
|
|
@ -89,22 +86,22 @@ namespace MWGui
|
||||||
virtual void setSectionAlignment(Alignment sectionAlignment) = 0;
|
virtual void setSectionAlignment(Alignment sectionAlignment) = 0;
|
||||||
|
|
||||||
// Layout a block of text with the specified style into the document.
|
// Layout a block of text with the specified style into the document.
|
||||||
virtual void write(Style* style, Utf8Span text) = 0;
|
virtual void write(Style* style, std::string_view text) = 0;
|
||||||
|
|
||||||
/// Adds a content block to the document without laying it out. An
|
/// Adds a content block to the document without laying it out. An
|
||||||
/// identifier is returned that can be used to refer to it. If select
|
/// identifier is returned that can be used to refer to it. If select
|
||||||
/// is true, the block is activated to be references by future writes.
|
/// is true, the block is activated to be references by future writes.
|
||||||
virtual intptr_t addContent(Utf8Span text, bool select = true) = 0;
|
virtual const TypesetBook::Content* addContent(std::string_view text, bool select = true) = 0;
|
||||||
|
|
||||||
/// Select a previously created content block for future writes.
|
/// Select a previously created content block for future writes.
|
||||||
virtual void selectContent(intptr_t contentHandle) = 0;
|
virtual void selectContent(const TypesetBook::Content* contentHandle) = 0;
|
||||||
|
|
||||||
/// Layout a span of the selected content block into the document
|
/// Layout a span of the selected content block into the document
|
||||||
/// using the specified style.
|
/// using the specified style.
|
||||||
virtual void write(Style* style, size_t begin, size_t end) = 0;
|
virtual void write(Style* style, size_t begin, size_t end) = 0;
|
||||||
|
|
||||||
/// Finalize the document layout, and return a pointer to it.
|
/// Finalize the document layout, and return a pointer to it.
|
||||||
virtual TypesetBook::Ptr complete() = 0;
|
virtual std::shared_ptr<TypesetBook> complete() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An interface to the BookPage widget.
|
/// An interface to the BookPage widget.
|
||||||
|
|
@ -112,11 +109,10 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MYGUI_RTTI_DERIVED(BookPage)
|
MYGUI_RTTI_DERIVED(BookPage)
|
||||||
public:
|
public:
|
||||||
typedef TypesetBook::InteractiveId InteractiveId;
|
using ClickCallback = std::function<void(TypesetBook::InteractiveId)>;
|
||||||
typedef std::function<void(InteractiveId)> ClickCallback;
|
|
||||||
|
|
||||||
/// Make the widget display the specified page from the specified book.
|
/// Make the widget display the specified page from the specified book.
|
||||||
virtual void showPage(TypesetBook::Ptr book, size_t page) = 0;
|
virtual void showPage(std::shared_ptr<TypesetBook> book, size_t page) = 0;
|
||||||
|
|
||||||
/// Set the callback for a clicking a hyper-link in the document.
|
/// Set the callback for a clicking a hyper-link in the document.
|
||||||
virtual void adviseLinkClicked(ClickCallback callback) = 0;
|
virtual void adviseLinkClicked(ClickCallback callback) = 0;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@
|
||||||
#include "bookpage.hpp"
|
#include "bookpage.hpp"
|
||||||
#include "textcolours.hpp"
|
#include "textcolours.hpp"
|
||||||
|
|
||||||
#include "journalbooks.hpp" // to_utf8_span
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
void ResponseCallback::addResponse(std::string_view title, std::string_view text)
|
void ResponseCallback::addResponse(std::string_view title, std::string_view text)
|
||||||
|
|
@ -208,7 +206,7 @@ namespace MWGui
|
||||||
mText = text;
|
mText = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch,
|
void Response::write(std::shared_ptr<BookTypesetter> typesetter, const TopicSearch& keywordSearch,
|
||||||
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const
|
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const
|
||||||
{
|
{
|
||||||
typesetter->sectionBreak(mNeedMargin ? 9 : 0);
|
typesetter->sectionBreak(mNeedMargin ? 9 : 0);
|
||||||
|
|
@ -218,12 +216,11 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
const MyGUI::Colour& headerColour = windowManager->getTextColours().header;
|
const MyGUI::Colour& headerColour = windowManager->getTextColours().header;
|
||||||
BookTypesetter::Style* title = typesetter->createStyle({}, headerColour, false);
|
BookTypesetter::Style* title = typesetter->createStyle({}, headerColour, false);
|
||||||
typesetter->write(title, to_utf8_span(mTitle));
|
typesetter->write(title, mTitle);
|
||||||
typesetter->sectionBreak();
|
typesetter->sectionBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::pair<size_t, size_t> Range;
|
std::map<std::pair<size_t, size_t>, const Link*> hyperLinks;
|
||||||
std::map<Range, intptr_t> hyperLinks;
|
|
||||||
|
|
||||||
// We need this copy for when @# hyperlinks are replaced
|
// We need this copy for when @# hyperlinks are replaced
|
||||||
std::string text = mText;
|
std::string text = mText;
|
||||||
|
|
@ -250,14 +247,13 @@ namespace MWGui
|
||||||
text.replace(posBegin, posEnd + 1 - posBegin, displayName);
|
text.replace(posBegin, posEnd + 1 - posBegin, displayName);
|
||||||
|
|
||||||
if (topicLinks.find(topicName) != topicLinks.end())
|
if (topicLinks.find(topicName) != topicLinks.end())
|
||||||
hyperLinks[std::make_pair(posBegin, posBegin + displayName.size())]
|
hyperLinks[std::make_pair(posBegin, posBegin + displayName.size())] = topicLinks[topicName].get();
|
||||||
= intptr_t(topicLinks[topicName].get());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
typesetter->addContent(to_utf8_span(text));
|
typesetter->addContent(text);
|
||||||
|
|
||||||
if (hyperLinks.size()
|
if (hyperLinks.size()
|
||||||
&& MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
&& MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
||||||
|
|
@ -266,48 +262,48 @@ namespace MWGui
|
||||||
|
|
||||||
BookTypesetter::Style* style = typesetter->createStyle({}, textColours.normal, false);
|
BookTypesetter::Style* style = typesetter->createStyle({}, textColours.normal, false);
|
||||||
size_t formatted = 0; // points to the first character that is not laid out yet
|
size_t formatted = 0; // points to the first character that is not laid out yet
|
||||||
for (auto& hyperLink : hyperLinks)
|
for (const auto& [range, link] : hyperLinks)
|
||||||
{
|
{
|
||||||
intptr_t topicId = hyperLink.second;
|
BookTypesetter::Style* hotStyle = typesetter->createHotStyle(style, textColours.link,
|
||||||
BookTypesetter::Style* hotStyle = typesetter->createHotStyle(
|
textColours.linkOver, textColours.linkPressed, TypesetBook::InteractiveId(link));
|
||||||
style, textColours.link, textColours.linkOver, textColours.linkPressed, topicId);
|
if (formatted < range.first)
|
||||||
if (formatted < hyperLink.first.first)
|
typesetter->write(style, formatted, range.first);
|
||||||
typesetter->write(style, formatted, hyperLink.first.first);
|
typesetter->write(hotStyle, range.first, range.second);
|
||||||
typesetter->write(hotStyle, hyperLink.first.first, hyperLink.first.second);
|
formatted = range.second;
|
||||||
formatted = hyperLink.first.second;
|
|
||||||
}
|
}
|
||||||
if (formatted < text.size())
|
if (formatted < text.size())
|
||||||
typesetter->write(style, formatted, text.size());
|
typesetter->write(style, formatted, text.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::vector<KeywordSearchT::Match> matches;
|
std::vector<TopicSearch::Match> matches;
|
||||||
keywordSearch->highlightKeywords(text.begin(), text.end(), matches);
|
keywordSearch.highlightKeywords(text.begin(), text.end(), matches);
|
||||||
|
|
||||||
std::string::const_iterator i = text.begin();
|
std::string::const_iterator i = text.begin();
|
||||||
for (KeywordSearchT::Match& match : matches)
|
for (TopicSearch::Match& match : matches)
|
||||||
{
|
{
|
||||||
if (i != match.mBeg)
|
if (i != match.mBeg)
|
||||||
addTopicLink(typesetter, 0, i - text.begin(), match.mBeg - text.begin());
|
addTopicLink(typesetter, nullptr, i - text.begin(), match.mBeg - text.begin());
|
||||||
|
|
||||||
addTopicLink(typesetter, match.mValue, match.mBeg - text.begin(), match.mEnd - text.begin());
|
addTopicLink(typesetter, match.mValue, match.mBeg - text.begin(), match.mEnd - text.begin());
|
||||||
|
|
||||||
i = match.mEnd;
|
i = match.mEnd;
|
||||||
}
|
}
|
||||||
if (i != text.end())
|
if (i != text.end())
|
||||||
addTopicLink(std::move(typesetter), 0, i - text.begin(), text.size());
|
addTopicLink(std::move(typesetter), nullptr, i - text.begin(), text.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const
|
void Response::addTopicLink(
|
||||||
|
std::shared_ptr<BookTypesetter> typesetter, const MWGui::Topic* topic, size_t begin, size_t end) const
|
||||||
{
|
{
|
||||||
const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
||||||
|
|
||||||
BookTypesetter::Style* style = typesetter->createStyle({}, textColours.normal, false);
|
BookTypesetter::Style* style = typesetter->createStyle({}, textColours.normal, false);
|
||||||
|
|
||||||
if (topicId)
|
if (topic)
|
||||||
style = typesetter->createHotStyle(
|
style = typesetter->createHotStyle(style, textColours.link, textColours.linkOver, textColours.linkPressed,
|
||||||
style, textColours.link, textColours.linkOver, textColours.linkPressed, topicId);
|
TypesetBook::InteractiveId(topic));
|
||||||
typesetter->write(style, begin, end);
|
typesetter->write(style, begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,13 +312,13 @@ namespace MWGui
|
||||||
mText = text;
|
mText = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch,
|
void Message::write(std::shared_ptr<BookTypesetter> typesetter, const TopicSearch&,
|
||||||
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const
|
std::map<std::string, std::unique_ptr<Link>>&) const
|
||||||
{
|
{
|
||||||
const MyGUI::Colour& textColour = MWBase::Environment::get().getWindowManager()->getTextColours().notify;
|
const MyGUI::Colour& textColour = MWBase::Environment::get().getWindowManager()->getTextColours().notify;
|
||||||
BookTypesetter::Style* title = typesetter->createStyle({}, textColour, false);
|
BookTypesetter::Style* title = typesetter->createStyle({}, textColour, false);
|
||||||
typesetter->sectionBreak(9);
|
typesetter->sectionBreak(9);
|
||||||
typesetter->write(title, to_utf8_span(mText));
|
typesetter->write(title, mText);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -661,7 +657,7 @@ namespace MWGui
|
||||||
mTopicsList->addItem(keyword, sVerticalPadding);
|
mTopicsList->addItem(keyword, sVerticalPadding);
|
||||||
|
|
||||||
auto t = std::make_unique<Topic>(keyword);
|
auto t = std::make_unique<Topic>(keyword);
|
||||||
mKeywordSearch.seed(topicId, intptr_t(t.get()));
|
mKeywordSearch.seed(topicId, t.get());
|
||||||
t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated);
|
t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated);
|
||||||
mTopicLinks[topicId] = std::move(t);
|
mTopicLinks[topicId] = std::move(t);
|
||||||
|
|
||||||
|
|
@ -689,10 +685,11 @@ namespace MWGui
|
||||||
mScrollBar->setVisible(true);
|
mScrollBar->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BookTypesetter::Ptr typesetter = BookTypesetter::create(mHistory->getWidth(), std::numeric_limits<int>::max());
|
std::shared_ptr<BookTypesetter> typesetter
|
||||||
|
= BookTypesetter::create(mHistory->getWidth(), std::numeric_limits<int>::max());
|
||||||
|
|
||||||
for (const auto& text : mHistoryContents)
|
for (const auto& text : mHistoryContents)
|
||||||
text->write(typesetter, &mKeywordSearch, mTopicLinks);
|
text->write(typesetter, mKeywordSearch, mTopicLinks);
|
||||||
|
|
||||||
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::White, false);
|
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::White, false);
|
||||||
|
|
||||||
|
|
@ -712,7 +709,7 @@ namespace MWGui
|
||||||
typesetter->lineBreak();
|
typesetter->lineBreak();
|
||||||
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(
|
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(
|
||||||
body, textColours.answer, textColours.answerOver, textColours.answerPressed, interactiveId);
|
body, textColours.answer, textColours.answerOver, textColours.answerPressed, interactiveId);
|
||||||
typesetter->write(questionStyle, to_utf8_span(choice.first));
|
typesetter->write(questionStyle, choice.first);
|
||||||
mChoiceStyles.push_back(questionStyle);
|
mChoiceStyles.push_back(questionStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,10 +728,10 @@ namespace MWGui
|
||||||
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(
|
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(
|
||||||
body, textColours.answer, textColours.answerOver, textColours.answerPressed, interactiveId);
|
body, textColours.answer, textColours.answerOver, textColours.answerPressed, interactiveId);
|
||||||
typesetter->lineBreak();
|
typesetter->lineBreak();
|
||||||
typesetter->write(questionStyle, to_utf8_span(goodbye));
|
typesetter->write(questionStyle, goodbye);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypesetBook::Ptr book = typesetter->complete();
|
std::shared_ptr<TypesetBook> book = typesetter->complete();
|
||||||
mHistory->showPage(book, 0);
|
mHistory->showPage(book, 0);
|
||||||
size_t viewHeight = mHistory->getParent()->getHeight();
|
size_t viewHeight = mHistory->getParent()->getHeight();
|
||||||
if (!scrollbar && book->getSize().second > viewHeight)
|
if (!scrollbar && book->getSize().second > viewHeight)
|
||||||
|
|
|
||||||
|
|
@ -79,14 +79,13 @@ namespace MWGui
|
||||||
|
|
||||||
struct Link
|
struct Link
|
||||||
{
|
{
|
||||||
virtual ~Link() {}
|
virtual ~Link() = default;
|
||||||
virtual void activated() = 0;
|
virtual void activated() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Topic : Link
|
struct Topic : Link
|
||||||
{
|
{
|
||||||
typedef MyGUI::delegates::MultiDelegate<const std::string&> EventHandle_TopicId;
|
MyGUI::delegates::MultiDelegate<const std::string&> eventTopicActivated;
|
||||||
EventHandle_TopicId eventTopicActivated;
|
|
||||||
Topic(const std::string& id)
|
Topic(const std::string& id)
|
||||||
: mTopicId(id)
|
: mTopicId(id)
|
||||||
{
|
{
|
||||||
|
|
@ -97,8 +96,7 @@ namespace MWGui
|
||||||
|
|
||||||
struct Choice : Link
|
struct Choice : Link
|
||||||
{
|
{
|
||||||
typedef MyGUI::delegates::MultiDelegate<int> EventHandle_ChoiceId;
|
MyGUI::delegates::MultiDelegate<int> eventChoiceActivated;
|
||||||
EventHandle_ChoiceId eventChoiceActivated;
|
|
||||||
Choice(int id)
|
Choice(int id)
|
||||||
: mChoiceId(id)
|
: mChoiceId(id)
|
||||||
{
|
{
|
||||||
|
|
@ -109,27 +107,28 @@ namespace MWGui
|
||||||
|
|
||||||
struct Goodbye : Link
|
struct Goodbye : Link
|
||||||
{
|
{
|
||||||
typedef MyGUI::delegates::MultiDelegate<> Event_Activated;
|
MyGUI::delegates::MultiDelegate<> eventActivated;
|
||||||
Event_Activated eventActivated;
|
|
||||||
void activated() override;
|
void activated() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef MWDialogue::KeywordSearch<intptr_t> KeywordSearchT;
|
using TopicSearch = MWDialogue::KeywordSearch<const Topic*>;
|
||||||
|
|
||||||
struct DialogueText
|
struct DialogueText
|
||||||
{
|
{
|
||||||
virtual ~DialogueText() = default;
|
virtual ~DialogueText() = default;
|
||||||
virtual void write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch,
|
virtual void write(std::shared_ptr<BookTypesetter> typesetter, const TopicSearch& keywordSearch,
|
||||||
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const = 0;
|
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const
|
||||||
|
= 0;
|
||||||
std::string mText;
|
std::string mText;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Response : DialogueText
|
struct Response : DialogueText
|
||||||
{
|
{
|
||||||
Response(std::string_view text, std::string_view title = {}, bool needMargin = true);
|
Response(std::string_view text, std::string_view title = {}, bool needMargin = true);
|
||||||
void write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch,
|
void write(std::shared_ptr<BookTypesetter> typesetter, const TopicSearch& keywordSearch,
|
||||||
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const override;
|
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const override;
|
||||||
void addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const;
|
void addTopicLink(
|
||||||
|
std::shared_ptr<BookTypesetter> typesetter, const Topic* topic, size_t begin, size_t end) const;
|
||||||
std::string mTitle;
|
std::string mTitle;
|
||||||
bool mNeedMargin;
|
bool mNeedMargin;
|
||||||
};
|
};
|
||||||
|
|
@ -137,7 +136,7 @@ namespace MWGui
|
||||||
struct Message : DialogueText
|
struct Message : DialogueText
|
||||||
{
|
{
|
||||||
Message(std::string_view text);
|
Message(std::string_view text);
|
||||||
void write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch,
|
void write(std::shared_ptr<BookTypesetter> typesetter, const TopicSearch& keywordSearch,
|
||||||
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const override;
|
std::map<std::string, std::unique_ptr<Link>>& topicLinks) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -150,9 +149,6 @@ namespace MWGui
|
||||||
|
|
||||||
bool exit() override;
|
bool exit() override;
|
||||||
|
|
||||||
// Events
|
|
||||||
typedef MyGUI::delegates::MultiDelegate<> EventHandle_Void;
|
|
||||||
|
|
||||||
void notifyLinkClicked(TypesetBook::InteractiveId link);
|
void notifyLinkClicked(TypesetBook::InteractiveId link);
|
||||||
|
|
||||||
void setPtr(const MWWorld::Ptr& actor) override;
|
void setPtr(const MWWorld::Ptr& actor) override;
|
||||||
|
|
@ -213,7 +209,7 @@ namespace MWGui
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Link>> mDeleteLater;
|
std::vector<std::unique_ptr<Link>> mDeleteLater;
|
||||||
|
|
||||||
KeywordSearchT mKeywordSearch;
|
TopicSearch mKeywordSearch;
|
||||||
|
|
||||||
BookPage* mHistory;
|
BookPage* mHistory;
|
||||||
Gui::MWList* mTopicsList;
|
Gui::MWList* mTopicsList;
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ namespace
|
||||||
{
|
{
|
||||||
struct AddContent
|
struct AddContent
|
||||||
{
|
{
|
||||||
MWGui::BookTypesetter::Ptr mTypesetter;
|
std::shared_ptr<MWGui::BookTypesetter> mTypesetter;
|
||||||
MWGui::BookTypesetter::Style* mBodyStyle;
|
MWGui::BookTypesetter::Style* mBodyStyle;
|
||||||
|
|
||||||
explicit AddContent(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* bodyStyle)
|
explicit AddContent(std::shared_ptr<MWGui::BookTypesetter> typesetter, MWGui::BookTypesetter::Style* bodyStyle)
|
||||||
: mTypesetter(std::move(typesetter))
|
: mTypesetter(std::move(typesetter))
|
||||||
, mBodyStyle(bodyStyle)
|
, mBodyStyle(bodyStyle)
|
||||||
{
|
{
|
||||||
|
|
@ -24,19 +24,19 @@ namespace
|
||||||
|
|
||||||
struct AddSpan : AddContent
|
struct AddSpan : AddContent
|
||||||
{
|
{
|
||||||
explicit AddSpan(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* bodyStyle)
|
explicit AddSpan(std::shared_ptr<MWGui::BookTypesetter> typesetter, MWGui::BookTypesetter::Style* bodyStyle)
|
||||||
: AddContent(std::move(typesetter), bodyStyle)
|
: AddContent(std::move(typesetter), bodyStyle)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(intptr_t topicId, size_t begin, size_t end)
|
void operator()(const MWDialogue::Topic* topic, size_t begin, size_t end)
|
||||||
{
|
{
|
||||||
MWGui::BookTypesetter::Style* style = mBodyStyle;
|
MWGui::BookTypesetter::Style* style = mBodyStyle;
|
||||||
|
|
||||||
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
||||||
if (topicId)
|
if (topic)
|
||||||
style = mTypesetter->createHotStyle(mBodyStyle, textColours.journalLink, textColours.journalLinkOver,
|
style = mTypesetter->createHotStyle(mBodyStyle, textColours.journalLink, textColours.journalLinkOver,
|
||||||
textColours.journalLinkPressed, topicId);
|
textColours.journalLinkPressed, MWGui::TypesetBook::InteractiveId(topic));
|
||||||
|
|
||||||
mTypesetter->write(style, begin, end);
|
mTypesetter->write(style, begin, end);
|
||||||
}
|
}
|
||||||
|
|
@ -44,10 +44,10 @@ namespace
|
||||||
|
|
||||||
struct AddEntry
|
struct AddEntry
|
||||||
{
|
{
|
||||||
MWGui::BookTypesetter::Ptr mTypesetter;
|
std::shared_ptr<MWGui::BookTypesetter> mTypesetter;
|
||||||
MWGui::BookTypesetter::Style* mBodyStyle;
|
MWGui::BookTypesetter::Style* mBodyStyle;
|
||||||
|
|
||||||
AddEntry(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* bodyStyle)
|
AddEntry(std::shared_ptr<MWGui::BookTypesetter> typesetter, MWGui::BookTypesetter::Style* bodyStyle)
|
||||||
: mTypesetter(std::move(typesetter))
|
: mTypesetter(std::move(typesetter))
|
||||||
, mBodyStyle(bodyStyle)
|
, mBodyStyle(bodyStyle)
|
||||||
{
|
{
|
||||||
|
|
@ -66,8 +66,8 @@ namespace
|
||||||
bool mAddHeader;
|
bool mAddHeader;
|
||||||
MWGui::BookTypesetter::Style* mHeaderStyle;
|
MWGui::BookTypesetter::Style* mHeaderStyle;
|
||||||
|
|
||||||
explicit AddJournalEntry(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* bodyStyle,
|
explicit AddJournalEntry(std::shared_ptr<MWGui::BookTypesetter> typesetter,
|
||||||
MWGui::BookTypesetter::Style* headerStyle, bool addHeader)
|
MWGui::BookTypesetter::Style* bodyStyle, MWGui::BookTypesetter::Style* headerStyle, bool addHeader)
|
||||||
: AddEntry(std::move(typesetter), bodyStyle)
|
: AddEntry(std::move(typesetter), bodyStyle)
|
||||||
, mAddHeader(addHeader)
|
, mAddHeader(addHeader)
|
||||||
, mHeaderStyle(headerStyle)
|
, mHeaderStyle(headerStyle)
|
||||||
|
|
@ -90,11 +90,12 @@ namespace
|
||||||
|
|
||||||
struct AddTopicEntry : AddEntry
|
struct AddTopicEntry : AddEntry
|
||||||
{
|
{
|
||||||
intptr_t mContentId;
|
const MWGui::TypesetBook::Content* mContentId;
|
||||||
MWGui::BookTypesetter::Style* mHeaderStyle;
|
MWGui::BookTypesetter::Style* mHeaderStyle;
|
||||||
|
|
||||||
explicit AddTopicEntry(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* bodyStyle,
|
explicit AddTopicEntry(std::shared_ptr<MWGui::BookTypesetter> typesetter,
|
||||||
MWGui::BookTypesetter::Style* headerStyle, intptr_t contentId)
|
MWGui::BookTypesetter::Style* bodyStyle, MWGui::BookTypesetter::Style* headerStyle,
|
||||||
|
const MWGui::TypesetBook::Content* contentId)
|
||||||
: AddEntry(std::move(typesetter), bodyStyle)
|
: AddEntry(std::move(typesetter), bodyStyle)
|
||||||
, mContentId(contentId)
|
, mContentId(contentId)
|
||||||
, mHeaderStyle(headerStyle)
|
, mHeaderStyle(headerStyle)
|
||||||
|
|
@ -117,12 +118,12 @@ namespace
|
||||||
|
|
||||||
struct AddTopicName : AddContent
|
struct AddTopicName : AddContent
|
||||||
{
|
{
|
||||||
AddTopicName(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style)
|
AddTopicName(std::shared_ptr<MWGui::BookTypesetter> typesetter, MWGui::BookTypesetter::Style* style)
|
||||||
: AddContent(std::move(typesetter), style)
|
: AddContent(std::move(typesetter), style)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(MWGui::JournalViewModel::Utf8Span topicName)
|
void operator()(std::string_view topicName)
|
||||||
{
|
{
|
||||||
mTypesetter->write(mBodyStyle, topicName);
|
mTypesetter->write(mBodyStyle, topicName);
|
||||||
mTypesetter->sectionBreak();
|
mTypesetter->sectionBreak();
|
||||||
|
|
@ -131,12 +132,12 @@ namespace
|
||||||
|
|
||||||
struct AddQuestName : AddContent
|
struct AddQuestName : AddContent
|
||||||
{
|
{
|
||||||
AddQuestName(MWGui::BookTypesetter::Ptr typesetter, MWGui::BookTypesetter::Style* style)
|
AddQuestName(std::shared_ptr<MWGui::BookTypesetter> typesetter, MWGui::BookTypesetter::Style* style)
|
||||||
: AddContent(std::move(typesetter), style)
|
: AddContent(std::move(typesetter), style)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(MWGui::JournalViewModel::Utf8Span topicName)
|
void operator()(std::string_view topicName)
|
||||||
{
|
{
|
||||||
mTypesetter->write(mBodyStyle, topicName);
|
mTypesetter->write(mBodyStyle, topicName);
|
||||||
mTypesetter->sectionBreak();
|
mTypesetter->sectionBreak();
|
||||||
|
|
@ -147,15 +148,6 @@ namespace
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
MWGui::BookTypesetter::Utf8Span to_utf8_span(std::string_view text)
|
|
||||||
{
|
|
||||||
typedef MWGui::BookTypesetter::Utf8Point point;
|
|
||||||
|
|
||||||
point begin = reinterpret_cast<point>(text.data());
|
|
||||||
|
|
||||||
return MWGui::BookTypesetter::Utf8Span(begin, begin + text.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
int getCyrillicIndexPageCount()
|
int getCyrillicIndexPageCount()
|
||||||
{
|
{
|
||||||
// For small font size split alphabet to two columns (2x15 characers), for big font size split it to three
|
// For small font size split alphabet to two columns (2x15 characers), for big font size split it to three
|
||||||
|
|
@ -163,33 +155,30 @@ namespace MWGui
|
||||||
return Settings::gui().mFontSize < 18 ? 2 : 3;
|
return Settings::gui().mFontSize < 18 ? 2 : 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef TypesetBook::Ptr book;
|
JournalBooks::JournalBooks(std::shared_ptr<JournalViewModel> model, ToUTF8::FromType encoding)
|
||||||
|
|
||||||
JournalBooks::JournalBooks(JournalViewModel::Ptr model, ToUTF8::FromType encoding)
|
|
||||||
: mModel(std::move(model))
|
: mModel(std::move(model))
|
||||||
, mEncoding(encoding)
|
, mEncoding(encoding)
|
||||||
, mIndexPagesCount(0)
|
, mIndexPagesCount(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
book JournalBooks::createEmptyJournalBook()
|
std::shared_ptr<TypesetBook> JournalBooks::createEmptyJournalBook()
|
||||||
{
|
{
|
||||||
BookTypesetter::Ptr typesetter = createTypesetter();
|
std::shared_ptr<BookTypesetter> typesetter = createTypesetter();
|
||||||
|
|
||||||
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
||||||
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
||||||
|
|
||||||
typesetter->write(header, to_utf8_span("You have no journal entries!"));
|
typesetter->write(header, "You have no journal entries!");
|
||||||
typesetter->lineBreak();
|
typesetter->lineBreak();
|
||||||
typesetter->write(
|
typesetter->write(body, "You should have gone though the starting quest and got an initial quest.");
|
||||||
body, to_utf8_span("You should have gone though the starting quest and got an initial quest."));
|
|
||||||
|
|
||||||
return typesetter->complete();
|
return typesetter->complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
book JournalBooks::createJournalBook()
|
std::shared_ptr<TypesetBook> JournalBooks::createJournalBook()
|
||||||
{
|
{
|
||||||
BookTypesetter::Ptr typesetter = createTypesetter();
|
std::shared_ptr<BookTypesetter> typesetter = createTypesetter();
|
||||||
|
|
||||||
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
||||||
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
||||||
|
|
@ -199,49 +188,50 @@ namespace MWGui
|
||||||
return typesetter->complete();
|
return typesetter->complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
book JournalBooks::createTopicBook(uintptr_t topicId)
|
std::shared_ptr<TypesetBook> JournalBooks::createTopicBook(const MWDialogue::Topic& topic)
|
||||||
{
|
{
|
||||||
BookTypesetter::Ptr typesetter = createTypesetter();
|
std::shared_ptr<BookTypesetter> typesetter = createTypesetter();
|
||||||
|
|
||||||
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
||||||
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
||||||
|
|
||||||
mModel->visitTopicName(topicId, AddTopicName(typesetter, header));
|
mModel->visitTopicName(topic, AddTopicName(typesetter, header));
|
||||||
|
|
||||||
intptr_t contentId = typesetter->addContent(to_utf8_span(", \""));
|
const TypesetBook::Content* contentId = typesetter->addContent(", \"");
|
||||||
|
|
||||||
mModel->visitTopicEntries(topicId, AddTopicEntry(typesetter, body, header, contentId));
|
mModel->visitTopicEntries(topic, AddTopicEntry(typesetter, body, header, contentId));
|
||||||
|
|
||||||
return typesetter->complete();
|
return typesetter->complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
book JournalBooks::createQuestBook(std::string_view questName)
|
std::shared_ptr<TypesetBook> JournalBooks::createQuestBook(std::string_view questName)
|
||||||
{
|
{
|
||||||
BookTypesetter::Ptr typesetter = createTypesetter();
|
std::shared_ptr<BookTypesetter> typesetter = createTypesetter();
|
||||||
|
|
||||||
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
BookTypesetter::Style* header = typesetter->createStyle({}, journalHeaderColour);
|
||||||
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
BookTypesetter::Style* body = typesetter->createStyle({}, MyGUI::Colour::Black);
|
||||||
|
|
||||||
AddQuestName addName(typesetter, header);
|
AddQuestName addName(typesetter, header);
|
||||||
addName(to_utf8_span(questName));
|
addName(questName);
|
||||||
|
|
||||||
mModel->visitJournalEntries(questName, AddJournalEntry(typesetter, body, header, false));
|
mModel->visitJournalEntries(questName, AddJournalEntry(typesetter, body, header, false));
|
||||||
|
|
||||||
return typesetter->complete();
|
return typesetter->complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
book JournalBooks::createTopicIndexBook()
|
std::shared_ptr<TypesetBook> JournalBooks::createTopicIndexBook()
|
||||||
{
|
{
|
||||||
bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251);
|
bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251);
|
||||||
|
|
||||||
BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex();
|
std::shared_ptr<BookTypesetter> typesetter
|
||||||
|
= isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex();
|
||||||
|
|
||||||
return typesetter->complete();
|
return typesetter->complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
BookTypesetter::Ptr JournalBooks::createLatinJournalIndex()
|
std::shared_ptr<BookTypesetter> JournalBooks::createLatinJournalIndex()
|
||||||
{
|
{
|
||||||
BookTypesetter::Ptr typesetter = BookTypesetter::create(92, 260);
|
std::shared_ptr<BookTypesetter> typesetter = BookTypesetter::create(92, 260);
|
||||||
|
|
||||||
typesetter->setSectionAlignment(BookTypesetter::AlignCenter);
|
typesetter->setSectionAlignment(BookTypesetter::AlignCenter);
|
||||||
|
|
||||||
|
|
@ -260,12 +250,12 @@ namespace MWGui
|
||||||
|
|
||||||
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
|
||||||
BookTypesetter::Style* style = typesetter->createHotStyle(body, textColours.journalTopic,
|
BookTypesetter::Style* style = typesetter->createHotStyle(body, textColours.journalTopic,
|
||||||
textColours.journalTopicOver, textColours.journalTopicPressed, (Utf8Stream::UnicodeChar)ch);
|
textColours.journalTopicOver, textColours.journalTopicPressed, Utf8Stream::UnicodeChar(ch));
|
||||||
|
|
||||||
if (i == 13)
|
if (i == 13)
|
||||||
typesetter->sectionBreak();
|
typesetter->sectionBreak();
|
||||||
|
|
||||||
typesetter->write(style, to_utf8_span(buffer));
|
typesetter->write(style, buffer);
|
||||||
typesetter->lineBreak();
|
typesetter->lineBreak();
|
||||||
|
|
||||||
ch++;
|
ch++;
|
||||||
|
|
@ -274,9 +264,9 @@ namespace MWGui
|
||||||
return typesetter;
|
return typesetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex()
|
std::shared_ptr<BookTypesetter> JournalBooks::createCyrillicJournalIndex()
|
||||||
{
|
{
|
||||||
BookTypesetter::Ptr typesetter = BookTypesetter::create(92, 260);
|
std::shared_ptr<BookTypesetter> typesetter = BookTypesetter::create(92, 260);
|
||||||
|
|
||||||
typesetter->setSectionAlignment(BookTypesetter::AlignCenter);
|
typesetter->setSectionAlignment(BookTypesetter::AlignCenter);
|
||||||
|
|
||||||
|
|
@ -314,14 +304,14 @@ namespace MWGui
|
||||||
if (i % sectionBreak == 0)
|
if (i % sectionBreak == 0)
|
||||||
typesetter->sectionBreak();
|
typesetter->sectionBreak();
|
||||||
|
|
||||||
typesetter->write(style, to_utf8_span(buffer));
|
typesetter->write(style, buffer);
|
||||||
typesetter->lineBreak();
|
typesetter->lineBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
return typesetter;
|
return typesetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
BookTypesetter::Ptr JournalBooks::createTypesetter()
|
std::shared_ptr<BookTypesetter> JournalBooks::createTypesetter()
|
||||||
{
|
{
|
||||||
// TODO: determine page size from layout...
|
// TODO: determine page size from layout...
|
||||||
return BookTypesetter::create(240, 320);
|
return BookTypesetter::create(240, 320);
|
||||||
|
|
|
||||||
|
|
@ -8,31 +8,29 @@
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
MWGui::BookTypesetter::Utf8Span to_utf8_span(std::string_view text);
|
|
||||||
int getCyrillicIndexPageCount();
|
int getCyrillicIndexPageCount();
|
||||||
|
|
||||||
const MyGUI::Colour journalHeaderColour = MyGUI::Colour(0.60f, 0.00f, 0.00f);
|
const MyGUI::Colour journalHeaderColour = MyGUI::Colour(0.60f, 0.00f, 0.00f);
|
||||||
|
|
||||||
struct JournalBooks
|
struct JournalBooks
|
||||||
{
|
{
|
||||||
typedef TypesetBook::Ptr Book;
|
std::shared_ptr<JournalViewModel> mModel;
|
||||||
JournalViewModel::Ptr mModel;
|
|
||||||
|
|
||||||
JournalBooks(JournalViewModel::Ptr model, ToUTF8::FromType encoding);
|
JournalBooks(std::shared_ptr<JournalViewModel> model, ToUTF8::FromType encoding);
|
||||||
|
|
||||||
Book createEmptyJournalBook();
|
std::shared_ptr<TypesetBook> createEmptyJournalBook();
|
||||||
Book createJournalBook();
|
std::shared_ptr<TypesetBook> createJournalBook();
|
||||||
Book createTopicBook(uintptr_t topicId);
|
std::shared_ptr<TypesetBook> createTopicBook(const MWDialogue::Topic& topic);
|
||||||
Book createQuestBook(std::string_view questName);
|
std::shared_ptr<TypesetBook> createQuestBook(std::string_view questName);
|
||||||
Book createTopicIndexBook();
|
std::shared_ptr<TypesetBook> createTopicIndexBook();
|
||||||
|
|
||||||
ToUTF8::FromType mEncoding;
|
ToUTF8::FromType mEncoding;
|
||||||
int mIndexPagesCount;
|
int mIndexPagesCount;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BookTypesetter::Ptr createTypesetter();
|
std::shared_ptr<BookTypesetter> createTypesetter();
|
||||||
BookTypesetter::Ptr createLatinJournalIndex();
|
std::shared_ptr<BookTypesetter> createLatinJournalIndex();
|
||||||
BookTypesetter::Ptr createCyrillicJournalIndex();
|
std::shared_ptr<BookTypesetter> createCyrillicJournalIndex();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,26 +22,15 @@ namespace MWGui
|
||||||
|
|
||||||
struct JournalViewModelImpl : JournalViewModel
|
struct JournalViewModelImpl : JournalViewModel
|
||||||
{
|
{
|
||||||
typedef MWDialogue::KeywordSearch<intptr_t> KeywordSearchT;
|
using TopicSearch = MWDialogue::KeywordSearch<const MWDialogue::Topic*>;
|
||||||
|
|
||||||
mutable bool mKeywordSearchLoaded;
|
mutable bool mKeywordSearchLoaded;
|
||||||
mutable KeywordSearchT mKeywordSearch;
|
mutable TopicSearch mKeywordSearch;
|
||||||
|
|
||||||
JournalViewModelImpl() { mKeywordSearchLoaded = false; }
|
JournalViewModelImpl() { mKeywordSearchLoaded = false; }
|
||||||
|
|
||||||
virtual ~JournalViewModelImpl() = default;
|
virtual ~JournalViewModelImpl() = default;
|
||||||
|
|
||||||
/// \todo replace this nasty BS
|
|
||||||
static Utf8Span toUtf8Span(std::string_view str)
|
|
||||||
{
|
|
||||||
if (str.empty())
|
|
||||||
return Utf8Span(Utf8Point(nullptr), Utf8Point(nullptr));
|
|
||||||
|
|
||||||
Utf8Point point = reinterpret_cast<Utf8Point>(str.data());
|
|
||||||
|
|
||||||
return Utf8Span(point, point + str.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void load() override {}
|
void load() override {}
|
||||||
|
|
||||||
void unload() override
|
void unload() override
|
||||||
|
|
@ -57,7 +46,7 @@ namespace MWGui
|
||||||
MWBase::Journal* journal = MWBase::Environment::get().getJournal();
|
MWBase::Journal* journal = MWBase::Environment::get().getJournal();
|
||||||
|
|
||||||
for (const auto& [_, topic] : journal->getTopics())
|
for (const auto& [_, topic] : journal->getTopics())
|
||||||
mKeywordSearch.seed(topic.getName(), intptr_t(&topic));
|
mKeywordSearch.seed(topic.getName(), &topic);
|
||||||
|
|
||||||
mKeywordSearchLoaded = true;
|
mKeywordSearchLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
@ -88,10 +77,8 @@ namespace MWGui
|
||||||
mutable bool loaded;
|
mutable bool loaded;
|
||||||
mutable std::string utf8text;
|
mutable std::string utf8text;
|
||||||
|
|
||||||
typedef std::pair<size_t, size_t> Range;
|
|
||||||
|
|
||||||
// hyperlinks in @link# notation
|
// hyperlinks in @link# notation
|
||||||
mutable std::map<Range, intptr_t> mHyperLinks;
|
mutable std::map<std::pair<size_t, size_t>, const MWDialogue::Topic*> mHyperLinks;
|
||||||
|
|
||||||
virtual std::string getText() const = 0;
|
virtual std::string getText() const = 0;
|
||||||
|
|
||||||
|
|
@ -126,7 +113,7 @@ namespace MWGui
|
||||||
|
|
||||||
utf8text.replace(posBegin, posEnd + 1 - posBegin, displayName);
|
utf8text.replace(posBegin, posEnd + 1 - posBegin, displayName);
|
||||||
|
|
||||||
intptr_t value = 0;
|
const MWDialogue::Topic* value = nullptr;
|
||||||
if (mModel->mKeywordSearch.containsKeyword(topicName, value))
|
if (mModel->mKeywordSearch.containsKeyword(topicName, value))
|
||||||
mHyperLinks[std::make_pair(posBegin, posBegin + displayName.size())] = value;
|
mHyperLinks[std::make_pair(posBegin, posBegin + displayName.size())] = value;
|
||||||
}
|
}
|
||||||
|
|
@ -138,14 +125,14 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Utf8Span body() const override
|
std::string_view body() const override
|
||||||
{
|
{
|
||||||
ensureLoaded();
|
ensureLoaded();
|
||||||
|
|
||||||
return toUtf8Span(utf8text);
|
return utf8text;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitSpans(std::function<void(TopicId, size_t, size_t)> visitor) const override
|
void visitSpans(std::function<void(const MWDialogue::Topic*, size_t, size_t)> visitor) const override
|
||||||
{
|
{
|
||||||
ensureLoaded();
|
ensureLoaded();
|
||||||
mModel->ensureKeyWordSearchLoaded();
|
mModel->ensureKeyWordSearchLoaded();
|
||||||
|
|
@ -154,25 +141,23 @@ namespace MWGui
|
||||||
&& MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
&& MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
||||||
{
|
{
|
||||||
size_t formatted = 0; // points to the first character that is not laid out yet
|
size_t formatted = 0; // points to the first character that is not laid out yet
|
||||||
for (std::map<Range, intptr_t>::const_iterator it = mHyperLinks.begin(); it != mHyperLinks.end();
|
for (const auto& [range, topicId] : mHyperLinks)
|
||||||
++it)
|
|
||||||
{
|
{
|
||||||
intptr_t topicId = it->second;
|
if (formatted < range.first)
|
||||||
if (formatted < it->first.first)
|
visitor(0, formatted, range.first);
|
||||||
visitor(0, formatted, it->first.first);
|
visitor(topicId, range.first, range.second);
|
||||||
visitor(topicId, it->first.first, it->first.second);
|
formatted = range.second;
|
||||||
formatted = it->first.second;
|
|
||||||
}
|
}
|
||||||
if (formatted < utf8text.size())
|
if (formatted < utf8text.size())
|
||||||
visitor(0, formatted, utf8text.size());
|
visitor(0, formatted, utf8text.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::vector<KeywordSearchT::Match> matches;
|
std::vector<TopicSearch::Match> matches;
|
||||||
mModel->mKeywordSearch.highlightKeywords(utf8text.begin(), utf8text.end(), matches);
|
mModel->mKeywordSearch.highlightKeywords(utf8text.begin(), utf8text.end(), matches);
|
||||||
|
|
||||||
std::string::const_iterator i = utf8text.begin();
|
std::string::const_iterator i = utf8text.begin();
|
||||||
for (const KeywordSearchT::Match& match : matches)
|
for (const TopicSearch::Match& match : matches)
|
||||||
{
|
{
|
||||||
if (i != match.mBeg)
|
if (i != match.mBeg)
|
||||||
visitor(0, i - utf8text.begin(), match.mBeg - utf8text.begin());
|
visitor(0, i - utf8text.begin(), match.mBeg - utf8text.begin());
|
||||||
|
|
@ -231,7 +216,7 @@ namespace MWGui
|
||||||
|
|
||||||
std::string getText() const override { return mEntry->getText(); }
|
std::string getText() const override { return mEntry->getText(); }
|
||||||
|
|
||||||
Utf8Span timestamp() const override
|
std::string_view timestamp() const override
|
||||||
{
|
{
|
||||||
if (timestamp_buffer.empty())
|
if (timestamp_buffer.empty())
|
||||||
{
|
{
|
||||||
|
|
@ -246,7 +231,7 @@ namespace MWGui
|
||||||
timestamp_buffer = os.str();
|
timestamp_buffer = os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
return toUtf8Span(timestamp_buffer);
|
return timestamp_buffer;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -288,10 +273,10 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitTopicName(TopicId topicId, std::function<void(Utf8Span)> visitor) const override
|
void visitTopicName(
|
||||||
|
const MWDialogue::Topic& topic, std::function<void(std::string_view)> visitor) const override
|
||||||
{
|
{
|
||||||
MWDialogue::Topic const& topic = *reinterpret_cast<MWDialogue::Topic const*>(topicId);
|
visitor(topic.getName());
|
||||||
visitor(toUtf8Span(topic.getName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitTopicNamesStartingWith(
|
void visitTopicNamesStartingWith(
|
||||||
|
|
@ -324,19 +309,18 @@ namespace MWGui
|
||||||
|
|
||||||
std::string getText() const override { return mEntry->getText(); }
|
std::string getText() const override { return mEntry->getText(); }
|
||||||
|
|
||||||
Utf8Span source() const override { return toUtf8Span(mEntry->mActorName); }
|
std::string_view source() const override { return mEntry->mActorName; }
|
||||||
};
|
};
|
||||||
|
|
||||||
void visitTopicEntries(TopicId topicId, std::function<void(TopicEntry const&)> visitor) const override
|
void visitTopicEntries(
|
||||||
|
const MWDialogue::Topic& topic, std::function<void(TopicEntry const&)> visitor) const override
|
||||||
{
|
{
|
||||||
MWDialogue::Topic const& topic = *reinterpret_cast<MWDialogue::Topic const*>(topicId);
|
|
||||||
|
|
||||||
for (const MWDialogue::Entry& entry : topic)
|
for (const MWDialogue::Entry& entry : topic)
|
||||||
visitor(TopicEntryImpl(this, topic, entry));
|
visitor(TopicEntryImpl(this, topic, entry));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
JournalViewModel::Ptr JournalViewModel::create()
|
std::shared_ptr<JournalViewModel> JournalViewModel::create()
|
||||||
{
|
{
|
||||||
return std::make_shared<JournalViewModelImpl>();
|
return std::make_shared<JournalViewModelImpl>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
#include <components/misc/utf8stream.hpp>
|
#include <components/misc/utf8stream.hpp>
|
||||||
|
|
||||||
|
namespace MWDialogue
|
||||||
|
{
|
||||||
|
class Topic;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
/// View-Model for the journal GUI
|
/// View-Model for the journal GUI
|
||||||
|
|
@ -18,13 +23,6 @@ namespace MWGui
|
||||||
/// game data store.
|
/// game data store.
|
||||||
struct JournalViewModel
|
struct JournalViewModel
|
||||||
{
|
{
|
||||||
typedef std::shared_ptr<JournalViewModel> Ptr;
|
|
||||||
|
|
||||||
typedef intptr_t QuestId;
|
|
||||||
typedef intptr_t TopicId;
|
|
||||||
typedef uint8_t const* Utf8Point;
|
|
||||||
typedef std::pair<Utf8Point, Utf8Point> Utf8Span;
|
|
||||||
|
|
||||||
/// The base interface for both journal entries and topics.
|
/// The base interface for both journal entries and topics.
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
|
|
@ -33,12 +31,12 @@ namespace MWGui
|
||||||
/// This function returns a borrowed reference to the body of the
|
/// This function returns a borrowed reference to the body of the
|
||||||
/// journal entry. The returned reference becomes invalid when the
|
/// journal entry. The returned reference becomes invalid when the
|
||||||
/// entry is destroyed.
|
/// entry is destroyed.
|
||||||
virtual Utf8Span body() const = 0;
|
virtual std::string_view body() const = 0;
|
||||||
|
|
||||||
/// Visits each subset of text in the body, delivering the beginning
|
/// Visits each subset of text in the body, delivering the beginning
|
||||||
/// and end of the span relative to the body, and a valid topic ID if
|
/// and end of the span relative to the body, and a valid topic ID if
|
||||||
/// the span represents a keyword, or zero if not.
|
/// the span represents a keyword, or zero if not.
|
||||||
virtual void visitSpans(std::function<void(TopicId, size_t, size_t)> visitor) const = 0;
|
virtual void visitSpans(std::function<void(const MWDialogue::Topic*, size_t, size_t)> visitor) const = 0;
|
||||||
|
|
||||||
virtual ~Entry() = default;
|
virtual ~Entry() = default;
|
||||||
};
|
};
|
||||||
|
|
@ -48,7 +46,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
/// Returns a pre-formatted span of UTF8 encoded text representing
|
/// Returns a pre-formatted span of UTF8 encoded text representing
|
||||||
/// the name of the NPC this portion of dialog was heard from.
|
/// the name of the NPC this portion of dialog was heard from.
|
||||||
virtual Utf8Span source() const = 0;
|
virtual std::string_view source() const = 0;
|
||||||
|
|
||||||
virtual ~TopicEntry() = default;
|
virtual ~TopicEntry() = default;
|
||||||
};
|
};
|
||||||
|
|
@ -58,7 +56,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
/// Returns a pre-formatted span of UTF8 encoded text representing
|
/// Returns a pre-formatted span of UTF8 encoded text representing
|
||||||
/// the in-game date this entry was added to the journal.
|
/// the in-game date this entry was added to the journal.
|
||||||
virtual Utf8Span timestamp() const = 0;
|
virtual std::string_view timestamp() const = 0;
|
||||||
|
|
||||||
virtual ~JournalEntry() = default;
|
virtual ~JournalEntry() = default;
|
||||||
};
|
};
|
||||||
|
|
@ -78,20 +76,25 @@ namespace MWGui
|
||||||
/// walks over the journal entries related to all quests with the given name
|
/// walks over the journal entries related to all quests with the given name
|
||||||
/// If \a questName is empty, simply visits all journal entries
|
/// If \a questName is empty, simply visits all journal entries
|
||||||
virtual void visitJournalEntries(
|
virtual void visitJournalEntries(
|
||||||
std::string_view questName, std::function<void(JournalEntry const&)> visitor) const = 0;
|
std::string_view questName, std::function<void(JournalEntry const&)> visitor) const
|
||||||
|
= 0;
|
||||||
|
|
||||||
/// provides the name of the topic specified by its id
|
/// provides the name of the topic specified by its id
|
||||||
virtual void visitTopicName(TopicId topicId, std::function<void(Utf8Span)> visitor) const = 0;
|
virtual void visitTopicName(const MWDialogue::Topic& topic, std::function<void(std::string_view)> visitor) const
|
||||||
|
= 0;
|
||||||
|
|
||||||
/// walks over the topics whose names start with the character
|
/// walks over the topics whose names start with the character
|
||||||
virtual void visitTopicNamesStartingWith(
|
virtual void visitTopicNamesStartingWith(
|
||||||
Utf8Stream::UnicodeChar character, std::function<void(std::string_view)> visitor) const = 0;
|
Utf8Stream::UnicodeChar character, std::function<void(std::string_view)> visitor) const
|
||||||
|
= 0;
|
||||||
|
|
||||||
/// walks over the topic entries for the topic specified by its identifier
|
/// walks over the topic entries for the topic specified by its identifier
|
||||||
virtual void visitTopicEntries(TopicId topicId, std::function<void(TopicEntry const&)> visitor) const = 0;
|
virtual void visitTopicEntries(
|
||||||
|
const MWDialogue::Topic& topic, std::function<void(TopicEntry const&)> visitor) const
|
||||||
|
= 0;
|
||||||
|
|
||||||
// create an instance of the default journal view model implementation
|
// create an instance of the default journal view model implementation
|
||||||
static Ptr create();
|
static std::shared_ptr<JournalViewModel> create();
|
||||||
|
|
||||||
virtual ~JournalViewModel() = default;
|
virtual ~JournalViewModel() = default;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,11 @@ namespace
|
||||||
struct DisplayState
|
struct DisplayState
|
||||||
{
|
{
|
||||||
size_t mPage;
|
size_t mPage;
|
||||||
Book mBook;
|
std::shared_ptr<MWGui::TypesetBook> mBook;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::stack<DisplayState> DisplayStateStack;
|
std::stack<DisplayState> mStates;
|
||||||
|
std::shared_ptr<MWGui::TypesetBook> mTopicIndexBook;
|
||||||
DisplayStateStack mStates;
|
|
||||||
Book mTopicIndexBook;
|
|
||||||
bool mQuestMode;
|
bool mQuestMode;
|
||||||
bool mOptionsMode;
|
bool mOptionsMode;
|
||||||
bool mTopicsMode;
|
bool mTopicsMode;
|
||||||
|
|
@ -91,7 +89,7 @@ namespace
|
||||||
|
|
||||||
MWGui::BookPage* getPage(std::string_view name) { return getWidget<MWGui::BookPage>(name); }
|
MWGui::BookPage* getPage(std::string_view name) { return getWidget<MWGui::BookPage>(name); }
|
||||||
|
|
||||||
JournalWindowImpl(MWGui::JournalViewModel::Ptr model, bool questList, ToUTF8::FromType encoding)
|
JournalWindowImpl(std::shared_ptr<MWGui::JournalViewModel> model, bool questList, ToUTF8::FromType encoding)
|
||||||
: JournalBooks(std::move(model), encoding)
|
: JournalBooks(std::move(model), encoding)
|
||||||
, JournalWindow()
|
, JournalWindow()
|
||||||
{
|
{
|
||||||
|
|
@ -123,7 +121,10 @@ namespace
|
||||||
topicsList->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyTopicSelected);
|
topicsList->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyTopicSelected);
|
||||||
|
|
||||||
{
|
{
|
||||||
MWGui::BookPage::ClickCallback callback = [this](intptr_t linkId) { notifyTopicClicked(linkId); };
|
MWGui::BookPage::ClickCallback callback = [this](MWGui::TypesetBook::InteractiveId linkId) {
|
||||||
|
const MWDialogue::Topic& topic = *reinterpret_cast<const MWDialogue::Topic*>(linkId);
|
||||||
|
notifyTopicClicked(topic);
|
||||||
|
};
|
||||||
|
|
||||||
getPage(LeftBookPage)->adviseLinkClicked(callback);
|
getPage(LeftBookPage)->adviseLinkClicked(callback);
|
||||||
getPage(RightBookPage)->adviseLinkClicked(std::move(callback));
|
getPage(RightBookPage)->adviseLinkClicked(std::move(callback));
|
||||||
|
|
@ -135,8 +136,9 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MWGui::BookPage::ClickCallback callback
|
MWGui::BookPage::ClickCallback callback = [this](MWGui::TypesetBook::InteractiveId index) {
|
||||||
= [this](MWGui::TypesetBook::InteractiveId index) { notifyIndexLinkClicked(index); };
|
notifyIndexLinkClicked(static_cast<Utf8Stream::UnicodeChar>(index));
|
||||||
|
};
|
||||||
|
|
||||||
getPage(LeftTopicIndex)->adviseLinkClicked(callback);
|
getPage(LeftTopicIndex)->adviseLinkClicked(callback);
|
||||||
getPage(CenterTopicIndex)->adviseLinkClicked(callback);
|
getPage(CenterTopicIndex)->adviseLinkClicked(callback);
|
||||||
|
|
@ -240,7 +242,7 @@ namespace
|
||||||
|
|
||||||
setBookMode();
|
setBookMode();
|
||||||
|
|
||||||
Book journalBook;
|
std::shared_ptr<MWGui::TypesetBook> journalBook;
|
||||||
if (mModel->isEmpty())
|
if (mModel->isEmpty())
|
||||||
journalBook = createEmptyJournalBook();
|
journalBook = createEmptyJournalBook();
|
||||||
else
|
else
|
||||||
|
|
@ -268,8 +270,8 @@ namespace
|
||||||
{
|
{
|
||||||
mModel->unload();
|
mModel->unload();
|
||||||
|
|
||||||
getPage(LeftBookPage)->showPage(Book(), 0);
|
getPage(LeftBookPage)->showPage({}, 0);
|
||||||
getPage(RightBookPage)->showPage(Book(), 0);
|
getPage(RightBookPage)->showPage({}, 0);
|
||||||
|
|
||||||
while (!mStates.empty())
|
while (!mStates.empty())
|
||||||
mStates.pop();
|
mStates.pop();
|
||||||
|
|
@ -315,7 +317,7 @@ namespace
|
||||||
|
|
||||||
// TODO: figure out how to make "options" page overlay book page
|
// TODO: figure out how to make "options" page overlay book page
|
||||||
// correctly, so that text may show underneath
|
// correctly, so that text may show underneath
|
||||||
getPage(RightBookPage)->showPage(Book(), 0);
|
getPage(RightBookPage)->showPage({}, 0);
|
||||||
|
|
||||||
// If in quest mode, ensure the quest list is updated
|
// If in quest mode, ensure the quest list is updated
|
||||||
if (mQuestMode)
|
if (mQuestMode)
|
||||||
|
|
@ -326,7 +328,7 @@ namespace
|
||||||
MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay();
|
MWBase::Environment::get().getWindowManager()->updateControllerButtonsOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushBook(Book& book)
|
void pushBook(std::shared_ptr<MWGui::TypesetBook>& book)
|
||||||
{
|
{
|
||||||
DisplayState bs;
|
DisplayState bs;
|
||||||
bs.mPage = 0;
|
bs.mPage = 0;
|
||||||
|
|
@ -336,7 +338,7 @@ namespace
|
||||||
updateCloseJournalButton();
|
updateCloseJournalButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
void replaceBook(Book& book)
|
void replaceBook(std::shared_ptr<MWGui::TypesetBook>& book)
|
||||||
{
|
{
|
||||||
assert(!mStates.empty());
|
assert(!mStates.empty());
|
||||||
mStates.top().mBook = book;
|
mStates.top().mBook = book;
|
||||||
|
|
@ -360,7 +362,7 @@ namespace
|
||||||
|
|
||||||
void updateShowingPages()
|
void updateShowingPages()
|
||||||
{
|
{
|
||||||
Book book;
|
std::shared_ptr<MWGui::TypesetBook> book;
|
||||||
size_t page;
|
size_t page;
|
||||||
size_t relPages;
|
size_t relPages;
|
||||||
|
|
||||||
|
|
@ -393,8 +395,16 @@ namespace
|
||||||
setVisible(PageOneNum, relPages > 0);
|
setVisible(PageOneNum, relPages > 0);
|
||||||
setVisible(PageTwoNum, relPages > 1);
|
setVisible(PageTwoNum, relPages > 1);
|
||||||
|
|
||||||
getPage(LeftBookPage)->showPage((relPages > 0) ? book : Book(), page + 0);
|
if (relPages > 0)
|
||||||
getPage(RightBookPage)->showPage((relPages > 0) ? std::move(book) : Book(), page + 1);
|
{
|
||||||
|
getPage(LeftBookPage)->showPage(book, page + 0);
|
||||||
|
getPage(RightBookPage)->showPage(std::move(book), page + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getPage(LeftBookPage)->showPage({}, page + 0);
|
||||||
|
getPage(RightBookPage)->showPage({}, page + 1);
|
||||||
|
}
|
||||||
|
|
||||||
setText(PageOneNum, page + 1);
|
setText(PageOneNum, page + 1);
|
||||||
setText(PageTwoNum, page + 2);
|
setText(PageTwoNum, page + 2);
|
||||||
|
|
@ -410,9 +420,9 @@ namespace
|
||||||
notifyNextPage(sender);
|
notifyNextPage(sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyTopicClicked(intptr_t linkId)
|
void notifyTopicClicked(const MWDialogue::Topic& topic)
|
||||||
{
|
{
|
||||||
Book topicBook = createTopicBook(linkId);
|
std::shared_ptr<MWGui::TypesetBook> topicBook = createTopicBook(topic);
|
||||||
|
|
||||||
if (mStates.size() > 1)
|
if (mStates.size() > 1)
|
||||||
replaceBook(topicBook);
|
replaceBook(topicBook);
|
||||||
|
|
@ -434,17 +444,14 @@ namespace
|
||||||
{
|
{
|
||||||
ESM::RefId topic = ESM::RefId::stringRefId(topicIdString);
|
ESM::RefId topic = ESM::RefId::stringRefId(topicIdString);
|
||||||
const MWBase::Journal* journal = MWBase::Environment::get().getJournal();
|
const MWBase::Journal* journal = MWBase::Environment::get().getJournal();
|
||||||
intptr_t topicId = 0; /// \todo get rid of intptr ids
|
|
||||||
const auto it = journal->getTopics().find(topic);
|
const auto it = journal->getTopics().find(topic);
|
||||||
if (it != journal->getTopics().end())
|
if (it != journal->getTopics().end())
|
||||||
topicId = intptr_t(&it->second);
|
notifyTopicClicked(it->second);
|
||||||
|
|
||||||
notifyTopicClicked(topicId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyQuestClicked(const std::string& name, int id)
|
void notifyQuestClicked(const std::string& name, int id)
|
||||||
{
|
{
|
||||||
Book book = createQuestBook(name);
|
std::shared_ptr<MWGui::TypesetBook> book = createQuestBook(name);
|
||||||
|
|
||||||
if (mStates.size() > 1)
|
if (mStates.size() > 1)
|
||||||
replaceBook(book);
|
replaceBook(book);
|
||||||
|
|
@ -508,7 +515,7 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyIndexLinkClicked(MWGui::TypesetBook::InteractiveId index)
|
void notifyIndexLinkClicked(Utf8Stream::UnicodeChar index)
|
||||||
{
|
{
|
||||||
setVisible(LeftTopicIndex, false);
|
setVisible(LeftTopicIndex, false);
|
||||||
setVisible(CenterTopicIndex, false);
|
setVisible(CenterTopicIndex, false);
|
||||||
|
|
@ -664,7 +671,7 @@ namespace
|
||||||
if (!mStates.empty())
|
if (!mStates.empty())
|
||||||
{
|
{
|
||||||
size_t& page = mStates.top().mPage;
|
size_t& page = mStates.top().mPage;
|
||||||
Book book = mStates.top().mBook;
|
std::shared_ptr<MWGui::TypesetBook> book = mStates.top().mBook;
|
||||||
|
|
||||||
if (page + 2 < book->pageCount())
|
if (page + 2 < book->pageCount())
|
||||||
{
|
{
|
||||||
|
|
@ -785,7 +792,8 @@ namespace
|
||||||
if (mSelectedIndex >= 27)
|
if (mSelectedIndex >= 27)
|
||||||
russianOffset++; // 27, not 28, because of skipping char 26
|
russianOffset++; // 27, not 28, because of skipping char 26
|
||||||
bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251);
|
bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251);
|
||||||
notifyIndexLinkClicked(isRussian ? mSelectedIndex + russianOffset : mSelectedIndex + 'A');
|
size_t ch = isRussian ? mSelectedIndex + russianOffset : mSelectedIndex + 'A';
|
||||||
|
notifyIndexLinkClicked(static_cast<Utf8Stream::UnicodeChar>(ch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (arg.button == SDL_CONTROLLER_BUTTON_B) // B: Back
|
else if (arg.button == SDL_CONTROLLER_BUTTON_B) // B: Back
|
||||||
|
|
@ -945,7 +953,7 @@ namespace
|
||||||
|
|
||||||
// glue the implementation to the interface
|
// glue the implementation to the interface
|
||||||
std::unique_ptr<MWGui::JournalWindow> MWGui::JournalWindow::create(
|
std::unique_ptr<MWGui::JournalWindow> MWGui::JournalWindow::create(
|
||||||
JournalViewModel::Ptr model, bool questList, ToUTF8::FromType encoding)
|
std::shared_ptr<JournalViewModel> model, bool questList, ToUTF8::FromType encoding)
|
||||||
{
|
{
|
||||||
return std::make_unique<JournalWindowImpl>(model, questList, encoding);
|
return std::make_unique<JournalWindowImpl>(model, questList, encoding);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue