From 17b259df9cb6b28779d4881b2b6c805ee2e48eea Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Fri, 7 Jun 2024 23:30:05 +0900 Subject: Rename to tde-ebook-reader Signed-off-by: Michele Calgaro --- reader/src/blockTree/ReaderNode.cpp | 275 ++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 reader/src/blockTree/ReaderNode.cpp (limited to 'reader/src/blockTree/ReaderNode.cpp') diff --git a/reader/src/blockTree/ReaderNode.cpp b/reader/src/blockTree/ReaderNode.cpp new file mode 100644 index 0000000..cdca140 --- /dev/null +++ b/reader/src/blockTree/ReaderNode.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include + +#include "ReaderNode.h" + +#include "../reader/Reader.h" +#include "../options/FBOptions.h" +#include "../options/FBTextStyle.h" + +const ZLTypeId ReaderNode::TYPE_ID(ZLBlockTreeNode::TYPE_ID); + +class ReaderNode::ExpandTreeAction : public ZLRunnableWithKey { + +public: + ExpandTreeAction(ReaderNode &node); + void run(); + ZLResourceKey key() const; + +private: + ReaderNode &myNode; +}; + +std::map > ReaderNode::ourDefaultCovers; + +ReaderNode::ReaderNode(ZLBlockTreeNode *parent, std::size_t atPosition) : ZLBlockTreeNode(parent, atPosition), myCoverImageIsStored(false), myIsInitialized(false) { +} + +void ReaderNode::init() { +} + +bool ReaderNode::highlighted() const { + return false; +} + +ReaderNode::~ReaderNode() { +} + +const ZLTypeId &ReaderNode::typeId() const { + return TYPE_ID; +} + +shared_ptr ReaderNode::coverImage() const { + if (!myCoverImageIsStored) { + myCoverImageIsStored = true; + myStoredCoverImage = extractCoverImage(); + } + return myStoredCoverImage; +} + +void ReaderNode::drawCover(ZLPaintContext &context, int vOffset) { + drawCoverReal(context, vOffset); +} + +void ReaderNode::drawCoverReal(ZLPaintContext &context, int vOffset) { + shared_ptr cover = coverImage(); + if (cover.isNull()) { + return; + } + + shared_ptr coverData = ZLImageManager::Instance().imageData(*cover); + if (coverData.isNull()) { + return; + } + + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int h = unit * 9 / 2, w = h * 3 / 4; + vOffset += unit / 2; + const int hOffset = level() * unit * 3 - unit * 2; + + const int origWidth = context.imageWidth(*coverData); + const int origHeight = context.imageHeight(*coverData); + if (origWidth == 0 || origHeight == 0) { + return; + } + + int coeff = std::min(w / origWidth, h / origHeight); + if (coeff == 0) { + coeff = 1; + } + int width = coeff * origWidth; + int height = coeff * origHeight; + if (width > w || height > h) { + width = context.imageWidth(*coverData, w, h, ZLPaintContext::SCALE_REDUCE_SIZE); + height = context.imageHeight(*coverData, w, h, ZLPaintContext::SCALE_REDUCE_SIZE); + } + context.drawImage(hOffset + (w - width) / 2, vOffset + (h + height) / 2, *coverData, width, height, ZLPaintContext::SCALE_FIT_TO_SIZE); +} + +void ReaderNode::drawTitle(ZLPaintContext &context, int vOffset) { + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int hOffset = level() * unit * 3 + unit * 2; + + context.setColor(highlighted() ? + FBOptions::Instance().colorOption(ZLTextStyle::HIGHLIGHTED_TEXT).value() : + FBOptions::Instance().RegularTextColorOption.value()); + context.setFont(style.fontFamily(), style.fontSize(), style.bold(), style.italic()); + + const std::string text = title(); + context.drawString(hOffset, vOffset + 2 * unit, text.data(), text.size(), false); +} + +void ReaderNode::drawSummary(ZLPaintContext &context, int vOffset) { + const std::string text = summary(); + if (text.empty()) { + return; + } + + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int hOffset = level() * unit * 3 + unit * 2; + + context.setColor(highlighted() ? + FBOptions::Instance().colorOption(ZLTextStyle::HIGHLIGHTED_TEXT).value() : + FBOptions::Instance().RegularTextColorOption.value()); + context.setFont(style.fontFamily(), style.fontSize() * 2 / 3, style.bold(), style.italic()); + + context.drawString(hOffset, vOffset + 13 * unit / 4, text.data(), text.size(), false); +} + +void ReaderNode::drawHyperlink(ZLPaintContext &context, int &hOffset, int &vOffset, shared_ptr action, bool auxiliary) { + // auxiliary makes font size and hSkip to be 70% of their normal sizes + if (action.isNull() || !action->makesSense()) { + return; + } + + const FBTextStyle &style = FBTextStyle::Instance(); + const int unit = unitSize(context, style); + const int h = auxiliary ? (unit * 11 / 2) : (unit * 9 / 2); + const int left = hOffset + level() * unit * 3 + unit * 2; + + context.setColor(FBOptions::Instance().colorOption("internal").value()); + context.setFont( + style.fontFamily(), + auxiliary ? (7 * style.fontSize() / 15) : (style.fontSize() * 2 / 3), + style.bold(), + style.italic() + ); + + const std::string text = action->text(resource()); + const int stringW = context.stringWidth(text.data(), text.size(), false); + const int stringH = context.stringHeight(); + context.drawString(left, vOffset + h, text.data(), text.size(), false); + addHyperlink(left, h - stringH, left + stringW, h, action); + hOffset += stringW + 4 * context.spaceWidth(); +} + +ReaderNode::ExpandTreeAction::ExpandTreeAction(ReaderNode &node) : myNode(node) { +} + +void ReaderNode::ExpandTreeAction::run() { + myNode.expandOrCollapseSubtree(); + Reader::Instance().refreshWindow(); +} + +ZLResourceKey ReaderNode::ExpandTreeAction::key() const { + return ZLResourceKey(myNode.isOpen() ? "collapseTree" : "expandTree"); +} + +void ReaderNode::expandOrCollapseSubtree() { + if (isOpen()) { + open(false); + } else if (!children().empty()) { + open(true); + if (view().visibilityMode(this) != ZLBlockTreeView::INVISIBLE) { + ZLBlockTreeNode *lastChild = children().back(); + while (view().visibilityMode(lastChild) != ZLBlockTreeView::VISIBLE && + this != view().firstVisibleNode()) { + view().setFirstVisibleNode(view().firstVisibleNode()->next()); + } + } + } +} + +void ReaderNode::registerAction(shared_ptr action, bool auxiliary) { + if (!action.isNull()) { + myActions.push_back(std::make_pair(action, auxiliary)); + } +} + +void ReaderNode::registerExpandTreeAction() { + registerAction(new ExpandTreeAction(*this)); +} + +shared_ptr ReaderNode::defaultCoverImage(const std::string &id) { + shared_ptr cover = ourDefaultCovers[id]; + if (cover.isNull()) { + cover = new ZLFileImage( + ZLFile(ZLibrary::ApplicationImageDirectory() + ZLibrary::FileNameDelimiter + id), 0 + ); + ourDefaultCovers[id] = cover; + } + return cover; +} + +int ReaderNode::height(ZLPaintContext &context) const { + bool hasAuxHyperlink = false; + for (std::vector,bool> >::const_iterator it = myActions.begin(); it != myActions.end(); ++it) { + if (it->second && it->first->makesSense()) { + hasAuxHyperlink = true; + break; + } + } + return + unitSize(context, FBTextStyle::Instance()) * + (hasAuxHyperlink ? 13 : 11) / 2; +} + +int ReaderNode::unitSize(ZLPaintContext &context, const FBTextStyle &style) const { + context.setFont(style.fontFamily(), style.fontSize(), style.bold(), style.italic()); + return (context.stringHeight() * 2 + 2) / 3; +} + +std::string ReaderNode::summary() const { + std::string result; + int count = 0; + const ZLBlockTreeNode::List &subNodes = children(); + ZLBlockTreeNode::List::const_iterator it = subNodes.begin(); + for (; it != subNodes.end() && count < 3; ++it, ++count) { + if (count > 0) { + result += ", "; + } + result += ((const ReaderNode*)*it)->title(); + } + if (it != subNodes.end()) { + result += ", ..."; + } + return result; +} + +void ReaderNode::paint(ZLPaintContext &context, int vOffset) { + if (!myIsInitialized) { + init(); + myIsInitialized = true; + } + + removeAllHyperlinks(); + + drawCover(context, vOffset); + drawTitle(context, vOffset); + drawSummary(context, vOffset); + + int left = 0; + int auxLeft = 0; + for (std::vector,bool> >::const_iterator it = myActions.begin(); it != myActions.end(); ++it) { + if (it->first->makesSense()) { + if (it->second) { + drawHyperlink(context, auxLeft, vOffset, it->first, true); + } else { + drawHyperlink(context, left, vOffset, it->first); + } + } + } +} -- cgit v1.2.3