Moved out spoiler data from Ui::Text::String to separate structure.

This commit is contained in:
23rd 2022-08-16 18:50:45 +03:00
parent 6ce4bedc28
commit 1cc74a41c4
4 changed files with 70 additions and 38 deletions

View file

@ -154,6 +154,7 @@ PRIVATE
ui/text/text_entity.cpp
ui/text/text_entity.h
ui/text/text_isolated_emoji.h
ui/text/text_spoiler_data.h
ui/text/text_utilities.cpp
ui/text/text_utilities.h
ui/text/text_variant.cpp

View file

@ -9,6 +9,7 @@
#include "ui/basic_click_handlers.h"
#include "ui/text/text_block.h"
#include "ui/text/text_isolated_emoji.h"
#include "ui/text/text_spoiler_data.h"
#include "ui/emoji_config.h"
#include "ui/integration.h"
#include "ui/round_rect.h"
@ -861,12 +862,17 @@ void Parser::finalize(const TextParseOptions &options) {
}
}
const auto spoilerIndex = block->spoilerIndex();
if (spoilerIndex && (_t->_spoilers.size() < spoilerIndex)) {
_t->_spoilers.resize(spoilerIndex);
const auto handler = (options.flags & TextParseLinks)
? std::make_shared<SpoilerClickHandler>()
: nullptr;
_t->setSpoiler(spoilerIndex, std::move(handler));
if (spoilerIndex) {
if (!_t->_spoiler) {
_t->_spoiler = std::make_shared<SpoilerData>();
}
if (_t->_spoiler->links.size() < spoilerIndex) {
_t->_spoiler->links.resize(spoilerIndex);
const auto handler = (options.flags & TextParseLinks)
? std::make_shared<SpoilerClickHandler>()
: nullptr;
_t->setSpoiler(spoilerIndex, std::move(handler));
}
}
const auto shiftedIndex = block->lnkIndex();
auto useCustomIndex = false;
@ -925,14 +931,16 @@ void Parser::finalize(const TextParseOptions &options) {
}
lastHandlerIndex.lnk = realIndex;
}
if (!_t->_hasCustomEmoji || !_t->_spoilers.empty()) {
if (!_t->_hasCustomEmoji || _t->_spoiler) {
_t->_isOnlyCustomEmoji = false;
}
if (_t->_blocks.empty() || !_t->_spoilers.empty()) {
if (_t->_blocks.empty() || _t->_spoiler) {
_t->_isIsolatedEmoji = false;
}
_t->_links.squeeze();
_t->_spoilers.squeeze();
if (_t->_spoiler) {
_t->_spoiler->links.squeeze();
}
_t->_blocks.shrink_to_fit();
_t->_text.squeeze();
}
@ -1961,8 +1969,9 @@ private:
}
const auto progress = float64(_now - _background.startMs)
/ st::fadeWrapDuration;
if ((progress > 1.) && _background.spoilerIndex) {
const auto link = _t->_spoilers.at(_background.spoilerIndex - 1);
if ((progress > 1.) && _background.spoilerIndex && _t->_spoiler) {
const auto link = _t->_spoiler->links.at(
_background.spoilerIndex - 1);
if (link) {
link->setStartMs(0);
}
@ -1979,6 +1988,9 @@ private:
if (!_background.color) {
return;
}
if (!_t->_spoiler) {
return;
}
const auto elideOffset = (_indexOfElidedBlock == currentBlockIndex)
? (_elideRemoveFromEnd + _f->elidew)
: 0;
@ -2011,8 +2023,8 @@ private:
const auto hasRight = (parts & RectPart::Right) != 0;
const auto &cache = _background.inFront
? _t->_spoilerCache
: _t->_spoilerShownCache;
? _t->_spoiler->spoilerCache
: _t->_spoiler->spoilerShownCache;
const auto cornerWidth = cache.corners[0].width()
/ style::DevicePixelRatio();
const auto useWidth = ((x + width).toInt() - x.toInt()) - elideOffset;
@ -2833,9 +2845,9 @@ private:
if (_p) {
const auto isMono = IsMono(block->flags());
_background = {};
if (block->spoilerIndex()) {
if (block->spoilerIndex() && _t->_spoiler) {
const auto handler
= _t->_spoilers.at(block->spoilerIndex() - 1);
= _t->_spoiler->links.at(block->spoilerIndex() - 1);
const auto inBack = (handler && handler->shown());
_background.inFront = !inBack;
_background.color = inBack
@ -2844,14 +2856,15 @@ private:
_background.startMs = handler ? handler->startMs() : 0;
_background.spoilerIndex = block->spoilerIndex();
Assert(_t->_spoiler != nullptr);
const auto &cache = _background.inFront
? _t->_spoilerCache
: _t->_spoilerShownCache;
? _t->_spoiler->spoilerCache
: _t->_spoiler->spoilerShownCache;
if (cache.color != (*_background.color)->c) {
auto mutableText = const_cast<String*>(_t);
auto &mutableCache = _background.inFront
? mutableText->_spoilerCache
: mutableText->_spoilerShownCache;
? mutableText->_spoiler->spoilerCache
: mutableText->_spoiler->spoilerShownCache;
mutableCache.corners = Images::PrepareCorners(
ImageRoundRadius::Small,
*_background.color);
@ -3134,19 +3147,20 @@ void String::setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk) {
void String::setSpoiler(
uint16 lnkIndex,
const std::shared_ptr<SpoilerClickHandler> &lnk) {
if (!lnkIndex || lnkIndex > _spoilers.size()) {
if (!lnkIndex || !_spoiler || lnkIndex > _spoiler->links.size()) {
return;
}
_spoilers[lnkIndex - 1] = lnk;
_spoiler->links[lnkIndex - 1] = lnk;
}
void String::setSpoilerShown(uint16 lnkIndex, bool shown) {
if (!lnkIndex
|| (lnkIndex > _spoilers.size())
|| !_spoilers[lnkIndex - 1]) {
|| !_spoiler
|| (lnkIndex > _spoiler->links.size())
|| !_spoiler->links[lnkIndex - 1]) {
return;
}
_spoilers[lnkIndex - 1]->setShown(shown);
_spoiler->links[lnkIndex - 1]->setShown(shown);
}
bool String::hasLinks() const {
@ -3154,7 +3168,7 @@ bool String::hasLinks() const {
}
int String::spoilersCount() const {
return _spoilers.size();
return !_spoiler ? 0 : int(_spoiler->links.size());
}
bool String::hasSkipBlock() const {
@ -3528,9 +3542,9 @@ void String::enumerateText(
if (rangeTo > rangeFrom) { // handle click handler
const auto r = base::StringViewMid(_text, rangeFrom, rangeTo - rangeFrom);
// Ignore links that are partially copied.
const auto handler = (spoilerFrom != rangeFrom || blockFrom != rangeTo)
const auto handler = (spoilerFrom != rangeFrom || blockFrom != rangeTo || !_spoiler)
? nullptr
: _spoilers.at(spoilerIndex - 1);
: _spoiler->links.at(spoilerIndex - 1);
const auto type = EntityType::Spoiler;
clickHandlerFinishCallback(r, handler, type);
}
@ -3784,8 +3798,7 @@ IsolatedEmoji String::toIsolatedEmoji() const {
auto result = IsolatedEmoji();
const auto skip = (_blocks.empty()
|| _blocks.back()->type() != TextBlockTSkip) ? 0 : 1;
if ((_blocks.size() > kIsolatedEmojiLimit + skip)
|| !_spoilers.empty()) {
if ((_blocks.size() > kIsolatedEmojiLimit + skip) || _spoiler) {
return {};
}
auto index = 0;
@ -3813,14 +3826,14 @@ void String::clear() {
void String::clearFields() {
_blocks.clear();
_links.clear();
_spoilers.clear();
_spoiler = nullptr;
_maxWidth = _minHeight = 0;
_startDir = Qt::LayoutDirectionAuto;
}
ClickHandlerPtr String::spoilerLink(uint16 spoilerIndex) const {
if (spoilerIndex) {
const auto &handler = _spoilers.at(spoilerIndex - 1);
if (spoilerIndex && _spoiler) {
const auto &handler = _spoiler->links.at(spoilerIndex - 1);
return (handler && !handler->shown()) ? handler : nullptr;
}
return nullptr;

View file

@ -64,6 +64,7 @@ namespace Ui::Text {
struct IsolatedEmoji;
struct OnlyCustomEmoji;
struct SpoilerData;
struct StateRequest {
enum class Flag {
@ -226,14 +227,9 @@ private:
TextBlocks _blocks;
TextLinks _links;
QVector<std::shared_ptr<SpoilerClickHandler>> _spoilers;
Qt::LayoutDirection _startDir = Qt::LayoutDirectionAuto;
struct {
std::array<QImage, 4> corners;
QColor color;
} _spoilerCache, _spoilerShownCache;
std::shared_ptr<SpoilerData> _spoiler;
friend class Parser;
friend class Renderer;

View file

@ -0,0 +1,22 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
class SpoilerClickHandler;
namespace Ui::Text {
struct SpoilerData {
struct {
std::array<QImage, 4> corners;
QColor color;
} spoilerCache, spoilerShownCache;
QVector<std::shared_ptr<SpoilerClickHandler>> links;
};
} // namespace Ui::Text