Optimize spoiler revealing.
This commit is contained in:
parent
a60fe582ad
commit
bc76e4f601
11 changed files with 93 additions and 178 deletions
|
|
@ -271,8 +271,6 @@ PRIVATE
|
||||||
ui/rect_part.h
|
ui/rect_part.h
|
||||||
ui/round_rect.cpp
|
ui/round_rect.cpp
|
||||||
ui/round_rect.h
|
ui/round_rect.h
|
||||||
ui/spoiler_click_handler.cpp
|
|
||||||
ui/spoiler_click_handler.h
|
|
||||||
ui/rp_widget.cpp
|
ui/rp_widget.cpp
|
||||||
ui/rp_widget.h
|
ui/rp_widget.h
|
||||||
ui/ui_utility.cpp
|
ui/ui_utility.cpp
|
||||||
|
|
|
||||||
|
|
@ -775,6 +775,10 @@ int SpoilerAnimation::index(crl::time now, bool paused) {
|
||||||
return absolute % kDefaultFramesCount;
|
return absolute % kDefaultFramesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fn<void()> SpoilerAnimation::repaintCallback() const {
|
||||||
|
return _repaint;
|
||||||
|
}
|
||||||
|
|
||||||
bool SpoilerAnimation::repaint(crl::time now) {
|
bool SpoilerAnimation::repaint(crl::time now) {
|
||||||
if (!_scheduled) {
|
if (!_scheduled) {
|
||||||
_scheduled = true;
|
_scheduled = true;
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,9 @@ public:
|
||||||
explicit SpoilerAnimation(Fn<void()> repaint);
|
explicit SpoilerAnimation(Fn<void()> repaint);
|
||||||
~SpoilerAnimation();
|
~SpoilerAnimation();
|
||||||
|
|
||||||
int index(crl::time now, bool paused);
|
[[nodiscard]] int index(crl::time now, bool paused);
|
||||||
|
|
||||||
|
[[nodiscard]] Fn<void()> repaintCallback() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SpoilerAnimationManager;
|
friend class SpoilerAnimationManager;
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
// 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
|
|
||||||
//
|
|
||||||
#include "ui/spoiler_click_handler.h"
|
|
||||||
|
|
||||||
#include "ui/effects/animation_value.h"
|
|
||||||
#include "ui/text/text_entity.h"
|
|
||||||
|
|
||||||
ClickHandler::TextEntity SpoilerClickHandler::getTextEntity() const {
|
|
||||||
return { EntityType::Spoiler };
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpoilerClickHandler::onClick(ClickContext context) const {
|
|
||||||
if (!_shown) {
|
|
||||||
const auto nonconst = const_cast<SpoilerClickHandler*>(this);
|
|
||||||
nonconst->_shown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpoilerClickHandler::shown() const {
|
|
||||||
return _shown;
|
|
||||||
}
|
|
||||||
|
|
||||||
crl::time SpoilerClickHandler::startMs() const {
|
|
||||||
return _startMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpoilerClickHandler::setStartMs(crl::time value) {
|
|
||||||
if (anim::Disabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_startMs = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpoilerClickHandler::setShown(bool value) {
|
|
||||||
_shown = value;
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
#include "ui/click_handler.h"
|
|
||||||
|
|
||||||
enum class EntityType : uchar;
|
|
||||||
|
|
||||||
class SpoilerClickHandler : public ClickHandler {
|
|
||||||
public:
|
|
||||||
SpoilerClickHandler() = default;
|
|
||||||
|
|
||||||
TextEntity getTextEntity() const override;
|
|
||||||
|
|
||||||
void onClick(ClickContext context) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] bool shown() const;
|
|
||||||
void setShown(bool value);
|
|
||||||
[[nodiscard]] crl::time startMs() const;
|
|
||||||
void setStartMs(crl::time value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _shown = false;
|
|
||||||
crl::time _startMs = 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
#include "ui/text/text_spoiler_data.h"
|
#include "ui/text/text_spoiler_data.h"
|
||||||
#include "ui/basic_click_handlers.h"
|
#include "ui/basic_click_handlers.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/spoiler_click_handler.h"
|
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "styles/style_basic.h"
|
#include "styles/style_basic.h"
|
||||||
|
|
||||||
|
|
@ -318,31 +317,40 @@ void String::setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk) {
|
||||||
_links[lnkIndex - 1] = lnk;
|
_links[lnkIndex - 1] = lnk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void String::setSpoiler(
|
void String::setSpoilerRevealed(bool revealed, anim::type animated) {
|
||||||
uint16 lnkIndex,
|
if (!_spoiler) {
|
||||||
const std::shared_ptr<SpoilerClickHandler> &lnk) {
|
return;
|
||||||
if (!lnkIndex || !_spoiler || lnkIndex > _spoiler->links.size()) {
|
} else if (_spoiler->revealed == revealed) {
|
||||||
|
if (animated == anim::type::instant
|
||||||
|
&& _spoiler->revealAnimation.animating()) {
|
||||||
|
_spoiler->revealAnimation.stop();
|
||||||
|
_spoiler->animation.repaintCallback()();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_spoiler->links[lnkIndex - 1] = lnk;
|
_spoiler->revealed = revealed;
|
||||||
|
if (animated == anim::type::instant) {
|
||||||
|
_spoiler->revealAnimation.stop();
|
||||||
|
_spoiler->animation.repaintCallback()();
|
||||||
|
} else {
|
||||||
|
_spoiler->revealAnimation.start(
|
||||||
|
_spoiler->animation.repaintCallback(),
|
||||||
|
revealed ? 0. : 1.,
|
||||||
|
revealed ? 1. : 0.,
|
||||||
|
st::fadeWrapDuration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void String::setSpoilerShown(uint16 lnkIndex, bool shown) {
|
void String::setSpoilerLink(const ClickHandlerPtr &lnk) {
|
||||||
if (!lnkIndex
|
_spoiler->link = lnk;
|
||||||
|| !_spoiler
|
|
||||||
|| (lnkIndex > _spoiler->links.size())
|
|
||||||
|| !_spoiler->links[lnkIndex - 1]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_spoiler->links[lnkIndex - 1]->setShown(shown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::hasLinks() const {
|
bool String::hasLinks() const {
|
||||||
return !_links.isEmpty();
|
return !_links.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
int String::spoilersCount() const {
|
bool String::hasSpoilers() const {
|
||||||
return !_spoiler ? 0 : int(_spoiler->links.size());
|
return (_spoiler != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::hasSkipBlock() const {
|
bool String::hasSkipBlock() const {
|
||||||
|
|
@ -752,9 +760,11 @@ 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 || !_spoiler)
|
const auto handler = (spoilerFrom != rangeFrom
|
||||||
|
|| blockFrom != rangeTo
|
||||||
|
|| !_spoiler)
|
||||||
? nullptr
|
? nullptr
|
||||||
: _spoiler->links.at(spoilerIndex - 1);
|
: _spoiler->link;
|
||||||
const auto type = EntityType::Spoiler;
|
const auto type = EntityType::Spoiler;
|
||||||
clickHandlerFinishCallback(r, handler, type);
|
clickHandlerFinishCallback(r, handler, type);
|
||||||
}
|
}
|
||||||
|
|
@ -1040,14 +1050,6 @@ void String::clearFields() {
|
||||||
_startDir = Qt::LayoutDirectionAuto;
|
_startDir = Qt::LayoutDirectionAuto;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClickHandlerPtr String::spoilerLink(uint16 spoilerIndex) const {
|
|
||||||
if (spoilerIndex && _spoiler) {
|
|
||||||
const auto &handler = _spoiler->links.at(spoilerIndex - 1);
|
|
||||||
return (handler && !handler->shown()) ? handler : nullptr;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsBad(QChar ch) {
|
bool IsBad(QChar ch) {
|
||||||
return (ch == 0)
|
return (ch == 0)
|
||||||
|| (ch >= 8232 && ch < 8237)
|
|| (ch >= 8232 && ch < 8237)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,10 @@
|
||||||
#include <any>
|
#include <any>
|
||||||
|
|
||||||
class Painter;
|
class Painter;
|
||||||
class SpoilerClickHandler;
|
|
||||||
|
namespace anim {
|
||||||
|
enum class type : uchar;
|
||||||
|
} // namespace anim
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
struct TextPalette;
|
struct TextPalette;
|
||||||
|
|
@ -162,13 +165,12 @@ public:
|
||||||
void setText(const style::TextStyle &st, const QString &text, const TextParseOptions &options = kDefaultTextOptions);
|
void setText(const style::TextStyle &st, const QString &text, const TextParseOptions &options = kDefaultTextOptions);
|
||||||
void setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options = kMarkupTextOptions, const std::any &context = {});
|
void setMarkedText(const style::TextStyle &st, const TextWithEntities &textWithEntities, const TextParseOptions &options = kMarkupTextOptions, const std::any &context = {});
|
||||||
|
|
||||||
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
|
|
||||||
[[nodiscard]] bool hasLinks() const;
|
[[nodiscard]] bool hasLinks() const;
|
||||||
void setSpoiler(
|
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
|
||||||
uint16 lnkIndex,
|
|
||||||
const std::shared_ptr<SpoilerClickHandler> &lnk);
|
[[nodiscard]] bool hasSpoilers() const;
|
||||||
void setSpoilerShown(uint16 lnkIndex, bool shown);
|
void setSpoilerRevealed(bool revealed, anim::type animated);
|
||||||
[[nodiscard]] int spoilersCount() const;
|
void setSpoilerLink(const ClickHandlerPtr &lnk);
|
||||||
|
|
||||||
[[nodiscard]] bool hasSkipBlock() const;
|
[[nodiscard]] bool hasSkipBlock() const;
|
||||||
bool updateSkipBlock(int width, int height);
|
bool updateSkipBlock(int width, int height);
|
||||||
|
|
@ -254,8 +256,6 @@ private:
|
||||||
// it is also called from move constructor / assignment operator
|
// it is also called from move constructor / assignment operator
|
||||||
void clearFields();
|
void clearFields();
|
||||||
|
|
||||||
[[nodiscard]] ClickHandlerPtr spoilerLink(uint16 spoilerIndex) const;
|
|
||||||
|
|
||||||
TextForMimeData toText(
|
TextForMimeData toText(
|
||||||
TextSelection selection,
|
TextSelection selection,
|
||||||
bool composeExpanded,
|
bool composeExpanded,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
#include "ui/text/text_isolated_emoji.h"
|
#include "ui/text/text_isolated_emoji.h"
|
||||||
#include "ui/text/text_spoiler_data.h"
|
#include "ui/text/text_spoiler_data.h"
|
||||||
#include "ui/spoiler_click_handler.h"
|
|
||||||
#include "styles/style_basic.h"
|
#include "styles/style_basic.h"
|
||||||
|
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
|
@ -634,19 +633,11 @@ void Parser::finalize(const TextParseOptions &options) {
|
||||||
_t->_isIsolatedEmoji = false;
|
_t->_isIsolatedEmoji = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto spoilerIndex = block->spoilerIndex();
|
if (block->spoilerIndex()) {
|
||||||
if (spoilerIndex) {
|
|
||||||
if (!_t->_spoiler) {
|
if (!_t->_spoiler) {
|
||||||
_t->_spoiler = std::make_unique<SpoilerData>(
|
_t->_spoiler = std::make_unique<SpoilerData>(
|
||||||
Integration::Instance().createSpoilerRepaint(_context));
|
Integration::Instance().createSpoilerRepaint(_context));
|
||||||
}
|
}
|
||||||
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();
|
const auto shiftedIndex = block->lnkIndex();
|
||||||
auto useCustomIndex = false;
|
auto useCustomIndex = false;
|
||||||
|
|
@ -712,9 +703,6 @@ void Parser::finalize(const TextParseOptions &options) {
|
||||||
_t->_isIsolatedEmoji = false;
|
_t->_isIsolatedEmoji = false;
|
||||||
}
|
}
|
||||||
_t->_links.squeeze();
|
_t->_links.squeeze();
|
||||||
if (_t->_spoiler) {
|
|
||||||
_t->_spoiler->links.squeeze();
|
|
||||||
}
|
|
||||||
_t->_blocks.shrink_to_fit();
|
_t->_blocks.shrink_to_fit();
|
||||||
_t->_text.squeeze();
|
_t->_text.squeeze();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include "ui/text/text_renderer.h"
|
#include "ui/text/text_renderer.h"
|
||||||
|
|
||||||
#include "ui/text/text_spoiler_data.h"
|
#include "ui/text/text_spoiler_data.h"
|
||||||
#include "ui/spoiler_click_handler.h"
|
|
||||||
#include "styles/style_basic.h"
|
#include "styles/style_basic.h"
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
|
@ -200,6 +199,10 @@ void Renderer::draw(QPainter &p, const PaintContext &context) {
|
||||||
_align = context.align;
|
_align = context.align;
|
||||||
_cachedNow = context.now;
|
_cachedNow = context.now;
|
||||||
_paused = context.paused;
|
_paused = context.paused;
|
||||||
|
_spoilerOpacity = _t->_spoiler
|
||||||
|
? (1. - _t->_spoiler->revealAnimation.value(
|
||||||
|
_t->_spoiler->revealed ? 1. : 0.))
|
||||||
|
: 0.;
|
||||||
enumerate();
|
enumerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -720,12 +723,8 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
if (!_p && _lookupX >= x && _lookupX < x + si.width) { // _lookupRequest
|
if (!_p && _lookupX >= x && _lookupX < x + si.width) { // _lookupRequest
|
||||||
if (_lookupLink) {
|
if (_lookupLink) {
|
||||||
if (_lookupY >= _y + _yDelta && _lookupY < _y + _yDelta + _fontHeight) {
|
if (_lookupY >= _y + _yDelta && _lookupY < _y + _yDelta + _fontHeight) {
|
||||||
const auto spoilerLink = _t->spoilerLink(currentBlock->spoilerIndex());
|
if (const auto link = lookupLink(currentBlock)) {
|
||||||
const auto resultLink = (spoilerLink || !currentBlock->lnkIndex())
|
_lookupResult.link = link;
|
||||||
? spoilerLink
|
|
||||||
: _t->_links.at(currentBlock->lnkIndex() - 1);
|
|
||||||
if (resultLink) {
|
|
||||||
_lookupResult.link = resultLink;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -802,19 +801,16 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto hasSpoiler = _background.inFront
|
const auto hasSpoiler = _background.spoiler
|
||||||
|| _background.startMs;
|
&& (_spoilerOpacity > 0.);
|
||||||
if (hasSpoiler) {
|
if (hasSpoiler) {
|
||||||
fillSpoiler = { x, x + si.width };
|
fillSpoiler = { x, x + si.width };
|
||||||
}
|
}
|
||||||
const auto spoilerOpacity = hasSpoiler
|
|
||||||
? fillSpoilerOpacity()
|
|
||||||
: 0.;
|
|
||||||
fillSelectRange(fillSelect);
|
fillSelectRange(fillSelect);
|
||||||
const auto opacity = _p->opacity();
|
const auto opacity = _p->opacity();
|
||||||
if (spoilerOpacity < 1.) {
|
if (!hasSpoiler || _spoilerOpacity < 1.) {
|
||||||
if (hasSpoiler) {
|
if (hasSpoiler) {
|
||||||
_p->setOpacity(opacity * (1. - spoilerOpacity));
|
_p->setOpacity(opacity * (1. - _spoilerOpacity));
|
||||||
}
|
}
|
||||||
const auto x = (glyphX + st::emojiPadding).toInt();
|
const auto x = (glyphX + st::emojiPadding).toInt();
|
||||||
const auto y = _y + _yDelta + emojiY;
|
const auto y = _y + _yDelta + emojiY;
|
||||||
|
|
@ -872,12 +868,8 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
if (!_p && _lookupX >= x && _lookupX < x + itemWidth) { // _lookupRequest
|
if (!_p && _lookupX >= x && _lookupX < x + itemWidth) { // _lookupRequest
|
||||||
if (_lookupLink) {
|
if (_lookupLink) {
|
||||||
if (_lookupY >= _y + _yDelta && _lookupY < _y + _yDelta + _fontHeight) {
|
if (_lookupY >= _y + _yDelta && _lookupY < _y + _yDelta + _fontHeight) {
|
||||||
const auto spoilerLink = _t->spoilerLink(currentBlock->spoilerIndex());
|
if (const auto link = lookupLink(currentBlock)) {
|
||||||
const auto resultLink = (spoilerLink || !currentBlock->lnkIndex())
|
_lookupResult.link = link;
|
||||||
? spoilerLink
|
|
||||||
: _t->_links.at(currentBlock->lnkIndex() - 1);
|
|
||||||
if (resultLink) {
|
|
||||||
_lookupResult.link = resultLink;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -987,17 +979,15 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
fillSelect = { selX, selX + selWidth };
|
fillSelect = { selX, selX + selWidth };
|
||||||
fillSelectRange(fillSelect);
|
fillSelectRange(fillSelect);
|
||||||
}
|
}
|
||||||
const auto hasSpoiler = (_background.inFront || _background.startMs);
|
const auto hasSpoiler = _background.spoiler
|
||||||
const auto spoilerOpacity = hasSpoiler
|
&& (_spoilerOpacity > 0.);
|
||||||
? fillSpoilerOpacity()
|
|
||||||
: 0.;
|
|
||||||
const auto opacity = _p->opacity();
|
const auto opacity = _p->opacity();
|
||||||
const auto isElidedBlock = !rtl
|
const auto isElidedBlock = !rtl
|
||||||
&& (_indexOfElidedBlock == blockIndex);
|
&& (_indexOfElidedBlock == blockIndex);
|
||||||
const auto complexClipping = hasSpoiler
|
const auto complexClipping = hasSpoiler
|
||||||
&& isElidedBlock
|
&& isElidedBlock
|
||||||
&& spoilerOpacity == 1.;
|
&& (_spoilerOpacity == 1.);
|
||||||
if ((spoilerOpacity < 1.) || isElidedBlock) {
|
if (!hasSpoiler || (_spoilerOpacity < 1.) || isElidedBlock) {
|
||||||
const auto complexClippingEnabled = complexClipping
|
const auto complexClippingEnabled = complexClipping
|
||||||
&& _p->hasClipping();
|
&& _p->hasClipping();
|
||||||
const auto complexClippingRegion = complexClipping
|
const auto complexClippingRegion = complexClipping
|
||||||
|
|
@ -1015,7 +1005,7 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
_y + 2 * _lineHeight),
|
_y + 2 * _lineHeight),
|
||||||
Qt::IntersectClip);
|
Qt::IntersectClip);
|
||||||
} else if (hasSpoiler && !isElidedBlock) {
|
} else if (hasSpoiler && !isElidedBlock) {
|
||||||
_p->setOpacity(opacity * (1. - spoilerOpacity));
|
_p->setOpacity(opacity * (1. - _spoilerOpacity));
|
||||||
}
|
}
|
||||||
if (Q_UNLIKELY(hasSelected)) {
|
if (Q_UNLIKELY(hasSelected)) {
|
||||||
if (Q_UNLIKELY(hasNotSelected)) {
|
if (Q_UNLIKELY(hasNotSelected)) {
|
||||||
|
|
@ -1091,22 +1081,6 @@ void Renderer::fillSelectRange(FixedRange range) {
|
||||||
_p->fillRect(left, _y + _yDelta, width, _fontHeight, _palette->selectBg);
|
_p->fillRect(left, _y + _yDelta, width, _fontHeight, _palette->selectBg);
|
||||||
}
|
}
|
||||||
|
|
||||||
float64 Renderer::fillSpoilerOpacity() {
|
|
||||||
if (!_background.startMs) {
|
|
||||||
return 1.;
|
|
||||||
}
|
|
||||||
const auto progress = float64(now() - _background.startMs)
|
|
||||||
/ st::fadeWrapDuration;
|
|
||||||
if ((progress > 1.) && _background.spoilerIndex && _t->_spoiler) {
|
|
||||||
const auto link = _t->_spoiler->links.at(
|
|
||||||
_background.spoilerIndex - 1);
|
|
||||||
if (link) {
|
|
||||||
link->setStartMs(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (1. - std::min(progress, 1.));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::pushSpoilerRange(
|
void Renderer::pushSpoilerRange(
|
||||||
FixedRange range,
|
FixedRange range,
|
||||||
FixedRange selected,
|
FixedRange selected,
|
||||||
|
|
@ -1159,9 +1133,15 @@ void Renderer::fillSpoilerRects(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::paintSpoilerRects() {
|
void Renderer::paintSpoilerRects() {
|
||||||
|
Expects(_p != nullptr);
|
||||||
|
|
||||||
if (!_t->_spoiler) {
|
if (!_t->_spoiler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto opacity = _p->opacity();
|
||||||
|
if (_spoilerOpacity < 1.) {
|
||||||
|
_p->setOpacity(opacity * _spoilerOpacity);
|
||||||
|
}
|
||||||
const auto index = _t->_spoiler->animation.index(now(), _paused);
|
const auto index = _t->_spoiler->animation.index(now(), _paused);
|
||||||
paintSpoilerRects(
|
paintSpoilerRects(
|
||||||
_spoilerRects,
|
_spoilerRects,
|
||||||
|
|
@ -1171,6 +1151,9 @@ void Renderer::paintSpoilerRects() {
|
||||||
_spoilerSelectedRects,
|
_spoilerSelectedRects,
|
||||||
_palette->selectSpoilerFg,
|
_palette->selectSpoilerFg,
|
||||||
index);
|
index);
|
||||||
|
if (_spoilerOpacity < 1.) {
|
||||||
|
_p->setOpacity(opacity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::paintSpoilerRects(
|
void Renderer::paintSpoilerRects(
|
||||||
|
|
@ -2009,15 +1992,11 @@ void Renderer::applyBlockProperties(const AbstractBlock *block) {
|
||||||
const auto isMono = IsMono(block->flags());
|
const auto isMono = IsMono(block->flags());
|
||||||
_background = {};
|
_background = {};
|
||||||
if (block->spoilerIndex() && _t->_spoiler) {
|
if (block->spoilerIndex() && _t->_spoiler) {
|
||||||
const auto handler
|
|
||||||
= _t->_spoiler->links.at(block->spoilerIndex() - 1);
|
|
||||||
const auto inBack = (handler && handler->shown());
|
|
||||||
_background.inFront = !inBack;
|
|
||||||
_background.spoiler = true;
|
_background.spoiler = true;
|
||||||
_background.startMs = handler ? handler->startMs() : 0;
|
|
||||||
_background.spoilerIndex = block->spoilerIndex();
|
|
||||||
}
|
}
|
||||||
if (isMono && block->lnkIndex() && !_background.inFront) {
|
if (isMono
|
||||||
|
&& block->lnkIndex()
|
||||||
|
&& (!_background.spoiler || _t->_spoiler->revealed)) {
|
||||||
_background.selectActiveBlock = ClickHandler::showAsPressed(
|
_background.selectActiveBlock = ClickHandler::showAsPressed(
|
||||||
_t->_links.at(block->lnkIndex() - 1));
|
_t->_links.at(block->lnkIndex() - 1));
|
||||||
}
|
}
|
||||||
|
|
@ -2036,4 +2015,15 @@ void Renderer::applyBlockProperties(const AbstractBlock *block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr Renderer::lookupLink(const AbstractBlock *block) const {
|
||||||
|
const auto spoilerLink = (_t->_spoiler
|
||||||
|
&& !_t->_spoiler->revealed
|
||||||
|
&& block->spoilerIndex())
|
||||||
|
? _t->_spoiler->link
|
||||||
|
: ClickHandlerPtr();
|
||||||
|
return (spoilerLink || !block->lnkIndex())
|
||||||
|
? spoilerLink
|
||||||
|
: _t->_links.at(block->lnkIndex() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Ui::Text
|
} // namespace Ui::Text
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ private:
|
||||||
const String::TextBlocks::const_iterator &_endBlockIter,
|
const String::TextBlocks::const_iterator &_endBlockIter,
|
||||||
const String::TextBlocks::const_iterator &_end);
|
const String::TextBlocks::const_iterator &_end);
|
||||||
void fillSelectRange(FixedRange range);
|
void fillSelectRange(FixedRange range);
|
||||||
[[nodiscard]] float64 fillSpoilerOpacity();
|
|
||||||
void pushSpoilerRange(
|
void pushSpoilerRange(
|
||||||
FixedRange range,
|
FixedRange range,
|
||||||
FixedRange selected,
|
FixedRange selected,
|
||||||
|
|
@ -108,6 +107,8 @@ private:
|
||||||
bool eBidiItemize(QScriptAnalysis *analysis, BidiControl &control);
|
bool eBidiItemize(QScriptAnalysis *analysis, BidiControl &control);
|
||||||
|
|
||||||
void applyBlockProperties(const AbstractBlock *block);
|
void applyBlockProperties(const AbstractBlock *block);
|
||||||
|
[[nodiscard]] ClickHandlerPtr lookupLink(
|
||||||
|
const AbstractBlock *block) const;
|
||||||
|
|
||||||
const String *_t = nullptr;
|
const String *_t = nullptr;
|
||||||
SpoilerMessCache *_spoilerCache = nullptr;
|
SpoilerMessCache *_spoilerCache = nullptr;
|
||||||
|
|
@ -123,11 +124,7 @@ private:
|
||||||
const QPen *_currentPen = nullptr;
|
const QPen *_currentPen = nullptr;
|
||||||
const QPen *_currentPenSelected = nullptr;
|
const QPen *_currentPenSelected = nullptr;
|
||||||
struct {
|
struct {
|
||||||
bool inFront = false;
|
bool spoiler = false;
|
||||||
bool spoiler = true;
|
|
||||||
crl::time startMs = 0;
|
|
||||||
uint16 spoilerIndex = 0;
|
|
||||||
|
|
||||||
bool selectActiveBlock = false; // For monospace.
|
bool selectActiveBlock = false; // For monospace.
|
||||||
} _background;
|
} _background;
|
||||||
int _yFrom = 0;
|
int _yFrom = 0;
|
||||||
|
|
@ -137,6 +134,7 @@ private:
|
||||||
bool _fullWidthSelection = true;
|
bool _fullWidthSelection = true;
|
||||||
const QChar *_str = nullptr;
|
const QChar *_str = nullptr;
|
||||||
mutable crl::time _cachedNow = 0;
|
mutable crl::time _cachedNow = 0;
|
||||||
|
float64 _spoilerOpacity = 0.;
|
||||||
QVarLengthArray<FixedRange> _spoilerRanges;
|
QVarLengthArray<FixedRange> _spoilerRanges;
|
||||||
QVarLengthArray<FixedRange> _spoilerSelectedRanges;
|
QVarLengthArray<FixedRange> _spoilerSelectedRanges;
|
||||||
QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerRects;
|
QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerRects;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/effects/spoiler_mess.h"
|
#include "ui/effects/spoiler_mess.h"
|
||||||
|
#include "ui/effects/animations.h"
|
||||||
|
|
||||||
class SpoilerClickHandler;
|
class SpoilerClickHandler;
|
||||||
|
|
||||||
|
|
@ -18,7 +19,9 @@ struct SpoilerData {
|
||||||
}
|
}
|
||||||
|
|
||||||
SpoilerAnimation animation;
|
SpoilerAnimation animation;
|
||||||
QVector<std::shared_ptr<SpoilerClickHandler>> links;
|
ClickHandlerPtr link;
|
||||||
|
Animations::Simple revealAnimation;
|
||||||
|
bool revealed = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Ui::Text
|
} // namespace Ui::Text
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue