Updated lib_ui sources to TDesktop version 3.2.5
This commit is contained in:
commit
9b56cbd4ab
60 changed files with 617 additions and 343 deletions
|
|
@ -24,7 +24,8 @@ generate_palette(lib_ui ui/colors.palette)
|
||||||
generate_styles(lib_ui ${src_loc} "${style_files}" ui/colors.palette)
|
generate_styles(lib_ui ${src_loc} "${style_files}" ui/colors.palette)
|
||||||
generate_emoji(lib_ui emoji.txt emoji_suggestions/emoji_autocomplete.json)
|
generate_emoji(lib_ui emoji.txt emoji_suggestions/emoji_autocomplete.json)
|
||||||
|
|
||||||
set_target_properties(lib_ui PROPERTIES AUTOMOC ON AUTORCC ON)
|
set_target_properties(lib_ui PROPERTIES AUTOMOC ON)
|
||||||
|
target_prepare_qrc(lib_ui)
|
||||||
|
|
||||||
target_precompile_headers(lib_ui PRIVATE ${src_loc}/ui/ui_pch.h)
|
target_precompile_headers(lib_ui PRIVATE ${src_loc}/ui/ui_pch.h)
|
||||||
nice_target_sources(lib_ui ${src_loc}
|
nice_target_sources(lib_ui ${src_loc}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ void AbstractButton::leaveEventHook(QEvent *e) {
|
||||||
return TWidget::leaveEventHook(e);
|
return TWidget::leaveEventHook(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractButton::enterEventHook(QEvent *e) {
|
void AbstractButton::enterEventHook(QEnterEvent *e) {
|
||||||
checkIfOver(mapFromGlobal(QCursor::pos()));
|
checkIfOver(mapFromGlobal(QCursor::pos()));
|
||||||
return TWidget::enterEventHook(e);
|
return TWidget::enterEventHook(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ public:
|
||||||
void clicked(Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
|
void clicked(Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void enterEventHook(QEvent *e) override;
|
void enterEventHook(QEnterEvent *e) override;
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "ui/text/text_entity.h"
|
#include "ui/text/text_entity.h"
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
#include "base/qthelp_url.h"
|
#include "base/qthelp_url.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
|
|
@ -80,13 +81,13 @@ bool UrlClickHandler::IsSuspicious(const QString &url) {
|
||||||
if (!match1.hasMatch()) {
|
if (!match1.hasMatch()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto domain = match1.capturedRef(3);
|
const auto domain = match1.capturedView(3);
|
||||||
static const auto Check2 = QRegularExpression("^(.*)\\.[a-zA-Z]+$");
|
static const auto Check2 = QRegularExpression("^(.*)\\.[a-zA-Z]+$");
|
||||||
const auto match2 = Check2.match(domain);
|
const auto match2 = Check2.match(domain);
|
||||||
if (!match2.hasMatch()) {
|
if (!match2.hasMatch()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto part = match2.capturedRef(1);
|
const auto part = match2.capturedView(1);
|
||||||
static const auto Check3 = QRegularExpression("[^a-zA-Z0-9\\.\\-]");
|
static const auto Check3 = QRegularExpression("[^a-zA-Z0-9\\.\\-]");
|
||||||
return Check3.match(part).hasMatch();
|
return Check3.match(part).hasMatch();
|
||||||
}
|
}
|
||||||
|
|
@ -100,11 +101,11 @@ QString UrlClickHandler::ShowEncoded(const QString &url) {
|
||||||
"^(https?://)?([^/#\\:]+)([/#\\:]|$)",
|
"^(https?://)?([^/#\\:]+)([/#\\:]|$)",
|
||||||
QRegularExpression::CaseInsensitiveOption);
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
if (const auto match1 = Check1.match(url); match1.hasMatch()) {
|
if (const auto match1 = Check1.match(url); match1.hasMatch()) {
|
||||||
const auto domain = match1.captured(1).append(match1.capturedRef(2));
|
const auto domain = match1.captured(1).append(match1.capturedView(2));
|
||||||
if (const auto u = QUrl(domain); u.isValid()) {
|
if (const auto u = QUrl(domain); u.isValid()) {
|
||||||
return QString(
|
return QString(
|
||||||
).append(QString::fromUtf8(u.toEncoded())
|
).append(QString::fromUtf8(u.toEncoded())
|
||||||
).append(url.midRef(match1.capturedEnd(2)));
|
).append(base::StringViewMid(url, match1.capturedEnd(2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ tooltipBg: #eef2f5; // tooltip background (like when you put mouse over the mess
|
||||||
tooltipFg: #5d6c80; // tooltip text
|
tooltipFg: #5d6c80; // tooltip text
|
||||||
tooltipBorderFg: #c9d1db; // tooltip border
|
tooltipBorderFg: #c9d1db; // tooltip border
|
||||||
|
|
||||||
// custom title bar for Windows and macOS
|
// custom title bar
|
||||||
titleShadow: #00000003; // one pixel line shadow at the bottom of custom window title
|
titleShadow: #00000003; // one pixel line shadow at the bottom of custom window title
|
||||||
titleBg: windowBgOver; // custom window title background when window is inactive
|
titleBg: windowBgOver; // custom window title background when window is inactive
|
||||||
titleBgActive: titleBg; // custom window title background when window is active
|
titleBgActive: titleBg; // custom window title background when window is active
|
||||||
|
|
@ -109,8 +109,8 @@ titleButtonCloseBgActive: titleButtonCloseBg; // custom window title close butto
|
||||||
titleButtonCloseFgActive: titleButtonCloseFg; // custom window title close button icon when window is active (Windows only)
|
titleButtonCloseFgActive: titleButtonCloseFg; // custom window title close button icon when window is active (Windows only)
|
||||||
titleButtonCloseBgActiveOver: titleButtonCloseBgOver; // custom window title close button background with mouse over when window is active (Windows only)
|
titleButtonCloseBgActiveOver: titleButtonCloseBgOver; // custom window title close button background with mouse over when window is active (Windows only)
|
||||||
titleButtonCloseFgActiveOver: titleButtonCloseFgOver; // custom window title close button icon with mouse over when window is active (Windows only)
|
titleButtonCloseFgActiveOver: titleButtonCloseFgOver; // custom window title close button icon with mouse over when window is active (Windows only)
|
||||||
titleFg: #acacac; // custom window title text when window is inactive (macOS only)
|
titleFg: #acacac; // custom window title text when window is inactive (Windows 11 and macOS)
|
||||||
titleFgActive: #3e3c3e; // custom window title text when window is active (macOS only)
|
titleFgActive: #3e3c3e; // custom window title text when window is active (Windows 11 and macOS)
|
||||||
|
|
||||||
// tray icon
|
// tray icon
|
||||||
trayCounterBg: #f23c34; // tray icon counter background
|
trayCounterBg: #f23c34; // tray icon counter background
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ TG_FORCE_INLINE float64 interpolateF(int a, int b, float64 b_ratio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TG_FORCE_INLINE int interpolate(int a, int b, float64 b_ratio) {
|
TG_FORCE_INLINE int interpolate(int a, int b, float64 b_ratio) {
|
||||||
return std::round(interpolateF(a, b, b_ratio));
|
return base::SafeRound(interpolateF(a, b, b_ratio));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARCH_CPU_32_BITS
|
#ifdef ARCH_CPU_32_BITS
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ void NumbersAnimation::realSetText(QString text, int value) {
|
||||||
}
|
}
|
||||||
auto oldSize = _digits.size();
|
auto oldSize = _digits.size();
|
||||||
auto animating = false;
|
auto animating = false;
|
||||||
for (auto i = 0, size = _digits.size(); i != size; ++i) {
|
for (auto i = 0, size = int(_digits.size()); i != size; ++i) {
|
||||||
auto &digit = _digits[i];
|
auto &digit = _digits[i];
|
||||||
digit.from = digit.to;
|
digit.from = digit.to;
|
||||||
digit.fromWidth = digit.toWidth;
|
digit.fromWidth = digit.toWidth;
|
||||||
|
|
|
||||||
|
|
@ -224,8 +224,8 @@ RadialState InfiniteRadialAnimation::computeState() {
|
||||||
if (anim::Disabled()) {
|
if (anim::Disabled()) {
|
||||||
return { 1., 0, kFullArcLength };
|
return { 1., 0, kFullArcLength };
|
||||||
}
|
}
|
||||||
const auto min = int(std::round(kFullArcLength * _st.arcMin));
|
const auto min = int(base::SafeRound(kFullArcLength * _st.arcMin));
|
||||||
const auto max = int(std::round(kFullArcLength * _st.arcMax));
|
const auto max = int(base::SafeRound(kFullArcLength * _st.arcMax));
|
||||||
if (now <= _workStarted) {
|
if (now <= _workStarted) {
|
||||||
// zero .. _workStarted
|
// zero .. _workStarted
|
||||||
const auto zero = _workStarted - _st.sineDuration;
|
const auto zero = _workStarted - _st.sineDuration;
|
||||||
|
|
@ -314,8 +314,8 @@ RadialState InfiniteRadialAnimation::computeState() {
|
||||||
// st.arcMax - st.arcMin,
|
// st.arcMax - st.arcMin,
|
||||||
// std::min(backCurrent, crl::time(st.sineDuration))
|
// std::min(backCurrent, crl::time(st.sineDuration))
|
||||||
// / float64(st.sineDuration));
|
// / float64(st.sineDuration));
|
||||||
//const auto front = linear + std::round((st.arcMin + frontProgress + frontPeriods * (st.arcMax - st.arcMin)) * kFullArcLength);
|
//const auto front = linear + base::SafeRound((st.arcMin + frontProgress + frontPeriods * (st.arcMax - st.arcMin)) * kFullArcLength);
|
||||||
//const auto from = linear + std::round((backProgress + backPeriods * (st.arcMax - st.arcMin)) * kFullArcLength);
|
//const auto from = linear + base::SafeRound((backProgress + backPeriods * (st.arcMax - st.arcMin)) * kFullArcLength);
|
||||||
//const auto length = (front - from);
|
//const auto length = (front - from);
|
||||||
|
|
||||||
//return {
|
//return {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,15 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, const QCol
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cache.isNull() || colorOverride != nullptr) {
|
if (_cache.isNull() || colorOverride != nullptr) {
|
||||||
auto radius = anim::interpolate(_radiusFrom, _radiusTo, _show.value(1.));
|
const auto shown = _show.value(1.);
|
||||||
|
Assert(!std::isnan(shown));
|
||||||
|
const auto diff = float64(_radiusTo - _radiusFrom);
|
||||||
|
Assert(!std::isnan(diff));
|
||||||
|
const auto mult = diff * shown;
|
||||||
|
Assert(!std::isnan(mult));
|
||||||
|
const auto interpolated = _radiusFrom + mult;//anim::interpolateF(_radiusFrom, _radiusTo, shown);
|
||||||
|
Assert(!std::isnan(interpolated));
|
||||||
|
auto radius = int(base::SafeRound(interpolated));//anim::interpolate(_radiusFrom, _radiusTo, _show.value(1.));
|
||||||
_frame.fill(Qt::transparent);
|
_frame.fill(Qt::transparent);
|
||||||
{
|
{
|
||||||
QPainter p(&_frame);
|
QPainter p(&_frame);
|
||||||
|
|
|
||||||
|
|
@ -733,7 +733,8 @@ QVector<EmojiPtr> GetDefaultRecent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) {
|
const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) {
|
||||||
auto &map = (fontHeight == st::normalFont->height * style::DevicePixelRatio())
|
const auto factor = style::DevicePixelRatio();
|
||||||
|
auto &map = (fontHeight == st::normalFont->height * factor)
|
||||||
? MainEmojiMap
|
? MainEmojiMap
|
||||||
: OtherEmojiMap[fontHeight];
|
: OtherEmojiMap[fontHeight];
|
||||||
auto i = map.find(emoji->index());
|
auto i = map.find(emoji->index());
|
||||||
|
|
@ -741,10 +742,10 @@ const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) {
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
auto image = QImage(
|
auto image = QImage(
|
||||||
SizeNormal + st::emojiPadding * 2,
|
SizeNormal + st::emojiPadding * factor * 2,
|
||||||
fontHeight,
|
fontHeight,
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
image.setDevicePixelRatio(style::DevicePixelRatio());
|
image.setDevicePixelRatio(factor);
|
||||||
image.fill(Qt::transparent);
|
image.fill(Qt::transparent);
|
||||||
{
|
{
|
||||||
QPainter p(&image);
|
QPainter p(&image);
|
||||||
|
|
@ -753,8 +754,8 @@ const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) {
|
||||||
p,
|
p,
|
||||||
emoji,
|
emoji,
|
||||||
SizeNormal,
|
SizeNormal,
|
||||||
st::emojiPadding * style::DevicePixelRatio(),
|
st::emojiPadding,
|
||||||
(fontHeight - SizeNormal) / 2);
|
(fontHeight - SizeNormal) / (2 * factor));
|
||||||
}
|
}
|
||||||
return map.emplace(
|
return map.emplace(
|
||||||
emoji->index(),
|
emoji->index(),
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "base/basic_types.h"
|
#include "base/basic_types.h"
|
||||||
#include "base/binary_guard.h"
|
#include "base/binary_guard.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
#include "emoji.h"
|
#include "emoji.h"
|
||||||
|
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
|
|
@ -118,7 +119,7 @@ private:
|
||||||
[[nodiscard]] inline EmojiPtr FromUrl(const QString &url) {
|
[[nodiscard]] inline EmojiPtr FromUrl(const QString &url) {
|
||||||
auto start = qstr("emoji://e.");
|
auto start = qstr("emoji://e.");
|
||||||
if (url.startsWith(start)) {
|
if (url.startsWith(start)) {
|
||||||
return internal::ByIndex(url.midRef(start.size()).toInt()); // skip emoji://e.
|
return internal::ByIndex(base::StringViewMid(url, start.size()).toInt()); // skip emoji://e.
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QtGui/QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
#include <QtGui/QOpenGLFunctions>
|
#include <QtGui/QOpenGLFunctions>
|
||||||
#include <QtWidgets/QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
|
|
@ -142,7 +142,7 @@ Capabilities CheckCapabilities(QWidget *widget) {
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] static const auto extensionsLogged = [&] {
|
static const auto checkVendor = [&] {
|
||||||
const auto renderer = reinterpret_cast<const char*>(
|
const auto renderer = reinterpret_cast<const char*>(
|
||||||
functions->glGetString(GL_RENDERER));
|
functions->glGetString(GL_RENDERER));
|
||||||
LOG(("OpenGL Renderer: %1").arg(renderer ? renderer : "[nullptr]"));
|
LOG(("OpenGL Renderer: %1").arg(renderer ? renderer : "[nullptr]"));
|
||||||
|
|
@ -166,8 +166,19 @@ Capabilities CheckCapabilities(QWidget *widget) {
|
||||||
LOG(("EGL Extensions: %1").arg(egllist.join(", ")));
|
LOG(("EGL Extensions: %1").arg(egllist.join(", ")));
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
if (version && QByteArray(version).contains("NVIDIA")) {
|
||||||
|
// https://github.com/telegramdesktop/tdesktop/issues/16830
|
||||||
|
LOG_ONCE(("OpenGL: Disable on NVIDIA driver on Linux."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // Q_OS_LINUX
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}();
|
}();
|
||||||
|
if (!checkVendor) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const auto version = u"%1.%2"_q
|
const auto version = u"%1.%2"_q
|
||||||
.arg(supported.majorVersion())
|
.arg(supported.majorVersion())
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@
|
||||||
#include "ui/gl/gl_math.h"
|
#include "ui/gl/gl_math.h"
|
||||||
#include "ui/style/style_core.h"
|
#include "ui/style/style_core.h"
|
||||||
|
|
||||||
#include <QtGui/QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
#include <QtGui/QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
|
|
||||||
class QOpenGLFunctions;
|
class QOpenGLFunctions;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtGui/QOpenGLShader>
|
#include <QOpenGLShader>
|
||||||
|
|
||||||
class OpenGLShaderProgram;
|
class OpenGLShaderProgram;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
#include <QtGui/QOpenGLContext>
|
#include <QtGui/QOpenGLContext>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QtGui/QPaintEngine>
|
#include <QtGui/QPaintEngine>
|
||||||
#include <QtWidgets/QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
namespace Ui::GL {
|
namespace Ui::GL {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
||||||
|
|
@ -878,6 +878,53 @@ QImage GenerateLinearGradient(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage GenerateShadow(
|
||||||
|
int height,
|
||||||
|
int topAlpha,
|
||||||
|
int bottomAlpha,
|
||||||
|
QColor color) {
|
||||||
|
Expects(topAlpha >= 0 && topAlpha < 256);
|
||||||
|
Expects(bottomAlpha >= 0 && bottomAlpha < 256);
|
||||||
|
Expects(height * style::DevicePixelRatio() < 65536);
|
||||||
|
|
||||||
|
const auto base = (uint32(color.red()) << 16)
|
||||||
|
| (uint32(color.green()) << 8)
|
||||||
|
| uint32(color.blue());
|
||||||
|
const auto premultiplied = (topAlpha == bottomAlpha) || !base;
|
||||||
|
auto result = QImage(
|
||||||
|
QSize(1, height * style::DevicePixelRatio()),
|
||||||
|
(premultiplied
|
||||||
|
? QImage::Format_ARGB32_Premultiplied
|
||||||
|
: QImage::Format_ARGB32));
|
||||||
|
if (topAlpha == bottomAlpha) {
|
||||||
|
color.setAlpha(topAlpha);
|
||||||
|
result.fill(color);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
constexpr auto kShift = 16;
|
||||||
|
constexpr auto kMultiply = (1U << kShift);
|
||||||
|
const auto values = std::abs(topAlpha - bottomAlpha);
|
||||||
|
const auto rows = uint32(result.height());
|
||||||
|
const auto step = (values * kMultiply) / (rows - 1);
|
||||||
|
const auto till = rows * uint32(step);
|
||||||
|
Assert(result.bytesPerLine() == sizeof(uint32));
|
||||||
|
auto ints = reinterpret_cast<uint32*>(result.bits());
|
||||||
|
if (topAlpha < bottomAlpha) {
|
||||||
|
for (auto i = uint32(0); i != till; i += step) {
|
||||||
|
*ints++ = base | ((topAlpha + (i >> kShift)) << 24);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto i = uint32(0); i != till; i += step) {
|
||||||
|
*ints++ = base | ((topAlpha - (i >> kShift)) << 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!premultiplied) {
|
||||||
|
result = std::move(result).convertToFormat(
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void prepareCircle(QImage &img) {
|
void prepareCircle(QImage &img) {
|
||||||
Assert(!img.isNull());
|
Assert(!img.isNull());
|
||||||
|
|
||||||
|
|
@ -893,7 +940,7 @@ void prepareCircle(QImage &img) {
|
||||||
|
|
||||||
void prepareRound(
|
void prepareRound(
|
||||||
QImage &image,
|
QImage &image,
|
||||||
QImage *cornerMasks,
|
gsl::span<const QImage, 4> cornerMasks,
|
||||||
RectParts corners,
|
RectParts corners,
|
||||||
QRect target) {
|
QRect target) {
|
||||||
if (target.isNull()) {
|
if (target.isNull()) {
|
||||||
|
|
@ -905,7 +952,7 @@ void prepareRound(
|
||||||
auto cornerHeight = cornerMasks[0].height();
|
auto cornerHeight = cornerMasks[0].height();
|
||||||
auto targetWidth = target.width();
|
auto targetWidth = target.width();
|
||||||
auto targetHeight = target.height();
|
auto targetHeight = target.height();
|
||||||
if (targetWidth < 2 * cornerWidth || targetHeight < 2 * cornerHeight) {
|
if (targetWidth < cornerWidth || targetHeight < cornerHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -970,8 +1017,8 @@ void prepareRound(
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
Assert(!image.isNull());
|
Assert(!image.isNull());
|
||||||
|
|
||||||
auto masks = CornersMask(radius);
|
const auto masks = CornersMask(radius);
|
||||||
prepareRound(image, masks.data(), corners, target);
|
prepareRound(image, masks, corners, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage prepareColored(style::color add, QImage image) {
|
QImage prepareColored(style::color add, QImage image) {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,12 @@ namespace Images {
|
||||||
const std::vector<QColor> &colors,
|
const std::vector<QColor> &colors,
|
||||||
int rotation = 0);
|
int rotation = 0);
|
||||||
|
|
||||||
|
[[nodiscard]] QImage GenerateShadow(
|
||||||
|
int height,
|
||||||
|
int topAlpha,
|
||||||
|
int bottomAlpha,
|
||||||
|
QColor color = QColor(0, 0, 0));
|
||||||
|
|
||||||
[[nodiscard]] const std::array<QImage, 4> &CornersMask(
|
[[nodiscard]] const std::array<QImage, 4> &CornersMask(
|
||||||
ImageRoundRadius radius);
|
ImageRoundRadius radius);
|
||||||
[[nodiscard]] std::array<QImage, 4> PrepareCorners(
|
[[nodiscard]] std::array<QImage, 4> PrepareCorners(
|
||||||
|
|
@ -81,7 +87,7 @@ void prepareRound(
|
||||||
QRect target = QRect());
|
QRect target = QRect());
|
||||||
void prepareRound(
|
void prepareRound(
|
||||||
QImage &image,
|
QImage &image,
|
||||||
QImage *cornerMasks,
|
gsl::span<const QImage, 4> cornerMasks,
|
||||||
RectParts corners = RectPart::AllCorners,
|
RectParts corners = RectPart::AllCorners,
|
||||||
QRect target = QRect());
|
QRect target = QRect());
|
||||||
void prepareCircle(QImage &image);
|
void prepareCircle(QImage &image);
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,14 @@
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/wrap/fade_wrap.h"
|
#include "ui/wrap/fade_wrap.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/rect_part.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
|
||||||
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
void BoxContent::setTitle(rpl::producer<QString> title) {
|
void BoxContent::setTitle(rpl::producer<QString> title) {
|
||||||
|
|
@ -85,8 +88,14 @@ void BoxContent::finishScrollCreate() {
|
||||||
_scroll->show();
|
_scroll->show();
|
||||||
}
|
}
|
||||||
updateScrollAreaGeometry();
|
updateScrollAreaGeometry();
|
||||||
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
_scroll->scrolls(
|
||||||
connect(_scroll, SIGNAL(innerResized()), this, SLOT(onInnerResize()));
|
) | rpl::start_with_next([=] {
|
||||||
|
onScroll();
|
||||||
|
}, lifetime());
|
||||||
|
_scroll->innerResizes(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
onInnerResize();
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BoxContent::scrollToWidget(not_null<QWidget*> widget) {
|
void BoxContent::scrollToWidget(not_null<QWidget*> widget) {
|
||||||
|
|
@ -95,6 +104,10 @@ void BoxContent::scrollToWidget(not_null<QWidget*> widget) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RectParts BoxContent::customCornersFilling() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void BoxContent::onScrollToY(int top, int bottom) {
|
void BoxContent::onScrollToY(int top, int bottom) {
|
||||||
if (_scroll) {
|
if (_scroll) {
|
||||||
_scroll->scrollToY(top, bottom);
|
_scroll->scrollToY(top, bottom);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
#include "ui/text/text_entity.h"
|
#include "ui/text/text_entity.h"
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
enum class RectPart;
|
||||||
|
using RectParts = base::flags<RectPart>;
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
struct RoundButton;
|
struct RoundButton;
|
||||||
struct IconButton;
|
struct IconButton;
|
||||||
|
|
@ -128,6 +131,7 @@ public:
|
||||||
|
|
||||||
virtual void showFinished() {
|
virtual void showFinished() {
|
||||||
}
|
}
|
||||||
|
virtual RectParts customCornersFilling();
|
||||||
void clearButtons() {
|
void clearButtons() {
|
||||||
getDelegate()->clearButtons();
|
getDelegate()->clearButtons();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,16 +115,21 @@ QRect BoxLayerWidget::loadingRect() const {
|
||||||
|
|
||||||
void BoxLayerWidget::paintEvent(QPaintEvent *e) {
|
void BoxLayerWidget::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
auto clip = e->rect();
|
|
||||||
auto paintTopRounded = clip.intersects(QRect(0, 0, width(), st::boxRadius));
|
const auto custom = _content->customCornersFilling();
|
||||||
auto paintBottomRounded = clip.intersects(QRect(0, height() - st::boxRadius, width(), st::boxRadius));
|
const auto clip = e->rect();
|
||||||
|
const auto paintTopRounded = !(custom & RectPart::FullTop)
|
||||||
|
&& clip.intersects(QRect(0, 0, width(), st::boxRadius));
|
||||||
|
const auto paintBottomRounded = !(custom & RectPart::FullBottom)
|
||||||
|
&& clip.intersects(
|
||||||
|
QRect(0, height() - st::boxRadius, width(), st::boxRadius));
|
||||||
if (paintTopRounded || paintBottomRounded) {
|
if (paintTopRounded || paintBottomRounded) {
|
||||||
auto parts = RectPart::None | 0;
|
_roundRect.paint(p, rect(), RectPart::None
|
||||||
if (paintTopRounded) parts |= RectPart::FullTop;
|
| (paintTopRounded ? RectPart::FullTop : RectPart::None)
|
||||||
if (paintBottomRounded) parts |= RectPart::FullBottom;
|
| (paintBottomRounded ? RectPart::FullBottom : RectPart::None));
|
||||||
_roundRect.paint(p, rect(), parts);
|
|
||||||
}
|
}
|
||||||
auto other = e->region().intersected(QRect(0, st::boxRadius, width(), height() - 2 * st::boxRadius));
|
const auto other = e->region().intersected(
|
||||||
|
QRect(0, st::boxRadius, width(), height() - 2 * st::boxRadius));
|
||||||
if (!other.isEmpty()) {
|
if (!other.isEmpty()) {
|
||||||
for (const auto &rect : other) {
|
for (const auto &rect : other) {
|
||||||
p.fillRect(rect, st().bg);
|
p.fillRect(rect, st().bg);
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ RadialBlob::RadialBlob(int n, float minScale, float minSpeed, float maxSpeed)
|
||||||
|
|
||||||
void RadialBlob::paint(Painter &p, const QBrush &brush, float outerScale) {
|
void RadialBlob::paint(Painter &p, const QBrush &brush, float outerScale) {
|
||||||
auto path = QPainterPath();
|
auto path = QPainterPath();
|
||||||
auto m = QMatrix();
|
auto m = QTransform();
|
||||||
|
|
||||||
const auto scale = (_minScale + (1. - _minScale) * _scale) * outerScale;
|
const auto scale = (_minScale + (1. - _minScale) * _scale) * outerScale;
|
||||||
if (scale == 0.) {
|
if (scale == 0.) {
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ public:
|
||||||
const PainterHighQualityEnabler &other) = delete;
|
const PainterHighQualityEnabler &other) = delete;
|
||||||
|
|
||||||
~PainterHighQualityEnabler() {
|
~PainterHighQualityEnabler() {
|
||||||
if (_hints) {
|
if (_hints && _painter.isActive()) {
|
||||||
_painter.setRenderHints(_hints, false);
|
_painter.setRenderHints(_hints, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
#include "base/debug_log.h"
|
#include "base/debug_log.h"
|
||||||
#include "ui/platform/linux/ui_linux_wayland_integration.h"
|
#include "ui/platform/linux/ui_linux_wayland_integration.h"
|
||||||
#include "base/const_string.h"
|
#include "base/const_string.h"
|
||||||
#include "base/qt_adapters.h"
|
|
||||||
#include "base/flat_set.h"
|
#include "base/flat_set.h"
|
||||||
|
|
||||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||||
|
|
@ -434,20 +433,18 @@ bool TranslucentWindowsSupported(QPoint globalPosition) {
|
||||||
|
|
||||||
if (::Platform::IsX11()) {
|
if (::Platform::IsX11()) {
|
||||||
if (const auto native = QGuiApplication::platformNativeInterface()) {
|
if (const auto native = QGuiApplication::platformNativeInterface()) {
|
||||||
if (const auto desktop = QApplication::desktop()) {
|
if (const auto screen = QGuiApplication::screenAt(globalPosition)) {
|
||||||
if (const auto screen = base::QScreenNearestTo(globalPosition)) {
|
if (native->nativeResourceForScreen(QByteArray("compositingEnabled"), screen)) {
|
||||||
if (native->nativeResourceForScreen(QByteArray("compositingEnabled"), screen)) {
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const auto index = QGuiApplication::screens().indexOf(screen);
|
|
||||||
static auto WarnedAbout = base::flat_set<int>();
|
|
||||||
if (!WarnedAbout.contains(index)) {
|
|
||||||
WarnedAbout.emplace(index);
|
|
||||||
LOG(("WARNING: Compositing is disabled for screen index %1 (for position %2,%3)").arg(index).arg(globalPosition.x()).arg(globalPosition.y()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(("WARNING: Could not get screen for position %1,%2").arg(globalPosition.x()).arg(globalPosition.y()));
|
|
||||||
}
|
}
|
||||||
|
const auto index = QGuiApplication::screens().indexOf(screen);
|
||||||
|
static auto WarnedAbout = base::flat_set<int>();
|
||||||
|
if (!WarnedAbout.contains(index)) {
|
||||||
|
WarnedAbout.emplace(index);
|
||||||
|
LOG(("WARNING: Compositing is disabled for screen index %1 (for position %2,%3)").arg(index).arg(globalPosition.x()).arg(globalPosition.y()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(("WARNING: Could not get screen for position %1,%2").arg(globalPosition.x()).arg(globalPosition.y()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include "ui/platform/mac/ui_utility_mac.h"
|
#include "ui/platform/mac/ui_utility_mac.h"
|
||||||
|
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
#include "base/qt_adapters.h"
|
|
||||||
|
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ui/platform/mac/ui_window_title_mac.h"
|
#include "ui/platform/mac/ui_window_title_mac.h"
|
||||||
#include "ui/widgets/rp_window.h"
|
#include "ui/widgets/rp_window.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
|
||||||
|
|
@ -15,7 +16,7 @@
|
||||||
#include <QtCore/QAbstractNativeEventFilter>
|
#include <QtCore/QAbstractNativeEventFilter>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
#include <QtWidgets/QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface WindowObserver : NSObject {
|
@interface WindowObserver : NSObject {
|
||||||
|
|
@ -84,24 +85,35 @@ private:
|
||||||
|
|
||||||
class EventFilter : public QObject, public QAbstractNativeEventFilter {
|
class EventFilter : public QObject, public QAbstractNativeEventFilter {
|
||||||
public:
|
public:
|
||||||
EventFilter(not_null<QObject*> parent, Fn<bool(void*)> checkPerformDrag)
|
EventFilter(
|
||||||
|
not_null<QObject*> parent,
|
||||||
|
Fn<bool()> checkStartDrag,
|
||||||
|
Fn<bool(void*)> checkPerformDrag)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
|
, _checkStartDrag(std::move(checkStartDrag))
|
||||||
, _checkPerformDrag(std::move(checkPerformDrag)) {
|
, _checkPerformDrag(std::move(checkPerformDrag)) {
|
||||||
Expects(_checkPerformDrag != nullptr);
|
Expects(_checkPerformDrag != nullptr);
|
||||||
|
Expects(_checkStartDrag != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nativeEventFilter(
|
bool nativeEventFilter(
|
||||||
const QByteArray &eventType,
|
const QByteArray &eventType,
|
||||||
void *message,
|
void *message,
|
||||||
long *result) {
|
base::NativeEventResult *result) {
|
||||||
NSEvent *e = static_cast<NSEvent*>(message);
|
if (NSEvent *e = static_cast<NSEvent*>(message)) {
|
||||||
return (e && [e type] == NSEventTypeLeftMouseDown)
|
if ([e type] == NSEventTypeLeftMouseDown) {
|
||||||
? _checkPerformDrag([e window])
|
_dragStarted = _checkStartDrag();
|
||||||
: false;
|
} else if (([e type] == NSEventTypeLeftMouseDragged)
|
||||||
|
&& _dragStarted) {
|
||||||
|
return _checkPerformDrag([e window]);
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _dragStarted = false;
|
||||||
|
Fn<bool()> _checkStartDrag;
|
||||||
Fn<bool(void*)> _checkPerformDrag;
|
Fn<bool(void*)> _checkPerformDrag;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -361,7 +373,10 @@ void WindowHelper::setGeometry(QRect rect) {
|
||||||
|
|
||||||
void WindowHelper::setupBodyTitleAreaEvents() {
|
void WindowHelper::setupBodyTitleAreaEvents() {
|
||||||
const auto controls = _private->controlsRect();
|
const auto controls = _private->controlsRect();
|
||||||
qApp->installNativeEventFilter(new EventFilter(window(), [=](void *nswindow) {
|
qApp->installNativeEventFilter(new EventFilter(window(), [=] {
|
||||||
|
const auto point = body()->mapFromGlobal(QCursor::pos());
|
||||||
|
return (bodyTitleAreaHit(point) & WindowTitleHitTestFlag::Move);
|
||||||
|
}, [=](void *nswindow) {
|
||||||
const auto point = body()->mapFromGlobal(QCursor::pos());
|
const auto point = body()->mapFromGlobal(QCursor::pos());
|
||||||
if (_private->checkNativeMove(nswindow)
|
if (_private->checkNativeMove(nswindow)
|
||||||
&& !controls.contains(point)
|
&& !controls.contains(point)
|
||||||
|
|
@ -398,6 +413,15 @@ void WindowHelper::init() {
|
||||||
size.width(),
|
size.width(),
|
||||||
size.height() - titleHeight);
|
size.height() - titleHeight);
|
||||||
}, _body->lifetime());
|
}, _body->lifetime());
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
setBodyTitleArea([](QPoint widgetPoint) {
|
||||||
|
using Flag = Ui::WindowTitleHitTestFlag;
|
||||||
|
return (widgetPoint.y() < 0)
|
||||||
|
? (Flag::Move | Flag::Maximize)
|
||||||
|
: Flag::None;
|
||||||
|
});
|
||||||
|
#endif // Qt >= 6.0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<BasicWindowHelper> CreateSpecialWindowHelper(
|
std::unique_ptr<BasicWindowHelper> CreateSpecialWindowHelper(
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,15 @@ void BasicWindowHelper::close() {
|
||||||
|
|
||||||
void BasicWindowHelper::setBodyTitleArea(
|
void BasicWindowHelper::setBodyTitleArea(
|
||||||
Fn<WindowTitleHitTestFlags(QPoint)> testMethod) {
|
Fn<WindowTitleHitTestFlags(QPoint)> testMethod) {
|
||||||
Expects(!_bodyTitleAreaTestMethod);
|
Expects(!_bodyTitleAreaTestMethod || testMethod);
|
||||||
|
|
||||||
if (!testMethod) {
|
if (!testMethod) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!_bodyTitleAreaTestMethod) {
|
||||||
|
setupBodyTitleAreaEvents();
|
||||||
|
}
|
||||||
_bodyTitleAreaTestMethod = std::move(testMethod);
|
_bodyTitleAreaTestMethod = std::move(testMethod);
|
||||||
setupBodyTitleAreaEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QMargins BasicWindowHelper::nativeFrameMargins() const {
|
QMargins BasicWindowHelper::nativeFrameMargins() const {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
#include "ui/platform/win/ui_window_win.h"
|
#include "ui/platform/win/ui_window_win.h"
|
||||||
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
|
|
@ -42,7 +43,8 @@ base::flat_map<HWND, not_null<WindowShadow*>> ShadowByHandle;
|
||||||
|
|
||||||
WindowShadow::WindowShadow(not_null<RpWidget*> window, QColor color)
|
WindowShadow::WindowShadow(not_null<RpWidget*> window, QColor color)
|
||||||
: _window(window)
|
: _window(window)
|
||||||
, _handle(GetWindowHandle(window)) {
|
, _handle(GetWindowHandle(window))
|
||||||
|
, _windows11(::Platform::IsWindows11OrGreater()) {
|
||||||
init(color);
|
init(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,7 +317,7 @@ void WindowShadow::horCorners(int w, Gdiplus::Graphics *pgraphics0, Gdiplus::Gra
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdiplus::Color WindowShadow::getColor(uchar alpha) const {
|
Gdiplus::Color WindowShadow::getColor(uchar alpha) const {
|
||||||
return Gdiplus::Color(BYTE(alpha), _r, _g, _b);
|
return Gdiplus::Color(BYTE(_windows11 ? 1 : alpha), _r, _g, _b);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdiplus::SolidBrush WindowShadow::getBrush(uchar alpha) const {
|
Gdiplus::SolidBrush WindowShadow::getBrush(uchar alpha) const {
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ private:
|
||||||
|
|
||||||
const not_null<RpWidget*> _window;
|
const not_null<RpWidget*> _window;
|
||||||
const HWND _handle;
|
const HWND _handle;
|
||||||
|
const bool _windows11 = false;
|
||||||
|
|
||||||
int _x = 0;
|
int _x = 0;
|
||||||
int _y = 0;
|
int _y = 0;
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ void TitleWidget::setStyle(const style::WindowTitle &st) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<const style::WindowTitle*> TitleWidget::st() const {
|
||||||
|
return _controls.st();
|
||||||
|
}
|
||||||
|
|
||||||
void TitleWidget::setResizeEnabled(bool enabled) {
|
void TitleWidget::setResizeEnabled(bool enabled) {
|
||||||
_controls.setResizeEnabled(enabled);
|
_controls.setResizeEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ public:
|
||||||
|
|
||||||
void setText(const QString &text);
|
void setText(const QString &text);
|
||||||
void setStyle(const style::WindowTitle &st);
|
void setStyle(const style::WindowTitle &st);
|
||||||
|
[[nodiscard]] not_null<const style::WindowTitle*> st() const;
|
||||||
[[nodiscard]] HitTestResult hitTest(QPoint point) const;
|
[[nodiscard]] HitTestResult hitTest(QPoint point) const;
|
||||||
void setResizeEnabled(bool enabled);
|
void setResizeEnabled(bool enabled);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "base/integration.h"
|
#include "base/integration.h"
|
||||||
#include "base/debug_log.h"
|
#include "base/debug_log.h"
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
#include <QtCore/QAbstractNativeEventFilter>
|
#include <QtCore/QAbstractNativeEventFilter>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
|
|
@ -29,7 +30,12 @@ namespace Ui {
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool IsCompositionEnabled() {
|
constexpr auto kDWMWCP_ROUND = DWORD(2);
|
||||||
|
constexpr auto kDWMWA_WINDOW_CORNER_PREFERENCE = DWORD(33);
|
||||||
|
constexpr auto kDWMWA_CAPTION_COLOR = DWORD(35);
|
||||||
|
constexpr auto kDWMWA_TEXT_COLOR = DWORD(36);
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsCompositionEnabled() {
|
||||||
auto result = BOOL(FALSE);
|
auto result = BOOL(FALSE);
|
||||||
const auto success = (DwmIsCompositionEnabled(&result) == S_OK);
|
const auto success = (DwmIsCompositionEnabled(&result) == S_OK);
|
||||||
return success && result;
|
return success && result;
|
||||||
|
|
@ -85,23 +91,6 @@ bool IsTaskbarAutoHidden(LPRECT rcMon = nullptr, PUINT pEdge = nullptr) {
|
||||||
return bAutoHidden;
|
return bAutoHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT WinApiSetWindowTheme(
|
|
||||||
HWND hWnd,
|
|
||||||
LPCWSTR pszSubAppName,
|
|
||||||
LPCWSTR pszSubIdList) {
|
|
||||||
static const auto method = [&] {
|
|
||||||
using f_SetWindowTheme = HRESULT(FAR STDAPICALLTYPE*)(
|
|
||||||
HWND hWnd,
|
|
||||||
LPCWSTR pszSubAppName,
|
|
||||||
LPCWSTR pszSubIdList);
|
|
||||||
auto result = f_SetWindowTheme();
|
|
||||||
const auto loaded = base::Platform::SafeLoadLibrary(L"uxtheme.dll");
|
|
||||||
base::Platform::LoadMethod(loaded, "SetWindowTheme", result);
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
return method ? method(hWnd, pszSubAppName, pszSubIdList) : HRESULT();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FixAeroSnap(HWND handle) {
|
void FixAeroSnap(HWND handle) {
|
||||||
SetWindowLongPtr(
|
SetWindowLongPtr(
|
||||||
handle,
|
handle,
|
||||||
|
|
@ -198,6 +187,7 @@ void WindowHelper::setTitle(const QString &title) {
|
||||||
|
|
||||||
void WindowHelper::setTitleStyle(const style::WindowTitle &st) {
|
void WindowHelper::setTitleStyle(const style::WindowTitle &st) {
|
||||||
_title->setStyle(st);
|
_title->setStyle(st);
|
||||||
|
updateWindowFrameColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowHelper::setNativeFrame(bool enabled) {
|
void WindowHelper::setNativeFrame(bool enabled) {
|
||||||
|
|
@ -216,6 +206,7 @@ void WindowHelper::setNativeFrame(bool enabled) {
|
||||||
initialShadowUpdate();
|
initialShadowUpdate();
|
||||||
}
|
}
|
||||||
updateMargins();
|
updateMargins();
|
||||||
|
updateWindowFrameColors();
|
||||||
fixMaximizedWindow();
|
fixMaximizedWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,6 +218,15 @@ void WindowHelper::initialShadowUpdate() {
|
||||||
} else {
|
} else {
|
||||||
_shadow->update(Change::Moved | Change::Resized | Change::Shown);
|
_shadow->update(Change::Moved | Change::Resized | Change::Shown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (::Platform::IsWindows11OrGreater()) {
|
||||||
|
auto preference = kDWMWCP_ROUND;
|
||||||
|
DwmSetWindowAttribute(
|
||||||
|
_handle,
|
||||||
|
kDWMWA_WINDOW_CORNER_PREFERENCE,
|
||||||
|
&preference,
|
||||||
|
sizeof(preference));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowHelper::setMinimumSize(QSize size) {
|
void WindowHelper::setMinimumSize(QSize size) {
|
||||||
|
|
@ -270,6 +270,7 @@ void WindowHelper::init() {
|
||||||
if (_shadow) {
|
if (_shadow) {
|
||||||
_shadow->setColor(st::windowShadowFg->c);
|
_shadow->setColor(st::windowShadowFg->c);
|
||||||
}
|
}
|
||||||
|
updateWindowFrameColors();
|
||||||
Ui::ForceFullRepaint(window());
|
Ui::ForceFullRepaint(window());
|
||||||
}, window()->lifetime());
|
}, window()->lifetime());
|
||||||
|
|
||||||
|
|
@ -291,9 +292,10 @@ void WindowHelper::init() {
|
||||||
updateMargins();
|
updateMargins();
|
||||||
|
|
||||||
if (!::Platform::IsWindows8OrGreater()) {
|
if (!::Platform::IsWindows8OrGreater()) {
|
||||||
WinApiSetWindowTheme(_handle, L" ", L" ");
|
SetWindowTheme(_handle, L" ", L" ");
|
||||||
QApplication::setStyle(QStyleFactory::create("Windows"));
|
QApplication::setStyle(QStyleFactory::create("Windows"));
|
||||||
}
|
}
|
||||||
|
updateWindowFrameColors();
|
||||||
|
|
||||||
_menu = GetSystemMenu(_handle, FALSE);
|
_menu = GetSystemMenu(_handle, FALSE);
|
||||||
updateSystemMenu();
|
updateSystemMenu();
|
||||||
|
|
@ -326,13 +328,15 @@ bool WindowHelper::handleNativeEvent(
|
||||||
if (LOWORD(wParam) == WA_CLICKACTIVE) {
|
if (LOWORD(wParam) == WA_CLICKACTIVE) {
|
||||||
Ui::MarkInactivePress(window(), true);
|
Ui::MarkInactivePress(window(), true);
|
||||||
}
|
}
|
||||||
|
const auto active = (LOWORD(wParam) != WA_INACTIVE);
|
||||||
if (_shadow) {
|
if (_shadow) {
|
||||||
if (LOWORD(wParam) != WA_INACTIVE) {
|
if (active) {
|
||||||
_shadow->update(WindowShadow::Change::Activate);
|
_shadow->update(WindowShadow::Change::Activate);
|
||||||
} else {
|
} else {
|
||||||
_shadow->update(WindowShadow::Change::Deactivate);
|
_shadow->update(WindowShadow::Change::Deactivate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateWindowFrameColors(active);
|
||||||
window()->update();
|
window()->update();
|
||||||
} return false;
|
} return false;
|
||||||
|
|
||||||
|
|
@ -553,6 +557,34 @@ int WindowHelper::titleHeight() const {
|
||||||
return _title->isHidden() ? 0 : _title->height();
|
return _title->isHidden() ? 0 : _title->height();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowHelper::updateWindowFrameColors() {
|
||||||
|
updateWindowFrameColors(window()->isActiveWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowHelper::updateWindowFrameColors(bool active) {
|
||||||
|
if (!::Platform::IsWindows11OrGreater()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto bg = active
|
||||||
|
? _title->st()->bgActive->c
|
||||||
|
: _title->st()->bg->c;
|
||||||
|
COLORREF bgRef = RGB(bg.red(), bg.green(), bg.blue());
|
||||||
|
DwmSetWindowAttribute(
|
||||||
|
_handle,
|
||||||
|
kDWMWA_CAPTION_COLOR,
|
||||||
|
&bgRef,
|
||||||
|
sizeof(COLORREF));
|
||||||
|
const auto fg = active
|
||||||
|
? _title->st()->fgActive->c
|
||||||
|
: _title->st()->fg->c;
|
||||||
|
COLORREF fgRef = RGB(fg.red(), fg.green(), fg.blue());
|
||||||
|
DwmSetWindowAttribute(
|
||||||
|
_handle,
|
||||||
|
kDWMWA_TEXT_COLOR,
|
||||||
|
&fgRef,
|
||||||
|
sizeof(COLORREF));
|
||||||
|
}
|
||||||
|
|
||||||
void WindowHelper::updateMargins() {
|
void WindowHelper::updateMargins() {
|
||||||
if (_updatingMargins) return;
|
if (_updatingMargins) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ private:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void updateMargins();
|
void updateMargins();
|
||||||
|
void updateWindowFrameColors();
|
||||||
|
void updateWindowFrameColors(bool active);
|
||||||
void updateSystemMenu();
|
void updateSystemMenu();
|
||||||
void updateSystemMenu(Qt::WindowState state);
|
void updateSystemMenu(Qt::WindowState state);
|
||||||
void initialShadowUpdate();
|
void initialShadowUpdate();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,30 @@
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<QPointer<QWidget>> GetChildWidgets(
|
||||||
|
not_null<QWidget*> widget) {
|
||||||
|
const auto &children = widget->children();
|
||||||
|
auto result = std::vector<QPointer<QWidget>>();
|
||||||
|
result.reserve(children.size());
|
||||||
|
for (const auto child : children) {
|
||||||
|
if (child && child->isWidgetType()) {
|
||||||
|
result.push_back(static_cast<QWidget*>(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void ToggleChildrenVisibility(not_null<QWidget*> widget, bool visible) {
|
||||||
|
for (const auto &child : GetChildWidgets(widget)) {
|
||||||
|
if (child) {
|
||||||
|
child->setVisible(visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ResizeFitChild(
|
void ResizeFitChild(
|
||||||
not_null<RpWidget*> parent,
|
not_null<RpWidget*> parent,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@
|
||||||
|
|
||||||
#include <QtWidgets/QWidget>
|
#include <QtWidgets/QWidget>
|
||||||
#include <QtCore/QPointer>
|
#include <QtCore/QPointer>
|
||||||
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
void ToggleChildrenVisibility(not_null<QWidget*> widget, bool visible);
|
||||||
|
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
class TWidget;
|
class TWidget;
|
||||||
|
|
||||||
|
|
@ -29,18 +36,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideChildren() {
|
void hideChildren() {
|
||||||
for (auto child : Base::children()) {
|
Ui::ToggleChildrenVisibility(this, false);
|
||||||
if (child->isWidgetType()) {
|
|
||||||
static_cast<QWidget*>(child)->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void showChildren() {
|
void showChildren() {
|
||||||
for (auto child : Base::children()) {
|
Ui::ToggleChildrenVisibility(this, true);
|
||||||
if (child->isWidgetType()) {
|
|
||||||
static_cast<QWidget*>(child)->show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveToLeft(int x, int y, int outerw = 0) {
|
void moveToLeft(int x, int y, int outerw = 0) {
|
||||||
|
|
@ -104,13 +103,22 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void enterEvent(QEvent *e) final override {
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
void enterEvent(QEnterEvent *e) final override {
|
||||||
if (auto parent = tparent()) {
|
if (auto parent = tparent()) {
|
||||||
parent->leaveToChildEvent(e, this);
|
parent->leaveToChildEvent(e, this);
|
||||||
}
|
}
|
||||||
return enterEventHook(e);
|
return enterEventHook(e);
|
||||||
}
|
}
|
||||||
virtual void enterEventHook(QEvent *e) {
|
#else // Qt >= 6.0.0
|
||||||
|
void enterEvent(QEvent *e) final override {
|
||||||
|
if (auto parent = tparent()) {
|
||||||
|
parent->leaveToChildEvent(e, this);
|
||||||
|
}
|
||||||
|
return enterEventHook(static_cast<QEnterEvent*>(e));
|
||||||
|
}
|
||||||
|
#endif // Qt < 6.0.0
|
||||||
|
virtual void enterEventHook(QEnterEvent *e) {
|
||||||
return Base::enterEvent(e);
|
return Base::enterEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ void ColorData::set(uchar r, uchar g, uchar b, uchar a) {
|
||||||
void ComplexColor::subscribeToPaletteChanges() {
|
void ComplexColor::subscribeToPaletteChanges() {
|
||||||
style::PaletteChanged(
|
style::PaletteChanged(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_owned.update(_generator());
|
refresh();
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,9 @@ public:
|
||||||
[[nodiscard]] const Color &color() const {
|
[[nodiscard]] const Color &color() const {
|
||||||
return _owned.color();
|
return _owned.color();
|
||||||
}
|
}
|
||||||
|
void refresh() {
|
||||||
|
_owned.update(_generator());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void subscribeToPaletteChanges();
|
void subscribeToPaletteChanges();
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
#include "base/algorithm.h"
|
||||||
#include "base/debug_log.h"
|
#include "base/debug_log.h"
|
||||||
|
#include "base/base_file_utilities.h"
|
||||||
#include "ui/style/style_core_custom_font.h"
|
#include "ui/style/style_core_custom_font.h"
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
|
|
||||||
|
|
@ -18,16 +19,22 @@
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
|
|
||||||
void style_InitFontsResource() {
|
void style_InitFontsResource() {
|
||||||
|
#ifdef Q_OS_MAC // Use resources from the .app bundle on macOS.
|
||||||
|
|
||||||
|
base::RegisterBundledResources(u"lib_ui.rcc"_q);
|
||||||
|
|
||||||
|
#else // Q_OS_MAC
|
||||||
|
|
||||||
#ifndef DESKTOP_APP_USE_PACKAGED_FONTS
|
#ifndef DESKTOP_APP_USE_PACKAGED_FONTS
|
||||||
Q_INIT_RESOURCE(fonts);
|
Q_INIT_RESOURCE(fonts);
|
||||||
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
|
#endif // !DESKTOP_APP_USE_PACKAGED_FONTS
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
Q_INIT_RESOURCE(win);
|
Q_INIT_RESOURCE(win);
|
||||||
#elif defined Q_OS_MAC // Q_OS_WIN
|
#elif defined Q_OS_UNIX && !defined DESKTOP_APP_USE_PACKAGED // Q_OS_WIN
|
||||||
Q_INIT_RESOURCE(mac);
|
|
||||||
#elif defined Q_OS_UNIX && !defined DESKTOP_APP_USE_PACKAGED // Q_OS_WIN || Q_OS_MAC
|
|
||||||
Q_INIT_RESOURCE(linux);
|
Q_INIT_RESOURCE(linux);
|
||||||
#endif // Q_OS_WIN || Q_OS_MAC || (Q_OS_UNIX && !DESKTOP_APP_USE_PACKAGED)
|
#endif // Q_OS_WIN || (Q_OS_UNIX && !DESKTOP_APP_USE_PACKAGED)
|
||||||
|
|
||||||
|
#endif // Q_OS_MAC
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "ui/style/style_core.h"
|
#include "ui/style/style_core.h"
|
||||||
#include "base/basic_types.h"
|
#include "base/basic_types.h"
|
||||||
|
|
||||||
|
#include <QtCore/QMutex>
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
|
|
@ -20,11 +21,15 @@ uint32 colorKey(QColor c) {
|
||||||
return (((((uint32(c.red()) << 8) | uint32(c.green())) << 8) | uint32(c.blue())) << 8) | uint32(c.alpha());
|
return (((((uint32(c.red()) << 8) | uint32(c.green())) << 8) | uint32(c.blue())) << 8) | uint32(c.alpha());
|
||||||
}
|
}
|
||||||
|
|
||||||
base::flat_map<const IconMask*, QImage> iconMasks;
|
base::flat_map<const IconMask*, QImage> IconMasks;
|
||||||
|
QMutex IconMasksMutex;
|
||||||
|
|
||||||
base::flat_map<QPair<const IconMask*, uint32>, QPixmap> iconPixmaps;
|
base::flat_map<QPair<const IconMask*, uint32>, QPixmap> iconPixmaps;
|
||||||
base::flat_set<IconData*> iconData;
|
base::flat_set<IconData*> iconData;
|
||||||
|
|
||||||
QImage createIconMask(const IconMask *mask, int scale) {
|
[[nodiscard]] QImage CreateIconMask(
|
||||||
|
not_null<const IconMask*> mask,
|
||||||
|
int scale) {
|
||||||
auto maskImage = QImage::fromData(mask->data(), mask->size(), "PNG");
|
auto maskImage = QImage::fromData(mask->data(), mask->size(), "PNG");
|
||||||
maskImage.setDevicePixelRatio(DevicePixelRatio());
|
maskImage.setDevicePixelRatio(DevicePixelRatio());
|
||||||
Assert(!maskImage.isNull());
|
Assert(!maskImage.isNull());
|
||||||
|
|
@ -55,6 +60,17 @@ QImage createIconMask(const IconMask *mask, int scale) {
|
||||||
Qt::SmoothTransformation);
|
Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QImage ResolveIconMask(not_null<const IconMask*> mask) {
|
||||||
|
QMutexLocker lock(&IconMasksMutex);
|
||||||
|
if (const auto i = IconMasks.find(mask); i != end(IconMasks)) {
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
return IconMasks.emplace(
|
||||||
|
mask,
|
||||||
|
CreateIconMask(mask, Scale())
|
||||||
|
).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
QSize readGeneratedSize(const IconMask *mask, int scale) {
|
QSize readGeneratedSize(const IconMask *mask, int scale) {
|
||||||
auto data = mask->data();
|
auto data = mask->data();
|
||||||
auto size = mask->size();
|
auto size = mask->size();
|
||||||
|
|
@ -181,7 +197,7 @@ void MonoIcon::paint(
|
||||||
auto size = readGeneratedSize(_mask, Scale());
|
auto size = readGeneratedSize(_mask, Scale());
|
||||||
auto maskImage = QImage();
|
auto maskImage = QImage();
|
||||||
if (size.isEmpty()) {
|
if (size.isEmpty()) {
|
||||||
maskImage = createIconMask(_mask, Scale());
|
maskImage = CreateIconMask(_mask, Scale());
|
||||||
size = maskImage.size() / DevicePixelRatio();
|
size = maskImage.size() / DevicePixelRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,7 +225,7 @@ void MonoIcon::fill(
|
||||||
auto size = readGeneratedSize(_mask, Scale());
|
auto size = readGeneratedSize(_mask, Scale());
|
||||||
auto maskImage = QImage();
|
auto maskImage = QImage();
|
||||||
if (size.isEmpty()) {
|
if (size.isEmpty()) {
|
||||||
maskImage = createIconMask(_mask, Scale());
|
maskImage = CreateIconMask(_mask, Scale());
|
||||||
size = maskImage.size() / DevicePixelRatio();
|
size = maskImage.size() / DevicePixelRatio();
|
||||||
}
|
}
|
||||||
if (!maskImage.isNull()) {
|
if (!maskImage.isNull()) {
|
||||||
|
|
@ -242,7 +258,7 @@ QImage MonoIcon::instance(QColor colorOverride, int scale) const {
|
||||||
result.fill(colorOverride);
|
result.fill(colorOverride);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
auto mask = createIconMask(_mask, scale);
|
auto mask = CreateIconMask(_mask, scale);
|
||||||
auto result = QImage(mask.size(), QImage::Format_ARGB32_Premultiplied);
|
auto result = QImage(mask.size(), QImage::Format_ARGB32_Premultiplied);
|
||||||
result.setDevicePixelRatio(DevicePixelRatio());
|
result.setDevicePixelRatio(DevicePixelRatio());
|
||||||
colorizeImage(mask, colorOverride, &result);
|
colorizeImage(mask, colorOverride, &result);
|
||||||
|
|
@ -252,26 +268,24 @@ QImage MonoIcon::instance(QColor colorOverride, int scale) const {
|
||||||
void MonoIcon::ensureLoaded() const {
|
void MonoIcon::ensureLoaded() const {
|
||||||
if (_size.isValid()) {
|
if (_size.isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
} else if (!_maskImage.isNull()) {
|
||||||
if (!_maskImage.isNull()) {
|
|
||||||
createCachedPixmap();
|
createCachedPixmap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_size = readGeneratedSize(_mask, Scale());
|
_size = readGeneratedSize(_mask, Scale());
|
||||||
if (_size.isEmpty()) {
|
if (_size.isEmpty()) {
|
||||||
auto i = iconMasks.find(_mask);
|
_maskImage = ResolveIconMask(_mask);
|
||||||
if (i == iconMasks.cend()) {
|
|
||||||
i = iconMasks.emplace(_mask, createIconMask(_mask, Scale())).first;
|
|
||||||
}
|
|
||||||
_maskImage = i->second;
|
|
||||||
|
|
||||||
createCachedPixmap();
|
createCachedPixmap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MonoIcon::ensureColorizedImage(QColor color) const {
|
void MonoIcon::ensureColorizedImage(QColor color) const {
|
||||||
if (_colorizedImage.isNull()) _colorizedImage = QImage(_maskImage.size(), QImage::Format_ARGB32_Premultiplied);
|
if (_colorizedImage.isNull()) {
|
||||||
|
_colorizedImage = QImage(
|
||||||
|
_maskImage.size(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
}
|
||||||
colorizeImage(_maskImage, color, &_colorizedImage);
|
colorizeImage(_maskImage, color, &_colorizedImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,7 +387,9 @@ void resetIcons() {
|
||||||
void destroyIcons() {
|
void destroyIcons() {
|
||||||
iconData.clear();
|
iconData.clear();
|
||||||
iconPixmaps.clear();
|
iconPixmaps.clear();
|
||||||
iconMasks.clear();
|
|
||||||
|
QMutexLocker lock(&IconMasksMutex);
|
||||||
|
IconMasks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/algorithm.h"
|
||||||
|
|
||||||
#include <QtCore/QSize>
|
#include <QtCore/QSize>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
@ -34,7 +36,7 @@ template <typename T>
|
||||||
[[nodiscard]] inline T ConvertScale(T value, int scale) {
|
[[nodiscard]] inline T ConvertScale(T value, int scale) {
|
||||||
return (value < 0.)
|
return (value < 0.)
|
||||||
? (-ConvertScale(-value, scale))
|
? (-ConvertScale(-value, scale))
|
||||||
: T(std::round((double(value) * scale / 100.) - 0.01));
|
: T(base::SafeRound((double(value) * scale / 100.) - 0.01));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,12 @@
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <private/qfontengine_p.h>
|
#include <private/qfontengine_p.h>
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
#include <private/qharfbuzz_p.h>
|
#include <private/qharfbuzz_p.h>
|
||||||
|
#endif // Qt < 6.0.0
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace Text {
|
namespace Text {
|
||||||
|
|
@ -161,7 +164,7 @@ QString textcmdStartLink(const QString &url) {
|
||||||
|
|
||||||
QString result;
|
QString result;
|
||||||
result.reserve(url.size() + 4);
|
result.reserve(url.size() + 4);
|
||||||
return result.append(TextCommand).append(QChar(TextCommandLinkText)).append(QChar(url.size())).append(url).append(TextCommand);
|
return result.append(TextCommand).append(QChar(TextCommandLinkText)).append(QChar(int(url.size()))).append(url).append(TextCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString textcmdStopLink() {
|
QString textcmdStopLink() {
|
||||||
|
|
@ -2058,10 +2061,21 @@ private:
|
||||||
auto analysis = _parAnalysis.data() + (_localFrom - _parStart);
|
auto analysis = _parAnalysis.data() + (_localFrom - _parStart);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
QUnicodeTools::ScriptItemArray scriptItems;
|
||||||
|
QUnicodeTools::initScripts(_e->layoutData->string, &scriptItems);
|
||||||
|
for (int i = 0; i < scriptItems.length(); ++i) {
|
||||||
|
const auto &item = scriptItems.at(i);
|
||||||
|
int end = i < scriptItems.length() - 1 ? scriptItems.at(i + 1).position : length;
|
||||||
|
for (int j = item.position; j < end; ++j)
|
||||||
|
analysis[j].script = item.script;
|
||||||
|
}
|
||||||
|
#else // Qt >= 6.0.0
|
||||||
QVarLengthArray<uchar> scripts(length);
|
QVarLengthArray<uchar> scripts(length);
|
||||||
QUnicodeTools::initScripts(string, length, scripts.data());
|
QUnicodeTools::initScripts(string, length, scripts.data());
|
||||||
for (int i = 0; i < length; ++i)
|
for (int i = 0; i < length; ++i)
|
||||||
analysis[i].script = scripts.at(i);
|
analysis[i].script = scripts.at(i);
|
||||||
|
#endif // Qt < 6.0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
blockIndex = _lineStartBlock;
|
blockIndex = _lineStartBlock;
|
||||||
|
|
@ -2082,7 +2096,9 @@ private:
|
||||||
} else {
|
} else {
|
||||||
analysis->flags = QScriptAnalysis::None;
|
analysis->flags = QScriptAnalysis::None;
|
||||||
}
|
}
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
analysis->script = hbscript_to_script(script_to_hbscript(analysis->script)); // retain the old behavior
|
analysis->script = hbscript_to_script(script_to_hbscript(analysis->script)); // retain the old behavior
|
||||||
|
#endif // Qt < 6.0.0
|
||||||
++start;
|
++start;
|
||||||
++analysis;
|
++analysis;
|
||||||
}
|
}
|
||||||
|
|
@ -3151,7 +3167,7 @@ void String::enumerateText(TextSelection selection, AppendPartCallback appendPar
|
||||||
auto rangeFrom = qMax(selection.from, lnkFrom);
|
auto rangeFrom = qMax(selection.from, lnkFrom);
|
||||||
auto rangeTo = qMin(selection.to, blockFrom);
|
auto rangeTo = qMin(selection.to, blockFrom);
|
||||||
if (rangeTo > rangeFrom) { // handle click handler
|
if (rangeTo > rangeFrom) { // handle click handler
|
||||||
QStringRef r = _text.midRef(rangeFrom, rangeTo - rangeFrom);
|
const auto r = base::StringViewMid(_text, rangeFrom, rangeTo - rangeFrom);
|
||||||
if (lnkFrom != rangeFrom || blockFrom != rangeTo) {
|
if (lnkFrom != rangeFrom || blockFrom != rangeTo) {
|
||||||
// Ignore links that are partially copied.
|
// Ignore links that are partially copied.
|
||||||
clickHandlerFinishCallback(r, nullptr);
|
clickHandlerFinishCallback(r, nullptr);
|
||||||
|
|
@ -3182,7 +3198,7 @@ void String::enumerateText(TextSelection selection, AppendPartCallback appendPar
|
||||||
auto rangeFrom = qMax(selection.from, blockFrom);
|
auto rangeFrom = qMax(selection.from, blockFrom);
|
||||||
auto rangeTo = qMin(selection.to, uint16(blockFrom + countBlockLength(i, e)));
|
auto rangeTo = qMin(selection.to, uint16(blockFrom + countBlockLength(i, e)));
|
||||||
if (rangeTo > rangeFrom) {
|
if (rangeTo > rangeFrom) {
|
||||||
appendPartCallback(_text.midRef(rangeFrom, rangeTo - rangeFrom));
|
appendPartCallback(base::StringViewMid(_text, rangeFrom, rangeTo - rangeFrom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3245,7 +3261,7 @@ TextForMimeData String::toText(
|
||||||
insertEntity({
|
insertEntity({
|
||||||
tracker.type,
|
tracker.type,
|
||||||
tracker.start,
|
tracker.start,
|
||||||
result.rich.text.size() - tracker.start });
|
int(result.rich.text.size()) - tracker.start });
|
||||||
} else if ((newFlags & flag) && !(oldFlags & flag)) {
|
} else if ((newFlags & flag) && !(oldFlags & flag)) {
|
||||||
tracker.start = result.rich.text.size();
|
tracker.start = result.rich.text.size();
|
||||||
}
|
}
|
||||||
|
|
@ -3255,7 +3271,7 @@ TextForMimeData String::toText(
|
||||||
linkStart = result.rich.text.size();
|
linkStart = result.rich.text.size();
|
||||||
};
|
};
|
||||||
const auto clickHandlerFinishCallback = [&](
|
const auto clickHandlerFinishCallback = [&](
|
||||||
const QStringRef &inText,
|
QStringView inText,
|
||||||
const ClickHandlerPtr &handler) {
|
const ClickHandlerPtr &handler) {
|
||||||
if (!handler || (!composeExpanded && !composeEntities)) {
|
if (!handler || (!composeExpanded && !composeEntities)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -3264,7 +3280,7 @@ TextForMimeData String::toText(
|
||||||
const auto plainUrl = (entity.type == EntityType::Url)
|
const auto plainUrl = (entity.type == EntityType::Url)
|
||||||
|| (entity.type == EntityType::Email);
|
|| (entity.type == EntityType::Email);
|
||||||
const auto full = plainUrl
|
const auto full = plainUrl
|
||||||
? entity.data.midRef(0, entity.data.size())
|
? QStringView(entity.data).mid(0, entity.data.size())
|
||||||
: inText;
|
: inText;
|
||||||
const auto customTextLink = (entity.type == EntityType::CustomUrl);
|
const auto customTextLink = (entity.type == EntityType::CustomUrl);
|
||||||
const auto internalLink = customTextLink
|
const auto internalLink = customTextLink
|
||||||
|
|
@ -3282,11 +3298,11 @@ TextForMimeData String::toText(
|
||||||
insertEntity({
|
insertEntity({
|
||||||
entity.type,
|
entity.type,
|
||||||
linkStart,
|
linkStart,
|
||||||
(result.rich.text.size() - linkStart),
|
int(result.rich.text.size() - linkStart),
|
||||||
plainUrl ? QString() : entity.data });
|
plainUrl ? QString() : entity.data });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto appendPartCallback = [&](const QStringRef &part) {
|
const auto appendPartCallback = [&](QStringView part) {
|
||||||
result.rich.text += part;
|
result.rich.text += part;
|
||||||
if (composeExpanded) {
|
if (composeExpanded) {
|
||||||
result.expanded += part;
|
result.expanded += part;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@
|
||||||
#include "base/qthelp_url.h"
|
#include "base/qthelp_url.h"
|
||||||
#include "base/qthelp_regex.h"
|
#include "base/qthelp_regex.h"
|
||||||
#include "base/crc32hash.h"
|
#include "base/crc32hash.h"
|
||||||
#include "base/qt_adapters.h"
|
|
||||||
#include "ui/text/text.h"
|
#include "ui/text/text.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtCore/QStack>
|
#include <QtCore/QStack>
|
||||||
#include <QtCore/QMimeData>
|
#include <QtCore/QMimeData>
|
||||||
|
|
@ -1156,13 +1156,13 @@ const QRegularExpression &RegExpWordSplit() {
|
||||||
for (const auto &entity : urls) {
|
for (const auto &entity : urls) {
|
||||||
const auto till = entity.offset() + entity.length();
|
const auto till = entity.offset() + entity.length();
|
||||||
if (till > offset) {
|
if (till > offset) {
|
||||||
result.append(original.midRef(offset, till - offset));
|
result.append(base::StringViewMid(original, offset, till - offset));
|
||||||
}
|
}
|
||||||
result.append(qstr(" (")).append(entity.data()).append(')');
|
result.append(qstr(" (")).append(entity.data()).append(')');
|
||||||
offset = till;
|
offset = till;
|
||||||
}
|
}
|
||||||
if (original.size() > offset) {
|
if (original.size() > offset) {
|
||||||
result.append(original.midRef(offset));
|
result.append(base::StringViewMid(original, offset));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -1402,7 +1402,7 @@ QStringList PrepareSearchWords(
|
||||||
auto list = clean.split(SplitterOverride
|
auto list = clean.split(SplitterOverride
|
||||||
? *SplitterOverride
|
? *SplitterOverride
|
||||||
: RegExpWordSplit(),
|
: RegExpWordSplit(),
|
||||||
base::QStringSkipEmptyParts);
|
Qt::SkipEmptyParts);
|
||||||
result.reserve(list.size());
|
result.reserve(list.size());
|
||||||
for (const auto &word : std::as_const(list)) {
|
for (const auto &word : std::as_const(list)) {
|
||||||
auto trimmed = word.trimmed();
|
auto trimmed = word.trimmed();
|
||||||
|
|
@ -1619,10 +1619,10 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) {
|
||||||
auto mentionIgnore = false;
|
auto mentionIgnore = false;
|
||||||
|
|
||||||
if (mHashtag.hasMatch()) {
|
if (mHashtag.hasMatch()) {
|
||||||
if (!mHashtag.capturedRef(1).isEmpty()) {
|
if (!mHashtag.capturedView(1).isEmpty()) {
|
||||||
++hashtagStart;
|
++hashtagStart;
|
||||||
}
|
}
|
||||||
if (!mHashtag.capturedRef(2).isEmpty()) {
|
if (!mHashtag.capturedView(2).isEmpty()) {
|
||||||
--hashtagEnd;
|
--hashtagEnd;
|
||||||
}
|
}
|
||||||
if (RegExpHashtagExclude().match(
|
if (RegExpHashtagExclude().match(
|
||||||
|
|
@ -1633,10 +1633,10 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (mMention.hasMatch()) {
|
while (mMention.hasMatch()) {
|
||||||
if (!mMention.capturedRef(1).isEmpty()) {
|
if (!mMention.capturedView(1).isEmpty()) {
|
||||||
++mentionStart;
|
++mentionStart;
|
||||||
}
|
}
|
||||||
if (!mMention.capturedRef(2).isEmpty()) {
|
if (!mMention.capturedView(2).isEmpty()) {
|
||||||
--mentionEnd;
|
--mentionEnd;
|
||||||
}
|
}
|
||||||
if (!(start + mentionStart + 1)->isLetter() || !(start + mentionEnd - 1)->isLetterOrNumber()) {
|
if (!(start + mentionStart + 1)->isLetter() || !(start + mentionEnd - 1)->isLetterOrNumber()) {
|
||||||
|
|
@ -1657,10 +1657,10 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mBotCommand.hasMatch()) {
|
if (mBotCommand.hasMatch()) {
|
||||||
if (!mBotCommand.capturedRef(1).isEmpty()) {
|
if (!mBotCommand.capturedView(1).isEmpty()) {
|
||||||
++botCommandStart;
|
++botCommandStart;
|
||||||
}
|
}
|
||||||
if (!mBotCommand.capturedRef(3).isEmpty()) {
|
if (!mBotCommand.capturedView(3).isEmpty()) {
|
||||||
--botCommandEnd;
|
--botCommandEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2019,16 +2019,16 @@ QString TagsTextMimeType() {
|
||||||
return QString::fromLatin1("application/x-td-field-text");
|
return QString::fromLatin1("application/x-td-field-text");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsMentionLink(const QStringRef &link) {
|
bool IsMentionLink(QStringView link) {
|
||||||
return link.startsWith(kMentionTagStart);
|
return link.startsWith(kMentionTagStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool IsSeparateTag(const QStringRef &tag) {
|
[[nodiscard]] bool IsSeparateTag(QStringView tag) {
|
||||||
return (tag == Ui::InputField::kTagCode)
|
return (tag == Ui::InputField::kTagCode)
|
||||||
|| (tag == Ui::InputField::kTagPre);
|
|| (tag == Ui::InputField::kTagPre);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString JoinTag(const QVector<QStringRef> &list) {
|
QString JoinTag(const QList<QStringView> &list) {
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
@ -2039,7 +2039,7 @@ QString JoinTag(const QVector<QStringRef> &list) {
|
||||||
auto result = QString();
|
auto result = QString();
|
||||||
result.reserve(length);
|
result.reserve(length);
|
||||||
result.append(list.front());
|
result.append(list.front());
|
||||||
for (auto i = 1, count = list.size(); i != count; ++i) {
|
for (auto i = 1, count = int(list.size()); i != count; ++i) {
|
||||||
if (!IsSeparateTag(list[i])) {
|
if (!IsSeparateTag(list[i])) {
|
||||||
result.append('|').append(list[i]);
|
result.append('|').append(list[i]);
|
||||||
}
|
}
|
||||||
|
|
@ -2051,8 +2051,8 @@ QString TagWithRemoved(const QString &tag, const QString &removed) {
|
||||||
if (tag == removed) {
|
if (tag == removed) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
auto list = tag.splitRef('|');
|
auto list = QStringView(tag).split('|');
|
||||||
list.erase(ranges::remove(list, removed.midRef(0)), list.end());
|
list.erase(ranges::remove(list, QStringView(removed)), list.end());
|
||||||
return JoinTag(list);
|
return JoinTag(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2060,13 +2060,13 @@ QString TagWithAdded(const QString &tag, const QString &added) {
|
||||||
if (tag.isEmpty() || tag == added) {
|
if (tag.isEmpty() || tag == added) {
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
auto list = tag.splitRef('|');
|
auto list = QStringView(tag).split('|');
|
||||||
const auto ref = added.midRef(0);
|
const auto ref = QStringView(added);
|
||||||
if (list.contains(ref)) {
|
if (list.contains(ref)) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
list.push_back(ref);
|
list.push_back(ref);
|
||||||
ranges::sort(list);
|
std::sort(list.begin(), list.end());
|
||||||
return JoinTag(list);
|
return JoinTag(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2156,7 +2156,7 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||||
if (IsMentionLink(nextState.link)) {
|
if (IsMentionLink(nextState.link)) {
|
||||||
const auto match = qthelp::regex_match(
|
const auto match = qthelp::regex_match(
|
||||||
"^(\\d+\\.\\d+)(/|$)",
|
"^(\\d+\\.\\d+)(/|$)",
|
||||||
nextState.link.midRef(kMentionTagStart.size()));
|
base::StringViewMid(nextState.link, kMentionTagStart.size()));
|
||||||
if (match) {
|
if (match) {
|
||||||
openType(EntityType::MentionName, match->captured(1));
|
openType(EntityType::MentionName, match->captured(1));
|
||||||
}
|
}
|
||||||
|
|
@ -2173,7 +2173,7 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||||
};
|
};
|
||||||
const auto stateForTag = [&](const QString &tag) {
|
const auto stateForTag = [&](const QString &tag) {
|
||||||
auto result = State();
|
auto result = State();
|
||||||
const auto list = tag.splitRef('|');
|
const auto list = QStringView(tag).split('|');
|
||||||
for (const auto &single : list) {
|
for (const auto &single : list) {
|
||||||
if (single == Ui::InputField::kTagBold) {
|
if (single == Ui::InputField::kTagBold) {
|
||||||
result.set(EntityType::Bold);
|
result.set(EntityType::Bold);
|
||||||
|
|
|
||||||
|
|
@ -363,17 +363,9 @@ void ApplyServerCleaning(TextWithEntities &result);
|
||||||
|
|
||||||
inline const auto kMentionTagStart = qstr("mention://user.");
|
inline const auto kMentionTagStart = qstr("mention://user.");
|
||||||
|
|
||||||
[[nodiscard]] bool IsMentionLink(const QStringRef &link);
|
[[nodiscard]] bool IsMentionLink(QStringView link);
|
||||||
[[nodiscard]] inline bool IsMentionLink(const QString &link) {
|
[[nodiscard]] bool IsSeparateTag(QStringView tag);
|
||||||
return IsMentionLink(link.midRef(0));
|
[[nodiscard]] QString JoinTag(const QList<QStringView> &list);
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsSeparateTag(const QStringRef &tag);
|
|
||||||
[[nodiscard]] inline bool IsSeparateTag(const QString &tag) {
|
|
||||||
return IsSeparateTag(tag.midRef(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QString JoinTag(const QVector<QStringRef> &list);
|
|
||||||
[[nodiscard]] QString TagWithRemoved(
|
[[nodiscard]] QString TagWithRemoved(
|
||||||
const QString &tag,
|
const QString &tag,
|
||||||
const QString &removed);
|
const QString &removed);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
|
|
||||||
#include "base/algorithm.h"
|
#include "base/algorithm.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ TextWithEntities WithSingleEntity(
|
||||||
EntityType type,
|
EntityType type,
|
||||||
const QString &data = QString()) {
|
const QString &data = QString()) {
|
||||||
auto result = TextWithEntities{ text };
|
auto result = TextWithEntities{ text };
|
||||||
result.entities.push_back({ type, 0, text.size(), data });
|
result.entities.push_back({ type, 0, int(text.size()), data });
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,25 +50,25 @@ TextWithEntities RichLangValue(const QString &text) {
|
||||||
while (offset < text.size()) {
|
while (offset < text.size()) {
|
||||||
const auto m = kStart.match(text, offset);
|
const auto m = kStart.match(text, offset);
|
||||||
if (!m.hasMatch()) {
|
if (!m.hasMatch()) {
|
||||||
result.text.append(text.midRef(offset));
|
result.text.append(base::StringViewMid(text, offset));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const auto position = m.capturedStart();
|
const auto position = m.capturedStart();
|
||||||
const auto from = m.capturedEnd();
|
const auto from = m.capturedEnd();
|
||||||
const auto tag = m.capturedRef();
|
const auto tag = m.capturedView();
|
||||||
const auto till = text.indexOf(tag, from + 1);
|
const auto till = text.indexOf(tag, from + 1);
|
||||||
if (till <= from) {
|
if (till <= from) {
|
||||||
offset = from;
|
offset = from;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (position > offset) {
|
if (position > offset) {
|
||||||
result.text.append(text.midRef(offset, position - offset));
|
result.text.append(base::StringViewMid(text, offset, position - offset));
|
||||||
}
|
}
|
||||||
const auto type = (tag == qstr("__"))
|
const auto type = (tag == qstr("__"))
|
||||||
? EntityType::Italic
|
? EntityType::Italic
|
||||||
: EntityType::Bold;
|
: EntityType::Bold;
|
||||||
result.entities.push_back({ type, result.text.size(), till - from });
|
result.entities.push_back({ type, int(result.text.size()), int(till - from) });
|
||||||
result.text.append(text.midRef(from, till - from));
|
result.text.append(base::StringViewMid(text, from, till - from));
|
||||||
offset = till + tag.size();
|
offset = till + tag.size();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
#include "ui/platform/ui_platform_utility.h"
|
||||||
#include "ui/style/style_core.h"
|
#include "ui/style/style_core.h"
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
|
@ -214,9 +213,7 @@ bool IsContentVisible(
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisableCustomScaling() {
|
void DisableCustomScaling() {
|
||||||
if (QCoreApplication::testAttribute(Qt::AA_DisableHighDpiScaling)) {
|
QHighDpiScaling::setGlobalFactor(1);
|
||||||
QHighDpiScaling::setGlobalFactor(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int WheelDirection(not_null<QWheelEvent*> e) {
|
int WheelDirection(not_null<QWheelEvent*> e) {
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,11 @@ void RoundButton::setBrushOverride(std::optional<QBrush> brush) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RoundButton::setPenOverride(std::optional<QPen> pen) {
|
||||||
|
_penOverride = std::move(pen);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void RoundButton::finishNumbersAnimation() {
|
void RoundButton::finishNumbersAnimation() {
|
||||||
if (_numbers) {
|
if (_numbers) {
|
||||||
_numbers->finishAnimating();
|
_numbers->finishAnimating();
|
||||||
|
|
@ -371,11 +376,12 @@ void RoundButton::paintEvent(QPaintEvent *e) {
|
||||||
if (_fullRadius) {
|
if (_fullRadius) {
|
||||||
const auto radius = rounded.height() / 2;
|
const auto radius = rounded.height() / 2;
|
||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(_penOverride ? *_penOverride : Qt::NoPen);
|
||||||
p.setBrush(_brushOverride ? *_brushOverride : rect.color()->b);
|
p.setBrush(_brushOverride ? *_brushOverride : rect.color()->b);
|
||||||
p.drawRoundedRect(fill, radius, radius);
|
p.drawRoundedRect(fill, radius, radius);
|
||||||
} else if (_brushOverride) {
|
} else if (_brushOverride) {
|
||||||
p.setPen(Qt::NoPen);
|
PainterHighQualityEnabler hq(p);
|
||||||
|
p.setPen(_penOverride ? *_penOverride : Qt::NoPen);
|
||||||
p.setBrush(*_brushOverride);
|
p.setBrush(*_brushOverride);
|
||||||
const auto radius = _st.radius ? _st.radius : st::buttonRadius;
|
const auto radius = _st.radius ? _st.radius : st::buttonRadius;
|
||||||
p.drawRoundedRect(fill, radius, radius);
|
p.drawRoundedRect(fill, radius, radius);
|
||||||
|
|
@ -383,6 +389,9 @@ void RoundButton::paintEvent(QPaintEvent *e) {
|
||||||
rect.paint(p, fill);
|
rect.paint(p, fill);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (_penOverride) {
|
||||||
|
paintRipple(p, rounded.topLeft());
|
||||||
|
}
|
||||||
drawRect(_roundRect);
|
drawRect(_roundRect);
|
||||||
|
|
||||||
auto over = isOver();
|
auto over = isOver();
|
||||||
|
|
@ -391,7 +400,9 @@ void RoundButton::paintEvent(QPaintEvent *e) {
|
||||||
drawRect(_roundRectOver);
|
drawRect(_roundRectOver);
|
||||||
}
|
}
|
||||||
|
|
||||||
paintRipple(p, rounded.topLeft());
|
if (!_penOverride) {
|
||||||
|
paintRipple(p, rounded.topLeft());
|
||||||
|
}
|
||||||
|
|
||||||
p.setFont(_st.font);
|
p.setFont(_st.font);
|
||||||
const auto textTop = _st.padding.top() + _st.textTop;
|
const auto textTop = _st.padding.top() + _st.textTop;
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ public:
|
||||||
}
|
}
|
||||||
void setWidthChangedCallback(Fn<void()> callback);
|
void setWidthChangedCallback(Fn<void()> callback);
|
||||||
void setBrushOverride(std::optional<QBrush> brush);
|
void setBrushOverride(std::optional<QBrush> brush);
|
||||||
|
void setPenOverride(std::optional<QPen> pen);
|
||||||
void finishNumbersAnimation();
|
void finishNumbersAnimation();
|
||||||
|
|
||||||
int contentWidth() const;
|
int contentWidth() const;
|
||||||
|
|
@ -167,6 +168,7 @@ private:
|
||||||
|
|
||||||
const style::RoundButton &_st;
|
const style::RoundButton &_st;
|
||||||
std::optional<QBrush> _brushOverride;
|
std::optional<QBrush> _brushOverride;
|
||||||
|
std::optional<QPen> _penOverride;
|
||||||
RoundRect _roundRect;
|
RoundRect _roundRect;
|
||||||
RoundRect _roundRectOver;
|
RoundRect _roundRectOver;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ InnerDropdown::InnerDropdown(
|
||||||
, _roundRect(ImageRoundRadius::Small, _st.bg)
|
, _roundRect(ImageRoundRadius::Small, _st.bg)
|
||||||
, _hideTimer([=] { hideAnimated(); })
|
, _hideTimer([=] { hideAnimated(); })
|
||||||
, _scroll(this, _st.scroll) {
|
, _scroll(this, _st.scroll) {
|
||||||
connect(_scroll, &ScrollArea::scrolled, [=] { scrolled(); });
|
_scroll->scrolls(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
scrolled();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
|
|
@ -126,7 +129,7 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::enterEventHook(QEvent *e) {
|
void InnerDropdown::enterEventHook(QEnterEvent *e) {
|
||||||
if (_autoHiding) {
|
if (_autoHiding) {
|
||||||
showAnimated(_origin);
|
showAnimated(_origin);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void enterEventHook(QEvent *e) override;
|
void enterEventHook(QEnterEvent *e) override;
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
bool eventFilter(QObject *obj, QEvent *e) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "emoji_suggestions_helper.h"
|
#include "emoji_suggestions_helper.h"
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtWidgets/QCommonStyle>
|
#include <QtWidgets/QCommonStyle>
|
||||||
#include <QtWidgets/QScrollBar>
|
#include <QtWidgets/QScrollBar>
|
||||||
|
|
@ -103,7 +104,7 @@ bool IsNewline(QChar ch) {
|
||||||
return (kNewlineChars.indexOf(ch) >= 0);
|
return (kNewlineChars.indexOf(ch) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool IsValidMarkdownLink(const QStringRef &link) {
|
[[nodiscard]] bool IsValidMarkdownLink(QStringView link) {
|
||||||
return (link.indexOf('.') >= 0) || (link.indexOf(':') >= 0);
|
return (link.indexOf('.') >= 0) || (link.indexOf(':') >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,21 +129,21 @@ bool IsNewline(QChar ch) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
auto found = false;
|
auto found = false;
|
||||||
for (const auto &single : existing.id.splitRef('|')) {
|
for (const auto &single : QStringView(existing.id).split('|')) {
|
||||||
const auto normalized = (single == kTagPre.midRef(0))
|
const auto normalized = (single == QStringView(kTagPre))
|
||||||
? kTagCode.midRef(0)
|
? QStringView(kTagCode)
|
||||||
: single;
|
: single;
|
||||||
if (checkingLink && IsValidMarkdownLink(single)) {
|
if (checkingLink && IsValidMarkdownLink(single)) {
|
||||||
if (resultLink.isEmpty()) {
|
if (resultLink.isEmpty()) {
|
||||||
resultLink = single.toString();
|
resultLink = single.toString();
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
} else if (resultLink.midRef(0) == single) {
|
} else if (QStringView(resultLink) == single) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
} else if (!checkingLink && tag.midRef(0) == normalized) {
|
} else if (!checkingLink && QStringView(tag) == normalized) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -687,7 +688,8 @@ void RemoveDocumentTags(
|
||||||
not_null<QTextDocument*> document,
|
not_null<QTextDocument*> document,
|
||||||
int from,
|
int from,
|
||||||
int end) {
|
int end) {
|
||||||
auto cursor = QTextCursor(document->docHandle(), from);
|
auto cursor = QTextCursor(document);
|
||||||
|
cursor.setPosition(from);
|
||||||
cursor.setPosition(end, QTextCursor::KeepAnchor);
|
cursor.setPosition(end, QTextCursor::KeepAnchor);
|
||||||
|
|
||||||
auto format = QTextCharFormat();
|
auto format = QTextCharFormat();
|
||||||
|
|
@ -704,7 +706,7 @@ QTextCharFormat PrepareTagFormat(
|
||||||
auto result = QTextCharFormat();
|
auto result = QTextCharFormat();
|
||||||
auto font = st.font;
|
auto font = st.font;
|
||||||
auto color = std::optional<style::color>();
|
auto color = std::optional<style::color>();
|
||||||
const auto applyOne = [&](const QStringRef &tag) {
|
const auto applyOne = [&](QStringView tag) {
|
||||||
if (IsValidMarkdownLink(tag)) {
|
if (IsValidMarkdownLink(tag)) {
|
||||||
color = st::defaultTextPalette.linkFg;
|
color = st::defaultTextPalette.linkFg;
|
||||||
} else if (tag == kTagBold) {
|
} else if (tag == kTagBold) {
|
||||||
|
|
@ -720,7 +722,7 @@ QTextCharFormat PrepareTagFormat(
|
||||||
font = font->monospace();
|
font = font->monospace();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (const auto &tag : tag.splitRef('|')) {
|
for (const auto &tag : QStringView(tag).split('|')) {
|
||||||
applyOne(tag);
|
applyOne(tag);
|
||||||
}
|
}
|
||||||
result.setFont(font);
|
result.setFont(font);
|
||||||
|
|
@ -764,7 +766,7 @@ int ProcessInsertedTags(
|
||||||
applyNoTagFrom,
|
applyNoTagFrom,
|
||||||
tagFrom);
|
tagFrom);
|
||||||
}
|
}
|
||||||
QTextCursor c(document->docHandle(), 0);
|
QTextCursor c(document);
|
||||||
c.setPosition(tagFrom);
|
c.setPosition(tagFrom);
|
||||||
c.setPosition(tagTo, QTextCursor::KeepAnchor);
|
c.setPosition(tagTo, QTextCursor::KeepAnchor);
|
||||||
|
|
||||||
|
|
@ -1024,7 +1026,7 @@ bool FlatInput::eventHook(QEvent *e) {
|
||||||
|| e->type() == QEvent::TouchEnd
|
|| e->type() == QEvent::TouchEnd
|
||||||
|| e->type() == QEvent::TouchCancel) {
|
|| e->type() == QEvent::TouchCancel) {
|
||||||
const auto ev = static_cast<QTouchEvent*>(e);
|
const auto ev = static_cast<QTouchEvent*>(e);
|
||||||
if (ev->device()->type() == QTouchDevice::TouchScreen) {
|
if (ev->device()->type() == base::TouchDevice::TouchScreen) {
|
||||||
touchEvent(ev);
|
touchEvent(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1057,6 +1059,8 @@ void FlatInput::touchEvent(QTouchEvent *e) {
|
||||||
if (_touchRightButton) {
|
if (_touchRightButton) {
|
||||||
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
|
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
|
||||||
contextMenuEvent(&contextEvent);
|
contextMenuEvent(&contextEvent);
|
||||||
|
} else {
|
||||||
|
QGuiApplication::inputMethod()->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (weak) {
|
if (weak) {
|
||||||
|
|
@ -1402,7 +1406,7 @@ bool InputField::viewportEventInner(QEvent *e) {
|
||||||
|| e->type() == QEvent::TouchEnd
|
|| e->type() == QEvent::TouchEnd
|
||||||
|| e->type() == QEvent::TouchCancel) {
|
|| e->type() == QEvent::TouchCancel) {
|
||||||
const auto ev = static_cast<QTouchEvent*>(e);
|
const auto ev = static_cast<QTouchEvent*>(e);
|
||||||
if (ev->device()->type() == QTouchDevice::TouchScreen) {
|
if (ev->device()->type() == base::TouchDevice::TouchScreen) {
|
||||||
handleTouchEvent(ev);
|
handleTouchEvent(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1465,7 +1469,7 @@ void InputField::setExtendedContextMenu(
|
||||||
value
|
value
|
||||||
) | rpl::start_with_next([=](auto pair) {
|
) | rpl::start_with_next([=](auto pair) {
|
||||||
auto &[menu, e] = pair;
|
auto &[menu, e] = pair;
|
||||||
contextMenuEventInner(&e, std::move(menu));
|
contextMenuEventInner(e.get(), std::move(menu));
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1514,14 +1518,14 @@ void InputField::setMaxLength(int length) {
|
||||||
if (_maxLength > 0) {
|
if (_maxLength > 0) {
|
||||||
const auto document = _inner->document();
|
const auto document = _inner->document();
|
||||||
_correcting = true;
|
_correcting = true;
|
||||||
QTextCursor(document->docHandle(), 0).joinPreviousEditBlock();
|
QTextCursor(document).joinPreviousEditBlock();
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
_correcting = false;
|
_correcting = false;
|
||||||
QTextCursor(document->docHandle(), 0).endEditBlock();
|
QTextCursor(document).endEditBlock();
|
||||||
handleContentsChanged();
|
handleContentsChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto cursor = QTextCursor(document->docHandle(), 0);
|
auto cursor = QTextCursor(document);
|
||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
chopByMaxLength(0, cursor.position());
|
chopByMaxLength(0, cursor.position());
|
||||||
}
|
}
|
||||||
|
|
@ -1610,7 +1614,7 @@ void InputField::insertTag(const QString &text, QString tagId) {
|
||||||
cursor.insertText(text + ' ', _defaultCharFormat);
|
cursor.insertText(text + ' ', _defaultCharFormat);
|
||||||
} else {
|
} else {
|
||||||
_insertedTags.clear();
|
_insertedTags.clear();
|
||||||
_insertedTags.push_back({ 0, text.size(), tagId });
|
_insertedTags.push_back({ 0, int(text.size()), tagId });
|
||||||
_insertedTagsAreFromMime = false;
|
_insertedTagsAreFromMime = false;
|
||||||
cursor.insertText(text + ' ');
|
cursor.insertText(text + ' ');
|
||||||
_insertedTags.clear();
|
_insertedTags.clear();
|
||||||
|
|
@ -1673,6 +1677,8 @@ void InputField::handleTouchEvent(QTouchEvent *e) {
|
||||||
if (_touchRightButton) {
|
if (_touchRightButton) {
|
||||||
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
|
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
|
||||||
contextMenuEvent(&contextEvent);
|
contextMenuEvent(&contextEvent);
|
||||||
|
} else {
|
||||||
|
QGuiApplication::inputMethod()->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (weak) {
|
if (weak) {
|
||||||
|
|
@ -2220,9 +2226,8 @@ void InputField::processFormatting(int insertPosition, int insertEnd) {
|
||||||
if (action.type != ActionType::Invalid) {
|
if (action.type != ActionType::Invalid) {
|
||||||
PrepareFormattingOptimization(document);
|
PrepareFormattingOptimization(document);
|
||||||
|
|
||||||
auto cursor = QTextCursor(
|
auto cursor = QTextCursor(document);
|
||||||
document->docHandle(),
|
cursor.setPosition(action.intervalStart);
|
||||||
action.intervalStart);
|
|
||||||
cursor.setPosition(action.intervalEnd, QTextCursor::KeepAnchor);
|
cursor.setPosition(action.intervalEnd, QTextCursor::KeepAnchor);
|
||||||
if (action.type == ActionType::InsertEmoji) {
|
if (action.type == ActionType::InsertEmoji) {
|
||||||
InsertEmojiAtCursor(cursor, action.emoji);
|
InsertEmojiAtCursor(cursor, action.emoji);
|
||||||
|
|
@ -2290,7 +2295,7 @@ void InputField::onDocumentContentsChange(
|
||||||
|
|
||||||
// Qt bug workaround https://bugreports.qt.io/browse/QTBUG-49062
|
// Qt bug workaround https://bugreports.qt.io/browse/QTBUG-49062
|
||||||
if (!position) {
|
if (!position) {
|
||||||
auto cursor = QTextCursor(document->docHandle(), 0);
|
auto cursor = QTextCursor(document);
|
||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
if (position + charsAdded > cursor.position()) {
|
if (position + charsAdded > cursor.position()) {
|
||||||
const auto delta = position + charsAdded - cursor.position();
|
const auto delta = position + charsAdded - cursor.position();
|
||||||
|
|
@ -2309,10 +2314,10 @@ void InputField::onDocumentContentsChange(
|
||||||
: charsAdded;
|
: charsAdded;
|
||||||
|
|
||||||
_correcting = true;
|
_correcting = true;
|
||||||
QTextCursor(document->docHandle(), 0).joinPreviousEditBlock();
|
QTextCursor(document).joinPreviousEditBlock();
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
_correcting = false;
|
_correcting = false;
|
||||||
QTextCursor(document->docHandle(), 0).endEditBlock();
|
QTextCursor(document).endEditBlock();
|
||||||
handleContentsChanged();
|
handleContentsChanged();
|
||||||
const auto added = charsAdded - _emojiSurrogateAmount;
|
const auto added = charsAdded - _emojiSurrogateAmount;
|
||||||
_documentContentsChanges.fire({position, charsRemoved, added});
|
_documentContentsChanges.fire({position, charsRemoved, added});
|
||||||
|
|
@ -2345,7 +2350,7 @@ void InputField::chopByMaxLength(int insertPosition, int insertLength) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cursor = QTextCursor(document()->docHandle(), 0);
|
auto cursor = QTextCursor(document());
|
||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
const auto fullSize = cursor.position();
|
const auto fullSize = cursor.position();
|
||||||
const auto toRemove = fullSize - _maxLength;
|
const auto toRemove = fullSize - _maxLength;
|
||||||
|
|
@ -2540,7 +2545,7 @@ void InputField::setTextWithTags(
|
||||||
_realInsertPosition = 0;
|
_realInsertPosition = 0;
|
||||||
_realCharsAdded = textWithTags.text.size();
|
_realCharsAdded = textWithTags.text.size();
|
||||||
const auto document = _inner->document();
|
const auto document = _inner->document();
|
||||||
auto cursor = QTextCursor(document->docHandle(), 0);
|
auto cursor = QTextCursor(document);
|
||||||
if (historyAction == HistoryAction::Clear) {
|
if (historyAction == HistoryAction::Clear) {
|
||||||
document->setUndoRedoEnabled(false);
|
document->setUndoRedoEnabled(false);
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
|
|
@ -2597,7 +2602,7 @@ TextWithTags InputField::getTextWithAppliedMarkdown() const {
|
||||||
auto from = 0;
|
auto from = 0;
|
||||||
const auto addOriginalTextUpTill = [&](int offset) {
|
const auto addOriginalTextUpTill = [&](int offset) {
|
||||||
if (offset > from) {
|
if (offset > from) {
|
||||||
result.text.append(originalText.midRef(from, offset - from));
|
result.text.append(base::StringViewMid(originalText, from, offset - from));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto link = links.begin();
|
auto link = links.begin();
|
||||||
|
|
@ -2653,7 +2658,8 @@ TextWithTags InputField::getTextWithAppliedMarkdown() const {
|
||||||
int(result.text.size()),
|
int(result.text.size()),
|
||||||
entityLength,
|
entityLength,
|
||||||
tag.tag });
|
tag.tag });
|
||||||
result.text.append(originalText.midRef(
|
result.text.append(base::StringViewMid(
|
||||||
|
originalText,
|
||||||
entityStart,
|
entityStart,
|
||||||
entityLength));
|
entityLength));
|
||||||
}
|
}
|
||||||
|
|
@ -2928,7 +2934,8 @@ auto InputField::selectionEditLinkData(EditLinkSelection selection) const
|
||||||
};
|
};
|
||||||
const auto stateTagHasLink = [&](const State &state) {
|
const auto stateTagHasLink = [&](const State &state) {
|
||||||
const auto tag = stateTag(state);
|
const auto tag = stateTag(state);
|
||||||
return (tag == link) || tag.splitRef('|').contains(link.midRef(0));
|
return (tag == link) || QStringView(tag).split('|').contains(
|
||||||
|
QStringView(link));
|
||||||
};
|
};
|
||||||
const auto stateStart = [&](const State &state) {
|
const auto stateStart = [&](const State &state) {
|
||||||
return state.i.fragment().position();
|
return state.i.fragment().position();
|
||||||
|
|
@ -3136,9 +3143,9 @@ void InputField::commitInstantReplacement(
|
||||||
const auto currentTag = cursor.charFormat().property(
|
const auto currentTag = cursor.charFormat().property(
|
||||||
kTagProperty
|
kTagProperty
|
||||||
).toString();
|
).toString();
|
||||||
const auto currentTags = currentTag.splitRef('|');
|
const auto currentTags = QStringView(currentTag).split('|');
|
||||||
if (currentTags.contains(kTagPre.midRef(0))
|
if (currentTags.contains(QStringView(kTagPre))
|
||||||
|| currentTags.contains(kTagCode.midRef(0))) {
|
|| currentTags.contains(QStringView(kTagCode))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3173,7 +3180,7 @@ bool InputField::commitMarkdownReplacement(
|
||||||
const QString &tag,
|
const QString &tag,
|
||||||
const QString &edge) {
|
const QString &edge) {
|
||||||
const auto end = [&] {
|
const auto end = [&] {
|
||||||
auto cursor = QTextCursor(document()->docHandle(), 0);
|
auto cursor = QTextCursor(document());
|
||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
return cursor.position();
|
return cursor.position();
|
||||||
}();
|
}();
|
||||||
|
|
@ -3187,7 +3194,8 @@ bool InputField::commitMarkdownReplacement(
|
||||||
const auto extended = getTextWithTagsPart(
|
const auto extended = getTextWithTagsPart(
|
||||||
from - extendLeft,
|
from - extendLeft,
|
||||||
till + extendRight).text;
|
till + extendRight).text;
|
||||||
const auto outer = extended.midRef(
|
const auto outer = base::StringViewMid(
|
||||||
|
extended,
|
||||||
extendLeft,
|
extendLeft,
|
||||||
extended.size() - extendLeft - extendRight);
|
extended.size() - extendLeft - extendRight);
|
||||||
if ((outer.size() <= 2 * edge.size())
|
if ((outer.size() <= 2 * edge.size())
|
||||||
|
|
@ -3251,7 +3259,7 @@ bool InputField::commitMarkdownReplacement(
|
||||||
if (tagTill > tagFrom) {
|
if (tagTill > tagFrom) {
|
||||||
_insertedTags.push_back({
|
_insertedTags.push_back({
|
||||||
tagFrom,
|
tagFrom,
|
||||||
tagTill - tagFrom,
|
int(tagTill - tagFrom),
|
||||||
tag,
|
tag,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -3283,8 +3291,7 @@ void InputField::addMarkdownTag(
|
||||||
int till,
|
int till,
|
||||||
const QString &tag) {
|
const QString &tag) {
|
||||||
const auto current = getTextWithTagsPart(from, till);
|
const auto current = getTextWithTagsPart(from, till);
|
||||||
const auto currentLength = current.text.size();
|
const auto currentLength = int(current.text.size());
|
||||||
const auto tagRef = tag.midRef(0);
|
|
||||||
|
|
||||||
// #TODO Trim inserted tag, so that all newlines are left outside.
|
// #TODO Trim inserted tag, so that all newlines are left outside.
|
||||||
auto tags = TagList();
|
auto tags = TagList();
|
||||||
|
|
@ -3322,7 +3329,6 @@ void InputField::removeMarkdownTag(
|
||||||
int till,
|
int till,
|
||||||
const QString &tag) {
|
const QString &tag) {
|
||||||
const auto current = getTextWithTagsPart(from, till);
|
const auto current = getTextWithTagsPart(from, till);
|
||||||
const auto tagRef = tag.midRef(0);
|
|
||||||
|
|
||||||
auto tags = TagList();
|
auto tags = TagList();
|
||||||
for (const auto &existing : current.tags) {
|
for (const auto &existing : current.tags) {
|
||||||
|
|
@ -3351,7 +3357,7 @@ void InputField::finishMarkdownTagChange(
|
||||||
_inner->setTextCursor(cursor);
|
_inner->setTextCursor(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputField::IsValidMarkdownLink(const QStringRef &link) {
|
bool InputField::IsValidMarkdownLink(QStringView link) {
|
||||||
return ::Ui::IsValidMarkdownLink(link);
|
return ::Ui::IsValidMarkdownLink(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3365,7 +3371,7 @@ void InputField::commitMarkdownLinkEdit(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_insertedTags.clear();
|
_insertedTags.clear();
|
||||||
_insertedTags.push_back({ 0, text.size(), link });
|
_insertedTags.push_back({ 0, int(text.size()), link });
|
||||||
|
|
||||||
auto cursor = textCursor();
|
auto cursor = textCursor();
|
||||||
const auto editData = selectionEditLinkData(selection);
|
const auto editData = selectionEditLinkData(selection);
|
||||||
|
|
@ -3852,7 +3858,7 @@ bool MaskedInputField::eventHook(QEvent *e) {
|
||||||
|| type == QEvent::TouchEnd
|
|| type == QEvent::TouchEnd
|
||||||
|| type == QEvent::TouchCancel) {
|
|| type == QEvent::TouchCancel) {
|
||||||
auto event = static_cast<QTouchEvent*>(e);
|
auto event = static_cast<QTouchEvent*>(e);
|
||||||
if (event->device()->type() == QTouchDevice::TouchScreen) {
|
if (event->device()->type() == base::TouchDevice::TouchScreen) {
|
||||||
touchEvent(event);
|
touchEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3885,6 +3891,8 @@ void MaskedInputField::touchEvent(QTouchEvent *e) {
|
||||||
if (_touchRightButton) {
|
if (_touchRightButton) {
|
||||||
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
|
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
|
||||||
contextMenuEvent(&contextEvent);
|
contextMenuEvent(&contextEvent);
|
||||||
|
} else {
|
||||||
|
QGuiApplication::inputMethod()->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (weak) {
|
if (weak) {
|
||||||
|
|
@ -4212,7 +4220,7 @@ void NumberInput::correctValue(
|
||||||
QString newText;
|
QString newText;
|
||||||
newText.reserve(now.size());
|
newText.reserve(now.size());
|
||||||
auto newPos = nowCursor;
|
auto newPos = nowCursor;
|
||||||
for (auto i = 0, l = now.size(); i < l; ++i) {
|
for (auto i = 0, l = int(now.size()); i < l; ++i) {
|
||||||
if (now.at(i).isDigit()) {
|
if (now.at(i).isDigit()) {
|
||||||
newText.append(now.at(i));
|
newText.append(now.at(i));
|
||||||
} else if (i < nowCursor) {
|
} else if (i < nowCursor) {
|
||||||
|
|
@ -4248,7 +4256,7 @@ void HexInput::correctValue(
|
||||||
QString newText;
|
QString newText;
|
||||||
newText.reserve(now.size());
|
newText.reserve(now.size());
|
||||||
auto newPos = nowCursor;
|
auto newPos = nowCursor;
|
||||||
for (auto i = 0, l = now.size(); i < l; ++i) {
|
for (auto i = 0, l = int(now.size()); i < l; ++i) {
|
||||||
const auto ch = now[i];
|
const auto ch = now[i];
|
||||||
if ((ch >= '0' && ch <= '9')
|
if ((ch >= '0' && ch <= '9')
|
||||||
|| (ch >= 'a' && ch <= 'f')
|
|| (ch >= 'a' && ch <= 'f')
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,7 @@ public:
|
||||||
|
|
||||||
struct ExtendedContextMenu {
|
struct ExtendedContextMenu {
|
||||||
QMenu *menu = nullptr;
|
QMenu *menu = nullptr;
|
||||||
QContextMenuEvent event;
|
std::shared_ptr<QContextMenuEvent> event;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setAdditionalMargin(int margin);
|
void setAdditionalMargin(int margin);
|
||||||
|
|
@ -258,10 +258,7 @@ public:
|
||||||
EditLinkSelection selection,
|
EditLinkSelection selection,
|
||||||
const QString &text,
|
const QString &text,
|
||||||
const QString &link);
|
const QString &link);
|
||||||
static bool IsValidMarkdownLink(const QStringRef &link);
|
static bool IsValidMarkdownLink(QStringView link);
|
||||||
static bool IsValidMarkdownLink(const QString &link) {
|
|
||||||
return IsValidMarkdownLink(link.midRef(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &getLastText() const {
|
const QString &getLastText() const {
|
||||||
return _lastTextWithTags.text;
|
return _lastTextWithTags.text;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "ui/widgets/box_content_divider.h"
|
#include "ui/widgets/box_content_divider.h"
|
||||||
#include "ui/basic_click_handlers.h" // UrlClickHandler
|
#include "ui/basic_click_handlers.h" // UrlClickHandler
|
||||||
#include "ui/inactive_press.h"
|
#include "ui/inactive_press.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
|
@ -491,7 +492,7 @@ void FlatLabel::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlatLabel::enterEventHook(QEvent *e) {
|
void FlatLabel::enterEventHook(QEnterEvent *e) {
|
||||||
_lastMousePos = QCursor::pos();
|
_lastMousePos = QCursor::pos();
|
||||||
dragActionUpdate();
|
dragActionUpdate();
|
||||||
}
|
}
|
||||||
|
|
@ -546,7 +547,7 @@ void FlatLabel::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
bool FlatLabel::eventHook(QEvent *e) {
|
bool FlatLabel::eventHook(QEvent *e) {
|
||||||
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
||||||
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
||||||
if (ev->device()->type() == QTouchDevice::TouchScreen) {
|
if (ev->device()->type() == base::TouchDevice::TouchScreen) {
|
||||||
touchEvent(ev);
|
touchEvent(ev);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ protected:
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||||
void enterEventHook(QEvent *e) override;
|
void enterEventHook(QEnterEvent *e) override;
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
void focusOutEvent(QFocusEvent *e) override;
|
void focusOutEvent(QFocusEvent *e) override;
|
||||||
void focusInEvent(QFocusEvent *e) override;
|
void focusInEvent(QFocusEvent *e) override;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace {
|
||||||
} else {
|
} else {
|
||||||
result.entities.append(EntityInText{
|
result.entities.append(EntityInText{
|
||||||
EntityType::Underline,
|
EntityType::Underline,
|
||||||
result.text.size(),
|
int(result.text.size()),
|
||||||
1 });
|
1 });
|
||||||
result.text.append(ch);
|
result.text.append(ch);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
//
|
//
|
||||||
#include "ui/widgets/menu/menu_common.h"
|
#include "ui/widgets/menu/menu_common.h"
|
||||||
|
|
||||||
#include <QtWidgets/QAction>
|
#include <QAction>
|
||||||
|
|
||||||
namespace Ui::Menu {
|
namespace Ui::Menu {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
#include "ui/delayed_activation.h"
|
#include "ui/delayed_activation.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "base/qt_adapters.h"
|
|
||||||
|
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
#include <QtGui/QPainter>
|
#include <QtGui/QPainter>
|
||||||
|
|
@ -731,7 +730,7 @@ void PopupMenu::popup(const QPoint &p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PopupMenu::showMenu(const QPoint &p, PopupMenu *parent, TriggeredSource source) {
|
void PopupMenu::showMenu(const QPoint &p, PopupMenu *parent, TriggeredSource source) {
|
||||||
const auto screen = base::QScreenNearestTo(p);
|
const auto screen = QGuiApplication::screenAt(p);
|
||||||
if (!screen
|
if (!screen
|
||||||
|| (!parent && ::Platform::IsMac() && !Platform::IsApplicationActive())) {
|
|| (!parent && ::Platform::IsMac() && !Platform::IsApplicationActive())) {
|
||||||
_hiding = false;
|
_hiding = false;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtWidgets/QScrollBar>
|
#include <QtWidgets/QScrollBar>
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
|
|
@ -38,14 +39,18 @@ ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::ScrollArea *st)
|
||||||
, _vertical(vert)
|
, _vertical(vert)
|
||||||
, _hiding(_st->hiding != 0)
|
, _hiding(_st->hiding != 0)
|
||||||
, _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar())
|
, _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar())
|
||||||
, _scrollMax(_connected->maximum()) {
|
, _scrollMax(_connected->maximum())
|
||||||
|
, _hideTimer([=] { hideTimer(); }) {
|
||||||
recountSize();
|
recountSize();
|
||||||
|
|
||||||
_hideTimer.setSingleShot(true);
|
connect(_connected, &QAbstractSlider::valueChanged, [=] {
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimer()));
|
area()->scrolled();
|
||||||
|
updateBar();
|
||||||
connect(_connected, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged()));
|
});
|
||||||
connect(_connected, SIGNAL(rangeChanged(int, int)), this, SLOT(onRangeChanged()));
|
connect(_connected, &QAbstractSlider::rangeChanged, [=] {
|
||||||
|
area()->innerResized();
|
||||||
|
updateBar();
|
||||||
|
});
|
||||||
|
|
||||||
updateBar();
|
updateBar();
|
||||||
}
|
}
|
||||||
|
|
@ -54,16 +59,6 @@ void ScrollBar::recountSize() {
|
||||||
setGeometry(_vertical ? QRect(style::RightToLeft() ? 0 : (area()->width() - _st->width), _st->deltat, _st->width, area()->height() - _st->deltat - _st->deltab) : QRect(_st->deltat, area()->height() - _st->width, area()->width() - _st->deltat - _st->deltab, _st->width));
|
setGeometry(_vertical ? QRect(style::RightToLeft() ? 0 : (area()->width() - _st->width), _st->deltat, _st->width, area()->height() - _st->deltat - _st->deltab) : QRect(_st->deltat, area()->height() - _st->width, area()->width() - _st->deltat - _st->deltab, _st->width));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollBar::onValueChanged() {
|
|
||||||
area()->onScrolled();
|
|
||||||
updateBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScrollBar::onRangeChanged() {
|
|
||||||
area()->onInnerResized();
|
|
||||||
updateBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScrollBar::updateBar(bool force) {
|
void ScrollBar::updateBar(bool force) {
|
||||||
QRect newBar;
|
QRect newBar;
|
||||||
if (_connected->maximum() != _scrollMax) {
|
if (_connected->maximum() != _scrollMax) {
|
||||||
|
|
@ -76,8 +71,18 @@ void ScrollBar::updateBar(bool force) {
|
||||||
if (h >= rh || !area()->scrollTopMax() || rh < _st->minHeight) {
|
if (h >= rh || !area()->scrollTopMax() || rh < _st->minHeight) {
|
||||||
if (!isHidden()) hide();
|
if (!isHidden()) hide();
|
||||||
bool newTopSh = (_st->topsh < 0), newBottomSh = (_st->bottomsh < 0);
|
bool newTopSh = (_st->topsh < 0), newBottomSh = (_st->bottomsh < 0);
|
||||||
if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh);
|
if (newTopSh != _topSh || force) {
|
||||||
if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh);
|
_shadowVisibilityChanged.fire({
|
||||||
|
.type = ScrollShadow::Type::Top,
|
||||||
|
.visible = (_topSh = newTopSh),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (newBottomSh != _bottomSh || force) {
|
||||||
|
_shadowVisibilityChanged.fire({
|
||||||
|
.type = ScrollShadow::Type::Bottom,
|
||||||
|
.visible = (_bottomSh = newBottomSh),
|
||||||
|
});
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,13 +110,23 @@ void ScrollBar::updateBar(bool force) {
|
||||||
}
|
}
|
||||||
if (_vertical) {
|
if (_vertical) {
|
||||||
bool newTopSh = (_st->topsh < 0) || (area()->scrollTop() > _st->topsh), newBottomSh = (_st->bottomsh < 0) || (area()->scrollTop() < area()->scrollTopMax() - _st->bottomsh);
|
bool newTopSh = (_st->topsh < 0) || (area()->scrollTop() > _st->topsh), newBottomSh = (_st->bottomsh < 0) || (area()->scrollTop() < area()->scrollTopMax() - _st->bottomsh);
|
||||||
if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh);
|
if (newTopSh != _topSh || force) {
|
||||||
if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh);
|
_shadowVisibilityChanged.fire({
|
||||||
|
.type = ScrollShadow::Type::Top,
|
||||||
|
.visible = (_topSh = newTopSh),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (newBottomSh != _bottomSh || force) {
|
||||||
|
_shadowVisibilityChanged.fire({
|
||||||
|
.type = ScrollShadow::Type::Bottom,
|
||||||
|
.visible = (_bottomSh = newBottomSh),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isHidden()) show();
|
if (isHidden()) show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollBar::onHideTimer() {
|
void ScrollBar::hideTimer() {
|
||||||
if (!_hiding) {
|
if (!_hiding) {
|
||||||
_hiding = true;
|
_hiding = true;
|
||||||
_a_opacity.start([this] { update(); }, 1., 0., _st->duration);
|
_a_opacity.start([this] { update(); }, 1., 0., _st->duration);
|
||||||
|
|
@ -162,7 +177,7 @@ void ScrollBar::setMoving(bool moving) {
|
||||||
_a_over.start([this] { update(); }, nowOver ? 0. : 1., nowOver ? 1. : 0., _st->duration);
|
_a_over.start([this] { update(); }, nowOver ? 0. : 1., nowOver ? 1. : 0., _st->duration);
|
||||||
}
|
}
|
||||||
if (!nowOver && _st->hiding && !_hiding) {
|
if (!nowOver && _st->hiding && !_hiding) {
|
||||||
_hideTimer.start(_hideIn);
|
_hideTimer.callOnce(_hideIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -202,12 +217,12 @@ void ScrollBar::hideTimeout(crl::time dt) {
|
||||||
}
|
}
|
||||||
_hideIn = dt;
|
_hideIn = dt;
|
||||||
if (!_moving) {
|
if (!_moving) {
|
||||||
_hideTimer.start(_hideIn);
|
_hideTimer.callOnce(_hideIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollBar::enterEventHook(QEvent *e) {
|
void ScrollBar::enterEventHook(QEnterEvent *e) {
|
||||||
_hideTimer.stop();
|
_hideTimer.cancel();
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
setOver(true);
|
setOver(true);
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +234,7 @@ void ScrollBar::leaveEventHook(QEvent *e) {
|
||||||
setOver(false);
|
setOver(false);
|
||||||
setOverBar(false);
|
setOverBar(false);
|
||||||
if (_st->hiding && !_hiding) {
|
if (_st->hiding && !_hiding) {
|
||||||
_hideTimer.start(_hideIn);
|
_hideTimer.callOnce(_hideIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,7 +267,6 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
area()->setMovingByScrollBar(true);
|
area()->setMovingByScrollBar(true);
|
||||||
area()->scrollStarted();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
|
void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
|
@ -260,7 +274,6 @@ void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
setMoving(false);
|
setMoving(false);
|
||||||
|
|
||||||
area()->setMovingByScrollBar(false);
|
area()->setMovingByScrollBar(false);
|
||||||
area()->scrollFinished();
|
|
||||||
}
|
}
|
||||||
if (!_over) {
|
if (!_over) {
|
||||||
setMouseTracking(false);
|
setMouseTracking(false);
|
||||||
|
|
@ -271,6 +284,11 @@ void ScrollBar::resizeEvent(QResizeEvent *e) {
|
||||||
updateBar();
|
updateBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ScrollBar::shadowVisibilityChanged() const
|
||||||
|
-> rpl::producer<ScrollBar::ShadowVisibility> {
|
||||||
|
return _shadowVisibilityChanged.events();
|
||||||
|
}
|
||||||
|
|
||||||
ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handleTouch)
|
ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handleTouch)
|
||||||
: Parent(parent)
|
: Parent(parent)
|
||||||
, _st(st)
|
, _st(st)
|
||||||
|
|
@ -282,8 +300,13 @@ ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handle
|
||||||
setLayoutDirection(style::LayoutDirection());
|
setLayoutDirection(style::LayoutDirection());
|
||||||
setFocusPolicy(Qt::NoFocus);
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
connect(_verticalBar, SIGNAL(topShadowVisibility(bool)), _topShadow, SLOT(changeVisibility(bool)));
|
_verticalBar->shadowVisibilityChanged(
|
||||||
connect(_verticalBar, SIGNAL(bottomShadowVisibility(bool)), _bottomShadow, SLOT(changeVisibility(bool)));
|
) | rpl::start_with_next([=](const ScrollBar::ShadowVisibility &data) {
|
||||||
|
((data.type == ScrollShadow::Type::Top)
|
||||||
|
? _topShadow
|
||||||
|
: _bottomShadow)->changeVisibility(data.visible);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_verticalBar->updateBar(true);
|
_verticalBar->updateBar(true);
|
||||||
|
|
||||||
verticalScrollBar()->setSingleStep(style::ConvertScale(verticalScrollBar()->singleStep()));
|
verticalScrollBar()->setSingleStep(style::ConvertScale(verticalScrollBar()->singleStep()));
|
||||||
|
|
@ -300,9 +323,8 @@ ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handle
|
||||||
|
|
||||||
if (_touchEnabled) {
|
if (_touchEnabled) {
|
||||||
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
|
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
_touchTimer.setSingleShot(true);
|
_touchTimer.setCallback([=] { _touchRightButton = true; });
|
||||||
connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
|
_touchScrollTimer.setCallback([=] { touchScrollTimer(); });
|
||||||
connect(&_touchScrollTimer, SIGNAL(timeout()), this, SLOT(onTouchScrollTimer()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,7 +335,7 @@ void ScrollArea::touchDeaccelerate(int32 elapsed) {
|
||||||
_touchSpeed.setY((y == 0) ? y : (y > 0) ? qMax(0, y - elapsed) : qMin(0, y + elapsed));
|
_touchSpeed.setY((y == 0) ? y : (y > 0) ? qMax(0, y - elapsed) : qMin(0, y + elapsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollArea::onScrolled() {
|
void ScrollArea::scrolled() {
|
||||||
if (const auto inner = widget()) {
|
if (const auto inner = widget()) {
|
||||||
SendPendingMoveResizeEvents(inner);
|
SendPendingMoveResizeEvents(inner);
|
||||||
}
|
}
|
||||||
|
|
@ -345,15 +367,15 @@ void ScrollArea::onScrolled() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (em) {
|
if (em) {
|
||||||
scrolled();
|
_scrolls.fire({});
|
||||||
if (!_movingByScrollBar) {
|
if (!_movingByScrollBar) {
|
||||||
SendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton);
|
SendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollArea::onInnerResized() {
|
void ScrollArea::innerResized() {
|
||||||
innerResized();
|
_innerResizes.fire({});
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScrollArea::scrollWidth() const {
|
int ScrollArea::scrollWidth() const {
|
||||||
|
|
@ -382,11 +404,7 @@ int ScrollArea::scrollTop() const {
|
||||||
return _verticalValue;
|
return _verticalValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollArea::onTouchTimer() {
|
void ScrollArea::touchScrollTimer() {
|
||||||
_touchRightButton = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScrollArea::onTouchScrollTimer() {
|
|
||||||
auto nowTime = crl::now();
|
auto nowTime = crl::now();
|
||||||
if (_touchScrollState == TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) {
|
if (_touchScrollState == TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) {
|
||||||
_touchScrollState = TouchScrollState::Manual;
|
_touchScrollState = TouchScrollState::Manual;
|
||||||
|
|
@ -399,7 +417,7 @@ void ScrollArea::onTouchScrollTimer() {
|
||||||
if (_touchSpeed.isNull() || !hasScrolled) {
|
if (_touchSpeed.isNull() || !hasScrolled) {
|
||||||
_touchScrollState = TouchScrollState::Manual;
|
_touchScrollState = TouchScrollState::Manual;
|
||||||
_touchScroll = false;
|
_touchScroll = false;
|
||||||
_touchScrollTimer.stop();
|
_touchScrollTimer.cancel();
|
||||||
} else {
|
} else {
|
||||||
_touchTime = nowTime;
|
_touchTime = nowTime;
|
||||||
}
|
}
|
||||||
|
|
@ -455,7 +473,7 @@ bool ScrollArea::eventFilter(QObject *obj, QEvent *e) {
|
||||||
bool res = QScrollArea::eventFilter(obj, e);
|
bool res = QScrollArea::eventFilter(obj, e);
|
||||||
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
||||||
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
||||||
if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) {
|
if (_touchEnabled && ev->device()->type() == base::TouchDevice::TouchScreen) {
|
||||||
if (obj == widget()) {
|
if (obj == widget()) {
|
||||||
touchEvent(ev);
|
touchEvent(ev);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -468,7 +486,7 @@ bool ScrollArea::eventFilter(QObject *obj, QEvent *e) {
|
||||||
bool ScrollArea::viewportEvent(QEvent *e) {
|
bool ScrollArea::viewportEvent(QEvent *e) {
|
||||||
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
||||||
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
||||||
if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) {
|
if (_touchEnabled && ev->device()->type() == base::TouchDevice::TouchScreen) {
|
||||||
touchEvent(ev);
|
touchEvent(ev);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -494,7 +512,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
|
||||||
_touchStart = _touchPos;
|
_touchStart = _touchPos;
|
||||||
} else {
|
} else {
|
||||||
_touchScroll = false;
|
_touchScroll = false;
|
||||||
_touchTimer.start(QApplication::startDragTime());
|
_touchTimer.callOnce(QApplication::startDragTime());
|
||||||
}
|
}
|
||||||
_touchStart = _touchPrevPos = _touchPos;
|
_touchStart = _touchPrevPos = _touchPos;
|
||||||
_touchRightButton = false;
|
_touchRightButton = false;
|
||||||
|
|
@ -503,7 +521,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
|
||||||
case QEvent::TouchUpdate: {
|
case QEvent::TouchUpdate: {
|
||||||
if (!_touchPress) return;
|
if (!_touchPress) return;
|
||||||
if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
|
if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
|
||||||
_touchTimer.stop();
|
_touchTimer.cancel();
|
||||||
_touchScroll = true;
|
_touchScroll = true;
|
||||||
touchUpdateSpeed();
|
touchUpdateSpeed();
|
||||||
}
|
}
|
||||||
|
|
@ -528,7 +546,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
|
||||||
if (_touchScrollState == TouchScrollState::Manual) {
|
if (_touchScrollState == TouchScrollState::Manual) {
|
||||||
_touchScrollState = TouchScrollState::Auto;
|
_touchScrollState = TouchScrollState::Auto;
|
||||||
_touchPrevPosValid = false;
|
_touchPrevPosValid = false;
|
||||||
_touchScrollTimer.start(15);
|
_touchScrollTimer.callEach(15);
|
||||||
_touchTime = crl::now();
|
_touchTime = crl::now();
|
||||||
} else if (_touchScrollState == TouchScrollState::Auto) {
|
} else if (_touchScrollState == TouchScrollState::Auto) {
|
||||||
_touchScrollState = TouchScrollState::Manual;
|
_touchScrollState = TouchScrollState::Manual;
|
||||||
|
|
@ -555,7 +573,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (weak) {
|
if (weak) {
|
||||||
_touchTimer.stop();
|
_touchTimer.cancel();
|
||||||
_touchRightButton = false;
|
_touchRightButton = false;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
@ -564,7 +582,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
|
||||||
_touchPress = false;
|
_touchPress = false;
|
||||||
_touchScroll = false;
|
_touchScroll = false;
|
||||||
_touchScrollState = TouchScrollState::Manual;
|
_touchScrollState = TouchScrollState::Manual;
|
||||||
_touchTimer.stop();
|
_touchTimer.cancel();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -604,12 +622,12 @@ void ScrollArea::resizeEvent(QResizeEvent *e) {
|
||||||
_verticalBar->recountSize();
|
_verticalBar->recountSize();
|
||||||
_topShadow->setGeometry(QRect(0, 0, width(), qAbs(_st.topsh)));
|
_topShadow->setGeometry(QRect(0, 0, width(), qAbs(_st.topsh)));
|
||||||
_bottomShadow->setGeometry(QRect(0, height() - qAbs(_st.bottomsh), width(), qAbs(_st.bottomsh)));
|
_bottomShadow->setGeometry(QRect(0, height() - qAbs(_st.bottomsh), width(), qAbs(_st.bottomsh)));
|
||||||
geometryChanged();
|
_geometryChanged.fire({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollArea::moveEvent(QMoveEvent *e) {
|
void ScrollArea::moveEvent(QMoveEvent *e) {
|
||||||
QScrollArea::moveEvent(e);
|
QScrollArea::moveEvent(e);
|
||||||
geometryChanged();
|
_geometryChanged.fire({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollArea::keyPressEvent(QKeyEvent *e) {
|
void ScrollArea::keyPressEvent(QKeyEvent *e) {
|
||||||
|
|
@ -622,7 +640,7 @@ void ScrollArea::keyPressEvent(QKeyEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollArea::enterEventHook(QEvent *e) {
|
void ScrollArea::enterEventHook(QEnterEvent *e) {
|
||||||
if (_disabled) return;
|
if (_disabled) return;
|
||||||
if (_st.hiding) {
|
if (_st.hiding) {
|
||||||
_horizontalBar->hideTimeout(_st.hiding);
|
_horizontalBar->hideTimeout(_st.hiding);
|
||||||
|
|
@ -724,4 +742,16 @@ void ScrollArea::setMovingByScrollBar(bool movingByScrollBar) {
|
||||||
_movingByScrollBar = movingByScrollBar;
|
_movingByScrollBar = movingByScrollBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> ScrollArea::scrolls() const {
|
||||||
|
return _scrolls.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> ScrollArea::innerResizes() const {
|
||||||
|
return _innerResizes.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> ScrollArea::geometryChanged() const {
|
||||||
|
return _geometryChanged.events();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "base/object_ptr.h"
|
#include "base/object_ptr.h"
|
||||||
|
#include "base/timer.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
#include <QtWidgets/QScrollArea>
|
#include <QtWidgets/QScrollArea>
|
||||||
#include <QtCore/QTimer>
|
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
@ -48,15 +48,15 @@ struct ScrollToRequest {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScrollShadow : public QWidget {
|
class ScrollShadow final : public QWidget {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
|
};
|
||||||
ScrollShadow(ScrollArea *parent, const style::ScrollArea *st);
|
ScrollShadow(ScrollArea *parent, const style::ScrollArea *st);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e);
|
void paintEvent(QPaintEvent *e);
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
void changeVisibility(bool shown);
|
void changeVisibility(bool shown);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -65,9 +65,11 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScrollBar : public TWidget {
|
class ScrollBar : public TWidget {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct ShadowVisibility {
|
||||||
|
ScrollShadow::Type type;
|
||||||
|
bool visible = false;
|
||||||
|
};
|
||||||
ScrollBar(ScrollArea *parent, bool vertical, const style::ScrollArea *st);
|
ScrollBar(ScrollArea *parent, bool vertical, const style::ScrollArea *st);
|
||||||
|
|
||||||
void recountSize();
|
void recountSize();
|
||||||
|
|
@ -75,18 +77,12 @@ public:
|
||||||
|
|
||||||
void hideTimeout(crl::time dt);
|
void hideTimeout(crl::time dt);
|
||||||
|
|
||||||
private Q_SLOTS:
|
[[nodiscard]] auto shadowVisibilityChanged() const
|
||||||
void onValueChanged();
|
-> rpl::producer<ShadowVisibility>;
|
||||||
void onRangeChanged();
|
|
||||||
void onHideTimer();
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void topShadowVisibility(bool);
|
|
||||||
void bottomShadowVisibility(bool);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void enterEventHook(QEvent *e) override;
|
void enterEventHook(QEnterEvent *e) override;
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
|
@ -100,6 +96,8 @@ private:
|
||||||
void setOverBar(bool overbar);
|
void setOverBar(bool overbar);
|
||||||
void setMoving(bool moving);
|
void setMoving(bool moving);
|
||||||
|
|
||||||
|
void hideTimer();
|
||||||
|
|
||||||
const style::ScrollArea *_st;
|
const style::ScrollArea *_st;
|
||||||
|
|
||||||
bool _vertical = true;
|
bool _vertical = true;
|
||||||
|
|
@ -116,20 +114,20 @@ private:
|
||||||
int32 _startFrom, _scrollMax;
|
int32 _startFrom, _scrollMax;
|
||||||
|
|
||||||
crl::time _hideIn = 0;
|
crl::time _hideIn = 0;
|
||||||
QTimer _hideTimer;
|
base::Timer _hideTimer;
|
||||||
|
|
||||||
Animations::Simple _a_over;
|
Animations::Simple _a_over;
|
||||||
Animations::Simple _a_barOver;
|
Animations::Simple _a_barOver;
|
||||||
Animations::Simple _a_opacity;
|
Animations::Simple _a_opacity;
|
||||||
|
|
||||||
QRect _bar;
|
QRect _bar;
|
||||||
|
|
||||||
|
rpl::event_stream<ShadowVisibility> _shadowVisibilityChanged;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScrollArea : public RpWidgetBase<QScrollArea> {
|
class ScrollArea : public RpWidgetBase<QScrollArea> {
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
using Parent = RpWidgetBase<QScrollArea>;
|
|
||||||
public:
|
public:
|
||||||
|
using Parent = RpWidgetBase<QScrollArea>;
|
||||||
ScrollArea(QWidget *parent, const style::ScrollArea &st = st::defaultScrollArea, bool handleTouch = true);
|
ScrollArea(QWidget *parent, const style::ScrollArea &st = st::defaultScrollArea, bool handleTouch = true);
|
||||||
|
|
||||||
int scrollWidth() const;
|
int scrollWidth() const;
|
||||||
|
|
@ -171,6 +169,15 @@ public:
|
||||||
void scrollTo(ScrollToRequest request);
|
void scrollTo(ScrollToRequest request);
|
||||||
void scrollToWidget(not_null<QWidget*> widget);
|
void scrollToWidget(not_null<QWidget*> widget);
|
||||||
|
|
||||||
|
void scrollToY(int toTop, int toBottom = -1);
|
||||||
|
void disableScroll(bool dis);
|
||||||
|
void scrolled();
|
||||||
|
void innerResized();
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<> scrolls() const;
|
||||||
|
[[nodiscard]] rpl::producer<> innerResizes() const;
|
||||||
|
[[nodiscard]] rpl::producer<> geometryChanged() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
bool eventFilter(QObject *obj, QEvent *e) override;
|
||||||
|
|
||||||
|
|
@ -178,25 +185,9 @@ protected:
|
||||||
void moveEvent(QMoveEvent *e) override;
|
void moveEvent(QMoveEvent *e) override;
|
||||||
void touchEvent(QTouchEvent *e);
|
void touchEvent(QTouchEvent *e);
|
||||||
|
|
||||||
void enterEventHook(QEvent *e) override;
|
void enterEventHook(QEnterEvent *e) override;
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
void scrollToY(int toTop, int toBottom = -1);
|
|
||||||
void disableScroll(bool dis);
|
|
||||||
void onScrolled();
|
|
||||||
void onInnerResized();
|
|
||||||
|
|
||||||
void onTouchTimer();
|
|
||||||
void onTouchScrollTimer();
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void scrolled();
|
|
||||||
void innerResized();
|
|
||||||
void scrollStarted();
|
|
||||||
void scrollFinished();
|
|
||||||
void geometryChanged();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void scrollContentsBy(int dx, int dy) override;
|
void scrollContentsBy(int dx, int dy) override;
|
||||||
|
|
||||||
|
|
@ -206,8 +197,8 @@ private:
|
||||||
|
|
||||||
void setWidget(QWidget *widget);
|
void setWidget(QWidget *widget);
|
||||||
|
|
||||||
|
void touchScrollTimer();
|
||||||
bool touchScroll(const QPoint &delta);
|
bool touchScroll(const QPoint &delta);
|
||||||
|
|
||||||
void touchScrollUpdated(const QPoint &screenPos);
|
void touchScrollUpdated(const QPoint &screenPos);
|
||||||
|
|
||||||
void touchResetSpeed();
|
void touchResetSpeed();
|
||||||
|
|
@ -223,7 +214,7 @@ private:
|
||||||
int _horizontalValue, _verticalValue;
|
int _horizontalValue, _verticalValue;
|
||||||
|
|
||||||
bool _touchEnabled;
|
bool _touchEnabled;
|
||||||
QTimer _touchTimer;
|
base::Timer _touchTimer;
|
||||||
bool _touchScroll = false;
|
bool _touchScroll = false;
|
||||||
bool _touchPress = false;
|
bool _touchPress = false;
|
||||||
bool _touchRightButton = false;
|
bool _touchRightButton = false;
|
||||||
|
|
@ -236,13 +227,16 @@ private:
|
||||||
crl::time _touchSpeedTime = 0;
|
crl::time _touchSpeedTime = 0;
|
||||||
crl::time _touchAccelerationTime = 0;
|
crl::time _touchAccelerationTime = 0;
|
||||||
crl::time _touchTime = 0;
|
crl::time _touchTime = 0;
|
||||||
QTimer _touchScrollTimer;
|
base::Timer _touchScrollTimer;
|
||||||
|
|
||||||
bool _widgetAcceptsTouch = false;
|
bool _widgetAcceptsTouch = false;
|
||||||
|
|
||||||
object_ptr<QWidget> _widget = { nullptr };
|
object_ptr<QWidget> _widget = { nullptr };
|
||||||
|
|
||||||
rpl::event_stream<int> _scrollTopUpdated;
|
rpl::event_stream<int> _scrollTopUpdated;
|
||||||
|
rpl::event_stream<> _scrolls;
|
||||||
|
rpl::event_stream<> _innerResizes;
|
||||||
|
rpl::event_stream<> _geometryChanged;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "base/qt_adapters.h"
|
||||||
|
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
@ -22,11 +23,11 @@ QTime ValidateTime(const QString &value) {
|
||||||
return QTime();
|
return QTime();
|
||||||
}
|
}
|
||||||
const auto readInt = [](const QString &value) {
|
const auto readInt = [](const QString &value) {
|
||||||
auto ref = value.midRef(0);
|
auto view = QStringView(value);
|
||||||
while (!ref.isEmpty() && ref.at(0) == '0') {
|
while (!view.isEmpty() && view.at(0) == '0') {
|
||||||
ref = ref.mid(1);
|
view = base::StringViewMid(view, 1);
|
||||||
}
|
}
|
||||||
return ref.toInt();
|
return view.toInt();
|
||||||
};
|
};
|
||||||
return QTime(readInt(match.captured(1)), readInt(match.captured(2)));
|
return QTime(readInt(match.captured(1)), readInt(match.captured(2)));
|
||||||
}
|
}
|
||||||
|
|
@ -78,12 +79,12 @@ private:
|
||||||
|
|
||||||
std::optional<int> Number(not_null<TimePart*> field) {
|
std::optional<int> Number(not_null<TimePart*> field) {
|
||||||
const auto text = field->getLastText();
|
const auto text = field->getLastText();
|
||||||
auto ref = text.midRef(0);
|
auto view = QStringView(text);
|
||||||
while (ref.size() > 1 && ref.at(0) == '0') {
|
while (view.size() > 1 && view.at(0) == '0') {
|
||||||
ref = ref.mid(1);
|
view = base::StringViewMid(view, 1);
|
||||||
}
|
}
|
||||||
return QRegularExpression("^\\d+$").match(ref).hasMatch()
|
return QRegularExpression("^\\d+$").match(view).hasMatch()
|
||||||
? std::make_optional(ref.toInt())
|
? std::make_optional(view.toInt())
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
#include "ui/platform/ui_platform_utility.h"
|
||||||
#include "base/invoke_queued.h"
|
#include "base/invoke_queued.h"
|
||||||
#include "base/qt_adapters.h"
|
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
#include <QtGui/QScreen>
|
#include <QtGui/QScreen>
|
||||||
|
|
@ -73,7 +72,7 @@ Tooltip::~Tooltip() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
|
void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
|
||||||
const auto screen = base::QScreenNearestTo(m);
|
const auto screen = QGuiApplication::screenAt(m);
|
||||||
if (!screen) {
|
if (!screen) {
|
||||||
Hide();
|
Hide();
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -260,8 +260,9 @@ void VerticalLayoutReorder::updateShift(
|
||||||
? indexHint
|
? indexHint
|
||||||
: indexOf(widget);
|
: indexOf(widget);
|
||||||
auto &entry = _entries[index];
|
auto &entry = _entries[index];
|
||||||
entry.shift = std::round(entry.shiftAnimation.value(entry.finalShift))
|
entry.shift = base::SafeRound(
|
||||||
+ entry.deltaShift;
|
entry.shiftAnimation.value(entry.finalShift)
|
||||||
|
) + entry.deltaShift;
|
||||||
if (entry.deltaShift && !entry.shiftAnimation.animating()) {
|
if (entry.deltaShift && !entry.shiftAnimation.animating()) {
|
||||||
entry.finalShift += entry.deltaShift;
|
entry.finalShift += entry.deltaShift;
|
||||||
entry.deltaShift = 0;
|
entry.deltaShift = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue