update icons

This commit is contained in:
dranik
2026-06-05 09:00:14 +03:00
parent 0db1e52468
commit e61b1dfa11
19 changed files with 83 additions and 145 deletions
+5 -4
View File
@@ -65,10 +65,11 @@
<file>controls/text-cursor.svg</file>
<file>controls/trash.svg</file>
<file>controls/x-circle.svg</file>
<file>tray/active.png</file>
<file>tray/default.png</file>
<file>tray/error.png</file>
<file>tray/icon.svg</file>
<file>tray/off-black.svg</file>
<file>tray/off-light.svg</file>
<file>tray/on-black.svg</file>
<file>tray/on-white.svg</file>
<file>tray/error.svg</file>
<file>controls/monitor.svg</file>
</qresource>
</RCC>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

@@ -32,9 +32,7 @@ void LinuxTrayIconBackend::show()
void LinuxTrayIconBackend::applyVisual(const TrayIconVisual &visual)
{
const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState);
const QColor indicatorColor = TrayIconCommon::indicatorColorForState(visual.connectionState);
const QIcon icon = buildTrayIcon(opacity, visual.darkTheme, indicatorColor);
const QIcon icon = buildTrayIcon(visual.connectionState, visual.darkTheme);
// Some tray implementations cache the first icon; clear before applying an update.
if (m_trayIcon.isVisible()) {
@@ -47,8 +45,7 @@ void LinuxTrayIconBackend::showMessage(const QString &title, const QString &mess
int timerMsec)
{
m_trayIcon.showMessage(title, message,
buildTrayIcon(TrayIconCommon::kConnectedOpacity, visual.darkTheme,
TrayIconCommon::indicatorColorForState(Vpn::ConnectionState::Connected)),
buildTrayIcon(Vpn::ConnectionState::Connected, visual.darkTheme),
timerMsec);
}
@@ -66,11 +63,11 @@ void LinuxTrayIconBackend::setActivatedHandler(std::function<void(QSystemTrayIco
[handler](QSystemTrayIcon::ActivationReason reason) { handler(reason); });
}
QIcon LinuxTrayIconBackend::buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const
QIcon LinuxTrayIconBackend::buildTrayIcon(Vpn::ConnectionState state, bool darkTheme) const
{
QIcon icon;
for (int size : kLinuxTrayIconSizes) {
icon.addPixmap(TrayIconCommon::buildPixmap(size, opacity, darkTheme, indicatorColor));
icon.addPixmap(TrayIconCommon::buildPixmap(size, state, darkTheme));
}
return icon;
}
@@ -21,7 +21,7 @@ public:
void setActivatedHandler(std::function<void(QSystemTrayIcon::ActivationReason)> handler) override;
private:
QIcon buildTrayIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor) const;
QIcon buildTrayIcon(Vpn::ConnectionState state, bool darkTheme) const;
QSystemTrayIcon m_trayIcon;
};
-1
View File
@@ -23,7 +23,6 @@ class MacOSStatusIcon final : public QObject {
public:
void setIcon(const QString& iconUrl);
void setIconFromData(const QByteArray& imageData);
void setIndicatorColor(const QColor& indicatorColor);
void setMenu(QMenu* menu);
void rebuildNativeMenu();
void setToolTip(const QString& tooltip);
+4 -53
View File
@@ -29,21 +29,17 @@
@end
/**
* Creates a NSStatusItem with that can hold an icon. Additionally a NSView is
* set as a subview to the button item of the status item. The view serves as
* an indicator that can be displayed in color eventhough the icon is set as a
* template. In that way we give the system control over its effective
* appearance.
* Creates a NSStatusItem that holds the tray icon. The icon is set as a
* template image, so the system controls its effective appearance for the
* current menu bar theme. The connection status is baked into the artwork, so
* no separate colored indicator is drawn.
*/
@interface MacOSStatusIconDelegate : NSObject
@property(assign) NSStatusItem* statusItem;
@property(assign) NSView* statusIndicator;
@property(retain) NSMenu* nativeMenu;
@property(retain) NSMutableArray* menuActionTargets;
- (void)setIcon:(NSData*)imageData;
- (void)setIndicator;
- (void)setIndicatorColor:(NSColor*)color;
- (void)setToolTip:(NSString*)tooltip;
- (void)rebuildMenuFromQMenu:(QMenu*)menu;
@end
@@ -62,8 +58,6 @@
self.statusItem =
[[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
self.statusItem.visible = true;
// Add the indicator as a subview
[self setIndicator];
return self;
}
@@ -87,34 +81,6 @@
[image release];
}
/**
* Adds status indicator as a subview to the status item button.
*/
- (void)setIndicator {
float viewHeight = NSHeight([self.statusItem.button bounds]);
float dotSize = viewHeight * 0.35;
float dotOrigin = (viewHeight - dotSize) * 0.8;
NSView* dot = [[NSView alloc] initWithFrame:NSMakeRect(dotOrigin, dotOrigin, dotSize, dotSize)];
self.statusIndicator = dot;
self.statusIndicator.wantsLayer = true;
self.statusIndicator.layer.cornerRadius = dotSize * 0.5;
[self.statusItem.button addSubview:self.statusIndicator];
[dot release];
}
/**
* Sets the color if the indicator.
*
* @param color The indicator background color.
*/
- (void)setIndicatorColor:(NSColor*)color {
if (self.statusIndicator) {
self.statusIndicator.layer.backgroundColor = color.CGColor;
}
}
/**
* Sets the status bar menu to the status item.
*
@@ -217,21 +183,6 @@ void MacOSStatusIcon::setIconFromData(const QByteArray& imageData) {
[m_statusBarIcon setIcon:data];
}
void MacOSStatusIcon::setIndicatorColor(const QColor& indicatorColor) {
logger.debug() << "Set indicator color";
if (!indicatorColor.isValid()) {
[m_statusBarIcon setIndicatorColor:[NSColor clearColor]];
return;
}
NSColor* color = [NSColor colorWithCalibratedRed:indicatorColor.red() / 255.0f
green:indicatorColor.green() / 255.0f
blue:indicatorColor.blue() / 255.0f
alpha:indicatorColor.alpha() / 255.0f];
[m_statusBarIcon setIndicatorColor:color];
}
void MacOSStatusIcon::setMenu(QMenu* menu) {
m_qtMenu = menu;
rebuildNativeMenu();
+1 -3
View File
@@ -23,9 +23,7 @@ void MacTrayIconBackend::show()
void MacTrayIconBackend::applyVisual(const TrayIconVisual &visual)
{
const qreal opacity = TrayIconCommon::opacityForState(visual.connectionState);
m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(opacity));
m_statusIcon.setIndicatorColor(TrayIconCommon::indicatorColorForState(visual.connectionState));
m_statusIcon.setIconFromData(TrayIconCommon::buildTemplatePng(visual.connectionState));
}
void MacTrayIconBackend::showMessage(const QString &title, const QString &message, const TrayIconVisual &visual, int timerMsec)
+4 -7
View File
@@ -6,22 +6,19 @@
namespace WinTrayIcon
{
QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor)
QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme)
{
return TrayIconCommon::buildIcon(opacity, darkTheme, indicatorColor);
return TrayIconCommon::buildIcon(state, darkTheme);
}
void applyTo(QSystemTrayIcon &trayIcon, Vpn::ConnectionState state, bool darkTheme)
{
const qreal opacity = TrayIconCommon::opacityForState(state);
const QColor indicatorColor = TrayIconCommon::indicatorColorForState(state);
trayIcon.setIcon(buildIcon(opacity, darkTheme, indicatorColor));
trayIcon.setIcon(buildIcon(state, darkTheme));
}
QIcon buildNotifyIcon(bool darkTheme)
{
return buildIcon(TrayIconCommon::kConnectedOpacity, darkTheme,
TrayIconCommon::indicatorColorForState(Vpn::ConnectionState::Connected));
return buildIcon(Vpn::ConnectionState::Connected, darkTheme);
}
void configure(QSystemTrayIcon &trayIcon, QMenu *menu, const QString &tooltip)
+1 -1
View File
@@ -12,7 +12,7 @@ class QString;
namespace WinTrayIcon
{
QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor);
QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme);
void applyTo(QSystemTrayIcon &trayIcon, Vpn::ConnectionState state, bool darkTheme);
QIcon buildNotifyIcon(bool darkTheme);
+14 -52
View File
@@ -7,93 +7,55 @@
namespace TrayIconCommon
{
qreal opacityForState(Vpn::ConnectionState state)
QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme)
{
switch (state) {
case Vpn::ConnectionState::Error:
return QString::fromLatin1(kIconError);
case Vpn::ConnectionState::Connected:
case Vpn::ConnectionState::Error: return kConnectedOpacity;
return QString::fromLatin1(darkTheme ? kIconOnWhite : kIconOnBlack);
case Vpn::ConnectionState::Disconnected:
case Vpn::ConnectionState::Preparing:
case Vpn::ConnectionState::Connecting:
case Vpn::ConnectionState::Disconnecting:
case Vpn::ConnectionState::Reconnecting:
case Vpn::ConnectionState::Unknown:
default: return kDisconnectedOpacity;
default:
return QString::fromLatin1(darkTheme ? kIconOffLight : kIconOffBlack);
}
}
QColor indicatorColorForState(Vpn::ConnectionState state)
{
switch (state) {
case Vpn::ConnectionState::Connected: return QColor(52, 199, 89);
case Vpn::ConnectionState::Error: return QColor(235, 87, 87);
default: return QColor();
}
}
QPixmap renderTemplate(const QString &resourcePath, qreal opacity, int size)
QPixmap renderIcon(const QString &resourcePath, int size)
{
QSvgRenderer renderer(resourcePath);
QPixmap pixmap(size, size);
pixmap.fill(Qt::transparent);
if (!renderer.isValid()) {
qWarning() << "Failed to load tray icon template:" << resourcePath;
qWarning() << "Failed to load tray icon:" << resourcePath;
return pixmap;
}
QPainter painter(&pixmap);
painter.setOpacity(opacity);
renderer.render(&painter, QRectF(0, 0, size, size));
return pixmap;
}
QPixmap colorizeTemplate(const QPixmap &mask, const QColor &foreground, int size)
QPixmap buildPixmap(int size, Vpn::ConnectionState state, bool darkTheme)
{
QPixmap result(size, size);
result.fill(Qt::transparent);
QPainter painter(&result);
painter.fillRect(result.rect(), foreground);
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.drawPixmap(0, 0, mask);
return result;
return renderIcon(resourcePathForState(state, darkTheme), size);
}
void drawStatusIndicator(QPainter &painter, const QColor &color, int size)
{
const qreal dotSize = size * 0.35;
const qreal dotOrigin = (size - dotSize) * 0.8;
painter.setPen(Qt::NoPen);
painter.setBrush(color);
painter.drawEllipse(QRectF(dotOrigin, dotOrigin, dotSize, dotSize));
}
QPixmap buildPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor)
{
const QPixmap mask = renderTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, size);
const QColor foreground = darkTheme ? Qt::white : Qt::black;
QPixmap pixmap = colorizeTemplate(mask, foreground, size);
if (indicatorColor.isValid()) {
QPainter painter(&pixmap);
drawStatusIndicator(painter, indicatorColor, size);
}
return pixmap;
}
QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor)
QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme)
{
QIcon icon;
icon.addPixmap(buildPixmap(kDefaultTrayIconSize, opacity, darkTheme, indicatorColor));
icon.addPixmap(buildPixmap(kDefaultTrayIconSize, state, darkTheme));
return icon;
}
QByteArray buildTemplatePng(qreal opacity)
QByteArray buildTemplatePng(Vpn::ConnectionState state)
{
const QPixmap pixmap = renderTemplate(QString::fromLatin1(kTrayTemplateIconPath), opacity, kDefaultTrayIconSize);
const QPixmap pixmap = renderIcon(resourcePathForState(state, /*darkTheme*/ true), kDefaultTrayIconSize);
QByteArray bytes;
QBuffer buffer(&bytes);
+11 -13
View File
@@ -2,31 +2,29 @@
#define TRAYICONCOMMON_H
#include <QByteArray>
#include <QColor>
#include <QIcon>
#include <QPainter>
#include <QPixmap>
#include <QString>
#include "core/protocols/vpnProtocol.h"
namespace TrayIconCommon
{
constexpr int kDefaultTrayIconSize = 128;
constexpr char kTrayTemplateIconPath[] = ":/images/tray/icon.svg";
constexpr qreal kDisconnectedOpacity = 0.5;
constexpr qreal kConnectedOpacity = 1.0;
constexpr char kIconOffBlack[] = ":/images/tray/off-black.svg";
constexpr char kIconOffLight[] = ":/images/tray/off-light.svg";
constexpr char kIconOnBlack[] = ":/images/tray/on-black.svg";
constexpr char kIconOnWhite[] = ":/images/tray/on-white.svg";
constexpr char kIconError[] = ":/images/tray/error.svg";
qreal opacityForState(Vpn::ConnectionState state);
QColor indicatorColorForState(Vpn::ConnectionState state);
QString resourcePathForState(Vpn::ConnectionState state, bool darkTheme);
QPixmap renderTemplate(const QString &resourcePath, qreal opacity, int size);
QPixmap colorizeTemplate(const QPixmap &mask, const QColor &foreground, int size);
void drawStatusIndicator(QPainter &painter, const QColor &color, int size);
QPixmap renderIcon(const QString &resourcePath, int size);
QPixmap buildPixmap(int size, qreal opacity, bool darkTheme, const QColor &indicatorColor);
QIcon buildIcon(qreal opacity, bool darkTheme, const QColor &indicatorColor);
QByteArray buildTemplatePng(qreal opacity);
QPixmap buildPixmap(int size, Vpn::ConnectionState state, bool darkTheme);
QIcon buildIcon(Vpn::ConnectionState state, bool darkTheme);
QByteArray buildTemplatePng(Vpn::ConnectionState state);
} // namespace TrayIconCommon