-
-
Notifications
You must be signed in to change notification settings - Fork 387
Expand file tree
/
Copy pathTrayProfileSelector.hpp
More file actions
86 lines (75 loc) · 3.61 KB
/
Copy pathTrayProfileSelector.hpp
File metadata and controls
86 lines (75 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#pragma once
#include <QString>
#include <QStringList>
#include <QList>
#include <functional>
#include <utility>
#include "include/ui/widget/TrayPopupFrame.hpp"
class QLabel;
class QListWidgetItem;
class QPushButton;
class QTimer;
// A small frameless popup used from the system-tray menu to pick a proxy profile or a
// routing profile. It replaces the old nested/paginated tray submenus.
//
// Why a widget instead of submenus: a tray context menu is not always painted by Qt.
// On Linux it is exported over SNI/DBusMenu and drawn by the shell, and on macOS it is a
// native NSMenu; in both cases a submenu that is populated lazily/dynamically will not
// reliably expand. A real Qt-drawn window has none of those constraints and behaves
// identically on every platform.
//
// Behaviour: a rounded card with a debounced search box on top over a compact, paginated
// list. A single click (or Enter) selects; it closes when it loses focus (like a menu) and
// also has an explicit Close button.
class TrayProfileSelector : public TrayPopupFrame {
Q_OBJECT
public:
enum Mode { Server, Routing };
// Data is read live from the config layer; only actions and the "running" snapshot
// are injected, so the widget stays decoupled from MainWindow's internals.
struct Callbacks {
std::function<void(int id)> startProfile; // start a proxy profile by id
std::function<void()> stopProfile; // stop the running proxy
std::function<void(int id)> chooseRoute; // apply a routing profile by id
std::function<bool()> isRunning; // a proxy profile is currently running
std::function<int()> runningId; // running profile id, -1 if none
std::function<int()> runningGid; // running profile's group id, -1 if none
std::function<QString()> runningName; // running profile name, empty if none
};
TrayProfileSelector(Mode mode, Callbacks cb, QWidget *parent = nullptr);
protected:
bool event(QEvent *e) override; // close when the panel loses activation
bool eventFilter(QObject *obj, QEvent *e) override; // list/search key handling
void preparePopup() override;
void afterShow() override;
private:
void rebuild(); // repopulate for the current view/query/page
void activateItem(QListWidgetItem *it);
void goBackToGroups();
void changePage(int delta);
// Lazily build the per-popup search caches (all id/name pairs + pre-lowercased names),
// so live filtering scans memory instead of hitting the DB on every keystroke.
void ensureServerCache();
void ensureRouteCache();
Mode m_mode;
Callbacks m_cb;
int m_groupId = -1; // Server mode: -1 = group list; else the drilled-in group id
int m_page = 0; // current page within the shown list
bool m_armed = false; // gate close-on-deactivate until the initial show settles
QString m_query; // active (debounced) search text
// Built once per popup on first search. Server = all profiles across groups; Route =
// all routing profiles. The *Lower lists are the names pre-folded for fast matching.
bool m_serverCacheBuilt = false;
QList<std::pair<int, QString>> m_serverCache;
QStringList m_serverCacheLower;
bool m_routeCacheBuilt = false;
QList<std::pair<int, QString>> m_routeCache;
QStringList m_routeCacheLower;
QTimer *m_debounce = nullptr;
QPushButton *m_backBtn = nullptr;
QLabel *m_title = nullptr;
QPushButton *m_stopBtn = nullptr;
QPushButton *m_prevBtn = nullptr;
QLabel *m_pageLabel = nullptr;
QPushButton *m_nextBtn = nullptr;
};