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.cpp
ui/text/text_entity.h ui/text/text_entity.h
ui/text/text_isolated_emoji.h ui/text/text_isolated_emoji.h
ui/text/text_spoiler_data.h
ui/text/text_utilities.cpp ui/text/text_utilities.cpp
ui/text/text_utilities.h ui/text/text_utilities.h
ui/text/text_variant.cpp ui/text/text_variant.cpp

View file

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

View file

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