diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 08b31f7ded..f69accb579 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -141,12 +141,7 @@ Application::Application(not_null launcher) , _langpack(std::make_unique()) , _langCloudManager(std::make_unique(langpack())) , _emojiKeywords(std::make_unique()) -, _logo(Window::LoadLogo()) -, _logoNoMargin(Window::LoadLogoNoMargin()) , _autoLockTimer([=] { checkAutoLock(); }) { - Expects(!_logo.isNull()); - Expects(!_logoNoMargin.isNull()); - Ui::Integration::Set(&_private->uiIntegration); passcodeLockChanges( diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index fa4beced6b..219579b271 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -145,12 +145,6 @@ public: bool hideMediaView(); [[nodiscard]] QPoint getPointForCallPanelCenter() const; - [[nodiscard]] QImage logo() const { - return _logo; - } - [[nodiscard]] QImage logoNoMargin() const { - return _logoNoMargin; - } void startSettingsAndBackground(); [[nodiscard]] Settings &settings() { @@ -354,9 +348,6 @@ private: Media::Player::FloatDelegate *_defaultFloatPlayerDelegate = nullptr; Media::Player::FloatDelegate *_replacementFloatPlayerDelegate = nullptr; - const QImage _logo; - const QImage _logoNoMargin; - rpl::variable _passcodeLock; bool _screenIsLocked = false; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index e98a4d3c3c..f91a4da295 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "core/click_handler_types.h" #include "window/window_session_controller.h" +#include "window/main_window.h" // Window::LogoNoMargin. #include "ui/image/image.h" #include "ui/empty_userpic.h" #include "ui/text/text_options.h" @@ -302,7 +303,7 @@ Image *PeerData::currentUserpic( _userpicEmpty = nullptr; } else if (isNotificationsUser()) { static auto result = Image( - Core::App().logoNoMargin().scaledToWidth( + Window::LogoNoMargin().scaledToWidth( kUserpicSize, Qt::SmoothTransformation)); return &result; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 4b80f55f37..de1a00f7c0 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -81,17 +81,6 @@ void FeedLangTestingKey(int key) { MainWindow::MainWindow(not_null controller) : Platform::MainWindow(controller) { - - auto logo = Core::App().logo(); - icon16 = logo.scaledToWidth(16, Qt::SmoothTransformation); - icon32 = logo.scaledToWidth(32, Qt::SmoothTransformation); - icon64 = logo.scaledToWidth(64, Qt::SmoothTransformation); - - auto logoNoMargin = Core::App().logoNoMargin(); - iconbig16 = logoNoMargin.scaledToWidth(16, Qt::SmoothTransformation); - iconbig32 = logoNoMargin.scaledToWidth(32, Qt::SmoothTransformation); - iconbig64 = logoNoMargin.scaledToWidth(64, Qt::SmoothTransformation); - resize(st::windowDefaultWidth, st::windowDefaultHeight); setLocale(QLocale(QLocale::English, QLocale::UnitedStates)); @@ -842,122 +831,6 @@ void MainWindow::updateControlsGeometry() { if (_main) _main->checkMainSectionToLayer(); } -void MainWindow::placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) { - QPainter p(&img); - - QString cnt = (count < 100) ? QString("%1").arg(count) : QString("..%1").arg(count % 10, 1, 10, QChar('0')); - int32 cntSize = cnt.size(); - - p.setBrush(bg->b); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing); - int32 fontSize; - if (size == 16) { - fontSize = 8; - } else if (size == 32) { - fontSize = (cntSize < 2) ? 12 : 12; - } else { - fontSize = (cntSize < 2) ? 22 : 22; - } - style::font f = { fontSize, 0, 0 }; - int32 w = f->width(cnt), d, r; - if (size == 16) { - d = (cntSize < 2) ? 2 : 1; - r = (cntSize < 2) ? 4 : 3; - } else if (size == 32) { - d = (cntSize < 2) ? 5 : 2; - r = (cntSize < 2) ? 8 : 7; - } else { - d = (cntSize < 2) ? 9 : 4; - r = (cntSize < 2) ? 16 : 14; - } - p.drawRoundedRect(QRect(shift.x() + size - w - d * 2, shift.y() + size - f->height, w + d * 2, f->height), r, r); - p.setFont(f->f); - - p.setPen(color->p); - - p.drawText(shift.x() + size - w - d, shift.y() + size - f->height + f->ascent, cnt); - -} - -QImage MainWindow::iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) { - bool layer = false; - if (size < 0) { - size = -size; - layer = true; - } - if (layer) { - if (size != 16 && size != 20 && size != 24) size = 32; - - // platform/linux/main_window_linux depends on count used the same - // way for all the same (count % 1000) values. - QString cnt = (count < 1000) ? QString("%1").arg(count) : QString("..%1").arg(count % 100, 2, 10, QChar('0')); - QImage result(size, size, QImage::Format_ARGB32); - int32 cntSize = cnt.size(); - result.fill(Qt::transparent); - { - QPainter p(&result); - p.setBrush(bg); - p.setPen(Qt::NoPen); - p.setRenderHint(QPainter::Antialiasing); - int32 fontSize; - if (size == 16) { - fontSize = (cntSize < 2) ? 11 : ((cntSize < 3) ? 11 : 8); - } else if (size == 20) { - fontSize = (cntSize < 2) ? 14 : ((cntSize < 3) ? 13 : 10); - } else if (size == 24) { - fontSize = (cntSize < 2) ? 17 : ((cntSize < 3) ? 16 : 12); - } else { - fontSize = (cntSize < 2) ? 22 : ((cntSize < 3) ? 20 : 16); - } - style::font f = { fontSize, 0, 0 }; - int32 w = f->width(cnt), d, r; - if (size == 16) { - d = (cntSize < 2) ? 5 : ((cntSize < 3) ? 2 : 1); - r = (cntSize < 2) ? 8 : ((cntSize < 3) ? 7 : 3); - } else if (size == 20) { - d = (cntSize < 2) ? 6 : ((cntSize < 3) ? 2 : 1); - r = (cntSize < 2) ? 10 : ((cntSize < 3) ? 9 : 5); - } else if (size == 24) { - d = (cntSize < 2) ? 7 : ((cntSize < 3) ? 3 : 1); - r = (cntSize < 2) ? 12 : ((cntSize < 3) ? 11 : 6); - } else { - d = (cntSize < 2) ? 9 : ((cntSize < 3) ? 4 : 2); - r = (cntSize < 2) ? 16 : ((cntSize < 3) ? 14 : 8); - } - p.drawRoundedRect(QRect(size - w - d * 2, size - f->height, w + d * 2, f->height), r, r); - p.setFont(f); - - p.setPen(fg); - - p.drawText(size - w - d, size - f->height + f->ascent, cnt); - } - return result; - } else { - if (size != 16 && size != 32) size = 64; - } - - QImage img(smallIcon ? ((size == 16) ? iconbig16 : (size == 32 ? iconbig32 : iconbig64)) : ((size == 16) ? icon16 : (size == 32 ? icon32 : icon64))); - if (const auto controller = sessionController()) { - if (controller->session().supportMode()) { - Window::ConvertIconToBlack(img); - } - } - if (!count) return img; - - if (smallIcon) { - placeSmallCounter(img, size, count, bg, QPoint(), fg); - } else { - QPainter p(&img); - p.drawPixmap( - size / 2, - size / 2, - Ui::PixmapFromImage( - iconWithCounter(-size / 2, count, bg, fg, false))); - } - return img; -} - void MainWindow::sendPaths() { if (controller().locked()) { return; diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 78b8bc4c42..245a794d4f 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -71,9 +71,6 @@ public: void sendPaths(); - QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) override; - void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) override; - bool contentOverlapped(const QRect &globalRect); bool contentOverlapped(QWidget *w, QPaintEvent *e) { return contentOverlapped(QRect(w->mapToGlobal(e->rect().topLeft()), e->rect().size())); @@ -148,8 +145,6 @@ private: std::unique_ptr _mediaControlsManager; - QImage icon16, icon32, icon64, iconbig16, iconbig32, iconbig64; - crl::time _lastTrayClickTime = 0; QPoint _lastMousePosition; bool _activeForTrayIconAction = true; diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 3bed688698..54f2c94082 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -305,7 +305,7 @@ QIcon TrayIconGen(int counter, bool muted) { } } } else { - currentImageBack = Core::App().logo(); + currentImageBack = Window::Logo(); } if (dprSize(currentImageBack) != desiredSize) { @@ -324,20 +324,19 @@ QIcon TrayIconGen(int counter, bool muted) { : st::trayCounterBg; const auto &fg = st::trayCounterFg; if (iconSize >= 22) { - auto layerSize = -16; - if (iconSize >= 48) { - layerSize = -32; - } else if (iconSize >= 36) { - layerSize = -24; - } else if (iconSize >= 32) { - layerSize = -20; - } - const auto layer = App::wnd()->iconWithCounter( - layerSize, - counter, - bg, - fg, - false); + const auto layerSize = (iconSize >= 48) + ? 32 + : (iconSize >= 36) + ? 24 + : (iconSize >= 32) + ? 20 + : 16; + const auto layer = Window::GenerateCounterLayer({ + .size = layerSize, + .count = counter, + .bg = bg, + .fg = fg, + }); QPainter p(&iconImage); p.drawImage( @@ -345,13 +344,12 @@ QIcon TrayIconGen(int counter, bool muted) { iconImage.height() - layer.height() - 1, layer); } else { - App::wnd()->placeSmallCounter( - iconImage, - 16, - counter, - bg, - QPoint(), - fg); + iconImage = Window::WithSmallCounter(std::move(iconImage), { + .size = 16, + .count = counter, + .bg = bg, + .fg = fg, + }); } } diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index 7bfb6f0cf0..6b675f8cff 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -20,13 +20,6 @@ class MainWindow : public Window::MainWindow { public: explicit MainWindow(not_null controller); - virtual QImage iconWithCounter( - int size, - int count, - style::color bg, - style::color fg, - bool smallIcon) = 0; - void psShowTrayMenu(); bool trayAvailable() { @@ -54,14 +47,6 @@ protected: void psTrayMenuUpdated(); void psSetupTrayIcon(); - virtual void placeSmallCounter( - QImage &img, - int size, - int count, - style::color bg, - const QPoint &shift, - style::color color) = 0; - private: class Private; friend class Private; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h index 7588e863a4..ed57eccd17 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.h +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h @@ -25,8 +25,6 @@ public: bool psFilterNativeEvent(void *event); - virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; - int getCustomTitleHeight() const { return _customTitleHeight; } @@ -77,7 +75,6 @@ protected: void psTrayMenuUpdated(); void psSetupTrayIcon(); - virtual void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) = 0; void closeWithoutDestroy() override; void createGlobalMenu() override; diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 4b3ffbb8e3..38a35eb663 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -13,7 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/win/windows_dlls.h" #include "platform/win/windows_event_filter.h" #include "window/notifications_manager.h" +#include "window/window_session_controller.h" #include "mainwindow.h" +#include "main/main_session.h" #include "base/crc32hash.h" #include "base/platform/win/base_windows_wrl.h" #include "base/platform/base_platform_info.h" @@ -59,47 +61,77 @@ constexpr auto kKeepActiveForTrayIcon = crl::time(500); using namespace Microsoft::WRL; -HICON createHIconFromQIcon(const QIcon &icon, int xSize, int ySize) { +[[nodiscard]] HICON NativeIcon(const QIcon &icon, QSize size) { if (!icon.isNull()) { - const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize))); - if (!pm.isNull()) { - return qt_pixmapToWinHICON(pm); + const auto pixmap = icon.pixmap(icon.actualSize(size)); + if (!pixmap.isNull()) { + return qt_pixmapToWinHICON(pixmap); } } return nullptr; } -HWND createTaskbarHider() { - HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); - HWND hWnd = 0; +[[nodiscard]] QImage IconWithCounter( + Window::CounterLayerArgs &&args, + Main::Session *session, + bool smallIcon) { + static constexpr auto kCount = 3; + static auto ScaledLogo = std::array(); + static auto ScaledLogoNoMargin = std::array(); - QString cn = QString("TelegramTaskbarHider"); - LPCWSTR _cn = (LPCWSTR)cn.utf16(); - WNDCLASSEX wc; + struct Dimensions { + int index = 0; + int size = 0; + }; + const auto d = [&]() -> Dimensions { + switch (args.size) { + case 16: + return { + .index = 0, + .size = 16, + }; + case 32: + return { + .index = 1, + .size = 32, + }; + default: + return { + .index = 2, + .size = 64, + }; + } + }(); + Assert(d.index < kCount); - wc.cbSize = sizeof(wc); - wc.style = 0; - wc.lpfnWndProc = DefWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = appinst; - wc.hIcon = 0; - wc.hCursor = 0; - wc.hbrBackground = 0; - wc.lpszMenuName = NULL; - wc.lpszClassName = _cn; - wc.hIconSm = 0; - if (!RegisterClassEx(&wc)) { - DEBUG_LOG(("Application Error: could not register taskbar hider window class, error: %1").arg(GetLastError())); - return hWnd; + auto &scaled = smallIcon ? ScaledLogoNoMargin : ScaledLogo; + auto result = [&] { + auto &image = scaled[d.index]; + if (image.isNull()) { + image = (smallIcon + ? Window::LogoNoMargin() + : Window::Logo()).scaledToWidth( + d.size, + Qt::SmoothTransformation); + } + return image; + }(); + if (session && session->supportMode()) { + Window::ConvertIconToBlack(result); } - - hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, _cn, 0, WS_POPUP, 0, 0, 0, 0, 0, 0, appinst, 0); - if (!hWnd) { - DEBUG_LOG(("Application Error: could not create taskbar hider window class, error: %1").arg(GetLastError())); - return hWnd; + if (!args.count) { + return result; + } else if (smallIcon) { + return Window::WithSmallCounter(std::move(result), std::move(args)); } - return hWnd; + QPainter p(&result); + const auto half = d.size / 2; + args.size = half; + p.drawPixmap( + half, + half, + Ui::PixmapFromImage(Window::GenerateCounterLayer(std::move(args)))); + return result; } ComPtr taskbarList; @@ -202,7 +234,8 @@ void MainWindow::psSetupTrayIcon() { if (!trayIcon) { trayIcon = new QSystemTrayIcon(this); - auto icon = QIcon(Ui::PixmapFromImage(Core::App().logoNoMargin())); + const auto icon = QIcon(Ui::PixmapFromImage( + QImage(Window::LogoNoMargin()))); trayIcon->setIcon(icon); connect( @@ -327,47 +360,72 @@ void MainWindow::unreadCounterChangedHook() { void MainWindow::updateIconCounters() { const auto counter = Core::App().unreadBadge(); const auto muted = Core::App().unreadBadgeMuted(); + const auto controller = sessionController(); + const auto session = controller ? &controller->session() : nullptr; - auto iconSizeSmall = QSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); - auto iconSizeBig = QSize(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); + const auto iconSizeSmall = QSize( + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON)); + const auto iconSizeBig = QSize( + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON)); - auto &bg = (muted ? st::trayCounterBgMute : st::trayCounterBg); - auto &fg = st::trayCounterFg; - auto iconSmallPixmap16 = Ui::PixmapFromImage( - iconWithCounter(16, counter, bg, fg, true)); - auto iconSmallPixmap32 = Ui::PixmapFromImage( - iconWithCounter(32, counter, bg, fg, true)); + const auto &bg = muted ? st::trayCounterBgMute : st::trayCounterBg; + const auto &fg = st::trayCounterFg; + const auto counterArgs = [&](int size, int counter) { + return Window::CounterLayerArgs{ + .size = size, + .count = counter, + .bg = bg, + .fg = fg, + }; + }; + const auto iconWithCounter = [&](int size, int counter, bool smallIcon) { + return Ui::PixmapFromImage(IconWithCounter( + counterArgs(size, counter), + session, + smallIcon)); + }; + + auto iconSmallPixmap16 = iconWithCounter(16, counter, true); + auto iconSmallPixmap32 = iconWithCounter(32, counter, true); QIcon iconSmall, iconBig; iconSmall.addPixmap(iconSmallPixmap16); iconSmall.addPixmap(iconSmallPixmap32); - iconBig.addPixmap(Ui::PixmapFromImage( - iconWithCounter(32, taskbarList.Get() ? 0 : counter, bg, fg, false))); - iconBig.addPixmap(Ui::PixmapFromImage( - iconWithCounter(64, taskbarList.Get() ? 0 : counter, bg, fg, false))); + const auto bigCounter = taskbarList.Get() ? 0 : counter; + iconBig.addPixmap(iconWithCounter(32, bigCounter, false)); + iconBig.addPixmap(iconWithCounter(64, bigCounter, false)); if (trayIcon) { // Force Qt to use right icon size, not the larger one. QIcon forTrayIcon; - forTrayIcon.addPixmap(iconSizeSmall.width() >= 20 ? iconSmallPixmap32 : iconSmallPixmap16); + forTrayIcon.addPixmap(iconSizeSmall.width() >= 20 + ? iconSmallPixmap32 + : iconSmallPixmap16); trayIcon->setIcon(forTrayIcon); } psDestroyIcons(); - ps_iconSmall = createHIconFromQIcon(iconSmall, iconSizeSmall.width(), iconSizeSmall.height()); - ps_iconBig = createHIconFromQIcon(iconBig, iconSizeBig.width(), iconSizeBig.height()); - SendMessage(ps_hWnd, WM_SETICON, 0, (LPARAM)ps_iconSmall); - SendMessage(ps_hWnd, WM_SETICON, 1, (LPARAM)(ps_iconBig ? ps_iconBig : ps_iconSmall)); - if (taskbarList.Get()) { + ps_iconSmall = NativeIcon(iconSmall, iconSizeSmall); + ps_iconBig = NativeIcon(iconBig, iconSizeBig); + SendMessage(ps_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)ps_iconSmall); + SendMessage(ps_hWnd, WM_SETICON, ICON_BIG, (LPARAM)(ps_iconBig ? ps_iconBig : ps_iconSmall)); + if (taskbarList) { if (counter > 0) { + const auto pixmap = [&](int size) { + return Ui::PixmapFromImage(Window::GenerateCounterLayer( + counterArgs(size, counter))); + }; QIcon iconOverlay; - iconOverlay.addPixmap(Ui::PixmapFromImage( - iconWithCounter(-16, counter, bg, fg, false))); - iconOverlay.addPixmap(Ui::PixmapFromImage( - iconWithCounter(-32, counter, bg, fg, false))); - ps_iconOverlay = createHIconFromQIcon(iconOverlay, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + iconOverlay.addPixmap(pixmap(16)); + iconOverlay.addPixmap(pixmap(32)); + ps_iconOverlay = NativeIcon(iconOverlay, iconSizeSmall); } - auto description = (counter > 0) ? tr::lng_unread_bar(tr::now, lt_count, counter) : QString(); - taskbarList->SetOverlayIcon(ps_hWnd, ps_iconOverlay, description.toStdWString().c_str()); + const auto description = (counter > 0) + ? tr::lng_unread_bar(tr::now, lt_count, counter).toStdWString() + : std::wstring(); + taskbarList->SetOverlayIcon(ps_hWnd, ps_iconOverlay, description.c_str()); } + psDestroyIcons(); SetWindowPos(ps_hWnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index b44872adbc..02a6efd62f 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -30,8 +30,6 @@ public: void psRefreshTaskbarIcon(); - virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0; - [[nodiscard]] static uint32 TaskbarCreatedMsgId(); static void TaskbarCreated(); @@ -59,7 +57,6 @@ protected: void psTrayMenuUpdated(); void psSetupTrayIcon(); - virtual void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) = 0; void showTrayTooltip() override; diff --git a/Telegram/SourceFiles/settings/settings_notifications.cpp b/Telegram/SourceFiles/settings/settings_notifications.cpp index 17c00d4453..9b477ef48c 100644 --- a/Telegram/SourceFiles/settings/settings_notifications.cpp +++ b/Telegram/SourceFiles/settings/settings_notifications.cpp @@ -258,7 +258,7 @@ void NotificationsCount::prepareNotificationSampleSmall() { void NotificationsCount::prepareNotificationSampleUserpic() { if (_notificationSampleUserpic.isNull()) { _notificationSampleUserpic = Ui::PixmapFromImage( - Core::App().logoNoMargin().scaled( + Window::LogoNoMargin().scaled( st::notifyPhotoSize * cIntRetinaFactor(), st::notifyPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 27c249b39a..597f45853b 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -49,12 +49,14 @@ constexpr auto kSaveWindowPositionTimeout = crl::time(1000); } // namespace -QImage LoadLogo() { - return QImage(qsl(":/gui/art/logo_256.png")); +const QImage &Logo() { + static const auto result = QImage(u":/gui/art/logo_256.png"_q); + return result; } -QImage LoadLogoNoMargin() { - return QImage(qsl(":/gui/art/logo_256_no_margin.png")); +const QImage &LogoNoMargin() { + static const auto result = QImage(u":/gui/art/logo_256_no_margin.png"_q); + return result; } void ConvertIconToBlack(QImage &image) { @@ -105,7 +107,7 @@ void ConvertIconToBlack(QImage &image) { } QIcon CreateOfficialIcon(Main::Session *session) { - auto image = Core::IsAppLaunched() ? Core::App().logo() : LoadLogo(); + auto image = Logo(); if (session && session->supportMode()) { ConvertIconToBlack(image); } @@ -156,6 +158,144 @@ QIcon CreateIcon(Main::Session *session) { return result; } +QImage GenerateCounterLayer(CounterLayerArgs &&args) { + // platform/linux/main_window_linux depends on count used the same + // way for all the same (count % 1000) values. + const auto count = args.count.value(); + const auto text = (count < 1000) + ? QString::number(count) + : u"..%1"_q.arg(count % 100, 2, 10, QChar('0')); + const auto textSize = text.size(); + + struct Dimensions { + int size = 0; + int font = 0; + int delta = 0; + int radius = 0; + }; + const auto d = [&]() -> Dimensions { + switch (args.size.value()) { + case 16: + return { + .size = 16, + .font = ((textSize < 2) ? 11 : (textSize < 3) ? 11 : 8), + .delta = ((textSize < 2) ? 5 : (textSize < 3) ? 2 : 1), + .radius = ((textSize < 2) ? 8 : (textSize < 3) ? 7 : 3), + }; + case 20: + return { + .size = 20, + .font = ((textSize < 2) ? 14 : (textSize < 3) ? 13 : 10), + .delta = ((textSize < 2) ? 6 : (textSize < 3) ? 2 : 1), + .radius = ((textSize < 2) ? 10 : (textSize < 3) ? 9 : 5), + }; + case 24: + return { + .size = 24, + .font = ((textSize < 2) ? 17 : (textSize < 3) ? 16 : 12), + .delta = ((textSize < 2) ? 7 : (textSize < 3) ? 3 : 1), + .radius = ((textSize < 2) ? 12 : (textSize < 3) ? 11 : 6), + }; + default: + return { + .size = 32, + .font = ((textSize < 2) ? 22 : (textSize < 3) ? 20 : 16), + .delta = ((textSize < 2) ? 9 : (textSize < 3) ? 4 : 2), + .radius = ((textSize < 2) ? 16 : (textSize < 3) ? 14 : 8), + }; + } + }(); + + auto result = QImage(d.size, d.size, QImage::Format_ARGB32); + result.fill(Qt::transparent); + + auto p = QPainter(&result); + auto hq = PainterHighQualityEnabler(p); + const auto f = style::font{ d.font, 0, 0 }; + const auto w = f->width(text); + + p.setBrush(args.bg.value()); + p.setPen(Qt::NoPen); + p.drawRoundedRect( + QRect( + d.size - w - d.delta * 2, + d.size - f->height, + w + d.delta * 2, + f->height), + d.radius, + d.radius); + + p.setFont(f); + p.setPen(args.fg.value()); + p.drawText(d.size - w - d.delta, d.size - f->height + f->ascent, text); + p.end(); + + return result; +} + +QImage WithSmallCounter(QImage image, CounterLayerArgs &&args) { + const auto count = args.count.value(); + const auto text = (count < 100) + ? QString::number(count) + : QString("..%1").arg(count % 10, 1, 10, QChar('0')); + const auto textSize = text.size(); + + struct Dimensions { + int size = 0; + int font = 0; + int delta = 0; + int radius = 0; + }; + const auto d = [&]() -> Dimensions { + switch (args.size.value()) { + case 16: + return { + .size = 16, + .font = 8, + .delta = ((textSize < 2) ? 2 : 1), + .radius = ((textSize < 2) ? 4 : 3), + }; + case 32: + return { + .size = 32, + .font = 12, + .delta = ((textSize < 2) ? 5 : 2), + .radius = ((textSize < 2) ? 8 : 7), + }; + default: + return { + .size = 64, + .font = 22, + .delta = ((textSize < 2) ? 9 : 4), + .radius = ((textSize < 2) ? 16 : 14), + }; + } + }(); + + auto p = QPainter(&image); + auto hq = PainterHighQualityEnabler(p); + const auto f = style::font{ d.font, 0, 0 }; + const auto w = f->width(text); + + p.setBrush(args.bg.value()); + p.setPen(Qt::NoPen); + p.drawRoundedRect( + QRect( + d.size - w - d.delta * 2, + d.size - f->height, + w + d.delta * 2, + f->height), + d.radius, + d.radius); + + p.setFont(f); + p.setPen(args.fg.value()); + p.drawText(d.size - w - d.delta, d.size - f->height + f->ascent, text); + p.end(); + + return image; +} + MainWindow::MainWindow(not_null controller) : _controller(controller) , _positionUpdatedTimer([=] { savePosition(); }) diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 8d831fc55a..c1a0a87c83 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" #include "base/object_ptr.h" #include "core/core_settings.h" +#include "base/required.h" #include @@ -35,11 +36,21 @@ class SessionController; class TitleWidget; struct TermsLock; -QImage LoadLogo(); -QImage LoadLogoNoMargin(); -QIcon CreateIcon(Main::Session *session = nullptr); +[[nodiscard]] const QImage &Logo(); +[[nodiscard]] const QImage &LogoNoMargin(); +[[nodiscard]] QIcon CreateIcon(Main::Session *session = nullptr); void ConvertIconToBlack(QImage &image); +struct CounterLayerArgs { + base::required size = 16; + base::required count = 1; + base::required bg; + base::required fg; +}; + +[[nodiscard]] QImage GenerateCounterLayer(CounterLayerArgs &&args); +[[nodiscard]] QImage WithSmallCounter(QImage image, CounterLayerArgs &&args); + class MainWindow : public Ui::RpWindow { public: explicit MainWindow(not_null controller); diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 8bfda66d21..7b612bf7ce 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -87,7 +87,7 @@ Manager::QueuedNotification::QueuedNotification( QPixmap Manager::hiddenUserpicPlaceholder() const { if (_hiddenUserpicPlaceholder.isNull()) { _hiddenUserpicPlaceholder = Ui::PixmapFromImage( - Core::App().logoNoMargin().scaled( + LogoNoMargin().scaled( st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, diff --git a/Telegram/SourceFiles/window/notifications_utilities.cpp b/Telegram/SourceFiles/window/notifications_utilities.cpp index 6c72b38cdc..2911ed575c 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.cpp +++ b/Telegram/SourceFiles/window/notifications_utilities.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "window/notifications_utilities.h" +#include "window/main_window.h" #include "base/platform/base_platform_file_utilities.h" #include "base/random.h" #include "core/application.h" @@ -79,7 +80,7 @@ QString CachedUserpics::get( peer->saveUserpic(view, v.path, st::notifyMacPhotoSize); } } else { - Core::App().logoNoMargin().save(v.path, "PNG"); + LogoNoMargin().save(v.path, "PNG"); } i = _images.insert(key, v); _someSavedFlag = true;