Skip to content

Commit

Permalink
feat: add main interface UI
Browse files Browse the repository at this point in the history
  • Loading branch information
lanthora committed Apr 9, 2024
1 parent 5db4d89 commit 45efe77
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 53 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Widgets Gui)
find_package(Qt6 REQUIRED COMPONENTS Widgets Gui Core)

add_executable(cake
main.cc
mainwindow.h mainwindow.cc
candylist.h candylist.cc
candyitem.h candyitem.cc
detailarea.h detailarea.cc
images.qrc
)

target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Gui)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Gui Qt6::Core)

set_target_properties(cake PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
QT_TARGET_DESCRIPTION "Cake"
)

include(FetchContent)
Expand Down
14 changes: 13 additions & 1 deletion candyitem.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
#include "candyitem.h"
#include "candy.h"

CandyItem::CandyItem() {}
CandyItem::CandyItem()
{
setTextAlignment(Qt::AlignCenter);
setSizeHint(QSize(0, 40));

candy = candy_client_create();
}

CandyItem::~CandyItem()
{
candy_client_release(candy);
}
4 changes: 4 additions & 0 deletions candyitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ class CandyItem : public QListWidgetItem
{
public:
explicit CandyItem();
~CandyItem();

private:
void *candy = nullptr;
};

#endif // CANDYITEM_H
15 changes: 14 additions & 1 deletion candylist.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
#include "candylist.h"

CandyList::CandyList() {}
CandyItem *CandyList::addButton = new CandyItem;

CandyList::CandyList()
{
// 网络列表最后一项 '+', 用于添加新客户端
addButton->setText("+");
addItem(addButton);
}

void CandyList::addCandyItem(CandyItem *item)
{
insertItem(count() - 1, item);
setCurrentItem(item);
}
4 changes: 4 additions & 0 deletions candylist.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#ifndef CANDYLIST_H
#define CANDYLIST_H

#include "candyitem.h"
#include <QListWidget>

class CandyList : public QListWidget
{
public:
explicit CandyList();
void addCandyItem(CandyItem *item);

static CandyItem *addButton;
};

#endif // CANDYLIST_H
67 changes: 65 additions & 2 deletions detailarea.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,68 @@
#include "detailarea.h"
#include "candylist.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>

DetailArea::DetailArea() {}
DetailArea::DetailArea()
{
detailWidget = new QWidget(this);
detailWidget->hide();
QVBoxLayout *layout = new QVBoxLayout(detailWidget);

void DetailArea::update(QListWidgetItem *item) {}
password->setEchoMode(QLineEdit::Password);

layout->addWidget(createInputWidget("网卡名", name));
layout->addWidget(createInputWidget("服务器地址", websocket));
layout->addWidget(createInputWidget("口令", password));
layout->addWidget(createInputWidget("静态地址", tun));
layout->addWidget(createInputWidget("STUN", stun));
layout->addWidget(createInputWidget("对等连接端口", port));
layout->addWidget(createInputWidget("主动发现间隔", discovery));
layout->addWidget(createInputWidget("本机路由代价", route));
layout->addWidget(createInputWidget("本机内网地址", localhost));
layout->addWidget(createSaveButton());
}

void DetailArea::update(QListWidgetItem *item)
{
detailWidget->show();
if (item == CandyList::addButton) {
return;
}

name->setReadOnly(true);
}

void DetailArea::save()
{
// TODO: 读出参数,根据网卡名更新配置,并重启对应的网络
return;
}

QWidget *DetailArea::createInputWidget(QString key, QLineEdit *input)
{
QWidget *widget = new QWidget;
QHBoxLayout *layout = new QHBoxLayout(widget);
QLabel *label = new QLabel;
label->setText(key);
label->setFixedWidth(110);
label->setAlignment(Qt::AlignRight);
label->setContentsMargins(0, 0, 10, 0);
input->setFixedWidth(400);
layout->addWidget(label, 1);
layout->addWidget(input, 5);
return widget;
}

QWidget *DetailArea::createSaveButton()
{
QWidget *widget = new QWidget;
QHBoxLayout *layout = new QHBoxLayout(widget);
QPushButton *saveButton = new QPushButton("保存");
saveButton->setFixedWidth(150);
connect(saveButton, &QPushButton::clicked, this, &DetailArea::save);
layout->addWidget(saveButton);
return widget;
}
20 changes: 20 additions & 0 deletions detailarea.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
#define DETAILAREA_H

#include <QFrame>
#include <QLabel>
#include <QLineEdit>
#include <QListWidgetItem>
#include <QVBoxLayout>

class DetailArea : public QFrame
{
Expand All @@ -11,6 +14,23 @@ class DetailArea : public QFrame
public:
explicit DetailArea();
void update(QListWidgetItem *item);
void save();

private:
QWidget *detailWidget = nullptr;

private:
QLineEdit *name = new QLineEdit;
QLineEdit *websocket = new QLineEdit;
QLineEdit *password = new QLineEdit;
QLineEdit *tun = new QLineEdit;
QLineEdit *stun = new QLineEdit;
QLineEdit *port = new QLineEdit;
QLineEdit *discovery = new QLineEdit;
QLineEdit *route = new QLineEdit;
QLineEdit *localhost = new QLineEdit;
QWidget *createInputWidget(QString label, QLineEdit *input);
QWidget *createSaveButton();
};

