diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e88ffd..ed89e80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,8 @@ generate_palette(lib_ui 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) -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) nice_target_sources(lib_ui ${src_loc} diff --git a/ui/abstract_button.cpp b/ui/abstract_button.cpp index e9a37d0..ec0dee0 100644 --- a/ui/abstract_button.cpp +++ b/ui/abstract_button.cpp @@ -32,7 +32,7 @@ void AbstractButton::leaveEventHook(QEvent *e) { return TWidget::leaveEventHook(e); } -void AbstractButton::enterEventHook(QEvent *e) { +void AbstractButton::enterEventHook(QEnterEvent *e) { checkIfOver(mapFromGlobal(QCursor::pos())); return TWidget::enterEventHook(e); } diff --git a/ui/abstract_button.h b/ui/abstract_button.h index 1b04bbb..820224a 100644 --- a/ui/abstract_button.h +++ b/ui/abstract_button.h @@ -54,7 +54,7 @@ public: void clicked(Qt::KeyboardModifiers modifiers, Qt::MouseButton button); protected: - void enterEventHook(QEvent *e) override; + void enterEventHook(QEnterEvent *e) override; void leaveEventHook(QEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; diff --git a/ui/basic_click_handlers.cpp b/ui/basic_click_handlers.cpp index c1e9d54..8c3e008 100644 --- a/ui/basic_click_handlers.cpp +++ b/ui/basic_click_handlers.cpp @@ -10,6 +10,7 @@ #include "ui/text/text_entity.h" #include "ui/integration.h" #include "base/qthelp_url.h" +#include "base/qt_adapters.h" #include #include @@ -80,13 +81,13 @@ bool UrlClickHandler::IsSuspicious(const QString &url) { if (!match1.hasMatch()) { return false; } - const auto domain = match1.capturedRef(3); + const auto domain = match1.capturedView(3); static const auto Check2 = QRegularExpression("^(.*)\\.[a-zA-Z]+$"); const auto match2 = Check2.match(domain); if (!match2.hasMatch()) { return false; } - const auto part = match2.capturedRef(1); + const auto part = match2.capturedView(1); static const auto Check3 = QRegularExpression("[^a-zA-Z0-9\\.\\-]"); return Check3.match(part).hasMatch(); } @@ -100,11 +101,11 @@ QString UrlClickHandler::ShowEncoded(const QString &url) { "^(https?://)?([^/#\\:]+)([/#\\:]|$)", QRegularExpression::CaseInsensitiveOption); 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()) { return QString( ).append(QString::fromUtf8(u.toEncoded()) - ).append(url.midRef(match1.capturedEnd(2))); + ).append(base::StringViewMid(url, match1.capturedEnd(2))); } } return url; diff --git a/ui/colors.palette b/ui/colors.palette index 11ff4ae..ad4fa73 100644 --- a/ui/colors.palette +++ b/ui/colors.palette @@ -89,7 +89,7 @@ tooltipBg: #eef2f5; // tooltip background (like when you put mouse over the mess tooltipFg: #5d6c80; // tooltip text 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 titleBg: windowBgOver; // custom window title background when window is inactive 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) 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) -titleFg: #acacac; // custom window title text when window is inactive (macOS only) -titleFgActive: #3e3c3e; // custom window title text when window is active (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 (Windows 11 and macOS) // tray icon trayCounterBg: #f23c34; // tray icon counter background diff --git a/ui/effects/animation_value.h b/ui/effects/animation_value.h index 4ecf3ff..8244227 100644 --- a/ui/effects/animation_value.h +++ b/ui/effects/animation_value.h @@ -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) { - return std::round(interpolateF(a, b, b_ratio)); + return base::SafeRound(interpolateF(a, b, b_ratio)); } #ifdef ARCH_CPU_32_BITS diff --git a/ui/effects/numbers_animation.cpp b/ui/effects/numbers_animation.cpp index eb0f5d4..6f81a75 100644 --- a/ui/effects/numbers_animation.cpp +++ b/ui/effects/numbers_animation.cpp @@ -62,7 +62,7 @@ void NumbersAnimation::realSetText(QString text, int value) { } auto oldSize = _digits.size(); 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]; digit.from = digit.to; digit.fromWidth = digit.toWidth; diff --git a/ui/effects/radial_animation.cpp b/ui/effects/radial_animation.cpp index 21e5a13..ffea2ac 100644 --- a/ui/effects/radial_animation.cpp +++ b/ui/effects/radial_animation.cpp @@ -224,8 +224,8 @@ RadialState InfiniteRadialAnimation::computeState() { if (anim::Disabled()) { return { 1., 0, kFullArcLength }; } - const auto min = int(std::round(kFullArcLength * _st.arcMin)); - const auto max = int(std::round(kFullArcLength * _st.arcMax)); + const auto min = int(base::SafeRound(kFullArcLength * _st.arcMin)); + const auto max = int(base::SafeRound(kFullArcLength * _st.arcMax)); if (now <= _workStarted) { // zero .. _workStarted const auto zero = _workStarted - _st.sineDuration; @@ -314,8 +314,8 @@ RadialState InfiniteRadialAnimation::computeState() { // st.arcMax - st.arcMin, // std::min(backCurrent, crl::time(st.sineDuration)) // / float64(st.sineDuration)); - //const auto front = linear + std::round((st.arcMin + frontProgress + frontPeriods * (st.arcMax - st.arcMin)) * kFullArcLength); - //const auto from = linear + std::round((backProgress + backPeriods * (st.arcMax - st.arcMin)) * kFullArcLength); + //const auto front = linear + base::SafeRound((st.arcMin + frontProgress + frontPeriods * (st.arcMax - st.arcMin)) * kFullArcLength); + //const auto from = linear + base::SafeRound((backProgress + backPeriods * (st.arcMax - st.arcMin)) * kFullArcLength); //const auto length = (front - from); //return { diff --git a/ui/effects/ripple_animation.cpp b/ui/effects/ripple_animation.cpp index df9b0f5..5fbb030 100644 --- a/ui/effects/ripple_animation.cpp +++ b/ui/effects/ripple_animation.cpp @@ -86,7 +86,15 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, const QCol } 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); { QPainter p(&_frame); diff --git a/ui/emoji_config.cpp b/ui/emoji_config.cpp index ebac3da..6b43bcf 100644 --- a/ui/emoji_config.cpp +++ b/ui/emoji_config.cpp @@ -733,7 +733,8 @@ QVector GetDefaultRecent() { } 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 : OtherEmojiMap[fontHeight]; auto i = map.find(emoji->index()); @@ -741,10 +742,10 @@ const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) { return i->second; } auto image = QImage( - SizeNormal + st::emojiPadding * 2, + SizeNormal + st::emojiPadding * factor * 2, fontHeight, QImage::Format_ARGB32_Premultiplied); - image.setDevicePixelRatio(style::DevicePixelRatio()); + image.setDevicePixelRatio(factor); image.fill(Qt::transparent); { QPainter p(&image); @@ -753,8 +754,8 @@ const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) { p, emoji, SizeNormal, - st::emojiPadding * style::DevicePixelRatio(), - (fontHeight - SizeNormal) / 2); + st::emojiPadding, + (fontHeight - SizeNormal) / (2 * factor)); } return map.emplace( emoji->index(), diff --git a/ui/emoji_config.h b/ui/emoji_config.h index 3183258..f24844b 100644 --- a/ui/emoji_config.h +++ b/ui/emoji_config.h @@ -8,6 +8,7 @@ #include "base/basic_types.h" #include "base/binary_guard.h" +#include "base/qt_adapters.h" #include "emoji.h" #include @@ -118,7 +119,7 @@ private: [[nodiscard]] inline EmojiPtr FromUrl(const QString &url) { auto start = qstr("emoji://e."); 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; } diff --git a/ui/gl/gl_detection.cpp b/ui/gl/gl_detection.cpp index 2f9a5a1..b2e3e13 100644 --- a/ui/gl/gl_detection.cpp +++ b/ui/gl/gl_detection.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #ifdef Q_OS_WIN #include @@ -142,7 +142,7 @@ Capabilities CheckCapabilities(QWidget *widget) { } break; } - [[maybe_unused]] static const auto extensionsLogged = [&] { + static const auto checkVendor = [&] { const auto renderer = reinterpret_cast( functions->glGetString(GL_RENDERER)); LOG(("OpenGL Renderer: %1").arg(renderer ? renderer : "[nullptr]")); @@ -166,8 +166,19 @@ Capabilities CheckCapabilities(QWidget *widget) { LOG(("EGL Extensions: %1").arg(egllist.join(", "))); #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; }(); + if (!checkVendor) { + return {}; + } const auto version = u"%1.%2"_q .arg(supported.majorVersion()) diff --git a/ui/gl/gl_primitives.h b/ui/gl/gl_primitives.h index 1988ffe..c50158a 100644 --- a/ui/gl/gl_primitives.h +++ b/ui/gl/gl_primitives.h @@ -9,8 +9,8 @@ #include "ui/gl/gl_math.h" #include "ui/style/style_core.h" -#include -#include +#include +#include class QOpenGLFunctions; diff --git a/ui/gl/gl_shader.h b/ui/gl/gl_shader.h index 0a4e22e..5dce379 100644 --- a/ui/gl/gl_shader.h +++ b/ui/gl/gl_shader.h @@ -7,7 +7,7 @@ #pragma once #include -#include +#include class OpenGLShaderProgram; diff --git a/ui/gl/gl_surface.cpp b/ui/gl/gl_surface.cpp index ba58ac2..fc45dd6 100644 --- a/ui/gl/gl_surface.cpp +++ b/ui/gl/gl_surface.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace Ui::GL { namespace { diff --git a/ui/image/image_prepare.cpp b/ui/image/image_prepare.cpp index 3219b3b..e12fe56 100644 --- a/ui/image/image_prepare.cpp +++ b/ui/image/image_prepare.cpp @@ -878,6 +878,53 @@ QImage GenerateLinearGradient( 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(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) { Assert(!img.isNull()); @@ -893,7 +940,7 @@ void prepareCircle(QImage &img) { void prepareRound( QImage &image, - QImage *cornerMasks, + gsl::span cornerMasks, RectParts corners, QRect target) { if (target.isNull()) { @@ -905,7 +952,7 @@ void prepareRound( auto cornerHeight = cornerMasks[0].height(); auto targetWidth = target.width(); auto targetHeight = target.height(); - if (targetWidth < 2 * cornerWidth || targetHeight < 2 * cornerHeight) { + if (targetWidth < cornerWidth || targetHeight < cornerHeight) { return; } @@ -970,8 +1017,8 @@ void prepareRound( QImage::Format_ARGB32_Premultiplied); Assert(!image.isNull()); - auto masks = CornersMask(radius); - prepareRound(image, masks.data(), corners, target); + const auto masks = CornersMask(radius); + prepareRound(image, masks, corners, target); } QImage prepareColored(style::color add, QImage image) { diff --git a/ui/image/image_prepare.h b/ui/image/image_prepare.h index b74495f..eaf0155 100644 --- a/ui/image/image_prepare.h +++ b/ui/image/image_prepare.h @@ -40,6 +40,12 @@ namespace Images { const std::vector &colors, int rotation = 0); +[[nodiscard]] QImage GenerateShadow( + int height, + int topAlpha, + int bottomAlpha, + QColor color = QColor(0, 0, 0)); + [[nodiscard]] const std::array &CornersMask( ImageRoundRadius radius); [[nodiscard]] std::array PrepareCorners( @@ -81,7 +87,7 @@ void prepareRound( QRect target = QRect()); void prepareRound( QImage &image, - QImage *cornerMasks, + gsl::span cornerMasks, RectParts corners = RectPart::AllCorners, QRect target = QRect()); void prepareCircle(QImage &image); diff --git a/ui/layers/box_content.cpp b/ui/layers/box_content.cpp index f651791..18dd440 100644 --- a/ui/layers/box_content.cpp +++ b/ui/layers/box_content.cpp @@ -12,11 +12,14 @@ #include "ui/widgets/shadow.h" #include "ui/wrap/fade_wrap.h" #include "ui/text/text_utilities.h" +#include "ui/rect_part.h" #include "ui/painter.h" #include "base/timer.h" #include "styles/style_layers.h" #include "styles/palette.h" +#include + namespace Ui { void BoxContent::setTitle(rpl::producer title) { @@ -85,8 +88,14 @@ void BoxContent::finishScrollCreate() { _scroll->show(); } updateScrollAreaGeometry(); - connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); - connect(_scroll, SIGNAL(innerResized()), this, SLOT(onInnerResize())); + _scroll->scrolls( + ) | rpl::start_with_next([=] { + onScroll(); + }, lifetime()); + _scroll->innerResizes( + ) | rpl::start_with_next([=] { + onInnerResize(); + }, lifetime()); } void BoxContent::scrollToWidget(not_null widget) { @@ -95,6 +104,10 @@ void BoxContent::scrollToWidget(not_null widget) { } } +RectParts BoxContent::customCornersFilling() { + return {}; +} + void BoxContent::onScrollToY(int top, int bottom) { if (_scroll) { _scroll->scrollToY(top, bottom); diff --git a/ui/layers/box_content.h b/ui/layers/box_content.h index bb8fa98..ec4740e 100644 --- a/ui/layers/box_content.h +++ b/ui/layers/box_content.h @@ -15,6 +15,9 @@ #include "ui/text/text_entity.h" #include "ui/rp_widget.h" +enum class RectPart; +using RectParts = base::flags; + namespace style { struct RoundButton; struct IconButton; @@ -128,6 +131,7 @@ public: virtual void showFinished() { } + virtual RectParts customCornersFilling(); void clearButtons() { getDelegate()->clearButtons(); } diff --git a/ui/layers/box_layer_widget.cpp b/ui/layers/box_layer_widget.cpp index 02a7d75..cd2b494 100644 --- a/ui/layers/box_layer_widget.cpp +++ b/ui/layers/box_layer_widget.cpp @@ -115,16 +115,21 @@ QRect BoxLayerWidget::loadingRect() const { void BoxLayerWidget::paintEvent(QPaintEvent *e) { Painter p(this); - auto clip = e->rect(); - auto paintTopRounded = clip.intersects(QRect(0, 0, width(), st::boxRadius)); - auto paintBottomRounded = clip.intersects(QRect(0, height() - st::boxRadius, width(), st::boxRadius)); + + const auto custom = _content->customCornersFilling(); + 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) { - auto parts = RectPart::None | 0; - if (paintTopRounded) parts |= RectPart::FullTop; - if (paintBottomRounded) parts |= RectPart::FullBottom; - _roundRect.paint(p, rect(), parts); + _roundRect.paint(p, rect(), RectPart::None + | (paintTopRounded ? RectPart::FullTop : RectPart::None) + | (paintBottomRounded ? RectPart::FullBottom : RectPart::None)); } - 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()) { for (const auto &rect : other) { p.fillRect(rect, st().bg); diff --git a/ui/paint/blob.cpp b/ui/paint/blob.cpp index 096948f..c694ebc 100644 --- a/ui/paint/blob.cpp +++ b/ui/paint/blob.cpp @@ -84,7 +84,7 @@ RadialBlob::RadialBlob(int n, float minScale, float minSpeed, float maxSpeed) void RadialBlob::paint(Painter &p, const QBrush &brush, float outerScale) { auto path = QPainterPath(); - auto m = QMatrix(); + auto m = QTransform(); const auto scale = (_minScale + (1. - _minScale) * _scale) * outerScale; if (scale == 0.) { diff --git a/ui/painter.h b/ui/painter.h index 1cbc6e2..89389f0 100644 --- a/ui/painter.h +++ b/ui/painter.h @@ -111,7 +111,7 @@ public: const PainterHighQualityEnabler &other) = delete; ~PainterHighQualityEnabler() { - if (_hints) { + if (_hints && _painter.isActive()) { _painter.setRenderHints(_hints, false); } } diff --git a/ui/platform/linux/ui_utility_linux.cpp b/ui/platform/linux/ui_utility_linux.cpp index 87c3c04..2a7fb2d 100644 --- a/ui/platform/linux/ui_utility_linux.cpp +++ b/ui/platform/linux/ui_utility_linux.cpp @@ -10,7 +10,6 @@ #include "base/debug_log.h" #include "ui/platform/linux/ui_linux_wayland_integration.h" #include "base/const_string.h" -#include "base/qt_adapters.h" #include "base/flat_set.h" #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION @@ -434,20 +433,18 @@ bool TranslucentWindowsSupported(QPoint globalPosition) { if (::Platform::IsX11()) { if (const auto native = QGuiApplication::platformNativeInterface()) { - if (const auto desktop = QApplication::desktop()) { - if (const auto screen = base::QScreenNearestTo(globalPosition)) { - if (native->nativeResourceForScreen(QByteArray("compositingEnabled"), screen)) { - return true; - } - const auto index = QGuiApplication::screens().indexOf(screen); - static auto WarnedAbout = base::flat_set(); - 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())); + if (const auto screen = QGuiApplication::screenAt(globalPosition)) { + if (native->nativeResourceForScreen(QByteArray("compositingEnabled"), screen)) { + return true; } + const auto index = QGuiApplication::screens().indexOf(screen); + static auto WarnedAbout = base::flat_set(); + 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())); } } } diff --git a/ui/platform/mac/ui_utility_mac.mm b/ui/platform/mac/ui_utility_mac.mm index c1139d7..b230169 100644 --- a/ui/platform/mac/ui_utility_mac.mm +++ b/ui/platform/mac/ui_utility_mac.mm @@ -7,7 +7,6 @@ #include "ui/platform/mac/ui_utility_mac.h" #include "ui/integration.h" -#include "base/qt_adapters.h" #include #include diff --git a/ui/platform/mac/ui_window_mac.mm b/ui/platform/mac/ui_window_mac.mm index 22e3863..b8357c2 100644 --- a/ui/platform/mac/ui_window_mac.mm +++ b/ui/platform/mac/ui_window_mac.mm @@ -8,6 +8,7 @@ #include "ui/platform/mac/ui_window_title_mac.h" #include "ui/widgets/rp_window.h" +#include "base/qt_adapters.h" #include "base/platform/base_platform_info.h" #include "styles/palette.h" @@ -15,7 +16,7 @@ #include #include #include -#include +#include #include @interface WindowObserver : NSObject { @@ -84,24 +85,35 @@ private: class EventFilter : public QObject, public QAbstractNativeEventFilter { public: - EventFilter(not_null parent, Fn checkPerformDrag) + EventFilter( + not_null parent, + Fn checkStartDrag, + Fn checkPerformDrag) : QObject(parent) + , _checkStartDrag(std::move(checkStartDrag)) , _checkPerformDrag(std::move(checkPerformDrag)) { Expects(_checkPerformDrag != nullptr); + Expects(_checkStartDrag != nullptr); } bool nativeEventFilter( const QByteArray &eventType, void *message, - long *result) { - NSEvent *e = static_cast(message); - return (e && [e type] == NSEventTypeLeftMouseDown) - ? _checkPerformDrag([e window]) - : false; + base::NativeEventResult *result) { + if (NSEvent *e = static_cast(message)) { + if ([e type] == NSEventTypeLeftMouseDown) { + _dragStarted = _checkStartDrag(); + } else if (([e type] == NSEventTypeLeftMouseDragged) + && _dragStarted) { + return _checkPerformDrag([e window]); + } + } return false; } private: + bool _dragStarted = false; + Fn _checkStartDrag; Fn _checkPerformDrag; }; @@ -361,7 +373,10 @@ void WindowHelper::setGeometry(QRect rect) { void WindowHelper::setupBodyTitleAreaEvents() { 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()); if (_private->checkNativeMove(nswindow) && !controls.contains(point) @@ -398,6 +413,15 @@ void WindowHelper::init() { size.width(), size.height() - titleHeight); }, _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 CreateSpecialWindowHelper( diff --git a/ui/platform/ui_platform_window.cpp b/ui/platform/ui_platform_window.cpp index a9046dc..9bb8c50 100644 --- a/ui/platform/ui_platform_window.cpp +++ b/ui/platform/ui_platform_window.cpp @@ -81,13 +81,15 @@ void BasicWindowHelper::close() { void BasicWindowHelper::setBodyTitleArea( Fn testMethod) { - Expects(!_bodyTitleAreaTestMethod); + Expects(!_bodyTitleAreaTestMethod || testMethod); if (!testMethod) { return; } + if (!_bodyTitleAreaTestMethod) { + setupBodyTitleAreaEvents(); + } _bodyTitleAreaTestMethod = std::move(testMethod); - setupBodyTitleAreaEvents(); } QMargins BasicWindowHelper::nativeFrameMargins() const { diff --git a/ui/platform/win/ui_window_shadow_win.cpp b/ui/platform/win/ui_window_shadow_win.cpp index 2463aa9..79abd98 100644 --- a/ui/platform/win/ui_window_shadow_win.cpp +++ b/ui/platform/win/ui_window_shadow_win.cpp @@ -8,6 +8,7 @@ #include "ui/rp_widget.h" #include "ui/platform/win/ui_window_win.h" +#include "base/platform/base_platform_info.h" #include "styles/style_widgets.h" #include @@ -42,7 +43,8 @@ base::flat_map> ShadowByHandle; WindowShadow::WindowShadow(not_null window, QColor color) : _window(window) -, _handle(GetWindowHandle(window)) { +, _handle(GetWindowHandle(window)) +, _windows11(::Platform::IsWindows11OrGreater()) { init(color); } @@ -315,7 +317,7 @@ void WindowShadow::horCorners(int w, Gdiplus::Graphics *pgraphics0, Gdiplus::Gra } 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 { diff --git a/ui/platform/win/ui_window_shadow_win.h b/ui/platform/win/ui_window_shadow_win.h index c157fa5..db63914 100644 --- a/ui/platform/win/ui_window_shadow_win.h +++ b/ui/platform/win/ui_window_shadow_win.h @@ -78,6 +78,7 @@ private: const not_null _window; const HWND _handle; + const bool _windows11 = false; int _x = 0; int _y = 0; diff --git a/ui/platform/win/ui_window_title_win.cpp b/ui/platform/win/ui_window_title_win.cpp index ba578f9..1e3e63d 100644 --- a/ui/platform/win/ui_window_title_win.cpp +++ b/ui/platform/win/ui_window_title_win.cpp @@ -41,6 +41,10 @@ void TitleWidget::setStyle(const style::WindowTitle &st) { update(); } +not_null TitleWidget::st() const { + return _controls.st(); +} + void TitleWidget::setResizeEnabled(bool enabled) { _controls.setResizeEnabled(enabled); } diff --git a/ui/platform/win/ui_window_title_win.h b/ui/platform/win/ui_window_title_win.h index bc5fed6..c6e7d0e 100644 --- a/ui/platform/win/ui_window_title_win.h +++ b/ui/platform/win/ui_window_title_win.h @@ -45,6 +45,7 @@ public: void setText(const QString &text); void setStyle(const style::WindowTitle &st); + [[nodiscard]] not_null st() const; [[nodiscard]] HitTestResult hitTest(QPoint point) const; void setResizeEnabled(bool enabled); diff --git a/ui/platform/win/ui_window_win.cpp b/ui/platform/win/ui_window_win.cpp index 21c9ea8..b48948e 100644 --- a/ui/platform/win/ui_window_win.cpp +++ b/ui/platform/win/ui_window_win.cpp @@ -13,6 +13,7 @@ #include "base/integration.h" #include "base/debug_log.h" #include "styles/palette.h" +#include "styles/style_widgets.h" #include #include @@ -29,7 +30,12 @@ namespace Ui { namespace Platform { 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); const auto success = (DwmIsCompositionEnabled(&result) == S_OK); return success && result; @@ -85,23 +91,6 @@ bool IsTaskbarAutoHidden(LPRECT rcMon = nullptr, PUINT pEdge = nullptr) { 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) { SetWindowLongPtr( handle, @@ -198,6 +187,7 @@ void WindowHelper::setTitle(const QString &title) { void WindowHelper::setTitleStyle(const style::WindowTitle &st) { _title->setStyle(st); + updateWindowFrameColors(); } void WindowHelper::setNativeFrame(bool enabled) { @@ -216,6 +206,7 @@ void WindowHelper::setNativeFrame(bool enabled) { initialShadowUpdate(); } updateMargins(); + updateWindowFrameColors(); fixMaximizedWindow(); } @@ -227,6 +218,15 @@ void WindowHelper::initialShadowUpdate() { } else { _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) { @@ -270,6 +270,7 @@ void WindowHelper::init() { if (_shadow) { _shadow->setColor(st::windowShadowFg->c); } + updateWindowFrameColors(); Ui::ForceFullRepaint(window()); }, window()->lifetime()); @@ -291,9 +292,10 @@ void WindowHelper::init() { updateMargins(); if (!::Platform::IsWindows8OrGreater()) { - WinApiSetWindowTheme(_handle, L" ", L" "); + SetWindowTheme(_handle, L" ", L" "); QApplication::setStyle(QStyleFactory::create("Windows")); } + updateWindowFrameColors(); _menu = GetSystemMenu(_handle, FALSE); updateSystemMenu(); @@ -326,13 +328,15 @@ bool WindowHelper::handleNativeEvent( if (LOWORD(wParam) == WA_CLICKACTIVE) { Ui::MarkInactivePress(window(), true); } + const auto active = (LOWORD(wParam) != WA_INACTIVE); if (_shadow) { - if (LOWORD(wParam) != WA_INACTIVE) { + if (active) { _shadow->update(WindowShadow::Change::Activate); } else { _shadow->update(WindowShadow::Change::Deactivate); } } + updateWindowFrameColors(active); window()->update(); } return false; @@ -553,6 +557,34 @@ int WindowHelper::titleHeight() const { 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() { if (_updatingMargins) return; diff --git a/ui/platform/win/ui_window_win.h b/ui/platform/win/ui_window_win.h index dadf5db..c5fce59 100644 --- a/ui/platform/win/ui_window_win.h +++ b/ui/platform/win/ui_window_win.h @@ -38,6 +38,8 @@ private: void init(); void updateMargins(); + void updateWindowFrameColors(); + void updateWindowFrameColors(bool active); void updateSystemMenu(); void updateSystemMenu(Qt::WindowState state); void initialShadowUpdate(); diff --git a/ui/rp_widget.cpp b/ui/rp_widget.cpp index 318df7b..053360c 100644 --- a/ui/rp_widget.cpp +++ b/ui/rp_widget.cpp @@ -12,6 +12,30 @@ #include namespace Ui { +namespace { + +[[nodiscard]] std::vector> GetChildWidgets( + not_null widget) { + const auto &children = widget->children(); + auto result = std::vector>(); + result.reserve(children.size()); + for (const auto child : children) { + if (child && child->isWidgetType()) { + result.push_back(static_cast(child)); + } + } + return result; +} + +} // namespace + +void ToggleChildrenVisibility(not_null widget, bool visible) { + for (const auto &child : GetChildWidgets(widget)) { + if (child) { + child->setVisible(visible); + } + } +} void ResizeFitChild( not_null parent, diff --git a/ui/rp_widget.h b/ui/rp_widget.h index 5c67939..f1260b9 100644 --- a/ui/rp_widget.h +++ b/ui/rp_widget.h @@ -16,6 +16,13 @@ #include #include +#include + +namespace Ui { + +void ToggleChildrenVisibility(not_null widget, bool visible); + +} // namespace Ui class TWidget; @@ -29,18 +36,10 @@ public: } void hideChildren() { - for (auto child : Base::children()) { - if (child->isWidgetType()) { - static_cast(child)->hide(); - } - } + Ui::ToggleChildrenVisibility(this, false); } void showChildren() { - for (auto child : Base::children()) { - if (child->isWidgetType()) { - static_cast(child)->show(); - } - } + Ui::ToggleChildrenVisibility(this, true); } void moveToLeft(int x, int y, int outerw = 0) { @@ -104,13 +103,22 @@ public: } 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()) { parent->leaveToChildEvent(e, this); } 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(e)); + } +#endif // Qt < 6.0.0 + virtual void enterEventHook(QEnterEvent *e) { return Base::enterEvent(e); } diff --git a/ui/style/style_core_color.cpp b/ui/style/style_core_color.cpp index f9b3227..3325cfd 100644 --- a/ui/style/style_core_color.cpp +++ b/ui/style/style_core_color.cpp @@ -31,7 +31,7 @@ void ColorData::set(uchar r, uchar g, uchar b, uchar a) { void ComplexColor::subscribeToPaletteChanges() { style::PaletteChanged( ) | rpl::start_with_next([=] { - _owned.update(_generator()); + refresh(); }, _lifetime); } diff --git a/ui/style/style_core_color.h b/ui/style/style_core_color.h index c11815c..40a4def 100644 --- a/ui/style/style_core_color.h +++ b/ui/style/style_core_color.h @@ -145,6 +145,9 @@ public: [[nodiscard]] const Color &color() const { return _owned.color(); } + void refresh() { + _owned.update(_generator()); + } private: void subscribeToPaletteChanges(); diff --git a/ui/style/style_core_font.cpp b/ui/style/style_core_font.cpp index bdc5a88..6dcb059 100644 --- a/ui/style/style_core_font.cpp +++ b/ui/style/style_core_font.cpp @@ -8,6 +8,7 @@ #include "base/algorithm.h" #include "base/debug_log.h" +#include "base/base_file_utilities.h" #include "ui/style/style_core_custom_font.h" #include "ui/integration.h" @@ -18,16 +19,22 @@ #include 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 Q_INIT_RESOURCE(fonts); #endif // !DESKTOP_APP_USE_PACKAGED_FONTS #ifdef Q_OS_WIN Q_INIT_RESOURCE(win); -#elif defined Q_OS_MAC // Q_OS_WIN - Q_INIT_RESOURCE(mac); -#elif defined Q_OS_UNIX && !defined DESKTOP_APP_USE_PACKAGED // Q_OS_WIN || Q_OS_MAC +#elif defined Q_OS_UNIX && !defined DESKTOP_APP_USE_PACKAGED // Q_OS_WIN 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 { diff --git a/ui/style/style_core_icon.cpp b/ui/style/style_core_icon.cpp index e26d406..e4330ff 100644 --- a/ui/style/style_core_icon.cpp +++ b/ui/style/style_core_icon.cpp @@ -10,6 +10,7 @@ #include "ui/style/style_core.h" #include "base/basic_types.h" +#include #include 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()); } -base::flat_map iconMasks; +base::flat_map IconMasks; +QMutex IconMasksMutex; + base::flat_map, QPixmap> iconPixmaps; base::flat_set iconData; -QImage createIconMask(const IconMask *mask, int scale) { +[[nodiscard]] QImage CreateIconMask( + not_null mask, + int scale) { auto maskImage = QImage::fromData(mask->data(), mask->size(), "PNG"); maskImage.setDevicePixelRatio(DevicePixelRatio()); Assert(!maskImage.isNull()); @@ -55,6 +60,17 @@ QImage createIconMask(const IconMask *mask, int scale) { Qt::SmoothTransformation); } +[[nodiscard]] QImage ResolveIconMask(not_null 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) { auto data = mask->data(); auto size = mask->size(); @@ -181,7 +197,7 @@ void MonoIcon::paint( auto size = readGeneratedSize(_mask, Scale()); auto maskImage = QImage(); if (size.isEmpty()) { - maskImage = createIconMask(_mask, Scale()); + maskImage = CreateIconMask(_mask, Scale()); size = maskImage.size() / DevicePixelRatio(); } @@ -209,7 +225,7 @@ void MonoIcon::fill( auto size = readGeneratedSize(_mask, Scale()); auto maskImage = QImage(); if (size.isEmpty()) { - maskImage = createIconMask(_mask, Scale()); + maskImage = CreateIconMask(_mask, Scale()); size = maskImage.size() / DevicePixelRatio(); } if (!maskImage.isNull()) { @@ -242,7 +258,7 @@ QImage MonoIcon::instance(QColor colorOverride, int scale) const { result.fill(colorOverride); return result; } - auto mask = createIconMask(_mask, scale); + auto mask = CreateIconMask(_mask, scale); auto result = QImage(mask.size(), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(DevicePixelRatio()); colorizeImage(mask, colorOverride, &result); @@ -252,26 +268,24 @@ QImage MonoIcon::instance(QColor colorOverride, int scale) const { void MonoIcon::ensureLoaded() const { if (_size.isValid()) { return; - } - if (!_maskImage.isNull()) { + } else if (!_maskImage.isNull()) { createCachedPixmap(); return; } _size = readGeneratedSize(_mask, Scale()); if (_size.isEmpty()) { - auto i = iconMasks.find(_mask); - if (i == iconMasks.cend()) { - i = iconMasks.emplace(_mask, createIconMask(_mask, Scale())).first; - } - _maskImage = i->second; - + _maskImage = ResolveIconMask(_mask); createCachedPixmap(); } } 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); } @@ -373,7 +387,9 @@ void resetIcons() { void destroyIcons() { iconData.clear(); iconPixmaps.clear(); - iconMasks.clear(); + + QMutexLocker lock(&IconMasksMutex); + IconMasks.clear(); } } // namespace internal diff --git a/ui/style/style_core_scale.h b/ui/style/style_core_scale.h index e25dcf0..a92c786 100644 --- a/ui/style/style_core_scale.h +++ b/ui/style/style_core_scale.h @@ -6,6 +6,8 @@ // #pragma once +#include "base/algorithm.h" + #include #include @@ -34,7 +36,7 @@ template [[nodiscard]] inline T ConvertScale(T value, int scale) { return (value < 0.) ? (-ConvertScale(-value, scale)) - : T(std::round((double(value) * scale / 100.) - 0.01)); + : T(base::SafeRound((double(value) * scale / 100.) - 0.01)); } template diff --git a/ui/text/text.cpp b/ui/text/text.cpp index 420d47e..9df1668 100644 --- a/ui/text/text.cpp +++ b/ui/text/text.cpp @@ -12,9 +12,12 @@ #include "ui/emoji_config.h" #include "ui/integration.h" #include "base/platform/base_platform_info.h" +#include "base/qt_adapters.h" #include +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include +#endif // Qt < 6.0.0 namespace Ui { namespace Text { @@ -161,7 +164,7 @@ QString textcmdStartLink(const QString &url) { QString result; 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() { @@ -2058,10 +2061,21 @@ private: 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 scripts(length); QUnicodeTools::initScripts(string, length, scripts.data()); for (int i = 0; i < length; ++i) analysis[i].script = scripts.at(i); +#endif // Qt < 6.0.0 } blockIndex = _lineStartBlock; @@ -2082,7 +2096,9 @@ private: } else { 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 +#endif // Qt < 6.0.0 ++start; ++analysis; } @@ -3151,7 +3167,7 @@ void String::enumerateText(TextSelection selection, AppendPartCallback appendPar auto rangeFrom = qMax(selection.from, lnkFrom); auto rangeTo = qMin(selection.to, blockFrom); 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) { // Ignore links that are partially copied. clickHandlerFinishCallback(r, nullptr); @@ -3182,7 +3198,7 @@ void String::enumerateText(TextSelection selection, AppendPartCallback appendPar auto rangeFrom = qMax(selection.from, blockFrom); auto rangeTo = qMin(selection.to, uint16(blockFrom + countBlockLength(i, e))); if (rangeTo > rangeFrom) { - appendPartCallback(_text.midRef(rangeFrom, rangeTo - rangeFrom)); + appendPartCallback(base::StringViewMid(_text, rangeFrom, rangeTo - rangeFrom)); } } } @@ -3245,7 +3261,7 @@ TextForMimeData String::toText( insertEntity({ tracker.type, tracker.start, - result.rich.text.size() - tracker.start }); + int(result.rich.text.size()) - tracker.start }); } else if ((newFlags & flag) && !(oldFlags & flag)) { tracker.start = result.rich.text.size(); } @@ -3255,7 +3271,7 @@ TextForMimeData String::toText( linkStart = result.rich.text.size(); }; const auto clickHandlerFinishCallback = [&]( - const QStringRef &inText, + QStringView inText, const ClickHandlerPtr &handler) { if (!handler || (!composeExpanded && !composeEntities)) { return; @@ -3264,7 +3280,7 @@ TextForMimeData String::toText( const auto plainUrl = (entity.type == EntityType::Url) || (entity.type == EntityType::Email); const auto full = plainUrl - ? entity.data.midRef(0, entity.data.size()) + ? QStringView(entity.data).mid(0, entity.data.size()) : inText; const auto customTextLink = (entity.type == EntityType::CustomUrl); const auto internalLink = customTextLink @@ -3282,11 +3298,11 @@ TextForMimeData String::toText( insertEntity({ entity.type, linkStart, - (result.rich.text.size() - linkStart), + int(result.rich.text.size() - linkStart), plainUrl ? QString() : entity.data }); } }; - const auto appendPartCallback = [&](const QStringRef &part) { + const auto appendPartCallback = [&](QStringView part) { result.rich.text += part; if (composeExpanded) { result.expanded += part; diff --git a/ui/text/text_entity.cpp b/ui/text/text_entity.cpp index cd4453e..614d967 100644 --- a/ui/text/text_entity.cpp +++ b/ui/text/text_entity.cpp @@ -9,10 +9,10 @@ #include "base/qthelp_url.h" #include "base/qthelp_regex.h" #include "base/crc32hash.h" -#include "base/qt_adapters.h" #include "ui/text/text.h" #include "ui/widgets/input_fields.h" #include "ui/emoji_config.h" +#include "base/qt_adapters.h" #include #include @@ -1156,13 +1156,13 @@ const QRegularExpression &RegExpWordSplit() { for (const auto &entity : urls) { const auto till = entity.offset() + entity.length(); 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(')'); offset = till; } if (original.size() > offset) { - result.append(original.midRef(offset)); + result.append(base::StringViewMid(original, offset)); } return result; } @@ -1402,7 +1402,7 @@ QStringList PrepareSearchWords( auto list = clean.split(SplitterOverride ? *SplitterOverride : RegExpWordSplit(), - base::QStringSkipEmptyParts); + Qt::SkipEmptyParts); result.reserve(list.size()); for (const auto &word : std::as_const(list)) { auto trimmed = word.trimmed(); @@ -1619,10 +1619,10 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) { auto mentionIgnore = false; if (mHashtag.hasMatch()) { - if (!mHashtag.capturedRef(1).isEmpty()) { + if (!mHashtag.capturedView(1).isEmpty()) { ++hashtagStart; } - if (!mHashtag.capturedRef(2).isEmpty()) { + if (!mHashtag.capturedView(2).isEmpty()) { --hashtagEnd; } if (RegExpHashtagExclude().match( @@ -1633,10 +1633,10 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) { } } while (mMention.hasMatch()) { - if (!mMention.capturedRef(1).isEmpty()) { + if (!mMention.capturedView(1).isEmpty()) { ++mentionStart; } - if (!mMention.capturedRef(2).isEmpty()) { + if (!mMention.capturedView(2).isEmpty()) { --mentionEnd; } 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.capturedRef(1).isEmpty()) { + if (!mBotCommand.capturedView(1).isEmpty()) { ++botCommandStart; } - if (!mBotCommand.capturedRef(3).isEmpty()) { + if (!mBotCommand.capturedView(3).isEmpty()) { --botCommandEnd; } } @@ -2019,16 +2019,16 @@ QString TagsTextMimeType() { return QString::fromLatin1("application/x-td-field-text"); } -bool IsMentionLink(const QStringRef &link) { +bool IsMentionLink(QStringView link) { return link.startsWith(kMentionTagStart); } -[[nodiscard]] bool IsSeparateTag(const QStringRef &tag) { +[[nodiscard]] bool IsSeparateTag(QStringView tag) { return (tag == Ui::InputField::kTagCode) || (tag == Ui::InputField::kTagPre); } -QString JoinTag(const QVector &list) { +QString JoinTag(const QList &list) { if (list.isEmpty()) { return QString(); } @@ -2039,7 +2039,7 @@ QString JoinTag(const QVector &list) { auto result = QString(); result.reserve(length); 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])) { result.append('|').append(list[i]); } @@ -2051,8 +2051,8 @@ QString TagWithRemoved(const QString &tag, const QString &removed) { if (tag == removed) { return QString(); } - auto list = tag.splitRef('|'); - list.erase(ranges::remove(list, removed.midRef(0)), list.end()); + auto list = QStringView(tag).split('|'); + list.erase(ranges::remove(list, QStringView(removed)), list.end()); return JoinTag(list); } @@ -2060,13 +2060,13 @@ QString TagWithAdded(const QString &tag, const QString &added) { if (tag.isEmpty() || tag == added) { return added; } - auto list = tag.splitRef('|'); - const auto ref = added.midRef(0); + auto list = QStringView(tag).split('|'); + const auto ref = QStringView(added); if (list.contains(ref)) { return tag; } list.push_back(ref); - ranges::sort(list); + std::sort(list.begin(), list.end()); return JoinTag(list); } @@ -2156,7 +2156,7 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) { if (IsMentionLink(nextState.link)) { const auto match = qthelp::regex_match( "^(\\d+\\.\\d+)(/|$)", - nextState.link.midRef(kMentionTagStart.size())); + base::StringViewMid(nextState.link, kMentionTagStart.size())); if (match) { openType(EntityType::MentionName, match->captured(1)); } @@ -2173,7 +2173,7 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) { }; const auto stateForTag = [&](const QString &tag) { auto result = State(); - const auto list = tag.splitRef('|'); + const auto list = QStringView(tag).split('|'); for (const auto &single : list) { if (single == Ui::InputField::kTagBold) { result.set(EntityType::Bold); diff --git a/ui/text/text_entity.h b/ui/text/text_entity.h index 74d14d7..d140fbc 100644 --- a/ui/text/text_entity.h +++ b/ui/text/text_entity.h @@ -363,17 +363,9 @@ void ApplyServerCleaning(TextWithEntities &result); inline const auto kMentionTagStart = qstr("mention://user."); -[[nodiscard]] bool IsMentionLink(const QStringRef &link); -[[nodiscard]] inline bool IsMentionLink(const QString &link) { - return IsMentionLink(link.midRef(0)); -} - -[[nodiscard]] bool IsSeparateTag(const QStringRef &tag); -[[nodiscard]] inline bool IsSeparateTag(const QString &tag) { - return IsSeparateTag(tag.midRef(0)); -} - -[[nodiscard]] QString JoinTag(const QVector &list); +[[nodiscard]] bool IsMentionLink(QStringView link); +[[nodiscard]] bool IsSeparateTag(QStringView tag); +[[nodiscard]] QString JoinTag(const QList &list); [[nodiscard]] QString TagWithRemoved( const QString &tag, const QString &removed); diff --git a/ui/text/text_utilities.cpp b/ui/text/text_utilities.cpp index 903bac6..37172fd 100644 --- a/ui/text/text_utilities.cpp +++ b/ui/text/text_utilities.cpp @@ -7,6 +7,7 @@ #include "ui/text/text_utilities.h" #include "base/algorithm.h" +#include "base/qt_adapters.h" #include @@ -19,7 +20,7 @@ TextWithEntities WithSingleEntity( EntityType type, const QString &data = QString()) { 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; } @@ -49,25 +50,25 @@ TextWithEntities RichLangValue(const QString &text) { while (offset < text.size()) { const auto m = kStart.match(text, offset); if (!m.hasMatch()) { - result.text.append(text.midRef(offset)); + result.text.append(base::StringViewMid(text, offset)); break; } const auto position = m.capturedStart(); const auto from = m.capturedEnd(); - const auto tag = m.capturedRef(); + const auto tag = m.capturedView(); const auto till = text.indexOf(tag, from + 1); if (till <= from) { offset = from; continue; } 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("__")) ? EntityType::Italic : EntityType::Bold; - result.entities.push_back({ type, result.text.size(), till - from }); - result.text.append(text.midRef(from, till - from)); + result.entities.push_back({ type, int(result.text.size()), int(till - from) }); + result.text.append(base::StringViewMid(text, from, till - from)); offset = till + tag.size(); } return result; diff --git a/ui/ui_utility.cpp b/ui/ui_utility.cpp index a2e55e6..5fef2af 100644 --- a/ui/ui_utility.cpp +++ b/ui/ui_utility.cpp @@ -9,7 +9,6 @@ #include "ui/platform/ui_platform_utility.h" #include "ui/style/style_core.h" -#include #include #include #include @@ -214,9 +213,7 @@ bool IsContentVisible( } void DisableCustomScaling() { - if (QCoreApplication::testAttribute(Qt::AA_DisableHighDpiScaling)) { - QHighDpiScaling::setGlobalFactor(1); - } + QHighDpiScaling::setGlobalFactor(1); } int WheelDirection(not_null e) { diff --git a/ui/widgets/buttons.cpp b/ui/widgets/buttons.cpp index ab2f2ea..bc9d890 100644 --- a/ui/widgets/buttons.cpp +++ b/ui/widgets/buttons.cpp @@ -301,6 +301,11 @@ void RoundButton::setBrushOverride(std::optional brush) { update(); } +void RoundButton::setPenOverride(std::optional pen) { + _penOverride = std::move(pen); + update(); +} + void RoundButton::finishNumbersAnimation() { if (_numbers) { _numbers->finishAnimating(); @@ -371,11 +376,12 @@ void RoundButton::paintEvent(QPaintEvent *e) { if (_fullRadius) { const auto radius = rounded.height() / 2; PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); + p.setPen(_penOverride ? *_penOverride : Qt::NoPen); p.setBrush(_brushOverride ? *_brushOverride : rect.color()->b); p.drawRoundedRect(fill, radius, radius); } else if (_brushOverride) { - p.setPen(Qt::NoPen); + PainterHighQualityEnabler hq(p); + p.setPen(_penOverride ? *_penOverride : Qt::NoPen); p.setBrush(*_brushOverride); const auto radius = _st.radius ? _st.radius : st::buttonRadius; p.drawRoundedRect(fill, radius, radius); @@ -383,6 +389,9 @@ void RoundButton::paintEvent(QPaintEvent *e) { rect.paint(p, fill); } }; + if (_penOverride) { + paintRipple(p, rounded.topLeft()); + } drawRect(_roundRect); auto over = isOver(); @@ -391,7 +400,9 @@ void RoundButton::paintEvent(QPaintEvent *e) { drawRect(_roundRectOver); } - paintRipple(p, rounded.topLeft()); + if (!_penOverride) { + paintRipple(p, rounded.topLeft()); + } p.setFont(_st.font); const auto textTop = _st.padding.top() + _st.textTop; diff --git a/ui/widgets/buttons.h b/ui/widgets/buttons.h index 7e0b83d..0d25b34 100644 --- a/ui/widgets/buttons.h +++ b/ui/widgets/buttons.h @@ -131,6 +131,7 @@ public: } void setWidthChangedCallback(Fn callback); void setBrushOverride(std::optional brush); + void setPenOverride(std::optional pen); void finishNumbersAnimation(); int contentWidth() const; @@ -167,6 +168,7 @@ private: const style::RoundButton &_st; std::optional _brushOverride; + std::optional _penOverride; RoundRect _roundRect; RoundRect _roundRectOver; diff --git a/ui/widgets/inner_dropdown.cpp b/ui/widgets/inner_dropdown.cpp index 5e715eb..c9e2cee 100644 --- a/ui/widgets/inner_dropdown.cpp +++ b/ui/widgets/inner_dropdown.cpp @@ -22,7 +22,10 @@ InnerDropdown::InnerDropdown( , _roundRect(ImageRoundRadius::Small, _st.bg) , _hideTimer([=] { hideAnimated(); }) , _scroll(this, _st.scroll) { - connect(_scroll, &ScrollArea::scrolled, [=] { scrolled(); }); + _scroll->scrolls( + ) | rpl::start_with_next([=] { + scrolled(); + }, lifetime()); hide(); @@ -126,7 +129,7 @@ void InnerDropdown::paintEvent(QPaintEvent *e) { } } -void InnerDropdown::enterEventHook(QEvent *e) { +void InnerDropdown::enterEventHook(QEnterEvent *e) { if (_autoHiding) { showAnimated(_origin); } diff --git a/ui/widgets/inner_dropdown.h b/ui/widgets/inner_dropdown.h index 1ed1080..d3bbcbb 100644 --- a/ui/widgets/inner_dropdown.h +++ b/ui/widgets/inner_dropdown.h @@ -73,7 +73,7 @@ public: protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; - void enterEventHook(QEvent *e) override; + void enterEventHook(QEnterEvent *e) override; void leaveEventHook(QEvent *e) override; bool eventFilter(QObject *obj, QEvent *e) override; diff --git a/ui/widgets/input_fields.cpp b/ui/widgets/input_fields.cpp index 067c6bc..3cd0018 100644 --- a/ui/widgets/input_fields.cpp +++ b/ui/widgets/input_fields.cpp @@ -16,6 +16,7 @@ #include "base/platform/base_platform_info.h" #include "emoji_suggestions_helper.h" #include "styles/palette.h" +#include "base/qt_adapters.h" #include #include @@ -103,7 +104,7 @@ bool IsNewline(QChar ch) { return (kNewlineChars.indexOf(ch) >= 0); } -[[nodiscard]] bool IsValidMarkdownLink(const QStringRef &link) { +[[nodiscard]] bool IsValidMarkdownLink(QStringView link) { return (link.indexOf('.') >= 0) || (link.indexOf(':') >= 0); } @@ -128,21 +129,21 @@ bool IsNewline(QChar ch) { return QString(); } auto found = false; - for (const auto &single : existing.id.splitRef('|')) { - const auto normalized = (single == kTagPre.midRef(0)) - ? kTagCode.midRef(0) + for (const auto &single : QStringView(existing.id).split('|')) { + const auto normalized = (single == QStringView(kTagPre)) + ? QStringView(kTagCode) : single; if (checkingLink && IsValidMarkdownLink(single)) { if (resultLink.isEmpty()) { resultLink = single.toString(); found = true; break; - } else if (resultLink.midRef(0) == single) { + } else if (QStringView(resultLink) == single) { found = true; break; } return QString(); - } else if (!checkingLink && tag.midRef(0) == normalized) { + } else if (!checkingLink && QStringView(tag) == normalized) { found = true; break; } @@ -687,7 +688,8 @@ void RemoveDocumentTags( not_null document, int from, int end) { - auto cursor = QTextCursor(document->docHandle(), from); + auto cursor = QTextCursor(document); + cursor.setPosition(from); cursor.setPosition(end, QTextCursor::KeepAnchor); auto format = QTextCharFormat(); @@ -704,7 +706,7 @@ QTextCharFormat PrepareTagFormat( auto result = QTextCharFormat(); auto font = st.font; auto color = std::optional(); - const auto applyOne = [&](const QStringRef &tag) { + const auto applyOne = [&](QStringView tag) { if (IsValidMarkdownLink(tag)) { color = st::defaultTextPalette.linkFg; } else if (tag == kTagBold) { @@ -720,7 +722,7 @@ QTextCharFormat PrepareTagFormat( font = font->monospace(); } }; - for (const auto &tag : tag.splitRef('|')) { + for (const auto &tag : QStringView(tag).split('|')) { applyOne(tag); } result.setFont(font); @@ -764,7 +766,7 @@ int ProcessInsertedTags( applyNoTagFrom, tagFrom); } - QTextCursor c(document->docHandle(), 0); + QTextCursor c(document); c.setPosition(tagFrom); c.setPosition(tagTo, QTextCursor::KeepAnchor); @@ -1024,7 +1026,7 @@ bool FlatInput::eventHook(QEvent *e) { || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { const auto ev = static_cast(e); - if (ev->device()->type() == QTouchDevice::TouchScreen) { + if (ev->device()->type() == base::TouchDevice::TouchScreen) { touchEvent(ev); } } @@ -1057,6 +1059,8 @@ void FlatInput::touchEvent(QTouchEvent *e) { if (_touchRightButton) { QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); contextMenuEvent(&contextEvent); + } else { + QGuiApplication::inputMethod()->show(); } } if (weak) { @@ -1402,7 +1406,7 @@ bool InputField::viewportEventInner(QEvent *e) { || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { const auto ev = static_cast(e); - if (ev->device()->type() == QTouchDevice::TouchScreen) { + if (ev->device()->type() == base::TouchDevice::TouchScreen) { handleTouchEvent(ev); } } @@ -1465,7 +1469,7 @@ void InputField::setExtendedContextMenu( value ) | rpl::start_with_next([=](auto pair) { auto &[menu, e] = pair; - contextMenuEventInner(&e, std::move(menu)); + contextMenuEventInner(e.get(), std::move(menu)); }, lifetime()); } @@ -1514,14 +1518,14 @@ void InputField::setMaxLength(int length) { if (_maxLength > 0) { const auto document = _inner->document(); _correcting = true; - QTextCursor(document->docHandle(), 0).joinPreviousEditBlock(); + QTextCursor(document).joinPreviousEditBlock(); const auto guard = gsl::finally([&] { _correcting = false; - QTextCursor(document->docHandle(), 0).endEditBlock(); + QTextCursor(document).endEditBlock(); handleContentsChanged(); }); - auto cursor = QTextCursor(document->docHandle(), 0); + auto cursor = QTextCursor(document); cursor.movePosition(QTextCursor::End); chopByMaxLength(0, cursor.position()); } @@ -1610,7 +1614,7 @@ void InputField::insertTag(const QString &text, QString tagId) { cursor.insertText(text + ' ', _defaultCharFormat); } else { _insertedTags.clear(); - _insertedTags.push_back({ 0, text.size(), tagId }); + _insertedTags.push_back({ 0, int(text.size()), tagId }); _insertedTagsAreFromMime = false; cursor.insertText(text + ' '); _insertedTags.clear(); @@ -1673,6 +1677,8 @@ void InputField::handleTouchEvent(QTouchEvent *e) { if (_touchRightButton) { QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); contextMenuEvent(&contextEvent); + } else { + QGuiApplication::inputMethod()->show(); } } if (weak) { @@ -2220,9 +2226,8 @@ void InputField::processFormatting(int insertPosition, int insertEnd) { if (action.type != ActionType::Invalid) { PrepareFormattingOptimization(document); - auto cursor = QTextCursor( - document->docHandle(), - action.intervalStart); + auto cursor = QTextCursor(document); + cursor.setPosition(action.intervalStart); cursor.setPosition(action.intervalEnd, QTextCursor::KeepAnchor); if (action.type == ActionType::InsertEmoji) { InsertEmojiAtCursor(cursor, action.emoji); @@ -2290,7 +2295,7 @@ void InputField::onDocumentContentsChange( // Qt bug workaround https://bugreports.qt.io/browse/QTBUG-49062 if (!position) { - auto cursor = QTextCursor(document->docHandle(), 0); + auto cursor = QTextCursor(document); cursor.movePosition(QTextCursor::End); if (position + charsAdded > cursor.position()) { const auto delta = position + charsAdded - cursor.position(); @@ -2309,10 +2314,10 @@ void InputField::onDocumentContentsChange( : charsAdded; _correcting = true; - QTextCursor(document->docHandle(), 0).joinPreviousEditBlock(); + QTextCursor(document).joinPreviousEditBlock(); const auto guard = gsl::finally([&] { _correcting = false; - QTextCursor(document->docHandle(), 0).endEditBlock(); + QTextCursor(document).endEditBlock(); handleContentsChanged(); const auto added = charsAdded - _emojiSurrogateAmount; _documentContentsChanges.fire({position, charsRemoved, added}); @@ -2345,7 +2350,7 @@ void InputField::chopByMaxLength(int insertPosition, int insertLength) { return; } - auto cursor = QTextCursor(document()->docHandle(), 0); + auto cursor = QTextCursor(document()); cursor.movePosition(QTextCursor::End); const auto fullSize = cursor.position(); const auto toRemove = fullSize - _maxLength; @@ -2540,7 +2545,7 @@ void InputField::setTextWithTags( _realInsertPosition = 0; _realCharsAdded = textWithTags.text.size(); const auto document = _inner->document(); - auto cursor = QTextCursor(document->docHandle(), 0); + auto cursor = QTextCursor(document); if (historyAction == HistoryAction::Clear) { document->setUndoRedoEnabled(false); cursor.beginEditBlock(); @@ -2597,7 +2602,7 @@ TextWithTags InputField::getTextWithAppliedMarkdown() const { auto from = 0; const auto addOriginalTextUpTill = [&](int offset) { if (offset > from) { - result.text.append(originalText.midRef(from, offset - from)); + result.text.append(base::StringViewMid(originalText, from, offset - from)); } }; auto link = links.begin(); @@ -2653,7 +2658,8 @@ TextWithTags InputField::getTextWithAppliedMarkdown() const { int(result.text.size()), entityLength, tag.tag }); - result.text.append(originalText.midRef( + result.text.append(base::StringViewMid( + originalText, entityStart, entityLength)); } @@ -2928,7 +2934,8 @@ auto InputField::selectionEditLinkData(EditLinkSelection selection) const }; const auto stateTagHasLink = [&](const State &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) { return state.i.fragment().position(); @@ -3136,9 +3143,9 @@ void InputField::commitInstantReplacement( const auto currentTag = cursor.charFormat().property( kTagProperty ).toString(); - const auto currentTags = currentTag.splitRef('|'); - if (currentTags.contains(kTagPre.midRef(0)) - || currentTags.contains(kTagCode.midRef(0))) { + const auto currentTags = QStringView(currentTag).split('|'); + if (currentTags.contains(QStringView(kTagPre)) + || currentTags.contains(QStringView(kTagCode))) { return; } } @@ -3173,7 +3180,7 @@ bool InputField::commitMarkdownReplacement( const QString &tag, const QString &edge) { const auto end = [&] { - auto cursor = QTextCursor(document()->docHandle(), 0); + auto cursor = QTextCursor(document()); cursor.movePosition(QTextCursor::End); return cursor.position(); }(); @@ -3187,7 +3194,8 @@ bool InputField::commitMarkdownReplacement( const auto extended = getTextWithTagsPart( from - extendLeft, till + extendRight).text; - const auto outer = extended.midRef( + const auto outer = base::StringViewMid( + extended, extendLeft, extended.size() - extendLeft - extendRight); if ((outer.size() <= 2 * edge.size()) @@ -3251,7 +3259,7 @@ bool InputField::commitMarkdownReplacement( if (tagTill > tagFrom) { _insertedTags.push_back({ tagFrom, - tagTill - tagFrom, + int(tagTill - tagFrom), tag, }); } @@ -3283,8 +3291,7 @@ void InputField::addMarkdownTag( int till, const QString &tag) { const auto current = getTextWithTagsPart(from, till); - const auto currentLength = current.text.size(); - const auto tagRef = tag.midRef(0); + const auto currentLength = int(current.text.size()); // #TODO Trim inserted tag, so that all newlines are left outside. auto tags = TagList(); @@ -3322,7 +3329,6 @@ void InputField::removeMarkdownTag( int till, const QString &tag) { const auto current = getTextWithTagsPart(from, till); - const auto tagRef = tag.midRef(0); auto tags = TagList(); for (const auto &existing : current.tags) { @@ -3351,7 +3357,7 @@ void InputField::finishMarkdownTagChange( _inner->setTextCursor(cursor); } -bool InputField::IsValidMarkdownLink(const QStringRef &link) { +bool InputField::IsValidMarkdownLink(QStringView link) { return ::Ui::IsValidMarkdownLink(link); } @@ -3365,7 +3371,7 @@ void InputField::commitMarkdownLinkEdit( return; } _insertedTags.clear(); - _insertedTags.push_back({ 0, text.size(), link }); + _insertedTags.push_back({ 0, int(text.size()), link }); auto cursor = textCursor(); const auto editData = selectionEditLinkData(selection); @@ -3852,7 +3858,7 @@ bool MaskedInputField::eventHook(QEvent *e) { || type == QEvent::TouchEnd || type == QEvent::TouchCancel) { auto event = static_cast(e); - if (event->device()->type() == QTouchDevice::TouchScreen) { + if (event->device()->type() == base::TouchDevice::TouchScreen) { touchEvent(event); } } @@ -3885,6 +3891,8 @@ void MaskedInputField::touchEvent(QTouchEvent *e) { if (_touchRightButton) { QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); contextMenuEvent(&contextEvent); + } else { + QGuiApplication::inputMethod()->show(); } } if (weak) { @@ -4212,7 +4220,7 @@ void NumberInput::correctValue( QString newText; newText.reserve(now.size()); 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()) { newText.append(now.at(i)); } else if (i < nowCursor) { @@ -4248,7 +4256,7 @@ void HexInput::correctValue( QString newText; newText.reserve(now.size()); 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]; if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') diff --git a/ui/widgets/input_fields.h b/ui/widgets/input_fields.h index 3617e65..e87bd29 100644 --- a/ui/widgets/input_fields.h +++ b/ui/widgets/input_fields.h @@ -244,7 +244,7 @@ public: struct ExtendedContextMenu { QMenu *menu = nullptr; - QContextMenuEvent event; + std::shared_ptr event; }; void setAdditionalMargin(int margin); @@ -258,10 +258,7 @@ public: EditLinkSelection selection, const QString &text, const QString &link); - static bool IsValidMarkdownLink(const QStringRef &link); - static bool IsValidMarkdownLink(const QString &link) { - return IsValidMarkdownLink(link.midRef(0)); - } + static bool IsValidMarkdownLink(QStringView link); const QString &getLastText() const { return _lastTextWithTags.text; diff --git a/ui/widgets/labels.cpp b/ui/widgets/labels.cpp index dbeb2fc..1200bbf 100644 --- a/ui/widgets/labels.cpp +++ b/ui/widgets/labels.cpp @@ -13,6 +13,7 @@ #include "ui/widgets/box_content_divider.h" #include "ui/basic_click_handlers.h" // UrlClickHandler #include "ui/inactive_press.h" +#include "base/qt_adapters.h" #include #include @@ -491,7 +492,7 @@ void FlatLabel::mouseDoubleClickEvent(QMouseEvent *e) { } } -void FlatLabel::enterEventHook(QEvent *e) { +void FlatLabel::enterEventHook(QEnterEvent *e) { _lastMousePos = QCursor::pos(); dragActionUpdate(); } @@ -546,7 +547,7 @@ void FlatLabel::contextMenuEvent(QContextMenuEvent *e) { bool FlatLabel::eventHook(QEvent *e) { if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { QTouchEvent *ev = static_cast(e); - if (ev->device()->type() == QTouchDevice::TouchScreen) { + if (ev->device()->type() == base::TouchDevice::TouchScreen) { touchEvent(ev); return true; } diff --git a/ui/widgets/labels.h b/ui/widgets/labels.h index ddc2edf..d14a4db 100644 --- a/ui/widgets/labels.h +++ b/ui/widgets/labels.h @@ -154,7 +154,7 @@ protected: void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseDoubleClickEvent(QMouseEvent *e) override; - void enterEventHook(QEvent *e) override; + void enterEventHook(QEnterEvent *e) override; void leaveEventHook(QEvent *e) override; void focusOutEvent(QFocusEvent *e) override; void focusInEvent(QFocusEvent *e) override; diff --git a/ui/widgets/menu/menu_action.cpp b/ui/widgets/menu/menu_action.cpp index c174578..20af513 100644 --- a/ui/widgets/menu/menu_action.cpp +++ b/ui/widgets/menu/menu_action.cpp @@ -26,7 +26,7 @@ namespace { } else { result.entities.append(EntityInText{ EntityType::Underline, - result.text.size(), + int(result.text.size()), 1 }); result.text.append(ch); } diff --git a/ui/widgets/menu/menu_common.cpp b/ui/widgets/menu/menu_common.cpp index 7e29038..badc14c 100644 --- a/ui/widgets/menu/menu_common.cpp +++ b/ui/widgets/menu/menu_common.cpp @@ -6,7 +6,7 @@ // #include "ui/widgets/menu/menu_common.h" -#include +#include namespace Ui::Menu { diff --git a/ui/widgets/popup_menu.cpp b/ui/widgets/popup_menu.cpp index 6a7cc17..37faaaa 100644 --- a/ui/widgets/popup_menu.cpp +++ b/ui/widgets/popup_menu.cpp @@ -16,7 +16,6 @@ #include "ui/delayed_activation.h" #include "ui/painter.h" #include "base/platform/base_platform_info.h" -#include "base/qt_adapters.h" #include #include @@ -731,7 +730,7 @@ void PopupMenu::popup(const QPoint &p) { } void PopupMenu::showMenu(const QPoint &p, PopupMenu *parent, TriggeredSource source) { - const auto screen = base::QScreenNearestTo(p); + const auto screen = QGuiApplication::screenAt(p); if (!screen || (!parent && ::Platform::IsMac() && !Platform::IsApplicationActive())) { _hiding = false; diff --git a/ui/widgets/scroll_area.cpp b/ui/widgets/scroll_area.cpp index 8639388..b4b59e6 100644 --- a/ui/widgets/scroll_area.cpp +++ b/ui/widgets/scroll_area.cpp @@ -8,6 +8,7 @@ #include "ui/painter.h" #include "ui/ui_utility.h" +#include "base/qt_adapters.h" #include #include @@ -38,14 +39,18 @@ ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::ScrollArea *st) , _vertical(vert) , _hiding(_st->hiding != 0) , _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar()) -, _scrollMax(_connected->maximum()) { +, _scrollMax(_connected->maximum()) +, _hideTimer([=] { hideTimer(); }) { recountSize(); - _hideTimer.setSingleShot(true); - connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimer())); - - connect(_connected, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged())); - connect(_connected, SIGNAL(rangeChanged(int, int)), this, SLOT(onRangeChanged())); + connect(_connected, &QAbstractSlider::valueChanged, [=] { + area()->scrolled(); + updateBar(); + }); + connect(_connected, &QAbstractSlider::rangeChanged, [=] { + area()->innerResized(); + 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)); } -void ScrollBar::onValueChanged() { - area()->onScrolled(); - updateBar(); -} - -void ScrollBar::onRangeChanged() { - area()->onInnerResized(); - updateBar(); -} - void ScrollBar::updateBar(bool force) { QRect newBar; if (_connected->maximum() != _scrollMax) { @@ -76,8 +71,18 @@ void ScrollBar::updateBar(bool force) { if (h >= rh || !area()->scrollTopMax() || rh < _st->minHeight) { if (!isHidden()) hide(); bool newTopSh = (_st->topsh < 0), newBottomSh = (_st->bottomsh < 0); - if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh); - if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh); + if (newTopSh != _topSh || force) { + _shadowVisibilityChanged.fire({ + .type = ScrollShadow::Type::Top, + .visible = (_topSh = newTopSh), + }); + } + if (newBottomSh != _bottomSh || force) { + _shadowVisibilityChanged.fire({ + .type = ScrollShadow::Type::Bottom, + .visible = (_bottomSh = newBottomSh), + }); + } return; } @@ -105,13 +110,23 @@ void ScrollBar::updateBar(bool force) { } if (_vertical) { 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 (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh); + if (newTopSh != _topSh || force) { + _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(); } -void ScrollBar::onHideTimer() { +void ScrollBar::hideTimer() { if (!_hiding) { _hiding = true; _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); } if (!nowOver && _st->hiding && !_hiding) { - _hideTimer.start(_hideIn); + _hideTimer.callOnce(_hideIn); } } } @@ -202,12 +217,12 @@ void ScrollBar::hideTimeout(crl::time dt) { } _hideIn = dt; if (!_moving) { - _hideTimer.start(_hideIn); + _hideTimer.callOnce(_hideIn); } } -void ScrollBar::enterEventHook(QEvent *e) { - _hideTimer.stop(); +void ScrollBar::enterEventHook(QEnterEvent *e) { + _hideTimer.cancel(); setMouseTracking(true); setOver(true); } @@ -219,7 +234,7 @@ void ScrollBar::leaveEventHook(QEvent *e) { setOver(false); setOverBar(false); if (_st->hiding && !_hiding) { - _hideTimer.start(_hideIn); + _hideTimer.callOnce(_hideIn); } } @@ -252,7 +267,6 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) { } area()->setMovingByScrollBar(true); - area()->scrollStarted(); } void ScrollBar::mouseReleaseEvent(QMouseEvent *e) { @@ -260,7 +274,6 @@ void ScrollBar::mouseReleaseEvent(QMouseEvent *e) { setMoving(false); area()->setMovingByScrollBar(false); - area()->scrollFinished(); } if (!_over) { setMouseTracking(false); @@ -271,6 +284,11 @@ void ScrollBar::resizeEvent(QResizeEvent *e) { updateBar(); } +auto ScrollBar::shadowVisibilityChanged() const +-> rpl::producer { + return _shadowVisibilityChanged.events(); +} + ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handleTouch) : Parent(parent) , _st(st) @@ -282,8 +300,13 @@ ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handle setLayoutDirection(style::LayoutDirection()); setFocusPolicy(Qt::NoFocus); - connect(_verticalBar, SIGNAL(topShadowVisibility(bool)), _topShadow, SLOT(changeVisibility(bool))); - connect(_verticalBar, SIGNAL(bottomShadowVisibility(bool)), _bottomShadow, SLOT(changeVisibility(bool))); + _verticalBar->shadowVisibilityChanged( + ) | rpl::start_with_next([=](const ScrollBar::ShadowVisibility &data) { + ((data.type == ScrollShadow::Type::Top) + ? _topShadow + : _bottomShadow)->changeVisibility(data.visible); + }, lifetime()); + _verticalBar->updateBar(true); verticalScrollBar()->setSingleStep(style::ConvertScale(verticalScrollBar()->singleStep())); @@ -300,9 +323,8 @@ ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handle if (_touchEnabled) { viewport()->setAttribute(Qt::WA_AcceptTouchEvents); - _touchTimer.setSingleShot(true); - connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); - connect(&_touchScrollTimer, SIGNAL(timeout()), this, SLOT(onTouchScrollTimer())); + _touchTimer.setCallback([=] { _touchRightButton = true; }); + _touchScrollTimer.setCallback([=] { touchScrollTimer(); }); } } @@ -313,7 +335,7 @@ void ScrollArea::touchDeaccelerate(int32 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()) { SendPendingMoveResizeEvents(inner); } @@ -345,15 +367,15 @@ void ScrollArea::onScrolled() { } } if (em) { - scrolled(); + _scrolls.fire({}); if (!_movingByScrollBar) { SendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton); } } } -void ScrollArea::onInnerResized() { - innerResized(); +void ScrollArea::innerResized() { + _innerResizes.fire({}); } int ScrollArea::scrollWidth() const { @@ -382,11 +404,7 @@ int ScrollArea::scrollTop() const { return _verticalValue; } -void ScrollArea::onTouchTimer() { - _touchRightButton = true; -} - -void ScrollArea::onTouchScrollTimer() { +void ScrollArea::touchScrollTimer() { auto nowTime = crl::now(); if (_touchScrollState == TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) { _touchScrollState = TouchScrollState::Manual; @@ -399,7 +417,7 @@ void ScrollArea::onTouchScrollTimer() { if (_touchSpeed.isNull() || !hasScrolled) { _touchScrollState = TouchScrollState::Manual; _touchScroll = false; - _touchScrollTimer.stop(); + _touchScrollTimer.cancel(); } else { _touchTime = nowTime; } @@ -455,7 +473,7 @@ bool ScrollArea::eventFilter(QObject *obj, QEvent *e) { bool res = QScrollArea::eventFilter(obj, e); if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { QTouchEvent *ev = static_cast(e); - if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) { + if (_touchEnabled && ev->device()->type() == base::TouchDevice::TouchScreen) { if (obj == widget()) { touchEvent(ev); return true; @@ -468,7 +486,7 @@ bool ScrollArea::eventFilter(QObject *obj, QEvent *e) { bool ScrollArea::viewportEvent(QEvent *e) { if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { QTouchEvent *ev = static_cast(e); - if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) { + if (_touchEnabled && ev->device()->type() == base::TouchDevice::TouchScreen) { touchEvent(ev); return true; } @@ -494,7 +512,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) { _touchStart = _touchPos; } else { _touchScroll = false; - _touchTimer.start(QApplication::startDragTime()); + _touchTimer.callOnce(QApplication::startDragTime()); } _touchStart = _touchPrevPos = _touchPos; _touchRightButton = false; @@ -503,7 +521,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) { case QEvent::TouchUpdate: { if (!_touchPress) return; if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { - _touchTimer.stop(); + _touchTimer.cancel(); _touchScroll = true; touchUpdateSpeed(); } @@ -528,7 +546,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) { if (_touchScrollState == TouchScrollState::Manual) { _touchScrollState = TouchScrollState::Auto; _touchPrevPosValid = false; - _touchScrollTimer.start(15); + _touchScrollTimer.callEach(15); _touchTime = crl::now(); } else if (_touchScrollState == TouchScrollState::Auto) { _touchScrollState = TouchScrollState::Manual; @@ -555,7 +573,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) { } } if (weak) { - _touchTimer.stop(); + _touchTimer.cancel(); _touchRightButton = false; } } break; @@ -564,7 +582,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) { _touchPress = false; _touchScroll = false; _touchScrollState = TouchScrollState::Manual; - _touchTimer.stop(); + _touchTimer.cancel(); } break; } } @@ -604,12 +622,12 @@ void ScrollArea::resizeEvent(QResizeEvent *e) { _verticalBar->recountSize(); _topShadow->setGeometry(QRect(0, 0, width(), qAbs(_st.topsh))); _bottomShadow->setGeometry(QRect(0, height() - qAbs(_st.bottomsh), width(), qAbs(_st.bottomsh))); - geometryChanged(); + _geometryChanged.fire({}); } void ScrollArea::moveEvent(QMoveEvent *e) { QScrollArea::moveEvent(e); - geometryChanged(); + _geometryChanged.fire({}); } 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 (_st.hiding) { _horizontalBar->hideTimeout(_st.hiding); @@ -724,4 +742,16 @@ void ScrollArea::setMovingByScrollBar(bool 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 diff --git a/ui/widgets/scroll_area.h b/ui/widgets/scroll_area.h index c393a1c..e7143d9 100644 --- a/ui/widgets/scroll_area.h +++ b/ui/widgets/scroll_area.h @@ -9,10 +9,10 @@ #include "ui/rp_widget.h" #include "ui/effects/animations.h" #include "base/object_ptr.h" +#include "base/timer.h" #include "styles/style_widgets.h" #include -#include #include namespace Ui { @@ -48,15 +48,15 @@ struct ScrollToRequest { }; -class ScrollShadow : public QWidget { - Q_OBJECT - +class ScrollShadow final : public QWidget { public: + enum class Type { + Top, + Bottom, + }; ScrollShadow(ScrollArea *parent, const style::ScrollArea *st); void paintEvent(QPaintEvent *e); - -public Q_SLOTS: void changeVisibility(bool shown); private: @@ -65,9 +65,11 @@ private: }; class ScrollBar : public TWidget { - Q_OBJECT - public: + struct ShadowVisibility { + ScrollShadow::Type type; + bool visible = false; + }; ScrollBar(ScrollArea *parent, bool vertical, const style::ScrollArea *st); void recountSize(); @@ -75,18 +77,12 @@ public: void hideTimeout(crl::time dt); -private Q_SLOTS: - void onValueChanged(); - void onRangeChanged(); - void onHideTimer(); - -Q_SIGNALS: - void topShadowVisibility(bool); - void bottomShadowVisibility(bool); + [[nodiscard]] auto shadowVisibilityChanged() const + -> rpl::producer; protected: void paintEvent(QPaintEvent *e) override; - void enterEventHook(QEvent *e) override; + void enterEventHook(QEnterEvent *e) override; void leaveEventHook(QEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override; @@ -100,6 +96,8 @@ private: void setOverBar(bool overbar); void setMoving(bool moving); + void hideTimer(); + const style::ScrollArea *_st; bool _vertical = true; @@ -116,20 +114,20 @@ private: int32 _startFrom, _scrollMax; crl::time _hideIn = 0; - QTimer _hideTimer; + base::Timer _hideTimer; Animations::Simple _a_over; Animations::Simple _a_barOver; Animations::Simple _a_opacity; QRect _bar; + + rpl::event_stream _shadowVisibilityChanged; }; class ScrollArea : public RpWidgetBase { - Q_OBJECT - - using Parent = RpWidgetBase; public: + using Parent = RpWidgetBase; ScrollArea(QWidget *parent, const style::ScrollArea &st = st::defaultScrollArea, bool handleTouch = true); int scrollWidth() const; @@ -171,6 +169,15 @@ public: void scrollTo(ScrollToRequest request); void scrollToWidget(not_null 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: bool eventFilter(QObject *obj, QEvent *e) override; @@ -178,25 +185,9 @@ protected: void moveEvent(QMoveEvent *e) override; void touchEvent(QTouchEvent *e); - void enterEventHook(QEvent *e) override; + void enterEventHook(QEnterEvent *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: void scrollContentsBy(int dx, int dy) override; @@ -206,8 +197,8 @@ private: void setWidget(QWidget *widget); + void touchScrollTimer(); bool touchScroll(const QPoint &delta); - void touchScrollUpdated(const QPoint &screenPos); void touchResetSpeed(); @@ -223,7 +214,7 @@ private: int _horizontalValue, _verticalValue; bool _touchEnabled; - QTimer _touchTimer; + base::Timer _touchTimer; bool _touchScroll = false; bool _touchPress = false; bool _touchRightButton = false; @@ -236,13 +227,16 @@ private: crl::time _touchSpeedTime = 0; crl::time _touchAccelerationTime = 0; crl::time _touchTime = 0; - QTimer _touchScrollTimer; + base::Timer _touchScrollTimer; bool _widgetAcceptsTouch = false; object_ptr _widget = { nullptr }; rpl::event_stream _scrollTopUpdated; + rpl::event_stream<> _scrolls; + rpl::event_stream<> _innerResizes; + rpl::event_stream<> _geometryChanged; }; diff --git a/ui/widgets/time_input.cpp b/ui/widgets/time_input.cpp index aea09ca..d7f9cac 100644 --- a/ui/widgets/time_input.cpp +++ b/ui/widgets/time_input.cpp @@ -8,6 +8,7 @@ #include "ui/widgets/input_fields.h" #include "ui/ui_utility.h" +#include "base/qt_adapters.h" #include #include @@ -22,11 +23,11 @@ QTime ValidateTime(const QString &value) { return QTime(); } const auto readInt = [](const QString &value) { - auto ref = value.midRef(0); - while (!ref.isEmpty() && ref.at(0) == '0') { - ref = ref.mid(1); + auto view = QStringView(value); + while (!view.isEmpty() && view.at(0) == '0') { + view = base::StringViewMid(view, 1); } - return ref.toInt(); + return view.toInt(); }; return QTime(readInt(match.captured(1)), readInt(match.captured(2))); } @@ -78,12 +79,12 @@ private: std::optional Number(not_null field) { const auto text = field->getLastText(); - auto ref = text.midRef(0); - while (ref.size() > 1 && ref.at(0) == '0') { - ref = ref.mid(1); + auto view = QStringView(text); + while (view.size() > 1 && view.at(0) == '0') { + view = base::StringViewMid(view, 1); } - return QRegularExpression("^\\d+$").match(ref).hasMatch() - ? std::make_optional(ref.toInt()) + return QRegularExpression("^\\d+$").match(view).hasMatch() + ? std::make_optional(view.toInt()) : std::nullopt; } diff --git a/ui/widgets/tooltip.cpp b/ui/widgets/tooltip.cpp index 0b8baf3..83c3ebd 100644 --- a/ui/widgets/tooltip.cpp +++ b/ui/widgets/tooltip.cpp @@ -9,7 +9,6 @@ #include "ui/ui_utility.h" #include "ui/platform/ui_platform_utility.h" #include "base/invoke_queued.h" -#include "base/qt_adapters.h" #include "styles/style_widgets.h" #include @@ -73,7 +72,7 @@ Tooltip::~Tooltip() { } 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) { Hide(); return; diff --git a/ui/wrap/vertical_layout_reorder.cpp b/ui/wrap/vertical_layout_reorder.cpp index 7ddc773..e8f778b 100644 --- a/ui/wrap/vertical_layout_reorder.cpp +++ b/ui/wrap/vertical_layout_reorder.cpp @@ -260,8 +260,9 @@ void VerticalLayoutReorder::updateShift( ? indexHint : indexOf(widget); auto &entry = _entries[index]; - entry.shift = std::round(entry.shiftAnimation.value(entry.finalShift)) - + entry.deltaShift; + entry.shift = base::SafeRound( + entry.shiftAnimation.value(entry.finalShift) + ) + entry.deltaShift; if (entry.deltaShift && !entry.shiftAnimation.animating()) { entry.finalShift += entry.deltaShift; entry.deltaShift = 0;