mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-18 13:04:37 +03:00
feat: set custom icon
feat: tray icon status point
This commit is contained in:
@@ -127,6 +127,7 @@ set(PROJECT_SOURCES
|
||||
sys/AutoRun.cpp
|
||||
|
||||
ui/ThemeManager.cpp
|
||||
ui/TrayIcon.cpp
|
||||
|
||||
ui/mainwindow_grpc.cpp
|
||||
ui/mainwindow.cpp
|
||||
|
||||
@@ -159,6 +159,26 @@
|
||||
<source>Include Pre-release when checking update</source>
|
||||
<translation>检查更新时包括 Pre-release</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set custom icon</source>
|
||||
<translation>自定义图标</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please select a PNG file.</source>
|
||||
<translation>请选择一个 PNG 文件。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation>重置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please select a valid square image.</source>
|
||||
<translation>请选择有效的正方形图像。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>取消</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DialogEditGroup</name>
|
||||
|
||||
39
ui/TrayIcon.cpp
Normal file
39
ui/TrayIcon.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "TrayIcon.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) {
|
||||
auto icon = QIcon::fromTheme("nekoray");
|
||||
auto pixmap = QPixmap("../nekoray.png");
|
||||
if (!pixmap.isNull()) icon = QIcon(pixmap);
|
||||
pixmap = QPixmap("./nekoray.png");
|
||||
if (!pixmap.isNull()) icon = QIcon(pixmap);
|
||||
|
||||
if (status == TrayIconStatus::NONE) return icon;
|
||||
|
||||
pixmap = icon.pixmap(icon.availableSizes().first());
|
||||
auto p = QPainter(&pixmap);
|
||||
|
||||
auto side = pixmap.width();
|
||||
auto radius = side * 0.4;
|
||||
auto d = side * 0.3;
|
||||
auto margin = side * 0.1;
|
||||
|
||||
if (status == TrayIconStatus::RUNNING) {
|
||||
p.setBrush(QBrush(Qt::darkGreen));
|
||||
} else if (status == TrayIconStatus::SYSTEM_PROXY) {
|
||||
p.setBrush(QBrush(Qt::blue));
|
||||
} else if (status == TrayIconStatus::VPN) {
|
||||
p.setBrush(QBrush(Qt::red));
|
||||
}
|
||||
p.drawRoundedRect(
|
||||
QRect(side - d - margin,
|
||||
side - d - margin,
|
||||
d,
|
||||
d),
|
||||
radius,
|
||||
radius);
|
||||
p.end();
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
16
ui/TrayIcon.hpp
Normal file
16
ui/TrayIcon.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
namespace TrayIcon {
|
||||
|
||||
enum TrayIconStatus {
|
||||
NONE,
|
||||
RUNNING,
|
||||
SYSTEM_PROXY,
|
||||
VPN,
|
||||
};
|
||||
|
||||
QIcon GetIcon(TrayIconStatus status);
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QStyleFactory>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
class ExtraCoreWidget : public QWidget {
|
||||
public:
|
||||
@@ -223,3 +224,26 @@ void DialogBasicSettings::accept() {
|
||||
dialog_message(Dialog_DialogBasicSettings, "UpdateDataStore");
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void DialogBasicSettings::on_set_custom_icon_clicked() {
|
||||
auto title = ui->set_custom_icon->text();
|
||||
auto c = QMessageBox::question(this, title, tr("Please select a PNG file."),
|
||||
tr("Select"), tr("Reset"), tr("Cancel"), 2, 2);
|
||||
if (c == 0) {
|
||||
auto fn = QFileDialog::getOpenFileName(this, QObject::tr("Select"), QDir::currentPath(),
|
||||
"*.png", nullptr, QFileDialog::Option::ReadOnly);
|
||||
if (!fn.isEmpty()) {
|
||||
QImage img(fn);
|
||||
if (img.isNull() || img.height() != img.width()) {
|
||||
MessageBoxWarning(title, tr("Please select a valid square image."));
|
||||
return;
|
||||
}
|
||||
QFile::copy(fn, "./nekoray.png");
|
||||
}
|
||||
} else if (c == 1) {
|
||||
QFile::remove("./nekoray.png");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
dialog_message(Dialog_DialogBasicSettings, "UpdateIcon");
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ private:
|
||||
QString custom_inbound;
|
||||
bool needRestart = false;
|
||||
} CACHE;
|
||||
|
||||
private slots:
|
||||
|
||||
void on_set_custom_icon_clicked();
|
||||
|
||||
};
|
||||
|
||||
#endif // DIALOG_BASIC_SETTINGS_H
|
||||
|
||||
@@ -264,6 +264,49 @@
|
||||
<string>Style</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Theme</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="theme">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>System</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">flatgray</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">lightblue</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">blacksoft</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
@@ -302,6 +345,33 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="horizontalGroupBox2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_20">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="start_minimal">
|
||||
<property name="text">
|
||||
<string>Minimize to tray icon on startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="set_custom_icon">
|
||||
<property name="text">
|
||||
<string>Set custom icon</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
@@ -358,62 +428,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Theme</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="theme">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>System</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">flatgray</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">lightblue</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">blacksoft</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="horizontalGroupBox2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_20">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="start_minimal">
|
||||
<property name="text">
|
||||
<string>Minimize to tray icon on startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "sys/AutoRun.hpp"
|
||||
|
||||
#include "ui/ThemeManager.hpp"
|
||||
#include "ui/TrayIcon.hpp"
|
||||
#include "ui/edit/dialog_edit_profile.h"
|
||||
#include "ui/dialog_basic_settings.h"
|
||||
#include "ui/dialog_manage_groups.h"
|
||||
@@ -228,15 +229,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
this->refresh_groups();
|
||||
|
||||
// Setup Tray
|
||||
auto icon = QIcon::fromTheme("nekoray");
|
||||
auto pixmap = QPixmap("../nekoray.png");
|
||||
if (!pixmap.isNull()) icon = QIcon(pixmap);
|
||||
pixmap = QPixmap("./nekoray.png");
|
||||
if (!pixmap.isNull()) icon = QIcon(pixmap);
|
||||
setWindowIcon(icon);
|
||||
|
||||
tray = new QSystemTrayIcon(this);//初始化托盘对象tray
|
||||
tray->setIcon(icon);//设定托盘图标,引号内是自定义的png图片路径
|
||||
tray->setContextMenu(ui->menu_program);//创建托盘菜单
|
||||
tray->show();//让托盘图标显示在系统托盘上
|
||||
connect(tray, &QSystemTrayIcon::activated, this,
|
||||
@@ -483,6 +476,10 @@ void MainWindow::show_group(int gid) {
|
||||
// callback
|
||||
|
||||
void MainWindow::dialog_message_impl(const QString &sender, const QString &info) {
|
||||
if (info.contains("UpdateIcon")) {
|
||||
icon_status = -1;
|
||||
refresh_status();
|
||||
}
|
||||
if (info.contains("UpdateDataStore")) {
|
||||
auto changed = NekoRay::dataStore->Save();
|
||||
if (info.contains("RouteChanged")) changed = true;
|
||||
@@ -679,8 +676,24 @@ void MainWindow::refresh_status(const QString &traffic_update) {
|
||||
return tt.join(isTray ? "\n" : " ");
|
||||
};
|
||||
|
||||
auto icon_status_new = TrayIcon::NONE;
|
||||
if (title_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY) {
|
||||
icon_status_new = TrayIcon::SYSTEM_PROXY;
|
||||
} else if (title_spmode == NekoRay::SystemProxyMode::VPN) {
|
||||
icon_status_new = TrayIcon::VPN;
|
||||
} else if (!running.isNull()) {
|
||||
icon_status_new = TrayIcon::RUNNING;
|
||||
}
|
||||
|
||||
setWindowTitle(make_title(false));
|
||||
if (tray != nullptr) tray->setToolTip(make_title(true));
|
||||
if (icon_status_new != icon_status) setWindowIcon(TrayIcon::GetIcon(TrayIcon::NONE));
|
||||
|
||||
if (tray != nullptr) {
|
||||
tray->setToolTip(make_title(true));
|
||||
if (icon_status_new != icon_status) tray->setIcon(TrayIcon::GetIcon(icon_status_new));
|
||||
}
|
||||
|
||||
icon_status = icon_status_new;
|
||||
}
|
||||
|
||||
// table显示
|
||||
|
||||
@@ -131,6 +131,7 @@ private:
|
||||
QString title_base;
|
||||
QString title_error;
|
||||
int title_spmode = NekoRay::SystemProxyMode::DISABLE;
|
||||
int icon_status = -1;
|
||||
QSharedPointer<NekoRay::ProxyEntity> running;
|
||||
QString traffic_update_cache;
|
||||
QTime last_test_time;
|
||||
|
||||
Reference in New Issue
Block a user