#endif // DETAILAREA_H
5 changes: 5 additions & 0 deletions images.qrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>logo.png</file>
</qresource>
</RCC>
Binary file added logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
121 changes: 75 additions & 46 deletions mainwindow.cc
Original file line number Diff line number Diff line change
@@ -1,64 +1,37 @@
#include "mainwindow.h"
#include "candyitem.h"
#include "candylist.h"
#include "detailarea.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QListWidget>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QPushButton>
#include <QWidgetAction>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 设置窗口标题
setWindowTitle("Cake");
setWindowTitle("CAKE");
setFixedSize(800, 600);

// 创建左侧列表
CandyList *list = new CandyList;
list->addItem(new CandyItem);
list->addItem(new CandyItem);

// 创建右侧详细信息区域
DetailArea *detailArea = new DetailArea;

// 将列表和详细信息区域添加到主窗口
setCentralWidget(new QWidget);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(list, 1);
layout->addWidget(detailArea, 3);
centralWidget()->setLayout(layout);

// 连接列表的 itemClicked() 信号到详细信息区域的更新函数
connect(list, &QListWidget::itemClicked, detailArea, &DetailArea::update);

// 通过系统托盘退出
if (QSystemTrayIcon ::isSystemTrayAvailable()) {
// TODO: 替换成好看的图标
QIcon quitIcon = QApplication::style()->standardIcon(QStyle::SP_TabCloseButton);
QIcon logoIcon = QApplication::style()->standardIcon(QStyle::SP_TitleBarMenuButton);

QAction *quitAction = new QAction(quitIcon, "Quit");
connect(quitAction, &QAction::triggered, this, &MainWindow::quit);

QMenu *trayMenu = new QMenu(this);
trayMenu->addAction(quitAction);

trayIcon = new QSystemTrayIcon(this);
connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::onSystemTrayActivated);
trayIcon->setIcon(logoIcon);
trayIcon->setToolTip("Candy");
trayIcon->setContextMenu(trayMenu);
trayIcon->show();
}
addFileMenu();
addEditMenu();
addHelpMenu();
addCentralWidget();
addSystemTray();
}

MainWindow::~MainWindow() {}

void MainWindow::closeEvent(QCloseEvent *event)
{
// 有系统托盘,后台运行
// 在菜单里选择退出时无需确认直接退出
if (forceQuit) {
event->accept();
return;
}

// 点击 X 退出,有系统托盘,发送通知并以托盘形式运行
if (QSystemTrayIcon ::isSystemTrayAvailable()) {
if (backgroundNotification) {
backgroundNotification = false;
Expand All @@ -69,19 +42,18 @@ void MainWindow::closeEvent(QCloseEvent *event)
return;
}

// 没有系统托盘,退出前确认
// 点击 X 退出,但没有系统托盘,退出前确认
if (QMessageBox::question(this, "退出", "退出后将断开所有虚拟网络连接,确认退出?")
== QMessageBox::No) {
event->ignore();
return;
}

// 退出
event->accept();
}

void MainWindow::onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
// 左键点击托盘图标隐藏或恢复主窗口
if (reason == QSystemTrayIcon::Trigger) {
if (isVisible() && !isMinimized()) {
hide();
Expand All @@ -94,5 +66,62 @@ void MainWindow::onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason)
void MainWindow::quit()
{
backgroundNotification = false;
forceQuit = true;
qApp->quit();
}

void MainWindow::addFileMenu()
{
QMenu *fileMenu = menuBar()->addMenu("文件");
QAction *quitAction = new QAction("退出");
connect(quitAction, &QAction::triggered, this, &MainWindow::quit);

fileMenu->addAction(quitAction);
}

void MainWindow::addEditMenu()
{
QMenu *settingMenu = menuBar()->addMenu("编辑");
QAction *autoStartAction = new QAction("启动选项");

settingMenu->addAction(autoStartAction);
}

void MainWindow::addHelpMenu()
{
QMenu *helpMenu = menuBar()->addMenu("帮助");
QAction *feedbackAction = new QAction("问题反馈");

helpMenu->addAction(feedbackAction);
}

void MainWindow::addCentralWidget()
{
// 创建左侧列表
candyList = new CandyList;

// 创建右侧详细信息区域
detailArea = new DetailArea;

// 将列表和详细信息区域添加到主窗口
setCentralWidget(new QWidget);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(candyList, 1);
layout->addWidget(detailArea, 3);
centralWidget()->setLayout(layout);

// 连接列表的 itemClicked() 信号到详细信息区域的更新函数
connect(candyList, &QListWidget::itemClicked, detailArea, &DetailArea::update);
}

void MainWindow::addSystemTray()
{
// 通过系统托盘退出
if (QSystemTrayIcon ::isSystemTrayAvailable()) {
trayIcon = new QSystemTrayIcon(this);
connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::onSystemTrayActivated);
trayIcon->setIcon(QIcon(":/logo.png"));
trayIcon->setToolTip("CAKE");
trayIcon->show();
}
}
13 changes: 13 additions & 0 deletions mainwindow.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "candylist.h"
#include "detailarea.h"
#include <QCloseEvent>
#include <QMainWindow>
#include <QSystemTrayIcon>
Expand All @@ -20,8 +22,19 @@ private slots:
void onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason);
void quit();

private:
void addFileMenu();
void addEditMenu();
void addHelpMenu();
void addCentralWidget();
void addSystemTray();

private:
QSystemTrayIcon *trayIcon = nullptr;
bool backgroundNotification = true;
bool forceQuit = false;

CandyList *candyList = nullptr;
DetailArea *detailArea = nullptr;
};
#endif // MAINWINDOW_H

0 comments on commit 45efe77

Please sign in to comment.