diff --git a/CMakeLists.txt b/CMakeLists.txt index a9f631e..60b03ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,15 @@ project(VideoClient LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +# set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTORCC ON) -find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets OpenGLWidgets Network SerialPort) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") +include(QWindowKit) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets OpenGLWidgets Network SerialPort) qt_standard_project_setup() diff --git a/cmake/QWindowKit.cmake b/cmake/QWindowKit.cmake new file mode 100644 index 0000000..01a3380 --- /dev/null +++ b/cmake/QWindowKit.cmake @@ -0,0 +1,9 @@ + +include(fetchcontent) + fetchcontent_declare( QWindowKit #库名字 + GIT_REPOSITORY https://github.com/stdware/qwindowkit # 仓库地址 + GIT_TAG 1.3.2 # 库版本 + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/QWindowKit # 指定库下载地址 + ) + +fetchcontent_makeavailable(QWindowKit) \ No newline at end of file diff --git a/ext/QWindowKit b/ext/QWindowKit new file mode 160000 index 0000000..bc03db3 --- /dev/null +++ b/ext/QWindowKit @@ -0,0 +1 @@ +Subproject commit bc03db3759e0d8644e626adcbda066ccb2c30062 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e48b1f4..529fd15 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,5 @@ + qt_add_executable(VideoClient WIN32 MACOSX_BUNDLE main.cpp @@ -6,25 +7,44 @@ qt_add_executable(VideoClient mainwindow.h mainwindow.ui global.h global.cpp - communicationsettingdlg.h communicationsettingdlg.cpp communicationsettingdlg.ui - commandwidget.h commandwidget.cpp commandwidget.ui + communicationsettingdlg.h communicationsettingdlg.cpp + commandwidget.h commandwidget.cpp +) + +qt6_add_resources(VideoClient "resources" + PREFIX "/" + FILES "resources/res.qrc" +) + +qt_add_ui(VideoClient SOURCES + commandwidget.ui + communicationsettingdlg.ui ) set(3RDPARTY_DIR ${CMAKE_CURRENT_LIST_DIR}/3rdparty) set(FFMPEG_DIR ${3RDPARTY_DIR}/ffmpeg) + add_subdirectory(video) add_subdirectory(3rdparty) +add_subdirectory(shared) target_link_libraries(VideoClient PRIVATE Qt::Core + Qt::Gui Qt::Widgets Qt6::OpenGLWidgets Qt6::Network Qt6::SerialPort video + QWindowKit::Widgets + WidgetFrame ) +# 指定头文件路径 +target_include_directories(VideoClient PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/) + + include(GNUInstallDirs) diff --git a/src/commandwidget.cpp b/src/commandwidget.cpp index a78a4a7..df0f79b 100644 --- a/src/commandwidget.cpp +++ b/src/commandwidget.cpp @@ -6,6 +6,9 @@ CommandWidget::CommandWidget(QWidget *parent) : QWidget(parent), ui(new Ui::CommandWidget) { ui->setupUi(this); ui->stopConnectionToolBtn->setDisabled(true); + ui->settingToolBtn->setIcon(QIcon(":/images/settings.png")); + ui->settingToolBtn->setText("通信设置"); + ui->settingToolBtn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); udpSocket = new QUdpSocket(this); connect(&settingDlg, &CommunicationSettingDlg::sendErrorMessage, this, diff --git a/src/commandwidget.ui b/src/commandwidget.ui index be9fd87..023afc0 100644 --- a/src/commandwidget.ui +++ b/src/commandwidget.ui @@ -6,7 +6,7 @@ 0 0 - 897 + 1039 105 @@ -24,7 +24,7 @@ 4 - 2 + 4 @@ -93,6 +93,9 @@ + + 6 + 12 diff --git a/src/communicationsettingdlg.cpp b/src/communicationsettingdlg.cpp index 1678c77..92bb063 100644 --- a/src/communicationsettingdlg.cpp +++ b/src/communicationsettingdlg.cpp @@ -6,6 +6,8 @@ CommunicationSettingDlg::CommunicationSettingDlg(QWidget *parent) : QDialog(parent), ui(new Ui::CommunicationSettingDlg) { ui->setupUi(this); + this->setWindowTitle("通信设置"); + initCombobox(); initNetworkSetting(); } diff --git a/src/communicationsettingdlg.ui b/src/communicationsettingdlg.ui index 4e09328..32b85e6 100644 --- a/src/communicationsettingdlg.ui +++ b/src/communicationsettingdlg.ui @@ -38,19 +38,25 @@ - 2 + 4 2 - 2 + 4 2 + + 4 + + + 4 + 7 diff --git a/src/main.cpp b/src/main.cpp index 9099e07..4fa58ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "mainwindow.h" int main(int argc, char *argv[]) { + QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); QApplication a(argc, argv); MainWindow w; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index dd9bdf2..980c77e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,13 +1,63 @@ #include "mainwindow.h" +#include +#include + #include #include "ui_mainwindow.h" +#include "widgetframe/windowbar.h" +#include "widgetframe/windowbutton.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); + this->setWindowTitle("载荷视频播放软件"); + // windowAgent = new QWK::WidgetWindowAgent(this); + // windowAgent->setup(this); + // auto windowBar = new QWK::WindowBar(); + // auto iconButton = new QWK::WindowButton(); + /* + iconButton->setObjectName(QStringLiteral("icon-button")); + iconButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + auto minButton = new QWK::WindowButton(); + minButton->setObjectName(QStringLiteral("min-button")); + minButton->setProperty("system-button", true); + minButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + auto maxButton = new QWK::WindowButton(); + maxButton->setCheckable(true); + maxButton->setObjectName(QStringLiteral("max-button")); + maxButton->setProperty("system-button", true); + maxButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + auto closeButton = new QWK::WindowButton(); + closeButton->setObjectName(QStringLiteral("close-button")); + closeButton->setProperty("system-button", true); + closeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + windowBar->setIconButton(iconButton); + windowBar->setMinButton(minButton); + windowBar->setMaxButton(maxButton); + windowBar->setCloseButton(closeButton); + windowAgent->setTitleBar(windowBar); +*/ + + // apply the qss + QFile qssfile(":/Qss/qss.qss"); + if (qssfile.open(QFile::ReadOnly)) { + // file.open(QFile::ReadOnly); + QString style = QLatin1String(qssfile.readAll()); + + qApp->setStyleSheet(style); + // qDebug()< list; // list.append("rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid"); // list.append("rtsp://182.92.130.23/nmyj/video"); diff --git a/src/res/3D.png b/src/res/3D.png deleted file mode 100644 index 6e218d0..0000000 Binary files a/src/res/3D.png and /dev/null differ diff --git a/src/res/981cs.png b/src/res/981cs.png deleted file mode 100644 index 0ecfaa7..0000000 Binary files a/src/res/981cs.png and /dev/null differ diff --git a/src/res/981csNew.png b/src/res/981csNew.png deleted file mode 100644 index 5f4d9e6..0000000 Binary files a/src/res/981csNew.png and /dev/null differ diff --git a/src/res/Ku.png b/src/res/Ku.png deleted file mode 100644 index 6d5b301..0000000 Binary files a/src/res/Ku.png and /dev/null differ diff --git a/src/res/LChain.png b/src/res/LChain.png deleted file mode 100644 index 867f397..0000000 Binary files a/src/res/LChain.png and /dev/null differ diff --git a/src/res/PDT.png b/src/res/PDT.png deleted file mode 100644 index 4d06f42..0000000 Binary files a/src/res/PDT.png and /dev/null differ diff --git a/src/res/SDFP2.png b/src/res/SDFP2.png deleted file mode 100644 index dca6775..0000000 Binary files a/src/res/SDFP2.png and /dev/null differ diff --git a/src/res/Sign.png b/src/res/Sign.png deleted file mode 100644 index 56c6921..0000000 Binary files a/src/res/Sign.png and /dev/null differ diff --git a/src/res/home.png b/src/res/home.png deleted file mode 100644 index 548f941..0000000 Binary files a/src/res/home.png and /dev/null differ diff --git a/src/res/research.png b/src/res/research.png deleted file mode 100644 index 755c335..0000000 Binary files a/src/res/research.png and /dev/null differ diff --git a/src/res/Qss/qss.qss b/src/resources/Qss/qss.qss similarity index 86% rename from src/res/Qss/qss.qss rename to src/resources/Qss/qss.qss index af2ee69..7f364e7 100644 --- a/src/res/Qss/qss.qss +++ b/src/resources/Qss/qss.qss @@ -4,6 +4,17 @@ QWidget{ } /************************QPushButton按钮设置****************************/ +QPushButton{ + background-color:rgb(50,50,50); + color:#2f3640; + background-color: #f5f6fa; + border-color: #2f3640; + border-radius: 6px; + border-style: solid; + border-width: 1px; + padding: 5px; +} + /*hover样式*/ QPushButton:hover{ background-color: rgb(155,155,155); @@ -12,15 +23,46 @@ QPushButton:hover{ QPushButton:pressed{ background-color: rgb(180,238,180); } -QPushButton{ - background-color:rgb(50,50,50); - color:rgb(255,255,255); - border-radius: 2px; - border: 1px groove gray; - border-style: outset; - font: 10pt "微软雅黑"; + +/**按钮失能情况下样式**/ +QPushButton::disabled { + color: #b0b0b0; + background-color: #cccccc; + border: 1px solid #cccccc; + opacity: 0.7; } + + + +/**************************QToolButton设置*************************/ +QToolButton{ + font: 10pt '微软雅黑'; + color: rgba(0,0,0,200); /*#2f3640*/ + background-color: #f5f6fa; + border-color: #2f3640; + border-radius: 15px; + border-style: solid; + border-width: 2px; + padding: 5px; +} + +/**鼠标停留在按钮上的样式**/ +QToolButton::hover{ + color: #FFFFFF; + background-color: #718093; + border-color: #2f3640; +} + +/**按钮失能情况下样式**/ +QToolButton::disabled { + color: #b0b0b0; + background-color: #cccccc; + border: 1px solid #cccccc; + opacity: 0.7; +} + + /**************************QLineEdit编辑框设置*************************/ QLineEdit{ color:rgb(255,255,255); @@ -170,8 +212,8 @@ QSpinBox{ /***************************QGroupBox设置***********************/ QGroupBox{ border:1px solid rgb(255,255,255); - border-radius:5px; - margin-top:2ex;/*文字在方框中位置的偏离度*/ + border-radius:6px; + margin-top:10px;/*文字在方框中位置的偏离度*/ color:rgb(153,255,153); font-family:"微软雅黑"; font-size:12pt; diff --git a/src/res/Qss/ysb.qss b/src/resources/Qss/ysb.qss similarity index 100% rename from src/res/Qss/ysb.qss rename to src/resources/Qss/ysb.qss diff --git a/src/res/GDDC.png b/src/resources/images/GDDC.png similarity index 100% rename from src/res/GDDC.png rename to src/resources/images/GDDC.png diff --git a/src/res/SDFP.png b/src/resources/images/SDFP.png similarity index 100% rename from src/res/SDFP.png rename to src/resources/images/SDFP.png diff --git a/src/res/SDFP3.png b/src/resources/images/SDFP3.png similarity index 100% rename from src/res/SDFP3.png rename to src/resources/images/SDFP3.png diff --git a/src/res/down.png b/src/resources/images/down.png similarity index 100% rename from src/res/down.png rename to src/resources/images/down.png diff --git a/src/res/left.png b/src/resources/images/left.png similarity index 100% rename from src/res/left.png rename to src/resources/images/left.png diff --git a/src/res/right.png b/src/resources/images/right.png similarity index 100% rename from src/res/right.png rename to src/resources/images/right.png diff --git a/src/res/settings.png b/src/resources/images/settings.png similarity index 100% rename from src/res/settings.png rename to src/resources/images/settings.png diff --git a/src/res/settings2.png b/src/resources/images/settings2.png similarity index 100% rename from src/res/settings2.png rename to src/resources/images/settings2.png diff --git a/src/res/tm.ico b/src/resources/images/tm.ico similarity index 100% rename from src/res/tm.ico rename to src/resources/images/tm.ico diff --git a/src/res/up.png b/src/resources/images/up.png similarity index 100% rename from src/res/up.png rename to src/resources/images/up.png diff --git a/src/res/wifi4G.png b/src/resources/images/wifi4G.png similarity index 100% rename from src/res/wifi4G.png rename to src/resources/images/wifi4G.png diff --git a/src/res/lamp/black.png b/src/resources/lamp/black.png similarity index 100% rename from src/res/lamp/black.png rename to src/resources/lamp/black.png diff --git a/src/res/lamp/blue.png b/src/resources/lamp/blue.png similarity index 100% rename from src/res/lamp/blue.png rename to src/resources/lamp/blue.png diff --git a/src/res/lamp/green.png b/src/resources/lamp/green.png similarity index 100% rename from src/res/lamp/green.png rename to src/resources/lamp/green.png diff --git a/src/res/lamp/grey.png b/src/resources/lamp/grey.png similarity index 100% rename from src/res/lamp/grey.png rename to src/resources/lamp/grey.png diff --git a/src/res/lamp/grey1.png b/src/resources/lamp/grey1.png similarity index 100% rename from src/res/lamp/grey1.png rename to src/resources/lamp/grey1.png diff --git a/src/res/lamp/grey3.png b/src/resources/lamp/grey3.png similarity index 100% rename from src/res/lamp/grey3.png rename to src/resources/lamp/grey3.png diff --git a/src/res/lamp/orange.png b/src/resources/lamp/orange.png similarity index 100% rename from src/res/lamp/orange.png rename to src/resources/lamp/orange.png diff --git a/src/res/lamp/red.png b/src/resources/lamp/red.png similarity index 100% rename from src/res/lamp/red.png rename to src/resources/lamp/red.png diff --git a/src/res/lamp/white.png b/src/resources/lamp/white.png similarity index 100% rename from src/res/lamp/white.png rename to src/resources/lamp/white.png diff --git a/src/res/lamp/yellow.png b/src/resources/lamp/yellow.png similarity index 100% rename from src/res/lamp/yellow.png rename to src/resources/lamp/yellow.png diff --git a/src/res/mdlg.qss b/src/resources/mdlg.qss similarity index 100% rename from src/res/mdlg.qss rename to src/resources/mdlg.qss diff --git a/src/resources/res.qrc b/src/resources/res.qrc new file mode 100644 index 0000000..a8dec87 --- /dev/null +++ b/src/resources/res.qrc @@ -0,0 +1,13 @@ + + + Qss/qss.qss + images/down.png + images/left.png + images/right.png + images/SDFP.png + images/SDFP3.png + images/settings.png + images/up.png + images/wifi4G.png + + diff --git a/src/res/style.qss b/src/resources/style.qss similarity index 100% rename from src/res/style.qss rename to src/resources/style.qss diff --git a/src/res/switch/switch_close.png b/src/resources/switch/switch_close.png similarity index 100% rename from src/res/switch/switch_close.png rename to src/resources/switch/switch_close.png diff --git a/src/res/switch/switch_close1.png b/src/resources/switch/switch_close1.png similarity index 100% rename from src/res/switch/switch_close1.png rename to src/resources/switch/switch_close1.png diff --git a/src/res/switch/switch_close2.png b/src/resources/switch/switch_close2.png similarity index 100% rename from src/res/switch/switch_close2.png rename to src/resources/switch/switch_close2.png diff --git a/src/res/switch/switch_close3.png b/src/resources/switch/switch_close3.png similarity index 100% rename from src/res/switch/switch_close3.png rename to src/resources/switch/switch_close3.png diff --git a/src/res/switch/switch_open.png b/src/resources/switch/switch_open.png similarity index 100% rename from src/res/switch/switch_open.png rename to src/resources/switch/switch_open.png diff --git a/src/res/switch/switch_open1.png b/src/resources/switch/switch_open1.png similarity index 100% rename from src/res/switch/switch_open1.png rename to src/resources/switch/switch_open1.png diff --git a/src/res/switch/switch_open2.png b/src/resources/switch/switch_open2.png similarity index 100% rename from src/res/switch/switch_open2.png rename to src/resources/switch/switch_open2.png diff --git a/src/res/switch/switch_open3.png b/src/resources/switch/switch_open3.png similarity index 100% rename from src/res/switch/switch_open3.png rename to src/resources/switch/switch_open3.png diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt new file mode 100644 index 0000000..187da26 --- /dev/null +++ b/src/shared/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(widgetframe) \ No newline at end of file diff --git a/src/shared/widgetframe/CMakeLists.txt b/src/shared/widgetframe/CMakeLists.txt new file mode 100644 index 0000000..7ccfec3 --- /dev/null +++ b/src/shared/widgetframe/CMakeLists.txt @@ -0,0 +1,37 @@ +project(WidgetFrame) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +file(GLOB _src *.h *.cpp) + +add_library(${PROJECT_NAME} STATIC "") + +target_sources(${PROJECT_NAME} +PRIVATE + windowbar.cpp + windowbutton.cpp +PUBLIC + windowbar_p.h + windowbutton.h + windowbutton_p.h +) + +qt6_add_resources(${PROJECT_NAME} "resources" + PREFIX "/" + FILES "resources/shared.qrc" +) + +target_link_libraries(${PROJECT_NAME} PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Widgets +) + +set_target_properties(${PROJECT_NAME} PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED TRUE +) + +target_include_directories(${PROJECT_NAME} PUBLIC . ..) diff --git a/src/shared/widgetframe/resources/app/example.icns b/src/shared/widgetframe/resources/app/example.icns new file mode 100644 index 0000000..bc4bb61 Binary files /dev/null and b/src/shared/widgetframe/resources/app/example.icns differ diff --git a/src/shared/widgetframe/resources/app/example.ico b/src/shared/widgetframe/resources/app/example.ico new file mode 100644 index 0000000..316795d Binary files /dev/null and b/src/shared/widgetframe/resources/app/example.ico differ diff --git a/src/shared/widgetframe/resources/app/example.png b/src/shared/widgetframe/resources/app/example.png new file mode 100644 index 0000000..61bf23c Binary files /dev/null and b/src/shared/widgetframe/resources/app/example.png differ diff --git a/src/shared/widgetframe/resources/shared.qrc b/src/shared/widgetframe/resources/shared.qrc new file mode 100644 index 0000000..5aec715 --- /dev/null +++ b/src/shared/widgetframe/resources/shared.qrc @@ -0,0 +1,11 @@ + + + window-bar/close.svg + window-bar/fullscreen.svg + window-bar/maximize.svg + window-bar/minimize.svg + window-bar/restore.svg + window-bar/more-line.svg + app/example.png + + diff --git a/src/shared/widgetframe/resources/window-bar/close.svg b/src/shared/widgetframe/resources/window-bar/close.svg new file mode 100644 index 0000000..103d04e --- /dev/null +++ b/src/shared/widgetframe/resources/window-bar/close.svg @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/src/shared/widgetframe/resources/window-bar/fullscreen.svg b/src/shared/widgetframe/resources/window-bar/fullscreen.svg new file mode 100644 index 0000000..fff0898 --- /dev/null +++ b/src/shared/widgetframe/resources/window-bar/fullscreen.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/src/shared/widgetframe/resources/window-bar/maximize.svg b/src/shared/widgetframe/resources/window-bar/maximize.svg new file mode 100644 index 0000000..a50c909 --- /dev/null +++ b/src/shared/widgetframe/resources/window-bar/maximize.svg @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/src/shared/widgetframe/resources/window-bar/minimize.svg b/src/shared/widgetframe/resources/window-bar/minimize.svg new file mode 100644 index 0000000..e4e4bfd --- /dev/null +++ b/src/shared/widgetframe/resources/window-bar/minimize.svg @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/src/shared/widgetframe/resources/window-bar/more-line.svg b/src/shared/widgetframe/resources/window-bar/more-line.svg new file mode 100644 index 0000000..246247f --- /dev/null +++ b/src/shared/widgetframe/resources/window-bar/more-line.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/shared/widgetframe/resources/window-bar/restore.svg b/src/shared/widgetframe/resources/window-bar/restore.svg new file mode 100644 index 0000000..bb6e245 --- /dev/null +++ b/src/shared/widgetframe/resources/window-bar/restore.svg @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/shared/widgetframe/windowbar.cpp b/src/shared/widgetframe/windowbar.cpp new file mode 100644 index 0000000..362383f --- /dev/null +++ b/src/shared/widgetframe/windowbar.cpp @@ -0,0 +1,298 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + +#include "windowbar.h" +#include "windowbar_p.h" + +#include +#include +#include + +namespace QWK { + + WindowBarPrivate::WindowBarPrivate() { + w = nullptr; + autoTitle = true; + autoIcon = false; + } + + WindowBarPrivate::~WindowBarPrivate() = default; + + void WindowBarPrivate::init() { + Q_Q(WindowBar); + layout = new QHBoxLayout(); + if (QLocale::system().textDirection() == Qt::RightToLeft) { + layout->setDirection(QBoxLayout::RightToLeft); + } + + layout->setContentsMargins(QMargins()); + layout->setSpacing(0); + for (int i = IconButton; i <= CloseButton; ++i) { + insertDefaultSpace(i); + } + q->setLayout(layout); + } + + void WindowBarPrivate::setWidgetAt(int index, QWidget *widget) { + auto item = layout->takeAt(index); + auto orgWidget = item->widget(); + if (orgWidget) { + orgWidget->deleteLater(); + } + delete item; + if (!widget) { + insertDefaultSpace(index); + } else { + layout->insertWidget(index, widget); + } + } + + QWidget *WindowBarPrivate::takeWidgetAt(int index) { + auto item = layout->itemAt(index); + auto orgWidget = item->widget(); + if (orgWidget) { + item = layout->takeAt(index); + delete item; + insertDefaultSpace(index); + } + return orgWidget; + } + + WindowBar::WindowBar(QWidget *parent) : WindowBar(*new WindowBarPrivate(), parent) { + } + + WindowBar::~WindowBar() = default; + + QMenuBar *WindowBar::menuBar() const { + Q_D(const WindowBar); + return static_cast(d->widgetAt(WindowBarPrivate::MenuWidget)); + } + + QLabel *WindowBar::titleLabel() const { + Q_D(const WindowBar); + return static_cast(d->widgetAt(WindowBarPrivate::TitleLabel)); + } + + QAbstractButton *WindowBar::iconButton() const { + Q_D(const WindowBar); + return static_cast(d->widgetAt(WindowBarPrivate::IconButton)); + } + + QAbstractButton *WindowBar::minButton() const { + Q_D(const WindowBar); + return static_cast(d->widgetAt(WindowBarPrivate::MinimumButton)); + } + + QAbstractButton *WindowBar::maxButton() const { + Q_D(const WindowBar); + return static_cast(d->widgetAt(WindowBarPrivate::MaximumButton)); + } + + QAbstractButton *WindowBar::closeButton() const { + Q_D(const WindowBar); + return static_cast(d->widgetAt(WindowBarPrivate::CloseButton)); + } + + void WindowBar::setMenuBar(QMenuBar *menuBar) { + Q_D(WindowBar); + auto org = takeMenuBar(); + if (org) + org->deleteLater(); + if (!menuBar) + return; + d->setWidgetAt(WindowBarPrivate::MenuWidget, menuBar); + menuBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); + } + + void WindowBar::setTitleLabel(QLabel *label) { + Q_D(WindowBar); + auto org = takeTitleLabel(); + if (org) + org->deleteLater(); + if (!label) + return; + d->setWidgetAt(WindowBarPrivate::TitleLabel, label); + if (d->autoTitle && d->w) + label->setText(d->w->windowTitle()); + label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + } + + void WindowBar::setIconButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeIconButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::IconButton, btn); + if (d->autoIcon && d->w) + btn->setIcon(d->w->windowIcon()); + btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + } + + void WindowBar::setMinButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeMinButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::MinimumButton, btn); + connect(btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested); + } + + void WindowBar::setMaxButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeMaxButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::MaximumButton, btn); + connect(btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested); + } + + void WindowBar::setCloseButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeCloseButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::CloseButton, btn); + connect(btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested); + } + + QMenuBar *WindowBar::takeMenuBar() { + Q_D(WindowBar); + return static_cast(d->takeWidgetAt(WindowBarPrivate::MenuWidget)); + } + + QLabel *WindowBar::takeTitleLabel() { + Q_D(WindowBar); + return static_cast(d->takeWidgetAt(WindowBarPrivate::TitleLabel)); + } + + QAbstractButton *WindowBar::takeIconButton() { + Q_D(WindowBar); + return static_cast(d->takeWidgetAt(WindowBarPrivate::IconButton)); + } + + QAbstractButton *WindowBar::takeMinButton() { + Q_D(WindowBar); + auto btn = static_cast(d->takeWidgetAt(WindowBarPrivate::MinimumButton)); + if (!btn) { + return nullptr; + } + disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested); + return btn; + } + + QAbstractButton *WindowBar::takeMaxButton() { + Q_D(WindowBar); + auto btn = static_cast(d->takeWidgetAt(WindowBarPrivate::MaximumButton)); + if (!btn) { + return nullptr; + } + disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested); + return btn; + } + + QAbstractButton *WindowBar::takeCloseButton() { + Q_D(WindowBar); + auto btn = static_cast(d->takeWidgetAt(WindowBarPrivate::CloseButton)); + if (!btn) { + return nullptr; + } + disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested); + return btn; + } + + QWidget *WindowBar::hostWidget() const { + Q_D(const WindowBar); + return d->w; + } + + void WindowBar::setHostWidget(QWidget *w) { + Q_D(WindowBar); + + QWidget *org = d->w; + if (org) { + org->removeEventFilter(this); + } + d_ptr->w = w; + if (w) { + w->installEventFilter(this); + } + } + + bool WindowBar::titleFollowWindow() const { + Q_D(const WindowBar); + return d->autoTitle; + } + + void WindowBar::setTitleFollowWindow(bool value) { + Q_D(WindowBar); + d->autoTitle = value; + } + + bool WindowBar::iconFollowWindow() const { + Q_D(const WindowBar); + return d->autoIcon; + } + + void WindowBar::setIconFollowWindow(bool value) { + Q_D(WindowBar); + d->autoIcon = value; + } + + bool WindowBar::eventFilter(QObject *obj, QEvent *event) { + Q_D(WindowBar); + auto w = d->w; + if (obj == w) { + QAbstractButton *iconBtn = iconButton(); + QLabel *label = titleLabel(); + QAbstractButton *maxBtn = maxButton(); + switch (event->type()) { + case QEvent::WindowIconChange: { + if (d_ptr->autoIcon && iconBtn) { + iconBtn->setIcon(w->windowIcon()); + iconChanged(w->windowIcon()); + } + break; + } + case QEvent::WindowTitleChange: { + if (d_ptr->autoTitle && label) { + label->setText(w->windowTitle()); + titleChanged(w->windowTitle()); + } + break; + } + case QEvent::WindowStateChange: { + if (maxBtn) { + maxBtn->setChecked(w->isMaximized()); + } + break; + } + default: + break; + } + } + return QWidget::eventFilter(obj, event); + } + + void WindowBar::titleChanged(const QString &text) { + Q_UNUSED(text) + } + + void WindowBar::iconChanged(const QIcon &icon){Q_UNUSED(icon)} + + WindowBar::WindowBar(WindowBarPrivate &d, QWidget *parent) + : QFrame(parent), d_ptr(&d) { + d.q_ptr = this; + + d.init(); + } + +} diff --git a/src/shared/widgetframe/windowbar.h b/src/shared/widgetframe/windowbar.h new file mode 100644 index 0000000..2e802f2 --- /dev/null +++ b/src/shared/widgetframe/windowbar.h @@ -0,0 +1,74 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + +#ifndef WINDOWBAR_H +#define WINDOWBAR_H + +#include +#include +#include +#include + +namespace QWK { + + class WindowBarPrivate; + + class WindowBar : public QFrame { + Q_OBJECT + Q_DECLARE_PRIVATE(WindowBar) + public: + explicit WindowBar(QWidget *parent = nullptr); + ~WindowBar(); + + public: + QMenuBar *menuBar() const; + QLabel *titleLabel() const; + QAbstractButton *iconButton() const; + QAbstractButton *minButton() const; + QAbstractButton *maxButton() const; + QAbstractButton *closeButton() const; + + void setMenuBar(QMenuBar *menuBar); + void setTitleLabel(QLabel *label); + void setIconButton(QAbstractButton *btn); + void setMinButton(QAbstractButton *btn); + void setMaxButton(QAbstractButton *btn); + void setCloseButton(QAbstractButton *btn); + + QMenuBar *takeMenuBar(); + QLabel *takeTitleLabel(); + QAbstractButton *takeIconButton(); + QAbstractButton *takeMinButton(); + QAbstractButton *takeMaxButton(); + QAbstractButton *takeCloseButton(); + + QWidget *hostWidget() const; + void setHostWidget(QWidget *w); + + bool titleFollowWindow() const; + void setTitleFollowWindow(bool value); + + bool iconFollowWindow() const; + void setIconFollowWindow(bool value); + + Q_SIGNALS: + void minimizeRequested(); + void maximizeRequested(bool max = false); + void closeRequested(); + + protected: + bool eventFilter(QObject *obj, QEvent *event) override; + + virtual void titleChanged(const QString &text); + virtual void iconChanged(const QIcon &icon); + + protected: + WindowBar(WindowBarPrivate &d, QWidget *parent = nullptr); + + QScopedPointer d_ptr; + }; + +} + +#endif // WINDOWBAR_H \ No newline at end of file diff --git a/src/shared/widgetframe/windowbar_p.h b/src/shared/widgetframe/windowbar_p.h new file mode 100644 index 0000000..36ceb17 --- /dev/null +++ b/src/shared/widgetframe/windowbar_p.h @@ -0,0 +1,57 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + +#ifndef WINDOWBARPRIVATE_H +#define WINDOWBARPRIVATE_H + +#include + +#include "windowbar.h" + +namespace QWK { + + class WindowBarPrivate { + Q_DECLARE_PUBLIC(WindowBar) + public: + WindowBarPrivate(); + virtual ~WindowBarPrivate(); + + void init(); + + WindowBar *q_ptr; + + QWidget *w; + bool autoTitle; + bool autoIcon; + + enum WindowBarItem { + IconButton, + MenuWidget, + TitleLabel, + MinimumButton, + MaximumButton, + CloseButton, + }; + + QHBoxLayout *layout; + + inline QWidget *widgetAt(int index) const { + return layout->itemAt(index)->widget(); + } + + void setWidgetAt(int index, QWidget *widget); + + QWidget *takeWidgetAt(int index); + + inline void insertDefaultSpace(int index) { + layout->insertSpacerItem(index, new QSpacerItem(0, 0)); + } + + private: + Q_DISABLE_COPY(WindowBarPrivate) + }; + +} + +#endif // WINDOWBARPRIVATE_H \ No newline at end of file diff --git a/src/shared/widgetframe/windowbutton.cpp b/src/shared/widgetframe/windowbutton.cpp new file mode 100644 index 0000000..f0b2c70 --- /dev/null +++ b/src/shared/widgetframe/windowbutton.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + +#include "windowbutton.h" +#include "windowbutton_p.h" + +#include +#include + +namespace QWK { + + WindowButtonPrivate::WindowButtonPrivate() = default; + + WindowButtonPrivate::~WindowButtonPrivate() = default; + + void WindowButtonPrivate::init() { + } + + void WindowButtonPrivate::reloadIcon() { + Q_Q(WindowButton); + + if (!q->isEnabled() && !iconDisabled.isNull()) { + q->setIcon(iconDisabled); + return; + } + + if (q->isChecked() && !iconChecked.isNull()) { + q->setIcon(iconChecked); + return; + } + + if (!iconNormal.isNull()) { + q->setIcon(iconNormal); + } + } + + WindowButton::WindowButton(QWidget *parent) : WindowButton(*new WindowButtonPrivate(), parent) { + } + + WindowButton::~WindowButton() = default; + + QIcon WindowButton::iconNormal() const { + Q_D(const WindowButton); + return d->iconNormal; + } + + void WindowButton::setIconNormal(const QIcon &icon) { + Q_D(WindowButton); + d->iconNormal = icon; + d->reloadIcon(); + } + + QIcon WindowButton::iconChecked() const { + Q_D(const WindowButton); + return d->iconChecked; + } + + void WindowButton::setIconChecked(const QIcon &icon) { + Q_D(WindowButton); + d->iconChecked = icon; + d->reloadIcon(); + } + + QIcon WindowButton::iconDisabled() const { + Q_D(const WindowButton); + return d->iconDisabled; + } + + void WindowButton::setIconDisabled(const QIcon &icon) { + Q_D(WindowButton); + d->iconDisabled = icon; + d->reloadIcon(); + } + + void WindowButton::checkStateSet() { + Q_D(WindowButton); + d->reloadIcon(); + } + + void WindowButton::mouseDoubleClickEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton) { + Q_EMIT doubleClicked(); + } + } + + WindowButton::WindowButton(WindowButtonPrivate &d, QWidget *parent) + : QPushButton(parent), d_ptr(&d) { + d.q_ptr = this; + + d.init(); + } + +} diff --git a/src/shared/widgetframe/windowbutton.h b/src/shared/widgetframe/windowbutton.h new file mode 100644 index 0000000..402b50f --- /dev/null +++ b/src/shared/widgetframe/windowbutton.h @@ -0,0 +1,50 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + +#ifndef WINDOWBUTTON_H +#define WINDOWBUTTON_H + +#include + +namespace QWK { + + class WindowButtonPrivate; + + class WindowButton : public QPushButton { + Q_OBJECT + Q_DECLARE_PRIVATE(WindowButton) + Q_PROPERTY(QIcon iconNormal READ iconNormal WRITE setIconNormal FINAL) + Q_PROPERTY(QIcon iconChecked READ iconChecked WRITE setIconChecked FINAL) + Q_PROPERTY(QIcon iconDisabled READ iconDisabled WRITE setIconDisabled FINAL) + public: + explicit WindowButton(QWidget *parent = nullptr); + ~WindowButton(); + + public: + QIcon iconNormal() const; + void setIconNormal(const QIcon &icon); + + QIcon iconChecked() const; + void setIconChecked(const QIcon &icon); + + QIcon iconDisabled() const; + void setIconDisabled(const QIcon &icon); + + Q_SIGNALS: + void doubleClicked(); + + protected: + void checkStateSet() override; + + void mouseDoubleClickEvent(QMouseEvent *event) override; + + protected: + WindowButton(WindowButtonPrivate &d, QWidget *parent = nullptr); + + QScopedPointer d_ptr; + }; + +} + +#endif // WINDOWBUTTON_H \ No newline at end of file diff --git a/src/shared/widgetframe/windowbutton_p.h b/src/shared/widgetframe/windowbutton_p.h new file mode 100644 index 0000000..34aaaaf --- /dev/null +++ b/src/shared/widgetframe/windowbutton_p.h @@ -0,0 +1,31 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + +#ifndef WINDOWBUTTONPRIVATE_H +#define WINDOWBUTTONPRIVATE_H + +#include "windowbutton.h" + +namespace QWK { + + class WindowButtonPrivate { + Q_DECLARE_PUBLIC(WindowButton) + public: + WindowButtonPrivate(); + virtual ~WindowButtonPrivate(); + + void init(); + + WindowButton *q_ptr; + + QIcon iconNormal; + QIcon iconChecked; + QIcon iconDisabled; + + void reloadIcon(); + }; + +} + +#endif // WINDOWBUTTONPRIVATE_H \ No newline at end of file