Updated lib_ui sources to TDesktop version 2.7.2

This commit is contained in:
Eric Kotato 2021-04-26 23:43:54 +03:00
commit 545a792033
20 changed files with 462 additions and 91 deletions

View file

@ -211,8 +211,6 @@ PRIVATE
ui/round_rect.h
ui/rp_widget.cpp
ui/rp_widget.h
ui/ui_log.cpp
ui/ui_log.h
ui/ui_utility.cpp
ui/ui_utility.h

View file

@ -10,10 +10,10 @@
#include "base/bytes.h"
#include "base/openssl_help.h"
#include "base/parse_helper.h"
#include "base/debug_log.h"
#include "ui/style/style_core.h"
#include "ui/painter.h"
#include "ui/ui_utility.h"
#include "ui/ui_log.h"
#include "styles/style_basic.h"
#include <QtCore/QJsonDocument>
@ -218,7 +218,7 @@ void SaveToFile(int id, const QImage &image, int size, int index) {
if (!f.open(QIODevice::WriteOnly)) {
if (!QDir::current().mkpath(internal::CacheFileFolder())
|| !f.open(QIODevice::WriteOnly)) {
UI_LOG(("App Error: Could not open emoji cache '%1' for size %2_%3"
LOG(("App Error: Could not open emoji cache '%1' for size %2_%3"
).arg(f.fileName()
).arg(size
).arg(index));
@ -244,7 +244,7 @@ void SaveToFile(int id, const QImage &image, int size, int index) {
|| !write(data)
|| !write(openssl::Sha256(bytes::make_span(header), data))
|| false) {
UI_LOG(("App Error: Could not write emoji cache '%1' for size %2"
LOG(("App Error: Could not write emoji cache '%1' for size %2"
).arg(f.fileName()
).arg(size));
}

View file

@ -36,12 +36,6 @@ void Integration::textActionsUpdated() {
void Integration::activationFromTopPanel() {
}
void Integration::startFontsBegin() {
}
void Integration::startFontsEnd() {
}
QString Integration::timeFormat() {
return u"hh:mm"_q;
}
@ -79,10 +73,6 @@ const Emoji::One *Integration::defaultEmojiVariant(const Emoji::One *emoji) {
return emoji;
}
QWidget *Integration::modalWindowParent() {
return nullptr;
}
rpl::producer<> Integration::forcePopupMenuHideRequests() {
return rpl::never<rpl::empty_value>();
}

View file

@ -35,15 +35,11 @@ public:
virtual void registerLeaveSubscription(not_null<QWidget*> widget) = 0;
virtual void unregisterLeaveSubscription(not_null<QWidget*> widget) = 0;
virtual void writeLogEntry(const QString &entry) = 0;
[[nodiscard]] virtual QString emojiCacheFolder() = 0;
virtual void textActionsUpdated();
virtual void activationFromTopPanel();
virtual void startFontsBegin();
virtual void startFontsEnd();
[[nodiscard]] virtual QString timeFormat();
[[nodiscard]] virtual std::shared_ptr<ClickHandler> createLinkHandler(
@ -56,8 +52,6 @@ public:
[[nodiscard]] virtual const Emoji::One *defaultEmojiVariant(
const Emoji::One *emoji);
[[nodiscard]] virtual QWidget *modalWindowParent();
[[nodiscard]] virtual rpl::producer<> forcePopupMenuHideRequests();
[[nodiscard]] virtual QString phraseContextCopyText();

View file

@ -16,7 +16,7 @@ namespace Ui {
void GenericBox::prepare() {
_init(this);
auto wrap = object_ptr<Ui::OverrideMargins>(this, std::move(_content));
auto wrap = object_ptr<Ui::OverrideMargins>(this, std::move(_owned));
setDimensionsToContent(_width ? _width : st::boxWidth, wrap.data());
setInnerWidget(std::move(wrap));
}
@ -26,7 +26,7 @@ void GenericBox::addSkip(int height) {
}
not_null<Ui::VerticalLayout*> GenericBox::verticalLayout() {
return _content.data();
return _content;
}
} // namespace Ui

View file

@ -120,7 +120,8 @@ private:
FnMut<void(not_null<GenericBox*>)> _init;
Fn<void()> _focus;
Fn<void()> _showFinished;
object_ptr<Ui::VerticalLayout> _content;
object_ptr<Ui::VerticalLayout> _owned;
not_null<Ui::VerticalLayout*> _content;
int _width = 0;
};
@ -166,7 +167,8 @@ inline GenericBox::GenericBox(
MakeIniter(
std::forward<InitMethod>(init),
std::forward<InitArgs>(args)...))
, _content(this) {
, _owned(this)
, _content(_owned.data()) {
}
} // namespace Ui

View file

@ -6,9 +6,9 @@
//
#include "ui/platform/linux/ui_utility_linux.h"
#include "ui/ui_log.h"
#include "base/platform/base_platform_info.h"
#include "base/platform/linux/base_linux_gtk_integration.h"
#include "base/debug_log.h"
#include "ui/platform/linux/ui_linux_wayland_integration.h"
#include "base/const_string.h"
#include "base/qt_adapters.h"
@ -33,6 +33,259 @@ namespace {
constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
std::optional<bool> XCBWindowMapped(xcb_window_t window) {
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return std::nullopt;
}
const auto cookie = xcb_get_window_attributes(connection, window);
const auto reply = xcb_get_window_attributes_reply(
connection,
cookie,
nullptr);
if (!reply) {
return std::nullopt;
}
const auto guard = gsl::finally([&] { free(reply); });
return reply->map_state == XCB_MAP_STATE_VIEWABLE;
}
std::optional<bool> XCBWindowHidden(xcb_window_t window) {
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return std::nullopt;
}
const auto stateAtom = base::Platform::XCB::GetAtom(
connection,
"_NET_WM_STATE");
const auto stateHiddenAtom = base::Platform::XCB::GetAtom(
connection,
"_NET_WM_STATE_HIDDEN");
if (!stateAtom.has_value() || !stateHiddenAtom.has_value()) {
return std::nullopt;
}
const auto cookie = xcb_get_property(
connection,
false,
window,
*stateAtom,
XCB_ATOM_ATOM,
0,
1024);
const auto reply = xcb_get_property_reply(
connection,
cookie,
nullptr);
if (!reply) {
return std::nullopt;
}
const auto guard = gsl::finally([&] { free(reply); });
if (reply->type != XCB_ATOM_ATOM || reply->format != 32) {
return std::nullopt;
}
const auto atomsStart = reinterpret_cast<xcb_atom_t*>(
xcb_get_property_value(reply));
const auto states = std::vector<xcb_atom_t>(
atomsStart,
atomsStart + reply->length);
return ranges::contains(states, *stateHiddenAtom);
}
QRect XCBWindowGeometry(xcb_window_t window) {
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return {};
}
const auto cookie = xcb_get_geometry(connection, window);
const auto reply = xcb_get_geometry_reply(
connection,
cookie,
nullptr);
if (!reply) {
return {};
}
const auto guard = gsl::finally([&] { free(reply); });
return QRect(reply->x, reply->y, reply->width, reply->height);
}
std::optional<uint> XCBCurrentWorkspace() {
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return std::nullopt;
}
const auto root = base::Platform::XCB::GetRootWindowFromQt();
if (!root.has_value()) {
return std::nullopt;
}
const auto currentDesktopAtom = base::Platform::XCB::GetAtom(
connection,
"_NET_CURRENT_DESKTOP");
if (!currentDesktopAtom.has_value()) {
return std::nullopt;
}
const auto cookie = xcb_get_property(
connection,
false,
*root,
*currentDesktopAtom,
XCB_ATOM_CARDINAL,
0,
1024);
const auto reply = xcb_get_property_reply(
connection,
cookie,
nullptr);
if (!reply) {
return std::nullopt;
}
const auto guard = gsl::finally([&] { free(reply); });
return (reply->type == XCB_ATOM_CARDINAL)
? std::make_optional(
*reinterpret_cast<ulong*>(xcb_get_property_value(reply)))
: std::nullopt;
}
std::optional<uint> XCBWindowWorkspace(xcb_window_t window) {
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return std::nullopt;
}
const auto desktopAtom = base::Platform::XCB::GetAtom(
connection,
"_NET_WM_DESKTOP");
if (!desktopAtom.has_value()) {
return std::nullopt;
}
const auto cookie = xcb_get_property(
connection,
false,
window,
*desktopAtom,
XCB_ATOM_CARDINAL,
0,
1024);
const auto reply = xcb_get_property_reply(
connection,
cookie,
nullptr);
if (!reply) {
return std::nullopt;
}
const auto guard = gsl::finally([&] { free(reply); });
return (reply->type == XCB_ATOM_CARDINAL)
? std::make_optional(
*reinterpret_cast<ulong*>(xcb_get_property_value(reply)))
: std::nullopt;
}
std::optional<bool> XCBIsOverlapped(
not_null<QWidget*> widget,
const QRect &rect) {
const auto window = widget->window()->winId();
Expects(window != XCB_WINDOW_NONE);
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return std::nullopt;
}
const auto root = base::Platform::XCB::GetRootWindowFromQt();
if (!root.has_value()) {
return std::nullopt;
}
const auto windowWorkspace = XCBWindowWorkspace(
window);
const auto currentWorkspace = XCBCurrentWorkspace();
if (windowWorkspace.has_value()
&& currentWorkspace.has_value()
&& *windowWorkspace != *currentWorkspace
&& *windowWorkspace != 0xFFFFFFFF) {
return true;
}
const auto cookie = xcb_query_tree(connection, *root);
const auto reply = xcb_query_tree_reply(connection, cookie, nullptr);
if (!reply) {
return std::nullopt;
}
const auto guard = gsl::finally([&] { free(reply); });
const auto tree = xcb_query_tree_children(reply);
auto aboveTheWindow = false;
for (auto i = 0, l = xcb_query_tree_children_length(reply); i < l; ++i) {
if (window == tree[i]) {
aboveTheWindow = true;
continue;
}
if (!aboveTheWindow) {
continue;
}
const auto geometry = XCBWindowGeometry(tree[i]);
if (!rect.intersects(geometry)) {
continue;
}
const auto workspace = XCBWindowWorkspace(tree[i]);
if (workspace.has_value()
&& windowWorkspace.has_value()
&& *workspace != *windowWorkspace
&& *workspace != 0xFFFFFFFF) {
continue;
}
const auto mapped = XCBWindowMapped(tree[i]);
if (mapped.has_value() && !*mapped) {
continue;
}
const auto hidden = XCBWindowHidden(tree[i]);
if (hidden.has_value()
&& *hidden) {
continue;
}
return true;
}
return false;
}
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
@ -169,10 +422,10 @@ bool TranslucentWindowsSupported(QPoint globalPosition) {
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()));
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()));
LOG(("WARNING: Could not get screen for position %1,%2").arg(globalPosition.x()).arg(globalPosition.y()));
}
}
}
@ -189,12 +442,24 @@ void ClearTransientParent(not_null<QWidget*> widget) {
if (::Platform::IsX11()) {
xcb_delete_property(
base::Platform::XCB::GetConnectionFromQt(),
widget->windowHandle()->winId(),
widget->winId(),
XCB_ATOM_WM_TRANSIENT_FOR);
}
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
}
std::optional<bool> IsOverlapped(
not_null<QWidget*> widget,
const QRect &rect) {
#ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION
if (::Platform::IsX11()) {
return XCBIsOverlapped(widget, rect);
}
#endif // !DESKTOP_APP_DISABLE_X11_INTEGRATION
return std::nullopt;
}
bool WindowExtentsSupported() {
#ifdef DESKTOP_APP_QT_PATCHED
if (::Platform::IsWayland()) {

View file

@ -7,6 +7,7 @@
#include "ui/platform/mac/ui_utility_mac.h"
#include "ui/integration.h"
#include "base/qt_adapters.h"
#include <QtGui/QPainter>
#include <QtGui/QtEvents>
@ -99,6 +100,60 @@ void DrainMainQueue() {
void IgnoreAllActivation(not_null<QWidget*> widget) {
}
std::optional<bool> IsOverlapped(
not_null<QWidget*> widget,
const QRect &rect) {
NSWindow *window = [reinterpret_cast<NSView*>(widget->window()->winId()) window];
Assert(window != nullptr);
if (![window isOnActiveSpace]) {
return true;
}
const auto nativeRect = CGRectMake(
rect.x(),
rect.y(),
rect.width(),
rect.height());
CGWindowID windowId = (CGWindowID)[window windowNumber];
const CGWindowListOption options = kCGWindowListExcludeDesktopElements
| kCGWindowListOptionOnScreenAboveWindow;
CFArrayRef windows = CGWindowListCopyWindowInfo(options, windowId);
if (!windows) {
return std::nullopt;
}
const auto guard = gsl::finally([&] {
CFRelease(windows);
});
NSMutableArray *list = (__bridge NSMutableArray*)windows;
for (NSDictionary *window in list) {
NSNumber *alphaValue = [window objectForKey:@"kCGWindowAlpha"];
const auto alpha = alphaValue ? [alphaValue doubleValue] : 1.;
if (alpha == 0.) {
continue;
}
NSString *owner = [window objectForKey:@"kCGWindowOwnerName"];
NSNumber *layerValue = [window objectForKey:@"kCGWindowLayer"];
const auto layer = layerValue ? [layerValue intValue] : 0;
if (owner && [owner isEqualToString:@"Dock"] && layer == 20) {
// It is always full screen.
continue;
}
CFDictionaryRef bounds = (__bridge CFDictionaryRef)[window objectForKey:@"kCGWindowBounds"];
if (!bounds) {
continue;
}
CGRect rect;
if (!CGRectMakeWithDictionaryRepresentation(bounds, &rect)) {
continue;
} else if (CGRectIntersectsRect(rect, nativeRect)) {
return true;
}
}
return false;
}
TitleControls::Layout TitleControlsLayout() {
return TitleControls::Layout{
.left = {

View file

@ -30,6 +30,10 @@ void BringToBack(not_null<QWidget*> widget);
void IgnoreAllActivation(not_null<QWidget*> widget);
void ClearTransientParent(not_null<QWidget*> widget);
[[nodiscard]] std::optional<bool> IsOverlapped(
not_null<QWidget*> widget,
const QRect &rect);
[[nodiscard]] constexpr bool UseMainQueueGeneric();
void DrainMainQueue(); // Needed only if UseMainQueueGeneric() is false.

View file

@ -11,6 +11,11 @@
#include <QtWidgets/QApplication>
#include <QtGui/QWindow>
#include <wrl/client.h>
#include <Shobjidl.h>
using namespace Microsoft::WRL;
namespace Ui {
namespace Platform {
@ -45,6 +50,55 @@ void IgnoreAllActivation(not_null<QWidget*> widget) {
ShowWindow(handle, SW_SHOW);
}
std::optional<bool> IsOverlapped(
not_null<QWidget*> widget,
const QRect &rect) {
const auto handle = reinterpret_cast<HWND>(widget->window()->winId());
Expects(handle != nullptr);
ComPtr<IVirtualDesktopManager> virtualDesktopManager;
HRESULT hr = CoCreateInstance(
CLSID_VirtualDesktopManager,
nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(&virtualDesktopManager));
if (SUCCEEDED(hr)) {
BOOL isCurrent;
hr = virtualDesktopManager->IsWindowOnCurrentVirtualDesktop(
handle,
&isCurrent);
if (SUCCEEDED(hr) && !isCurrent) {
return true;
}
}
std::vector<HWND> visited;
const RECT nativeRect{
rect.left(),
rect.top(),
rect.right(),
rect.bottom(),
};
for (auto curHandle = handle;
curHandle != nullptr && !ranges::contains(visited, curHandle);
curHandle = GetWindow(curHandle, GW_HWNDPREV)) {
visited.push_back(curHandle);
if (curHandle == handle) {
continue;
}
RECT testRect, intersection;
if (IsWindowVisible(curHandle)
&& GetWindowRect(curHandle, &testRect)
&& IntersectRect(&intersection, &nativeRect, &testRect)) {
return true;
}
}
return false;
}
bool ShowWindowMenu(QWindow *window) {
const auto pos = QCursor::pos();

View file

@ -10,7 +10,7 @@
#include "ui/platform/win/ui_window_title_win.h"
#include "base/platform/base_platform_info.h"
#include "base/platform/win/base_windows_safe_library.h"
#include "base/integration.h"
#include "base/debug_log.h"
#include "styles/palette.h"
#include <QtCore/QAbstractNativeEventFilter>
@ -75,7 +75,7 @@ bool IsTaskbarAutoHidden(LPRECT rcMon = nullptr, PUINT pEdge = nullptr) {
*pEdge = pos.uEdge;
}
} else {
base::Integration::Instance().logMessage("Failed to get taskbar pos");
DEBUG_LOG(("Failed to get taskbar pos"));
if (pEdge) {
*pEdge = ABE_BOTTOM;
}

View file

@ -6,9 +6,9 @@
//
#include "ui/style/style_core_font.h"
#include "ui/style/style_core_custom_font.h"
#include "ui/ui_log.h"
#include "base/algorithm.h"
#include "base/debug_log.h"
#include "ui/style/style_core_custom_font.h"
#include "ui/integration.h"
#include <QtCore/QMap>
@ -49,13 +49,13 @@ 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, realFamily));
LOG(("Font Error: could not resolve '%1' font, got '%2'.").arg(familyName, realFamily));
return false;
}
auto metrics = QFontMetrics(checkFont);
if (!metrics.height()) {
UI_LOG(("Font Error: got a zero height in '%1'.").arg(familyName));
LOG(("Font Error: got a zero height in '%1'.").arg(familyName));
return false;
}
@ -65,13 +65,13 @@ bool ValidateFont(const QString &familyName, int flags = 0) {
bool LoadCustomFont(const QString &filePath, const QString &familyName, int flags = 0) {
auto regularId = QFontDatabase::addApplicationFont(filePath);
if (regularId < 0) {
UI_LOG(("Font Error: could not add '%1'.").arg(filePath));
LOG(("Font Error: could not add '%1'.").arg(filePath));
return false;
}
const auto found = [&] {
for (auto &family : QFontDatabase::applicationFontFamilies(regularId)) {
UI_LOG(("Font: from '%1' loaded '%2'").arg(filePath, family));
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, filePath));
LOG(("Font Error: could not locate '%1' font in '%2'.").arg(familyName, filePath));
return false;
}
@ -194,11 +194,6 @@ void StartFonts() {
style_InitFontsResource();
const auto integrationExists = Ui::Integration::Exists();
if (integrationExists) {
Ui::Integration::Instance().startFontsBegin();
}
#ifndef DESKTOP_APP_USE_PACKAGED_FONTS
if (!UseSystemFont) {
bool areGood[FontTypesCount] = { false };
@ -222,7 +217,7 @@ void StartFonts() {
if (!areGood[i]) {
if (ValidateFont(fallback, flags)) {
Overrides[i] = fallback;
UI_LOG(("Fonts Info: Using '%1' instead of '%2'.").arg(fallback).arg(name));
LOG(("Fonts Info: Using '%1' instead of '%2'.").arg(fallback).arg(name));
}
}
// Disable default fallbacks to Segoe UI, see:
@ -264,10 +259,6 @@ void StartFonts() {
auto appFont = QApplication::font();
appFont.setStyleStrategy(QFont::PreferQuality);
QApplication::setFont(appFont);
if (integrationExists) {
Ui::Integration::Instance().startFontsEnd();
}
}
QString GetPossibleEmptyOverride(int32 flags) {

View file

@ -7,7 +7,7 @@
#include "ui/text/text_block.h"
#include "styles/style_basic.h"
#include "base/integration.h"
#include "base/debug_log.h"
#include <private/qfontengine_p.h>
@ -161,8 +161,8 @@ void addNextCluster(
for (auto i = 0; i < pos; ++i) {
str.append(QString::number(logClusters[i]));
}
base::Integration::Instance().logAssertionViolation(QString("text: %1 (from: %2, length: %3) part: %4").arg(DebugCurrentParsingString).arg(DebugCurrentParsingFrom).arg(DebugCurrentParsingLength).arg(DebugCurrentParsingPart));
base::Integration::Instance().logAssertionViolation(QString("pos: %1, end: %2, glyphPosition: %3, glyphCount: %4, lineLength: %5, num_glyphs: %6, logClusters[0..pos]: %7").arg(pos).arg(end).arg(glyphPosition).arg(glyphCount).arg(line.length).arg(current.num_glyphs).arg(str.join(",")));
LOG(("text: %1 (from: %2, length: %3) part: %4").arg(DebugCurrentParsingString).arg(DebugCurrentParsingFrom).arg(DebugCurrentParsingLength).arg(DebugCurrentParsingPart));
LOG(("pos: %1, end: %2, glyphPosition: %3, glyphCount: %4, lineLength: %5, num_glyphs: %6, logClusters[0..pos]: %7").arg(pos).arg(end).arg(glyphPosition).arg(glyphCount).arg(line.length).arg(current.num_glyphs).arg(str.join(",")));
Unexpected("Values in addNextCluster()");
}
Q_ASSERT((pos == end && glyphPosition == current.num_glyphs)

View file

@ -301,17 +301,22 @@ QStringList PrepareSearchWords(const QString &query, const QRegularExpression *S
bool CutPart(TextWithEntities &sending, TextWithEntities &left, int limit);
struct MentionNameFields {
MentionNameFields(int32 userId = 0, uint64 accessHash = 0) : userId(userId), accessHash(accessHash) {
MentionNameFields(uint64 userId = 0, uint64 accessHash = 0)
: userId(userId), accessHash(accessHash) {
}
int32 userId = 0;
uint64 userId = 0;
uint64 accessHash = 0;
};
inline MentionNameFields MentionNameDataToFields(const QString &data) {
auto components = data.split('.');
if (!components.isEmpty()) {
return { components.at(0).toInt(), (components.size() > 1) ? components.at(1).toULongLong() : 0 };
return {
components.at(0).toULongLong(),
(components.size() > 1) ? components.at(1).toULongLong() : 0
};
}
return MentionNameFields {};
return MentionNameFields{};
}
inline QString MentionNameDataFromFields(const MentionNameFields &fields) {

View file

@ -1,19 +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/ui_log.h"
#include "ui/integration.h"
namespace Ui {
void WriteLogEntry(const QString &message) {
if (Integration::Exists()) {
Integration::Instance().writeLogEntry(message);
}
}
} // namespace Ui

View file

@ -1,15 +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
namespace Ui {
void WriteLogEntry(const QString &message);
} // namespace Ui
#define UI_LOG(message) (::Ui::WriteLogEntry(QString message))

View file

@ -6,11 +6,13 @@
//
#include "ui/ui_utility.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/style/style_core.h"
#include <QtWidgets/QApplication>
#include <QtGui/QWindow>
#include <QtGui/QtEvents>
#include <private/qhighdpiscaling_p.h>
#include <array>
@ -179,6 +181,36 @@ QPixmap PixmapFromImage(QImage &&image) {
return QPixmap::fromImage(std::move(image), Qt::ColorOnly);
}
bool IsContentVisible(
not_null<QWidget*> widget,
const QRect &rect) {
Expects(widget->window()->windowHandle());
const auto activeOrNotOverlapped = [&] {
if (const auto active = widget->isActiveWindow()) {
return active;
}
const auto mappedRect = QHighDpi::toNativePixels(
rect.isNull()
? QRect(
widget->mapToGlobal(QPoint()),
widget->mapToGlobal(
QPoint(widget->width(), widget->height())))
: QRect(
widget->mapToGlobal(rect.topLeft()),
widget->mapToGlobal(rect.bottomRight())),
widget->window()->windowHandle());
const auto overlapped = Platform::IsOverlapped(widget, mappedRect);
return overlapped.has_value() && !*overlapped;
}();
return activeOrNotOverlapped
&& widget->isVisible()
&& !widget->window()->isMinimized();
}
void DisableCustomScaling() {
qunsetenv("QT_DEVICE_PIXEL_RATIO");
qunsetenv("QT_SCALE_FACTOR");

View file

@ -187,6 +187,10 @@ QPointer<const Widget> MakeWeak(not_null<const Widget*> object) {
[[nodiscard]] QPixmap PixmapFromImage(QImage &&image);
[[nodiscard]] bool IsContentVisible(
not_null<QWidget*> widget,
const QRect &rect = QRect());
void DisableCustomScaling();
} // namespace Ui

View file

@ -296,6 +296,11 @@ void RoundButton::setWidthChangedCallback(Fn<void()> callback) {
_numbers->setWidthChangedCallback(std::move(callback));
}
void RoundButton::setBrushOverride(std::optional<QBrush> brush) {
_brushOverride = std::move(brush);
update();
}
void RoundButton::finishNumbersAnimation() {
if (_numbers) {
_numbers->finishAnimating();
@ -367,8 +372,12 @@ void RoundButton::paintEvent(QPaintEvent *e) {
const auto radius = rounded.height() / 2;
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(rect.color());
p.setBrush(_brushOverride ? *_brushOverride : rect.color()->b);
p.drawRoundedRect(fill, radius, radius);
} else if (_brushOverride) {
p.setPen(Qt::NoPen);
p.setBrush(*_brushOverride);
p.drawRoundedRect(fill, st::buttonRadius, st::buttonRadius);
} else {
rect.paint(p, fill);
}
@ -377,7 +386,7 @@ void RoundButton::paintEvent(QPaintEvent *e) {
auto over = isOver();
auto down = isDown();
if (over || down) {
if (!_brushOverride && (over || down)) {
drawRect(_roundRectOver);
}

View file

@ -130,6 +130,7 @@ public:
setNumbersText(QString::number(numbers), numbers);
}
void setWidthChangedCallback(Fn<void()> callback);
void setBrushOverride(std::optional<QBrush> brush);
void finishNumbersAnimation();
int contentWidth() const;
@ -165,6 +166,7 @@ private:
int _fullWidthOverride = 0;
const style::RoundButton &_st;
std::optional<QBrush> _brushOverride;
RoundRect _roundRect;
RoundRect _roundRectOver;