Updated lib_ui sources to TDesktop version 2.7.1+c08a148
This commit is contained in:
commit
84a46ce773
39 changed files with 186 additions and 1237 deletions
|
|
@ -141,8 +141,6 @@ PRIVATE
|
|||
ui/widgets/buttons.h
|
||||
ui/widgets/call_button.cpp
|
||||
ui/widgets/call_button.h
|
||||
ui/widgets/call_mute_button.cpp
|
||||
ui/widgets/call_mute_button.h
|
||||
ui/widgets/checkbox.cpp
|
||||
ui/widgets/checkbox.h
|
||||
ui/widgets/dropdown_menu.cpp
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 963 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB |
|
|
@ -6,11 +6,11 @@
|
|||
//
|
||||
#pragma once
|
||||
|
||||
#include "ui/style/style_core.h"
|
||||
#include "base/basic_types.h"
|
||||
|
||||
#include "ui/style/style_core.h"
|
||||
|
||||
#include <QtGui/QPainterPath>
|
||||
#include <crl/crl_time.h>
|
||||
|
||||
namespace anim {
|
||||
|
||||
|
|
|
|||
|
|
@ -323,12 +323,12 @@ std::vector<QImage> LoadSprites(int id) {
|
|||
? internal::SetDataPath(id) + '/'
|
||||
: QStringLiteral(":/gui/emoji/");
|
||||
const auto base = folder + "emoji_";
|
||||
return ranges::view::ints(
|
||||
return ranges::views::ints(
|
||||
0,
|
||||
SpritesCount
|
||||
) | ranges::view::transform([&](int index) {
|
||||
) | ranges::views::transform([&](int index) {
|
||||
return base + QString::number(index + 1) + ".webp";
|
||||
}) | ranges::view::transform([](const QString &path) {
|
||||
}) | ranges::views::transform([](const QString &path) {
|
||||
return QImage(path, "WEBP").convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}) | ranges::to_vector;
|
||||
|
|
@ -343,15 +343,15 @@ std::vector<QImage> LoadAndValidateSprites(int id) {
|
|||
return {};
|
||||
}
|
||||
auto result = LoadSprites(id);
|
||||
const auto sizes = ranges::view::ints(
|
||||
const auto sizes = ranges::views::ints(
|
||||
0,
|
||||
SpritesCount
|
||||
) | ranges::view::transform([](int index) {
|
||||
) | ranges::views::transform([](int index) {
|
||||
return QSize(
|
||||
kImagesPerRow * kUniversalSize,
|
||||
RowsCount(index) * kUniversalSize);
|
||||
});
|
||||
const auto good = ranges::view::zip_with(
|
||||
const auto good = ranges::views::zip_with(
|
||||
[](const QImage &data, QSize size) { return data.size() == size; },
|
||||
result,
|
||||
sizes);
|
||||
|
|
@ -588,10 +588,10 @@ bool SetIsReady(int id) {
|
|||
return true;
|
||||
}
|
||||
const auto folder = internal::SetDataPath(id) + '/';
|
||||
auto names = ranges::view::ints(
|
||||
auto names = ranges::views::ints(
|
||||
0,
|
||||
SpritesCount + 1
|
||||
) | ranges::view::transform([](int index) {
|
||||
) | ranges::views::transform([](int index) {
|
||||
return index
|
||||
? "emoji_" + QString::number(index) + ".webp"
|
||||
: QString("config.json");
|
||||
|
|
|
|||
|
|
@ -274,8 +274,8 @@ QImage BlurLargeImage(QImage image, int radius) {
|
|||
const auto rgb = take(widthxheight * 3).data();
|
||||
const auto dvs = take(dvcount);
|
||||
|
||||
auto &&ints = ranges::view::ints;
|
||||
for (auto &&[value, index] : ranges::view::zip(dvs, ints(0, ranges::unreachable))) {
|
||||
auto &&ints = ranges::views::ints;
|
||||
for (auto &&[value, index] : ranges::views::zip(dvs, ints(0, ranges::unreachable))) {
|
||||
value = (index / divsum);
|
||||
}
|
||||
const auto dv = dvs.data();
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ public:
|
|||
|
||||
void scrollByDraggingDelta(int delta);
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void onScrollToY(int top, int bottom = -1);
|
||||
|
||||
protected:
|
||||
|
|
@ -260,7 +260,7 @@ protected:
|
|||
void paintEvent(QPaintEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void onScroll();
|
||||
void onInnerResize();
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ float ArcsAnimation::width() const {
|
|||
if (_arcs.empty()) {
|
||||
return 0;
|
||||
}
|
||||
for (const auto &arc : ranges::view::reverse(_arcs)) {
|
||||
for (const auto &arc : ranges::views::reverse(_arcs)) {
|
||||
if ((arc.progress != 1.)) {
|
||||
return arc.rect.x() + arc.rect.width();
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ float ArcsAnimation::finishedWidth() const {
|
|||
if (_arcs.empty()) {
|
||||
return 0;
|
||||
}
|
||||
for (const auto &arc : ranges::view::reverse(_arcs)) {
|
||||
for (const auto &arc : ranges::views::reverse(_arcs)) {
|
||||
if (arc.threshold <= _currentValue) {
|
||||
return arc.rect.x() + arc.rect.width();
|
||||
}
|
||||
|
|
@ -224,6 +224,7 @@ void ArcsAnimation::paint(Painter &p, std::optional<QColor> colorOverride) {
|
|||
: InterpolatedRect(arc.rect, previousRect, progress);
|
||||
p.drawArc(rect, _startAngle, _spanAngle);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
void ArcsAnimation::setStrokeRatio(float ratio) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
// private headers are using keywords :(
|
||||
#ifdef QT_NO_KEYWORDS
|
||||
#define signals Q_SIGNALS
|
||||
#define slots Q_SLOTS
|
||||
#endif // QT_NO_KEYWORDS
|
||||
|
||||
#include <private/qwaylanddisplay_p.h>
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <private/qwaylandshellsurface_p.h>
|
||||
|
|
|
|||
|
|
@ -32,10 +32,6 @@ namespace {
|
|||
|
||||
constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
|
||||
|
||||
constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs;
|
||||
constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs;
|
||||
constexpr auto kSettingsPortalInterface = "org.freedesktop.portal.Settings"_cs;
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
|
|
@ -161,23 +157,27 @@ bool TranslucentWindowsSupported(QPoint globalPosition) {
|
|||
if (::Platform::IsWayland()) {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
|
||||
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<int>();
|
||||
if (!WarnedAbout.contains(index)) {
|
||||
WarnedAbout.emplace(index);
|
||||
UI_LOG(("WARNING: Compositing is disabled for screen index %1 (for position %2,%3)").arg(index).arg(globalPosition.x()).arg(globalPosition.y()));
|
||||
}
|
||||
} else {
|
||||
UI_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);
|
||||
UI_LOG(("WARNING: Compositing is disabled for screen index %1 (for position %2,%3)").arg(index).arg(globalPosition.x()).arg(globalPosition.y()));
|
||||
}
|
||||
} else {
|
||||
UI_LOG(("WARNING: Could not get screen for position %1,%2").arg(globalPosition.x()).arg(globalPosition.y()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ bool WindowExtentsSupported() {
|
|||
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
namespace XCB = base::Platform::XCB;
|
||||
if (!::Platform::IsWayland()
|
||||
if (::Platform::IsX11()
|
||||
&& XCB::IsSupportedByWM(kXCBFrameExtentsAtomName.utf16())) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -210,13 +210,15 @@ bool SetWindowExtents(QWindow *window, const QMargins &extents) {
|
|||
#else // DESKTOP_APP_QT_PATCHED
|
||||
return false;
|
||||
#endif // !DESKTOP_APP_QT_PATCHED
|
||||
} else {
|
||||
} else if (::Platform::IsX11()) {
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return SetXCBFrameExtents(window, extents);
|
||||
#else // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return false;
|
||||
#endif // DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnsetWindowExtents(QWindow *window) {
|
||||
|
|
@ -227,28 +229,41 @@ bool UnsetWindowExtents(QWindow *window) {
|
|||
#else // DESKTOP_APP_QT_PATCHED
|
||||
return false;
|
||||
#endif // !DESKTOP_APP_QT_PATCHED
|
||||
} else {
|
||||
} else if (::Platform::IsX11()) {
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return UnsetXCBFrameExtents(window);
|
||||
#else // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return false;
|
||||
#endif // DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShowWindowMenu(QWindow *window) {
|
||||
if (const auto integration = WaylandIntegration::Instance()) {
|
||||
return integration->showWindowMenu(window);
|
||||
} else {
|
||||
} else if (::Platform::IsX11()) {
|
||||
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return ShowXCBWindowMenu(window);
|
||||
#else // !DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
return false;
|
||||
#endif // DESKTOP_APP_DISABLE_X11_INTEGRATION
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TitleControls::Layout TitleControlsLayout() {
|
||||
if (static auto Once = false; !std::exchange(Once, true)) {
|
||||
const auto integration = base::Platform::GtkIntegration::Instance();
|
||||
if (integration && integration->checkVersion(3, 12, 0)) {
|
||||
integration->connectToSetting(
|
||||
"gtk-decoration-layout",
|
||||
NotifyTitleControlsLayoutChanged);
|
||||
}
|
||||
}
|
||||
|
||||
const auto gtkResult = []() -> std::optional<TitleControls::Layout> {
|
||||
const auto integration = base::Platform::GtkIntegration::Instance();
|
||||
if (!integration || !integration->checkVersion(3, 12, 0)) {
|
||||
|
|
@ -257,7 +272,7 @@ TitleControls::Layout TitleControlsLayout() {
|
|||
|
||||
const auto decorationLayoutSetting = integration->getStringSetting(
|
||||
"gtk-decoration-layout");
|
||||
|
||||
|
||||
if (!decorationLayoutSetting.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,6 +385,11 @@ void WindowHelper::close() {
|
|||
}
|
||||
|
||||
void WindowHelper::init() {
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
Ui::ForceFullRepaint(window());
|
||||
}, window()->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
window()->sizeValue(),
|
||||
_title->heightValue(),
|
||||
|
|
|
|||
|
|
@ -122,29 +122,36 @@ void TitleControls::init(Fn<void(bool maximized)> maximize) {
|
|||
updateControlsPosition();
|
||||
}, _close->lifetime());
|
||||
|
||||
const auto winIdEventFilter = std::make_shared<QObject*>(nullptr);
|
||||
*winIdEventFilter = base::install_event_filter(
|
||||
window(),
|
||||
[=](not_null<QEvent*> e) {
|
||||
if (!*winIdEventFilter || e->type() != QEvent::WinIdChange) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
window()->windowHandle(),
|
||||
&QWindow::windowStateChanged,
|
||||
[=](Qt::WindowState state) {
|
||||
handleWindowStateChanged(state);
|
||||
});
|
||||
|
||||
base::take(*winIdEventFilter)->deleteLater();
|
||||
return base::EventFilterResult::Continue;
|
||||
});
|
||||
subscribeToStateChanges();
|
||||
|
||||
_activeState = parent()->isActiveWindow();
|
||||
updateButtonsState();
|
||||
}
|
||||
|
||||
void TitleControls::subscribeToStateChanges() {
|
||||
const auto subscribe = [=] {
|
||||
QObject::connect(
|
||||
window()->windowHandle(),
|
||||
&QWindow::windowStateChanged,
|
||||
[=](Qt::WindowState state) { handleWindowStateChanged(state); });
|
||||
};
|
||||
if (window()->windowHandle()) {
|
||||
subscribe();
|
||||
} else {
|
||||
const auto winIdEventFilter = std::make_shared<QObject*>(nullptr);
|
||||
*winIdEventFilter = base::install_event_filter(
|
||||
window(),
|
||||
[=](not_null<QEvent*> e) {
|
||||
if (!*winIdEventFilter || e->type() != QEvent::WinIdChange) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
subscribe();
|
||||
base::take(*winIdEventFilter)->deleteLater();
|
||||
return base::EventFilterResult::Continue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void TitleControls::setResizeEnabled(bool enabled) {
|
||||
_resizeEnabled = enabled;
|
||||
updateControlsPosition();
|
||||
|
|
@ -170,6 +177,23 @@ void TitleControls::updateControlsPosition() {
|
|||
const auto controlsLayout = TitleControlsLayout();
|
||||
auto controlsLeft = controlsLayout.left;
|
||||
auto controlsRight = controlsLayout.right;
|
||||
const auto moveFromTo = [&](auto &from, auto &to) {
|
||||
for (const auto control : from) {
|
||||
if (!ranges::contains(to, control)) {
|
||||
to.push_back(control);
|
||||
}
|
||||
}
|
||||
from.clear();
|
||||
};
|
||||
if (ranges::contains(controlsLeft, Control::Close)) {
|
||||
moveFromTo(controlsRight, controlsLeft);
|
||||
} else if (ranges::contains(controlsRight, Control::Close)) {
|
||||
moveFromTo(controlsLeft, controlsRight);
|
||||
} else if (controlsLeft.size() > controlsRight.size()) {
|
||||
moveFromTo(controlsRight, controlsLeft);
|
||||
} else {
|
||||
moveFromTo(controlsLeft, controlsRight);
|
||||
}
|
||||
|
||||
const auto controlPresent = [&](Control control) {
|
||||
return ranges::contains(controlsLeft, control)
|
||||
|
|
@ -216,7 +240,7 @@ void TitleControls::updateControlsPositionBySide(
|
|||
const std::vector<Control> &controls,
|
||||
bool right) {
|
||||
auto preparedControls = right
|
||||
? (ranges::view::reverse(controls) | ranges::to_vector)
|
||||
? (ranges::views::reverse(controls) | ranges::to_vector)
|
||||
: controls;
|
||||
|
||||
RemoveDuplicates(preparedControls);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ private:
|
|||
[[nodiscard]] Ui::IconButton *controlWidget(Control control) const;
|
||||
|
||||
void init(Fn<void(bool maximized)> maximize);
|
||||
void subscribeToStateChanges();
|
||||
void updateButtonsState();
|
||||
void updateControlsPosition();
|
||||
void updateControlsPositionBySide(
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ void WindowHelper::init() {
|
|||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
_shadow.setColor(st::windowShadowFg->c);
|
||||
Ui::ForceFullRepaint(window());
|
||||
}, window()->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
|
|
@ -350,7 +351,7 @@ bool WindowHelper::handleNativeEvent(
|
|||
} else if (wParam == SIZE_MINIMIZED) {
|
||||
state = Qt::WindowMinimized;
|
||||
}
|
||||
emit window()->windowHandle()->windowStateChanged(state);
|
||||
window()->windowHandle()->windowStateChanged(state);
|
||||
}
|
||||
updateMargins();
|
||||
const auto changes = (wParam == SIZE_MINIMIZED
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ bool ValidateFont(const QString &familyName, int flags = 0) {
|
|||
checkFont.setUnderline(flags & style::internal::FontUnderline);
|
||||
auto realFamily = QFontInfo(checkFont).family();
|
||||
if (realFamily.trimmed().compare(familyName, Qt::CaseInsensitive)) {
|
||||
UI_LOG(("Font Error: could not resolve '%1' font, got '%2'.").arg(familyName).arg(realFamily));
|
||||
UI_LOG(("Font Error: could not resolve '%1' font, got '%2'.").arg(familyName, realFamily));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag
|
|||
|
||||
const auto found = [&] {
|
||||
for (auto &family : QFontDatabase::applicationFontFamilies(regularId)) {
|
||||
UI_LOG(("Font: from '%1' loaded '%2'").arg(filePath).arg(family));
|
||||
UI_LOG(("Font: from '%1' loaded '%2'").arg(filePath, family));
|
||||
if (!family.trimmed().compare(familyName, Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag
|
|||
return false;
|
||||
}();
|
||||
if (!found) {
|
||||
UI_LOG(("Font Error: could not locate '%1' font in '%2'.").arg(familyName).arg(filePath));
|
||||
UI_LOG(("Font Error: could not locate '%1' font in '%2'.").arg(familyName, filePath));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ QString MonospaceFont() {
|
|||
}
|
||||
|
||||
void destroyFonts() {
|
||||
for (auto fontData : fontsMap) {
|
||||
for (auto fontData : std::as_const(fontsMap)) {
|
||||
delete fontData;
|
||||
}
|
||||
fontsMap.clear();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ uint32 colorKey(QColor c) {
|
|||
return (((((uint32(c.red()) << 8) | uint32(c.green())) << 8) | uint32(c.blue())) << 8) | uint32(c.alpha());
|
||||
}
|
||||
|
||||
QMap<const IconMask*, QImage> iconMasks;
|
||||
base::flat_map<const IconMask*, QImage> iconMasks;
|
||||
QMap<QPair<const IconMask*, uint32>, QPixmap> iconPixmaps;
|
||||
OrderedSet<IconData*> iconData;
|
||||
|
||||
|
|
@ -251,11 +251,11 @@ void MonoIcon::ensureLoaded() const {
|
|||
|
||||
_size = readGeneratedSize(_mask, Scale());
|
||||
if (_size.isEmpty()) {
|
||||
auto i = iconMasks.constFind(_mask);
|
||||
auto i = iconMasks.find(_mask);
|
||||
if (i == iconMasks.cend()) {
|
||||
i = iconMasks.insert(_mask, createIconMask(_mask, Scale()));
|
||||
i = iconMasks.emplace(_mask, createIconMask(_mask, Scale())).first;
|
||||
}
|
||||
_maskImage = i.value();
|
||||
_maskImage = i->second;
|
||||
|
||||
createCachedPixmap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1146,7 +1146,7 @@ const QRegularExpression &RegExpWordSplit() {
|
|||
auto &&urls = ranges::make_subrange(
|
||||
entities.begin(),
|
||||
entities.end()
|
||||
) | ranges::view::filter([](const EntityInText &entity) {
|
||||
) | ranges::views::filter([](const EntityInText &entity) {
|
||||
return entity.type() == EntityType::CustomUrl;
|
||||
});
|
||||
const auto &original = text.text;
|
||||
|
|
@ -2146,7 +2146,7 @@ int EntityInText::FirstMonospaceOffset(
|
|||
auto &&monospace = ranges::make_subrange(
|
||||
entities.begin(),
|
||||
entities.end()
|
||||
) | ranges::view::filter([](const EntityInText & entity) {
|
||||
) | ranges::views::filter([](const EntityInText & entity) {
|
||||
return (entity.type() == EntityType::Pre)
|
||||
|| (entity.type() == EntityType::Code);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,962 +0,0 @@
|
|||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "ui/widgets/call_mute_button.h"
|
||||
|
||||
#include "base/flat_map.h"
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/paint/blobs.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/widgets/call_button.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
||||
#include "styles/palette.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtCore/QtMath>
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
using Radiuses = Paint::Blob::Radiuses;
|
||||
|
||||
constexpr auto kMaxLevel = 1.;
|
||||
|
||||
constexpr auto kLevelDuration = 100. + 500. * 0.33;
|
||||
|
||||
constexpr auto kScaleBig = 0.807 - 0.1;
|
||||
constexpr auto kScaleSmall = 0.704 - 0.1;
|
||||
|
||||
constexpr auto kScaleBigMin = 0.878;
|
||||
constexpr auto kScaleSmallMin = 0.926;
|
||||
|
||||
constexpr auto kScaleBigMax = (float)(kScaleBigMin + kScaleBig);
|
||||
constexpr auto kScaleSmallMax = (float)(kScaleSmallMin + kScaleSmall);
|
||||
|
||||
constexpr auto kMainRadiusFactor = (float)(50. / 57.);
|
||||
|
||||
constexpr auto kGlowPaddingFactor = 1.2;
|
||||
constexpr auto kGlowMinScale = 0.6;
|
||||
constexpr auto kGlowAlpha = 150;
|
||||
|
||||
constexpr auto kOverrideColorBgAlpha = 76;
|
||||
constexpr auto kOverrideColorRippleAlpha = 50;
|
||||
|
||||
constexpr auto kShiftDuration = crl::time(300);
|
||||
constexpr auto kSwitchStateDuration = crl::time(120);
|
||||
constexpr auto kSwitchLabelDuration = crl::time(180);
|
||||
|
||||
// Switch state from Connecting animation.
|
||||
constexpr auto kSwitchRadialDuration = crl::time(350);
|
||||
constexpr auto kSwitchCirclelDuration = crl::time(275);
|
||||
constexpr auto kBlobsScaleEnterDuration = crl::time(400);
|
||||
constexpr auto kSwitchStateFromConnectingDuration = kSwitchRadialDuration
|
||||
+ kSwitchCirclelDuration
|
||||
+ kBlobsScaleEnterDuration;
|
||||
|
||||
constexpr auto kRadialEndPartAnimation = float(kSwitchRadialDuration)
|
||||
/ kSwitchStateFromConnectingDuration;
|
||||
constexpr auto kBlobsWidgetPartAnimation = 1. - kRadialEndPartAnimation;
|
||||
constexpr auto kFillCirclePartAnimation = float(kSwitchCirclelDuration)
|
||||
/ (kSwitchCirclelDuration + kBlobsScaleEnterDuration);
|
||||
constexpr auto kBlobPartAnimation = float(kBlobsScaleEnterDuration)
|
||||
/ (kSwitchCirclelDuration + kBlobsScaleEnterDuration);
|
||||
|
||||
constexpr auto kOverlapProgressRadialHide = 1.2;
|
||||
|
||||
constexpr auto kRadialFinishArcShift = 1200;
|
||||
|
||||
auto MuteBlobs() {
|
||||
return std::vector<Paint::Blobs::BlobData>{
|
||||
{
|
||||
.segmentsCount = 9,
|
||||
.minScale = kScaleSmallMin / kScaleSmallMax,
|
||||
.minRadius = st::callMuteMinorBlobMinRadius
|
||||
* kScaleSmallMax
|
||||
* kMainRadiusFactor,
|
||||
.maxRadius = st::callMuteMinorBlobMaxRadius
|
||||
* kScaleSmallMax
|
||||
* kMainRadiusFactor,
|
||||
.speedScale = 1.,
|
||||
.alpha = (76. / 255.),
|
||||
},
|
||||
{
|
||||
.segmentsCount = 12,
|
||||
.minScale = kScaleBigMin / kScaleBigMax,
|
||||
.minRadius = st::callMuteMajorBlobMinRadius
|
||||
* kScaleBigMax
|
||||
* kMainRadiusFactor,
|
||||
.maxRadius = st::callMuteMajorBlobMaxRadius
|
||||
* kScaleBigMax
|
||||
* kMainRadiusFactor,
|
||||
.speedScale = 1.,
|
||||
.alpha = (76. / 255.),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
auto Colors() {
|
||||
using Vector = std::vector<QColor>;
|
||||
using Colors = anim::gradient_colors;
|
||||
return base::flat_map<CallMuteButtonType, Colors>{
|
||||
{
|
||||
CallMuteButtonType::ForceMuted,
|
||||
Colors(QGradientStops{
|
||||
{ .0, st::groupCallForceMuted1->c },
|
||||
{ .5, st::groupCallForceMuted2->c },
|
||||
{ 1., st::groupCallForceMuted3->c } })
|
||||
},
|
||||
{
|
||||
CallMuteButtonType::Active,
|
||||
Colors(Vector{ st::groupCallLive1->c, st::groupCallLive2->c })
|
||||
},
|
||||
{
|
||||
CallMuteButtonType::Connecting,
|
||||
Colors(st::callIconBg->c)
|
||||
},
|
||||
{
|
||||
CallMuteButtonType::Muted,
|
||||
Colors(Vector{ st::groupCallMuted1->c, st::groupCallMuted2->c })
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
bool IsMuted(CallMuteButtonType type) {
|
||||
return (type != CallMuteButtonType::Active);
|
||||
}
|
||||
|
||||
bool IsConnecting(CallMuteButtonType type) {
|
||||
return (type == CallMuteButtonType::Connecting);
|
||||
}
|
||||
|
||||
bool IsInactive(CallMuteButtonType type) {
|
||||
return IsConnecting(type) || (type == CallMuteButtonType::ForceMuted);
|
||||
}
|
||||
|
||||
auto Clamp(float64 value) {
|
||||
return std::clamp(value, 0., 1.);
|
||||
}
|
||||
|
||||
void ComputeRadialFinish(
|
||||
int &value,
|
||||
float64 progress,
|
||||
int to = -RadialState::kFull) {
|
||||
value = anim::interpolate(value, to, Clamp(progress));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class AnimatedLabel final : public RpWidget {
|
||||
public:
|
||||
AnimatedLabel(
|
||||
QWidget *parent,
|
||||
rpl::producer<QString> &&text,
|
||||
crl::time duration,
|
||||
int additionalHeight,
|
||||
const style::FlatLabel &st = st::defaultFlatLabel);
|
||||
|
||||
int height() const;
|
||||
|
||||
private:
|
||||
int realHeight() const;
|
||||
|
||||
void setText(const QString &text);
|
||||
|
||||
const style::FlatLabel &_st;
|
||||
const crl::time _duration;
|
||||
const int _additionalHeight;
|
||||
const TextParseOptions _options;
|
||||
|
||||
Text::String _text;
|
||||
Text::String _previousText;
|
||||
|
||||
Animations::Simple _animation;
|
||||
|
||||
};
|
||||
|
||||
AnimatedLabel::AnimatedLabel(
|
||||
QWidget *parent,
|
||||
rpl::producer<QString> &&text,
|
||||
crl::time duration,
|
||||
int additionalHeight,
|
||||
const style::FlatLabel &st)
|
||||
: RpWidget(parent)
|
||||
, _st(st)
|
||||
, _duration(duration)
|
||||
, _additionalHeight(additionalHeight)
|
||||
, _options({ 0, 0, 0, Qt::LayoutDirectionAuto }) {
|
||||
std::move(
|
||||
text
|
||||
) | rpl::start_with_next([=](const QString &value) {
|
||||
setText(value);
|
||||
}, lifetime());
|
||||
|
||||
paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
Painter p(this);
|
||||
const auto progress = _animation.value(1.);
|
||||
|
||||
p.setFont(_st.style.font);
|
||||
p.setPen(_st.textFg);
|
||||
p.setTextPalette(_st.palette);
|
||||
|
||||
const auto textHeight = height();
|
||||
const auto diffHeight = realHeight() - textHeight;
|
||||
const auto center = (diffHeight) / 2;
|
||||
|
||||
p.setOpacity(1. - progress);
|
||||
if (p.opacity()) {
|
||||
_previousText.draw(
|
||||
p,
|
||||
0,
|
||||
anim::interpolate(center, diffHeight, progress),
|
||||
width(),
|
||||
style::al_center);
|
||||
}
|
||||
|
||||
p.setOpacity(progress);
|
||||
if (p.opacity()) {
|
||||
_text.draw(
|
||||
p,
|
||||
0,
|
||||
anim::interpolate(0, center, progress),
|
||||
width(),
|
||||
style::al_center);
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
int AnimatedLabel::height() const {
|
||||
return _st.style.font->height;
|
||||
}
|
||||
|
||||
int AnimatedLabel::realHeight() const {
|
||||
return RpWidget::height();
|
||||
}
|
||||
|
||||
void AnimatedLabel::setText(const QString &text) {
|
||||
if (_text.toString() == text) {
|
||||
return;
|
||||
}
|
||||
_previousText = _text;
|
||||
_text.setText(_st.style, text, _options);
|
||||
|
||||
const auto width = std::max(
|
||||
_st.style.font->width(_text.toString()),
|
||||
_st.style.font->width(_previousText.toString()));
|
||||
resize(width + _additionalHeight, height() + _additionalHeight * 2);
|
||||
|
||||
_animation.stop();
|
||||
_animation.start([=] { update(); }, 0., 1., _duration);
|
||||
}
|
||||
|
||||
class BlobsWidget final : public RpWidget {
|
||||
public:
|
||||
BlobsWidget(
|
||||
not_null<RpWidget*> parent,
|
||||
rpl::producer<bool> &&hideBlobs);
|
||||
|
||||
void setLevel(float level);
|
||||
void setBlobBrush(QBrush brush);
|
||||
void setGlowBrush(QBrush brush);
|
||||
|
||||
[[nodiscard]] QRectF innerRect() const;
|
||||
|
||||
[[nodiscard]] float64 switchConnectingProgress() const;
|
||||
void setSwitchConnectingProgress(float64 progress);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
Paint::Blobs _blobs;
|
||||
|
||||
const float _circleRadius;
|
||||
QBrush _blobBrush;
|
||||
QBrush _glowBrush;
|
||||
int _center = 0;
|
||||
QRectF _circleRect;
|
||||
|
||||
float64 _switchConnectingProgress = 0.;
|
||||
|
||||
crl::time _blobsLastTime = 0;
|
||||
crl::time _blobsHideLastTime = 0;
|
||||
|
||||
float64 _blobsScaleEnter = 0.;
|
||||
crl::time _blobsScaleLastTime = 0;
|
||||
|
||||
bool _hideBlobs = true;
|
||||
|
||||
Animations::Basic _animation;
|
||||
|
||||
};
|
||||
|
||||
BlobsWidget::BlobsWidget(
|
||||
not_null<RpWidget*> parent,
|
||||
rpl::producer<bool> &&hideBlobs)
|
||||
: RpWidget(parent)
|
||||
, _blobs(MuteBlobs(), kLevelDuration, kMaxLevel)
|
||||
, _circleRadius(st::callMuteButtonActive.bgSize / 2.)
|
||||
, _blobBrush(Qt::transparent)
|
||||
, _glowBrush(Qt::transparent)
|
||||
, _blobsLastTime(crl::now())
|
||||
, _blobsScaleLastTime(crl::now()) {
|
||||
init();
|
||||
|
||||
std::move(
|
||||
hideBlobs
|
||||
) | rpl::start_with_next([=](bool hide) {
|
||||
if (_hideBlobs != hide) {
|
||||
const auto now = crl::now();
|
||||
if ((now - _blobsScaleLastTime) >= kBlobsScaleEnterDuration) {
|
||||
_blobsScaleLastTime = now;
|
||||
}
|
||||
_hideBlobs = hide;
|
||||
}
|
||||
if (hide) {
|
||||
setLevel(0.);
|
||||
}
|
||||
_blobsHideLastTime = hide ? crl::now() : 0;
|
||||
if (!hide && !_animation.animating()) {
|
||||
_animation.start();
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void BlobsWidget::init() {
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
const auto cutRect = [](Painter &p, const QRectF &r) {
|
||||
p.save();
|
||||
p.setOpacity(1.);
|
||||
p.setBrush(st::groupCallBg);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.drawEllipse(r);
|
||||
p.restore();
|
||||
};
|
||||
|
||||
{
|
||||
const auto s = _blobs.maxRadius() * 2 * kGlowPaddingFactor;
|
||||
resize(s, s);
|
||||
}
|
||||
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
_center = size.width() / 2;
|
||||
|
||||
{
|
||||
const auto &r = _circleRadius;
|
||||
const auto left = (size.width() - r * 2.) / 2.;
|
||||
const auto add = st::callConnectingRadial.thickness / 2;
|
||||
_circleRect = QRectF(left, left, r * 2, r * 2).marginsAdded(
|
||||
style::margins(add, add, add, add));
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
Painter p(this);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
// Glow.
|
||||
const auto s = kGlowMinScale
|
||||
+ (1. - kGlowMinScale) * _blobs.currentLevel();
|
||||
p.translate(_center, _center);
|
||||
p.scale(s, s);
|
||||
p.translate(-_center, -_center);
|
||||
p.fillRect(rect(), _glowBrush);
|
||||
p.resetTransform();
|
||||
|
||||
// Blobs.
|
||||
p.translate(_center, _center);
|
||||
const auto scale = (_switchConnectingProgress > 0.)
|
||||
? anim::easeOutBack(
|
||||
1.,
|
||||
_blobsScaleEnter * (1. - Clamp(
|
||||
_switchConnectingProgress / kBlobPartAnimation)))
|
||||
: _blobsScaleEnter;
|
||||
_blobs.paint(p, _blobBrush, scale);
|
||||
p.translate(-_center, -_center);
|
||||
|
||||
if (scale < 1.) {
|
||||
cutRect(p, _circleRect);
|
||||
}
|
||||
|
||||
// Main circle.
|
||||
const auto circleProgress =
|
||||
Clamp(_switchConnectingProgress - kBlobPartAnimation)
|
||||
/ kFillCirclePartAnimation;
|
||||
const auto skipColoredCircle = (circleProgress == 1.);
|
||||
|
||||
if (!skipColoredCircle) {
|
||||
p.setBrush(_blobBrush);
|
||||
p.drawEllipse(_circleRect);
|
||||
}
|
||||
|
||||
if (_switchConnectingProgress > 0.) {
|
||||
p.resetTransform();
|
||||
|
||||
const auto mF = (_circleRect.width() / 2) * (1. - circleProgress);
|
||||
const auto cutOutRect = _circleRect.marginsRemoved(
|
||||
QMarginsF(mF, mF, mF, mF));
|
||||
|
||||
if (!skipColoredCircle) {
|
||||
p.setBrush(st::callConnectingRadial.color);
|
||||
p.setOpacity(circleProgress);
|
||||
p.drawEllipse(_circleRect);
|
||||
}
|
||||
|
||||
p.setOpacity(1.);
|
||||
|
||||
cutRect(p, cutOutRect);
|
||||
|
||||
p.setBrush(st::callIconBg);
|
||||
p.drawEllipse(cutOutRect);
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
_animation.init([=](crl::time now) {
|
||||
if (const auto &last = _blobsHideLastTime; (last > 0)
|
||||
&& (now - last >= kBlobsScaleEnterDuration)) {
|
||||
_animation.stop();
|
||||
return false;
|
||||
}
|
||||
_blobs.updateLevel(now - _blobsLastTime);
|
||||
_blobsLastTime = now;
|
||||
|
||||
const auto dt = Clamp(
|
||||
(now - _blobsScaleLastTime) / float64(kBlobsScaleEnterDuration));
|
||||
_blobsScaleEnter = _hideBlobs
|
||||
? (1. - anim::easeInCirc(1., dt))
|
||||
: anim::easeOutBack(1., dt);
|
||||
|
||||
update();
|
||||
return true;
|
||||
});
|
||||
shownValue(
|
||||
) | rpl::start_with_next([=](bool shown) {
|
||||
if (shown) {
|
||||
_animation.start();
|
||||
} else {
|
||||
_animation.stop();
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
QRectF BlobsWidget::innerRect() const {
|
||||
return _circleRect;
|
||||
}
|
||||
|
||||
void BlobsWidget::setBlobBrush(QBrush brush) {
|
||||
if (_blobBrush == brush) {
|
||||
return;
|
||||
}
|
||||
_blobBrush = brush;
|
||||
}
|
||||
|
||||
void BlobsWidget::setGlowBrush(QBrush brush) {
|
||||
if (_glowBrush == brush) {
|
||||
return;
|
||||
}
|
||||
_glowBrush = brush;
|
||||
}
|
||||
|
||||
void BlobsWidget::setLevel(float level) {
|
||||
if (_blobsHideLastTime) {
|
||||
return;
|
||||
}
|
||||
_blobs.setLevel(level);
|
||||
}
|
||||
|
||||
float64 BlobsWidget::switchConnectingProgress() const {
|
||||
return _switchConnectingProgress;
|
||||
}
|
||||
|
||||
void BlobsWidget::setSwitchConnectingProgress(float64 progress) {
|
||||
_switchConnectingProgress = progress;
|
||||
}
|
||||
|
||||
CallMuteButton::CallMuteButton(
|
||||
not_null<RpWidget*> parent,
|
||||
rpl::producer<bool> &&hideBlobs,
|
||||
CallMuteButtonState initial)
|
||||
: _state(initial)
|
||||
, _st(st::callMuteButtonActive)
|
||||
, _blobs(base::make_unique_q<BlobsWidget>(
|
||||
parent,
|
||||
rpl::combine(
|
||||
rpl::single(anim::Disabled()) | rpl::then(anim::Disables()),
|
||||
std::move(hideBlobs),
|
||||
_state.value(
|
||||
) | rpl::map([](const CallMuteButtonState &state) {
|
||||
return IsInactive(state.type);
|
||||
})
|
||||
) | rpl::map([](bool animDisabled, bool hide, bool isBadState) {
|
||||
return isBadState || !(!animDisabled && !hide);
|
||||
})))
|
||||
, _content(base::make_unique_q<AbstractButton>(parent))
|
||||
, _centerLabel(base::make_unique_q<AnimatedLabel>(
|
||||
parent,
|
||||
_state.value(
|
||||
) | rpl::map([](const CallMuteButtonState &state) {
|
||||
return state.subtext.isEmpty() ? state.text : QString();
|
||||
}),
|
||||
kSwitchLabelDuration,
|
||||
st::callMuteButtonLabelAdditional,
|
||||
_st.label))
|
||||
, _label(base::make_unique_q<AnimatedLabel>(
|
||||
parent,
|
||||
_state.value(
|
||||
) | rpl::map([](const CallMuteButtonState &state) {
|
||||
return state.subtext.isEmpty() ? QString() : state.text;
|
||||
}),
|
||||
kSwitchLabelDuration,
|
||||
st::callMuteButtonLabelAdditional,
|
||||
_st.label))
|
||||
, _sublabel(base::make_unique_q<AnimatedLabel>(
|
||||
parent,
|
||||
_state.value(
|
||||
) | rpl::map([](const CallMuteButtonState &state) {
|
||||
return state.subtext;
|
||||
}),
|
||||
kSwitchLabelDuration,
|
||||
st::callMuteButtonLabelAdditional,
|
||||
st::callMuteButtonSublabel))
|
||||
, _radial(nullptr)
|
||||
, _colors(Colors())
|
||||
, _crossLineMuteAnimation(st::callMuteCrossLine) {
|
||||
init();
|
||||
}
|
||||
|
||||
void CallMuteButton::init() {
|
||||
_content->resize(_st.button.width, _st.button.height);
|
||||
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
_crossLineMuteAnimation.invalidate();
|
||||
}, lifetime());
|
||||
|
||||
// Label text.
|
||||
_label->show();
|
||||
rpl::combine(
|
||||
_content->geometryValue(),
|
||||
_label->sizeValue()
|
||||
) | rpl::start_with_next([=](QRect my, QSize size) {
|
||||
updateLabelGeometry(my, size);
|
||||
}, _label->lifetime());
|
||||
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
_sublabel->show();
|
||||
rpl::combine(
|
||||
_content->geometryValue(),
|
||||
_sublabel->sizeValue()
|
||||
) | rpl::start_with_next([=](QRect my, QSize size) {
|
||||
updateSublabelGeometry(my, size);
|
||||
}, _sublabel->lifetime());
|
||||
_sublabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
_centerLabel->show();
|
||||
rpl::combine(
|
||||
_content->geometryValue(),
|
||||
_centerLabel->sizeValue()
|
||||
) | rpl::start_with_next([=](QRect my, QSize size) {
|
||||
updateCenterLabelGeometry(my, size);
|
||||
}, _centerLabel->lifetime());
|
||||
_centerLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
rpl::combine(
|
||||
_radialInfo.rawShowProgress.value(),
|
||||
anim::Disables()
|
||||
) | rpl::start_with_next([=](float64 value, bool disabled) {
|
||||
auto &info = _radialInfo;
|
||||
info.realShowProgress = (1. - value) / kRadialEndPartAnimation;
|
||||
|
||||
const auto guard = gsl::finally([&] {
|
||||
_content->update();
|
||||
});
|
||||
|
||||
if (((value == 0.) || disabled) && _radial) {
|
||||
_radial->stop();
|
||||
_radial = nullptr;
|
||||
return;
|
||||
}
|
||||
if ((value > 0.) && !disabled && !_radial) {
|
||||
_radial = std::make_unique<InfiniteRadialAnimation>(
|
||||
[=] { _content->update(); },
|
||||
_radialInfo.st);
|
||||
_radial->start();
|
||||
}
|
||||
if ((info.realShowProgress < 1.) && !info.isDirectionToShow) {
|
||||
if (_radial) {
|
||||
_radial->stop(anim::type::instant);
|
||||
_radial->start();
|
||||
}
|
||||
info.state = std::nullopt;
|
||||
return;
|
||||
}
|
||||
|
||||
if (value == 1.) {
|
||||
info.state = std::nullopt;
|
||||
} else {
|
||||
if (_radial && !info.state.has_value()) {
|
||||
info.state = _radial->computeState();
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
// State type.
|
||||
const auto previousType =
|
||||
lifetime().make_state<CallMuteButtonType>(_state.current().type);
|
||||
setHandleMouseState(HandleMouseState::Disabled);
|
||||
|
||||
const auto blobsInner = [&] {
|
||||
// The point of the circle at 45 degrees.
|
||||
const auto w = _blobs->innerRect().width();
|
||||
const auto mF = (1 - std::cos(M_PI / 4.)) * (w / 2.);
|
||||
return _blobs->innerRect().marginsRemoved(QMarginsF(mF, mF, mF, mF));
|
||||
}();
|
||||
|
||||
auto linearGradients = anim::linear_gradients<CallMuteButtonType>(
|
||||
_colors,
|
||||
QPointF(blobsInner.x() + blobsInner.width(), blobsInner.y()),
|
||||
QPointF(blobsInner.x(), blobsInner.y() + blobsInner.height()));
|
||||
|
||||
auto glowColors = [&] {
|
||||
auto copy = _colors;
|
||||
for (auto &[type, stops] : copy) {
|
||||
auto firstColor = IsInactive(type)
|
||||
? st::groupCallBg->c
|
||||
: stops.stops[0].second;
|
||||
firstColor.setAlpha(kGlowAlpha);
|
||||
stops.stops = QGradientStops{
|
||||
{ 0., std::move(firstColor) },
|
||||
{ 1., QColor(Qt::transparent) }
|
||||
};
|
||||
}
|
||||
return copy;
|
||||
}();
|
||||
auto glows = anim::radial_gradients<CallMuteButtonType>(
|
||||
std::move(glowColors),
|
||||
blobsInner.center(),
|
||||
_blobs->width() / 2);
|
||||
|
||||
_state.value(
|
||||
) | rpl::map([](const CallMuteButtonState &state) {
|
||||
return state.type;
|
||||
}) | rpl::start_with_next([=](CallMuteButtonType type) {
|
||||
const auto previous = *previousType;
|
||||
*previousType = type;
|
||||
|
||||
const auto mouseState = HandleMouseStateFromType(type);
|
||||
setHandleMouseState(HandleMouseState::Disabled);
|
||||
if (mouseState != HandleMouseState::Enabled) {
|
||||
setHandleMouseState(mouseState);
|
||||
}
|
||||
|
||||
const auto fromConnecting = IsConnecting(previous);
|
||||
const auto toConnecting = IsConnecting(type);
|
||||
|
||||
const auto crossFrom = IsMuted(previous) ? 0. : 1.;
|
||||
const auto crossTo = IsMuted(type) ? 0. : 1.;
|
||||
|
||||
const auto radialShowFrom = fromConnecting ? 1. : 0.;
|
||||
const auto radialShowTo = toConnecting ? 1. : 0.;
|
||||
|
||||
const auto from = (_switchAnimation.animating() && !fromConnecting)
|
||||
? (1. - _switchAnimation.value(0.))
|
||||
: 0.;
|
||||
const auto to = 1.;
|
||||
|
||||
_radialInfo.isDirectionToShow = fromConnecting;
|
||||
|
||||
auto callback = [=](float64 value) {
|
||||
const auto brushProgress = fromConnecting ? 1. : value;
|
||||
_blobs->setBlobBrush(QBrush(
|
||||
linearGradients.gradient(previous, type, brushProgress)));
|
||||
_blobs->setGlowBrush(QBrush(
|
||||
glows.gradient(previous, type, value)));
|
||||
_blobs->update();
|
||||
|
||||
const auto crossProgress = (crossFrom == crossTo)
|
||||
? crossTo
|
||||
: anim::interpolateF(crossFrom, crossTo, value);
|
||||
if (crossProgress != _crossLineProgress) {
|
||||
_crossLineProgress = crossProgress;
|
||||
_content->update(_muteIconRect);
|
||||
}
|
||||
|
||||
const auto radialShowProgress = (radialShowFrom == radialShowTo)
|
||||
? radialShowTo
|
||||
: anim::interpolateF(radialShowFrom, radialShowTo, value);
|
||||
if (radialShowProgress != _radialInfo.rawShowProgress.current()) {
|
||||
_radialInfo.rawShowProgress = radialShowProgress;
|
||||
_blobs->setSwitchConnectingProgress(Clamp(
|
||||
radialShowProgress / kBlobsWidgetPartAnimation));
|
||||
}
|
||||
|
||||
overridesColors(previous, type, value);
|
||||
|
||||
if (value == to) {
|
||||
setHandleMouseState(mouseState);
|
||||
}
|
||||
};
|
||||
|
||||
_switchAnimation.stop();
|
||||
const auto duration = (1. - from) * ((fromConnecting || toConnecting)
|
||||
? kSwitchStateFromConnectingDuration
|
||||
: kSwitchStateDuration);
|
||||
_switchAnimation.start(std::move(callback), from, to, duration);
|
||||
}, lifetime());
|
||||
|
||||
// Icon rect.
|
||||
_content->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
const auto &icon = _st.button.icon;
|
||||
const auto &pos = _st.button.iconPosition;
|
||||
|
||||
_muteIconRect = QRect(
|
||||
(pos.x() < 0) ? ((size.width() - icon.width()) / 2) : pos.x(),
|
||||
(pos.y() < 0) ? ((size.height() - icon.height()) / 2) : pos.y(),
|
||||
icon.width(),
|
||||
icon.height());
|
||||
}, lifetime());
|
||||
|
||||
// Paint.
|
||||
_content->paintRequest(
|
||||
) | rpl::start_with_next([=](QRect clip) {
|
||||
Painter p(_content);
|
||||
|
||||
_crossLineMuteAnimation.paint(
|
||||
p,
|
||||
_muteIconRect.topLeft(),
|
||||
1. - _crossLineProgress);
|
||||
|
||||
if (_radialInfo.state.has_value() && _switchAnimation.animating()) {
|
||||
const auto radialProgress = _radialInfo.realShowProgress;
|
||||
|
||||
auto r = *_radialInfo.state;
|
||||
r.shown = 1.;
|
||||
if (_radialInfo.isDirectionToShow) {
|
||||
const auto to = r.arcFrom - kRadialFinishArcShift;
|
||||
ComputeRadialFinish(r.arcFrom, radialProgress, to);
|
||||
ComputeRadialFinish(r.arcLength, radialProgress);
|
||||
} else {
|
||||
r.arcLength = RadialState::kFull;
|
||||
}
|
||||
|
||||
const auto opacity = (radialProgress > kOverlapProgressRadialHide)
|
||||
? 0.
|
||||
: _blobs->switchConnectingProgress();
|
||||
p.setOpacity(opacity);
|
||||
InfiniteRadialAnimation::Draw(
|
||||
p,
|
||||
r,
|
||||
_st.bgPosition,
|
||||
_radialInfo.st.size,
|
||||
_content->width(),
|
||||
QPen(_radialInfo.st.color),
|
||||
_radialInfo.st.thickness);
|
||||
} else if (_radial) {
|
||||
auto state = _radial->computeState();
|
||||
state.shown = 1.;
|
||||
|
||||
InfiniteRadialAnimation::Draw(
|
||||
p,
|
||||
std::move(state),
|
||||
_st.bgPosition,
|
||||
_radialInfo.st.size,
|
||||
_content->width(),
|
||||
QPen(_radialInfo.st.color),
|
||||
_radialInfo.st.thickness);
|
||||
}
|
||||
}, _content->lifetime());
|
||||
}
|
||||
|
||||
void CallMuteButton::updateLabelsGeometry() {
|
||||
updateLabelGeometry(_content->geometry(), _label->size());
|
||||
updateCenterLabelGeometry(_content->geometry(), _centerLabel->size());
|
||||
updateSublabelGeometry(_content->geometry(), _sublabel->size());
|
||||
}
|
||||
|
||||
void CallMuteButton::updateLabelGeometry(QRect my, QSize size) {
|
||||
const auto skip = st::callMuteButtonSublabelSkip
|
||||
+ st::callMuteButtonLabelsSkip;
|
||||
_label->moveToLeft(
|
||||
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||
my.y() + my.height() - _label->height() - skip,
|
||||
my.width());
|
||||
}
|
||||
|
||||
void CallMuteButton::updateCenterLabelGeometry(QRect my, QSize size) {
|
||||
const auto skip = (st::callMuteButtonSublabelSkip / 2)
|
||||
+ st::callMuteButtonLabelsSkip;
|
||||
_centerLabel->moveToLeft(
|
||||
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||
my.y() + my.height() - _centerLabel->height() - skip,
|
||||
my.width());
|
||||
}
|
||||
|
||||
void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) {
|
||||
const auto skip = st::callMuteButtonLabelsSkip;
|
||||
_sublabel->moveToLeft(
|
||||
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||
my.y() + my.height() - _sublabel->height() - skip,
|
||||
my.width());
|
||||
}
|
||||
|
||||
void CallMuteButton::shake() {
|
||||
if (_shakeAnimation.animating()) {
|
||||
return;
|
||||
}
|
||||
const auto update = [=] {
|
||||
const auto fullProgress = _shakeAnimation.value(1.) * 6;
|
||||
const auto segment = std::clamp(int(std::floor(fullProgress)), 0, 5);
|
||||
const auto part = fullProgress - segment;
|
||||
const auto from = (segment == 0)
|
||||
? 0.
|
||||
: (segment == 1 || segment == 3 || segment == 5)
|
||||
? 1.
|
||||
: -1.;
|
||||
const auto to = (segment == 0 || segment == 2 || segment == 4)
|
||||
? 1.
|
||||
: (segment == 1 || segment == 3)
|
||||
? -1.
|
||||
: 0.;
|
||||
const auto shift = from * (1. - part) + to * part;
|
||||
_labelShakeShift = int(std::round(shift * st::shakeShift));
|
||||
updateLabelsGeometry();
|
||||
};
|
||||
_shakeAnimation.start(
|
||||
update,
|
||||
0.,
|
||||
1.,
|
||||
kShiftDuration);
|
||||
}
|
||||
|
||||
CallMuteButton::HandleMouseState CallMuteButton::HandleMouseStateFromType(
|
||||
CallMuteButtonType type) {
|
||||
switch (type) {
|
||||
case CallMuteButtonType::Active:
|
||||
case CallMuteButtonType::Muted:
|
||||
return HandleMouseState::Enabled;
|
||||
case CallMuteButtonType::Connecting:
|
||||
return HandleMouseState::Disabled;
|
||||
case CallMuteButtonType::ForceMuted:
|
||||
return HandleMouseState::Blocked;
|
||||
}
|
||||
Unexpected("Type in HandleMouseStateFromType.");
|
||||
}
|
||||
|
||||
void CallMuteButton::setState(const CallMuteButtonState &state) {
|
||||
_state = state;
|
||||
}
|
||||
|
||||
void CallMuteButton::setLevel(float level) {
|
||||
_level = level;
|
||||
_blobs->setLevel(level);
|
||||
}
|
||||
|
||||
rpl::producer<Qt::MouseButton> CallMuteButton::clicks() const {
|
||||
return _content->clicks();
|
||||
}
|
||||
|
||||
QSize CallMuteButton::innerSize() const {
|
||||
return innerGeometry().size();
|
||||
}
|
||||
|
||||
QRect CallMuteButton::innerGeometry() const {
|
||||
const auto &skip = _st.outerRadius;
|
||||
return QRect(
|
||||
_content->x(),
|
||||
_content->y(),
|
||||
_content->width() - 2 * skip,
|
||||
_content->width() - 2 * skip);
|
||||
}
|
||||
|
||||
void CallMuteButton::moveInner(QPoint position) {
|
||||
const auto &skip = _st.outerRadius;
|
||||
_content->move(position - QPoint(skip, skip));
|
||||
|
||||
{
|
||||
const auto offset = QPoint(
|
||||
(_blobs->width() - _content->width()) / 2,
|
||||
(_blobs->height() - _content->width()) / 2);
|
||||
_blobs->move(_content->pos() - offset);
|
||||
}
|
||||
}
|
||||
|
||||
void CallMuteButton::setVisible(bool visible) {
|
||||
_content->setVisible(visible);
|
||||
_blobs->setVisible(visible);
|
||||
}
|
||||
|
||||
void CallMuteButton::raise() {
|
||||
_blobs->raise();
|
||||
_content->raise();
|
||||
}
|
||||
|
||||
void CallMuteButton::lower() {
|
||||
_content->lower();
|
||||
_blobs->lower();
|
||||
}
|
||||
|
||||
void CallMuteButton::setHandleMouseState(HandleMouseState state) {
|
||||
if (_handleMouseState == state) {
|
||||
return;
|
||||
}
|
||||
_handleMouseState = state;
|
||||
const auto handle = (_handleMouseState != HandleMouseState::Disabled);
|
||||
const auto pointer = (_handleMouseState == HandleMouseState::Enabled);
|
||||
_content->setAttribute(Qt::WA_TransparentForMouseEvents, !handle);
|
||||
_content->setPointerCursor(pointer);
|
||||
}
|
||||
|
||||
void CallMuteButton::overridesColors(
|
||||
CallMuteButtonType fromType,
|
||||
CallMuteButtonType toType,
|
||||
float64 progress) {
|
||||
const auto forceMutedToConnecting = [](CallMuteButtonType &type) {
|
||||
if (type == CallMuteButtonType::ForceMuted) {
|
||||
type = CallMuteButtonType::Connecting;
|
||||
}
|
||||
};
|
||||
forceMutedToConnecting(toType);
|
||||
forceMutedToConnecting(fromType);
|
||||
const auto toInactive = IsInactive(toType);
|
||||
const auto fromInactive = IsInactive(fromType);
|
||||
if (toInactive && (progress == 1)) {
|
||||
_colorOverrides.fire({ std::nullopt, std::nullopt });
|
||||
return;
|
||||
}
|
||||
auto from = _colors.find(fromType)->second.stops[0].second;
|
||||
auto to = _colors.find(toType)->second.stops[0].second;
|
||||
auto fromRipple = from;
|
||||
auto toRipple = to;
|
||||
if (!toInactive) {
|
||||
toRipple.setAlpha(kOverrideColorRippleAlpha);
|
||||
to.setAlpha(kOverrideColorBgAlpha);
|
||||
}
|
||||
if (!fromInactive) {
|
||||
fromRipple.setAlpha(kOverrideColorRippleAlpha);
|
||||
from.setAlpha(kOverrideColorBgAlpha);
|
||||
}
|
||||
const auto resultBg = anim::color(from, to, progress);
|
||||
const auto resultRipple = anim::color(fromRipple, toRipple, progress);
|
||||
_colorOverrides.fire({ resultBg, resultRipple });
|
||||
}
|
||||
|
||||
rpl::producer<CallButtonColors> CallMuteButton::colorOverrides() const {
|
||||
return _colorOverrides.events();
|
||||
}
|
||||
|
||||
rpl::lifetime &CallMuteButton::lifetime() {
|
||||
return _blobs->lifetime();
|
||||
}
|
||||
|
||||
CallMuteButton::~CallMuteButton() = default;
|
||||
|
||||
} // namespace Ui
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/unique_qptr.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/cross_line.h"
|
||||
#include "ui/effects/gradient.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class BlobsWidget;
|
||||
|
||||
class AbstractButton;
|
||||
class FlatLabel;
|
||||
class RpWidget;
|
||||
class AnimatedLabel;
|
||||
|
||||
struct CallButtonColors;
|
||||
|
||||
enum class CallMuteButtonType {
|
||||
Connecting,
|
||||
Active,
|
||||
Muted,
|
||||
ForceMuted,
|
||||
};
|
||||
|
||||
struct CallMuteButtonState {
|
||||
QString text;
|
||||
QString subtext;
|
||||
CallMuteButtonType type = CallMuteButtonType::Connecting;
|
||||
};
|
||||
|
||||
class CallMuteButton final {
|
||||
public:
|
||||
explicit CallMuteButton(
|
||||
not_null<RpWidget*> parent,
|
||||
rpl::producer<bool> &&hideBlobs,
|
||||
CallMuteButtonState initial = CallMuteButtonState());
|
||||
~CallMuteButton();
|
||||
|
||||
void setState(const CallMuteButtonState &state);
|
||||
void setLevel(float level);
|
||||
[[nodiscard]] rpl::producer<Qt::MouseButton> clicks() const;
|
||||
|
||||
[[nodiscard]] QSize innerSize() const;
|
||||
[[nodiscard]] QRect innerGeometry() const;
|
||||
void moveInner(QPoint position);
|
||||
|
||||
void shake();
|
||||
|
||||
void setVisible(bool visible);
|
||||
void show() {
|
||||
setVisible(true);
|
||||
}
|
||||
void hide() {
|
||||
setVisible(false);
|
||||
}
|
||||
void raise();
|
||||
void lower();
|
||||
|
||||
[[nodiscard]] rpl::producer<CallButtonColors> colorOverrides() const;
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
enum class HandleMouseState {
|
||||
Enabled,
|
||||
Blocked,
|
||||
Disabled,
|
||||
};
|
||||
struct RadialInfo {
|
||||
std::optional<RadialState> state = std::nullopt;
|
||||
bool isDirectionToShow = false;
|
||||
rpl::variable<float64> rawShowProgress = 0.;
|
||||
float64 realShowProgress = 0.;
|
||||
const style::InfiniteRadialAnimation &st = st::callConnectingRadial;
|
||||
};
|
||||
void init();
|
||||
void overridesColors(
|
||||
CallMuteButtonType fromType,
|
||||
CallMuteButtonType toType,
|
||||
float64 progress);
|
||||
|
||||
void setHandleMouseState(HandleMouseState state);
|
||||
void updateCenterLabelGeometry(QRect my, QSize size);
|
||||
void updateLabelGeometry(QRect my, QSize size);
|
||||
void updateSublabelGeometry(QRect my, QSize size);
|
||||
void updateLabelsGeometry();
|
||||
|
||||
[[nodiscard]] static HandleMouseState HandleMouseStateFromType(
|
||||
CallMuteButtonType type);
|
||||
|
||||
rpl::variable<CallMuteButtonState> _state;
|
||||
float _level = 0.;
|
||||
float64 _crossLineProgress = 0.;
|
||||
QRect _muteIconRect;
|
||||
HandleMouseState _handleMouseState = HandleMouseState::Enabled;
|
||||
|
||||
const style::CallButton &_st;
|
||||
|
||||
const base::unique_qptr<BlobsWidget> _blobs;
|
||||
const base::unique_qptr<AbstractButton> _content;
|
||||
const base::unique_qptr<AnimatedLabel> _centerLabel;
|
||||
const base::unique_qptr<AnimatedLabel> _label;
|
||||
const base::unique_qptr<AnimatedLabel> _sublabel;
|
||||
int _labelShakeShift = 0;
|
||||
|
||||
RadialInfo _radialInfo;
|
||||
std::unique_ptr<InfiniteRadialAnimation> _radial;
|
||||
const base::flat_map<CallMuteButtonType, anim::gradient_colors> _colors;
|
||||
|
||||
CrossLineAnimation _crossLineMuteAnimation;
|
||||
Animations::Simple _switchAnimation;
|
||||
Animations::Simple _shakeAnimation;
|
||||
|
||||
rpl::event_stream<CallButtonColors> _colorOverrides;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Ui
|
||||
|
|
@ -95,7 +95,7 @@ void DropdownMenu::handleTriggered(const Menu::CallbackData &data) {
|
|||
if (!popupSubmenuFromAction(data)) {
|
||||
hideMenu();
|
||||
_triggering = true;
|
||||
emit data.action->trigger();
|
||||
data.action->trigger();
|
||||
_triggering = false;
|
||||
if (_deleteLater) {
|
||||
_deleteLater = false;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@ public:
|
|||
_hiddenCallback = std::move(callback);
|
||||
}
|
||||
|
||||
const std::vector<not_null<QAction*>> &actions() const;
|
||||
bool empty() const;
|
||||
[[nodiscard]] const std::vector<not_null<QAction*>> &actions() const;
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
[[nodiscard]] not_null<Menu::Menu*> menu() const {
|
||||
return _menu;
|
||||
}
|
||||
|
||||
~DropdownMenu();
|
||||
|
||||
|
|
@ -39,7 +43,7 @@ protected:
|
|||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void onHidden() {
|
||||
hideFinish();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ protected:
|
|||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void onHideAnimated() {
|
||||
hideAnimated();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1094,7 +1094,7 @@ void FlatInput::focusInEvent(QFocusEvent *e) {
|
|||
update();
|
||||
}
|
||||
QLineEdit::focusInEvent(e);
|
||||
emit focused();
|
||||
focused();
|
||||
}
|
||||
|
||||
void FlatInput::focusOutEvent(QFocusEvent *e) {
|
||||
|
|
@ -1108,7 +1108,7 @@ void FlatInput::focusOutEvent(QFocusEvent *e) {
|
|||
update();
|
||||
}
|
||||
QLineEdit::focusOutEvent(e);
|
||||
emit blurred();
|
||||
blurred();
|
||||
}
|
||||
|
||||
void FlatInput::resizeEvent(QResizeEvent *e) {
|
||||
|
|
@ -1196,13 +1196,13 @@ void FlatInput::keyPressEvent(QKeyEvent *e) {
|
|||
if (wasText == newText) { // call correct manually
|
||||
correctValue(wasText, newText);
|
||||
_oldtext = newText;
|
||||
if (wasText != _oldtext) emit changed();
|
||||
if (wasText != _oldtext) changed();
|
||||
updatePlaceholder();
|
||||
}
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
emit cancelled();
|
||||
cancelled();
|
||||
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
emit submitted(e->modifiers());
|
||||
submitted(e->modifiers());
|
||||
#ifdef Q_OS_MAC
|
||||
} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
|
||||
auto selected = selectedText();
|
||||
|
|
@ -1218,7 +1218,7 @@ void FlatInput::onTextEdited() {
|
|||
|
||||
correctValue(wasText, newText);
|
||||
_oldtext = newText;
|
||||
if (wasText != _oldtext) emit changed();
|
||||
if (wasText != _oldtext) changed();
|
||||
updatePlaceholder();
|
||||
|
||||
Integration::Instance().textActionsUpdated();
|
||||
|
|
@ -1604,7 +1604,7 @@ bool InputField::heightAutoupdated() {
|
|||
|
||||
void InputField::checkContentHeight() {
|
||||
if (heightAutoupdated()) {
|
||||
emit resized();
|
||||
resized();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1800,13 +1800,13 @@ void InputField::focusInEventInner(QFocusEvent *e) {
|
|||
: (width() / 2);
|
||||
setFocused(true);
|
||||
_inner->QTextEdit::focusInEvent(e);
|
||||
emit focused();
|
||||
focused();
|
||||
}
|
||||
|
||||
void InputField::focusOutEventInner(QFocusEvent *e) {
|
||||
setFocused(false);
|
||||
_inner->QTextEdit::focusOutEvent(e);
|
||||
emit blurred();
|
||||
blurred();
|
||||
}
|
||||
|
||||
void InputField::setFocused(bool focused) {
|
||||
|
|
@ -2335,7 +2335,7 @@ void InputField::handleContentsChanged() {
|
|||
if (tagsChanged || (_lastTextWithTags.text != currentText)) {
|
||||
_lastTextWithTags.text = currentText;
|
||||
const auto weak = MakeWeak(this);
|
||||
emit changed();
|
||||
changed();
|
||||
if (!weak) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2690,15 +2690,15 @@ void InputField::keyPressEventInner(QKeyEvent *e) {
|
|||
&& revertFormatReplace()) {
|
||||
e->accept();
|
||||
} else if (enter && enterSubmit) {
|
||||
emit submitted(e->modifiers());
|
||||
submitted(e->modifiers());
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
e->ignore();
|
||||
emit cancelled();
|
||||
cancelled();
|
||||
} else if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab) {
|
||||
if (alt || ctrl) {
|
||||
e->ignore();
|
||||
} else if (_customTab) {
|
||||
emit tabbed();
|
||||
tabbed();
|
||||
} else if (!focusNextPrevChild(e->key() == Qt::Key_Tab && !shift)) {
|
||||
e->ignore();
|
||||
}
|
||||
|
|
@ -3857,13 +3857,13 @@ void MaskedInputField::focusInEvent(QFocusEvent *e) {
|
|||
_borderAnimationStart = (e->reason() == Qt::MouseFocusReason) ? mapFromGlobal(QCursor::pos()).x() : (width() / 2);
|
||||
setFocused(true);
|
||||
QLineEdit::focusInEvent(e);
|
||||
emit focused();
|
||||
focused();
|
||||
}
|
||||
|
||||
void MaskedInputField::focusOutEvent(QFocusEvent *e) {
|
||||
setFocused(false);
|
||||
QLineEdit::focusOutEvent(e);
|
||||
emit blurred();
|
||||
blurred();
|
||||
}
|
||||
|
||||
void MaskedInputField::setFocused(bool focused) {
|
||||
|
|
@ -3989,14 +3989,14 @@ void MaskedInputField::keyPressEvent(QKeyEvent *e) {
|
|||
correctValue(wasText, wasCursor, newText, newCursor);
|
||||
_oldtext = newText;
|
||||
_oldcursor = newCursor;
|
||||
if (wasText != _oldtext) emit changed();
|
||||
if (wasText != _oldtext) changed();
|
||||
startPlaceholderAnimation();
|
||||
}
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
e->ignore();
|
||||
emit cancelled();
|
||||
cancelled();
|
||||
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
emit submitted(e->modifiers());
|
||||
submitted(e->modifiers());
|
||||
#ifdef Q_OS_MAC
|
||||
} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
|
||||
auto selected = selectedText();
|
||||
|
|
@ -4014,7 +4014,7 @@ void MaskedInputField::onTextEdited() {
|
|||
correctValue(wasText, wasCursor, newText, newCursor);
|
||||
_oldtext = newText;
|
||||
_oldcursor = newCursor;
|
||||
if (wasText != _oldtext) emit changed();
|
||||
if (wasText != _oldtext) changed();
|
||||
startPlaceholderAnimation();
|
||||
|
||||
Integration::Instance().textActionsUpdated();
|
||||
|
|
|
|||
|
|
@ -85,13 +85,13 @@ public:
|
|||
return _oldtext;
|
||||
}
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void onTextChange(const QString &text);
|
||||
void onTextEdited();
|
||||
|
||||
void onTouchTimer();
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
void cancelled();
|
||||
void submitted(Qt::KeyboardModifiers);
|
||||
|
|
@ -338,7 +338,7 @@ public:
|
|||
|
||||
~InputField();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void onTouchTimer();
|
||||
|
||||
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
||||
|
|
@ -349,7 +349,7 @@ private slots:
|
|||
|
||||
void onFocusInner();
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
void submitted(Qt::KeyboardModifiers);
|
||||
void cancelled();
|
||||
|
|
@ -589,7 +589,7 @@ public:
|
|||
startPlaceholderAnimation();
|
||||
}
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void onTextChange(const QString &text);
|
||||
void onCursorPositionChanged(int oldPosition, int position);
|
||||
|
||||
|
|
@ -597,7 +597,7 @@ public slots:
|
|||
|
||||
void onTouchTimer();
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void changed();
|
||||
void cancelled();
|
||||
void submitted(Qt::KeyboardModifiers);
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ protected:
|
|||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void onCopySelectedText();
|
||||
void onCopyContextText();
|
||||
|
||||
|
|
|
|||
|
|
@ -129,28 +129,29 @@ not_null<QAction*> Menu::addAction(base::unique_qptr<ItemBase> widget) {
|
|||
const auto raw = widget.get();
|
||||
_actionWidgets.push_back(std::move(widget));
|
||||
|
||||
raw->minWidthValue(
|
||||
rpl::combine(
|
||||
raw->minWidthValue(),
|
||||
raw->heightValue()
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto newWidth = _forceWidth
|
||||
? _forceWidth
|
||||
: std::clamp(
|
||||
_actionWidgets.empty()
|
||||
? 0
|
||||
: (*ranges::max_element(
|
||||
_actionWidgets,
|
||||
std::less<>(),
|
||||
&ItemBase::minWidth))->minWidth(),
|
||||
? 0
|
||||
: (*ranges::max_element(
|
||||
_actionWidgets,
|
||||
std::less<>(),
|
||||
&ItemBase::minWidth))->minWidth(),
|
||||
_st.widthMin,
|
||||
_st.widthMax);
|
||||
resizeFromInner(newWidth, height());
|
||||
const auto newHeight = ranges::accumulate(
|
||||
_actionWidgets,
|
||||
0,
|
||||
ranges::plus(),
|
||||
&ItemBase::height);
|
||||
resizeFromInner(newWidth, newHeight);
|
||||
}, raw->lifetime());
|
||||
|
||||
const auto newHeight = ranges::accumulate(
|
||||
_actionWidgets,
|
||||
0,
|
||||
ranges::plus(),
|
||||
&ItemBase::height);
|
||||
resizeFromInner(width(), newHeight);
|
||||
updateSelected(QCursor::pos());
|
||||
|
||||
return action;
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ void PopupMenu::handleTriggered(const Menu::CallbackData &data) {
|
|||
if (!popupSubmenuFromAction(data)) {
|
||||
_triggering = true;
|
||||
hideMenu();
|
||||
emit data.action->trigger();
|
||||
data.action->trigger();
|
||||
_triggering = false;
|
||||
if (_deleteLater) {
|
||||
_deleteLater = false;
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ 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) emit topShadowVisibility(_topSh = newTopSh);
|
||||
if (newBottomSh != _bottomSh || force) emit bottomShadowVisibility(_bottomSh = newBottomSh);
|
||||
if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh);
|
||||
if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -105,8 +105,8 @@ 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) emit topShadowVisibility(_topSh = newTopSh);
|
||||
if (newBottomSh != _bottomSh || force) emit bottomShadowVisibility(_bottomSh = newBottomSh);
|
||||
if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh);
|
||||
if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh);
|
||||
}
|
||||
if (isHidden()) show();
|
||||
}
|
||||
|
|
@ -252,7 +252,7 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
area()->setMovingByScrollBar(true);
|
||||
emit area()->scrollStarted();
|
||||
area()->scrollStarted();
|
||||
}
|
||||
|
||||
void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
|
@ -260,7 +260,7 @@ void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
|
|||
setMoving(false);
|
||||
|
||||
area()->setMovingByScrollBar(false);
|
||||
emit area()->scrollFinished();
|
||||
area()->scrollFinished();
|
||||
}
|
||||
if (!_over) {
|
||||
setMouseTracking(false);
|
||||
|
|
@ -342,7 +342,7 @@ void ScrollArea::onScrolled() {
|
|||
}
|
||||
}
|
||||
if (em) {
|
||||
emit scrolled();
|
||||
scrolled();
|
||||
if (!_movingByScrollBar) {
|
||||
SendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton);
|
||||
}
|
||||
|
|
@ -350,7 +350,7 @@ void ScrollArea::onScrolled() {
|
|||
}
|
||||
|
||||
void ScrollArea::onInnerResized() {
|
||||
emit innerResized();
|
||||
innerResized();
|
||||
}
|
||||
|
||||
int ScrollArea::scrollWidth() const {
|
||||
|
|
@ -601,12 +601,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)));
|
||||
emit geometryChanged();
|
||||
geometryChanged();
|
||||
}
|
||||
|
||||
void ScrollArea::moveEvent(QMoveEvent *e) {
|
||||
QScrollArea::moveEvent(e);
|
||||
emit geometryChanged();
|
||||
geometryChanged();
|
||||
}
|
||||
|
||||
void ScrollArea::keyPressEvent(QKeyEvent *e) {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void changeVisibility(bool shown);
|
||||
|
||||
private:
|
||||
|
|
@ -75,12 +75,12 @@ public:
|
|||
|
||||
void hideTimeout(crl::time dt);
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void onValueChanged();
|
||||
void onRangeChanged();
|
||||
void onHideTimer();
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void topShadowVisibility(bool);
|
||||
void bottomShadowVisibility(bool);
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ protected:
|
|||
void enterEventHook(QEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void scrollToY(int toTop, int toBottom = -1);
|
||||
void disableScroll(bool dis);
|
||||
void onScrolled();
|
||||
|
|
@ -189,7 +189,7 @@ public slots:
|
|||
void onTouchTimer();
|
||||
void onTouchScrollTimer();
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void scrolled();
|
||||
void innerResized();
|
||||
void scrollStarted();
|
||||
|
|
|
|||
|
|
@ -354,7 +354,6 @@ void ImportantTooltip::updateGeometry() {
|
|||
}
|
||||
|
||||
void ImportantTooltip::resizeEvent(QResizeEvent *e) {
|
||||
auto inner = countInner();
|
||||
auto contentTop = _st.padding.top();
|
||||
if (_useTransparency && (_side & RectPart::Bottom)) {
|
||||
contentTop += _st.arrow;
|
||||
|
|
|
|||
|
|
@ -1431,13 +1431,9 @@ callMuteMinorBlobMaxRadius: 74px;
|
|||
callMuteMajorBlobMinRadius: 67px;
|
||||
callMuteMajorBlobMaxRadius: 77px;
|
||||
|
||||
callMuteButtonActiveIcon: icon {{ "calls/voice_unmuted_large", groupCallIconFg }};
|
||||
callMuteButtonActiveInner: IconButton {
|
||||
width: 136px;
|
||||
height: 165px;
|
||||
|
||||
iconPosition: point(-1px, 50px);
|
||||
icon: callMuteButtonActiveIcon;
|
||||
}
|
||||
callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: groupCallMembersFg;
|
||||
|
|
@ -1462,29 +1458,15 @@ callMuteButtonActive: CallButton {
|
|||
label: callMuteButtonLabel;
|
||||
}
|
||||
callMuteButtonMuted: CallButton(callMuteButtonActive) {
|
||||
button: IconButton(callMuteButtonActiveInner) {
|
||||
icon: icon {{ "calls/voice_muted_large", groupCallIconFg }};
|
||||
}
|
||||
bg: groupCallMuted1;
|
||||
label: callMuteButtonLabel;
|
||||
}
|
||||
callMuteButtonConnecting: CallButton(callMuteButtonMuted) {
|
||||
button: IconButton(callMuteButtonActiveInner) {
|
||||
icon: icon {{ "calls/voice_muted_large", groupCallIconFg }};
|
||||
}
|
||||
bg: callIconBg;
|
||||
label: callMuteButtonLabel;
|
||||
}
|
||||
callMuteButtonLabelAdditional: 5px;
|
||||
|
||||
callMuteCrossLine: CrossLineAnimation {
|
||||
fg: groupCallIconFg;
|
||||
icon: callMuteButtonActiveIcon;
|
||||
startPosition: point(7px, 2px);
|
||||
endPosition: point(34px, 30px);
|
||||
stroke: 4px;
|
||||
}
|
||||
|
||||
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
|
||||
color: lightButtonFg;
|
||||
thickness: 4px;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue