Moved out spoiler data from Ui::Text::String to separate structure.
This commit is contained in:
parent
6ce4bedc28
commit
1cc74a41c4
4 changed files with 70 additions and 38 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,13 +862,18 @@ 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) {
|
||||||
|
_t->_spoiler = std::make_shared<SpoilerData>();
|
||||||
|
}
|
||||||
|
if (_t->_spoiler->links.size() < spoilerIndex) {
|
||||||
|
_t->_spoiler->links.resize(spoilerIndex);
|
||||||
const auto handler = (options.flags & TextParseLinks)
|
const auto handler = (options.flags & TextParseLinks)
|
||||||
? std::make_shared<SpoilerClickHandler>()
|
? std::make_shared<SpoilerClickHandler>()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
_t->setSpoiler(spoilerIndex, std::move(handler));
|
_t->setSpoiler(spoilerIndex, std::move(handler));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const auto shiftedIndex = block->lnkIndex();
|
const auto shiftedIndex = block->lnkIndex();
|
||||||
auto useCustomIndex = false;
|
auto useCustomIndex = false;
|
||||||
if (shiftedIndex <= kStringLinkIndexShift) {
|
if (shiftedIndex <= kStringLinkIndexShift) {
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
22
ui/text/text_spoiler_data.h
Normal file
22
ui/text/text_spoiler_data.h
Normal 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
|
||||||
Loading…
Add table
Reference in a new issue