mirror of
https://github.com/Linloir/SceneEditor.git
synced 2025-12-17 15:38:11 +08:00
Merge UI development
UI development
This commit is contained in:
commit
ef9580af3f
@ -103,23 +103,32 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="aboutpage.cpp" />
|
||||||
<ClCompile Include="camera.cpp" />
|
<ClCompile Include="camera.cpp" />
|
||||||
<ClCompile Include="ebo.cpp" />
|
<ClCompile Include="ebo.cpp" />
|
||||||
|
<ClCompile Include="editorpage.cpp" />
|
||||||
|
<ClCompile Include="framelesswindow.cpp" />
|
||||||
|
<ClCompile Include="lineeditwidget.cpp" />
|
||||||
<ClCompile Include="logger.cpp" />
|
<ClCompile Include="logger.cpp" />
|
||||||
<ClCompile Include="mesh.cpp" />
|
<ClCompile Include="mesh.cpp" />
|
||||||
<ClCompile Include="model.cpp" />
|
<ClCompile Include="model.cpp" />
|
||||||
<ClCompile Include="modelselectable.cpp" />
|
<ClCompile Include="modelselectable.cpp" />
|
||||||
<ClCompile Include="modelselector.cpp" />
|
<ClCompile Include="modelselector.cpp" />
|
||||||
<ClCompile Include="modelsetter.cpp" />
|
<ClCompile Include="modelsetter.cpp" />
|
||||||
|
<ClCompile Include="modelthumbnailwidget.cpp" />
|
||||||
|
<ClCompile Include="pagewidget.cpp" />
|
||||||
|
<ClCompile Include="pushbutton.cpp" />
|
||||||
<ClCompile Include="renderable.cpp" />
|
<ClCompile Include="renderable.cpp" />
|
||||||
|
<ClCompile Include="roundedcornerwidget.cpp" />
|
||||||
<ClCompile Include="sceneviewer.cpp" />
|
<ClCompile Include="sceneviewer.cpp" />
|
||||||
|
<ClCompile Include="scrolllistwidget.cpp" />
|
||||||
<ClCompile Include="shader.cpp" />
|
<ClCompile Include="shader.cpp" />
|
||||||
|
<ClCompile Include="sidebar.cpp" />
|
||||||
<ClCompile Include="texture.cpp" />
|
<ClCompile Include="texture.cpp" />
|
||||||
<ClCompile Include="vao.cpp" />
|
<ClCompile Include="vao.cpp" />
|
||||||
<ClCompile Include="vbo.cpp" />
|
<ClCompile Include="vbo.cpp" />
|
||||||
<ClCompile Include="vertex.cpp" />
|
<ClCompile Include="vertex.cpp" />
|
||||||
<QtRcc Include="mainwindow.qrc" />
|
<QtRcc Include="mainwindow.qrc" />
|
||||||
<QtUic Include="mainwindow.ui" />
|
|
||||||
<QtMoc Include="mainwindow.h" />
|
<QtMoc Include="mainwindow.h" />
|
||||||
<ClCompile Include="mainwindow.cpp" />
|
<ClCompile Include="mainwindow.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
@ -128,18 +137,28 @@
|
|||||||
<QtMoc Include="sceneviewer.h" />
|
<QtMoc Include="sceneviewer.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<QtMoc Include="aboutpage.h" />
|
||||||
<ClInclude Include="camera.h" />
|
<ClInclude Include="camera.h" />
|
||||||
|
<QtMoc Include="editorpage.h" />
|
||||||
|
<QtMoc Include="framelesswindow.h" />
|
||||||
|
<QtMoc Include="lineeditwidget.h" />
|
||||||
<ClInclude Include="logger.h" />
|
<ClInclude Include="logger.h" />
|
||||||
<ClInclude Include="mesh.h" />
|
<ClInclude Include="mesh.h" />
|
||||||
<ClInclude Include="model.h" />
|
<ClInclude Include="model.h" />
|
||||||
|
<QtMoc Include="sidebar.h" />
|
||||||
|
<QtMoc Include="pagewidget.h" />
|
||||||
|
<QtMoc Include="pushbutton.h" />
|
||||||
|
<QtMoc Include="roundedcornerwidget.h" />
|
||||||
|
<QtMoc Include="scrolllistwidget.h" />
|
||||||
|
<QtMoc Include="modelthumbnailwidget.h" />
|
||||||
<ClInclude Include="texture.h" />
|
<ClInclude Include="texture.h" />
|
||||||
<ClInclude Include="utils.h" />
|
<ClInclude Include="utils.h" />
|
||||||
<ClInclude Include="vbo.h" />
|
<ClInclude Include="vbo.h" />
|
||||||
<ClInclude Include="ebo.h" />
|
<ClInclude Include="ebo.h" />
|
||||||
<ClInclude Include="vertex.h" />
|
<ClInclude Include="vertex.h" />
|
||||||
<ClInclude Include="vao.h" />
|
<ClInclude Include="vao.h" />
|
||||||
<ClInclude Include="modelselectable.h" />
|
<QtMoc Include="modelselectable.h" />
|
||||||
<ClInclude Include="modelselector.h" />
|
<QtMoc Include="modelselector.h" />
|
||||||
<ClInclude Include="modelsetter.h" />
|
<ClInclude Include="modelsetter.h" />
|
||||||
<ClInclude Include="renderable.h" />
|
<ClInclude Include="renderable.h" />
|
||||||
<ClInclude Include="shader.h" />
|
<ClInclude Include="shader.h" />
|
||||||
|
|||||||
@ -13,10 +13,6 @@
|
|||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
<Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
<Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="Form Files">
|
|
||||||
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
|
|
||||||
<Extensions>ui</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Translation Files">
|
<Filter Include="Translation Files">
|
||||||
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
|
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
|
||||||
<Extensions>ts</Extensions>
|
<Extensions>ts</Extensions>
|
||||||
@ -39,14 +35,53 @@
|
|||||||
<Filter Include="Source Files\Utils">
|
<Filter Include="Source Files\Utils">
|
||||||
<UniqueIdentifier>{602fc1ed-84a6-4d4a-ad71-5e7415d8d429}</UniqueIdentifier>
|
<UniqueIdentifier>{602fc1ed-84a6-4d4a-ad71-5e7415d8d429}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\Pages">
|
||||||
|
<UniqueIdentifier>{dd0c6d73-36ab-44ac-9780-4c378faa5774}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\Pages\Scene Editor">
|
||||||
|
<UniqueIdentifier>{d0eeae28-809f-4e8e-b1e0-d5d7c5cca3e7}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\Pages">
|
||||||
|
<UniqueIdentifier>{0ee9dd70-07d0-44ec-9cb5-37478f6d9ede}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\Pages\Scene Editor">
|
||||||
|
<UniqueIdentifier>{c6368565-9e0a-487b-953c-6c4bc9e3f655}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\Pages\About Page">
|
||||||
|
<UniqueIdentifier>{2ce6e2ec-f0bf-4d49-8b11-cdf0f31693c5}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\Pages\About Page">
|
||||||
|
<UniqueIdentifier>{f8b17ddd-9689-45cc-84a1-5c321b0290b0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\GUI Components">
|
||||||
|
<UniqueIdentifier>{469e46b8-328a-474b-bf82-19c86b980e82}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\GUI Components">
|
||||||
|
<UniqueIdentifier>{1351d841-7665-48d3-9850-da0738823396}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\Pages\Scene Editor\Object Selector">
|
||||||
|
<UniqueIdentifier>{5e6e1e89-1c77-4a89-92cc-d64ea2546961}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\Pages\Scene Editor\Object Setter">
|
||||||
|
<UniqueIdentifier>{d2b9abbc-ef10-4990-96a1-a88f9c217dcf}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Qt Widgets\Pages\Scene Editor\Scene Viewer">
|
||||||
|
<UniqueIdentifier>{d6a38868-baed-45d5-9cbf-3faa3b563fa9}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\Pages\Scene Editor\Scene Viewer">
|
||||||
|
<UniqueIdentifier>{4b5e61f5-3dfe-44d7-bfcc-cf5b70528b16}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\Pages\Scene Editor\Object Selector">
|
||||||
|
<UniqueIdentifier>{995296ff-ac0c-4996-9692-c0e017e5fc03}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\Qt Widgets\Pages\Scene Editor\Object Setter">
|
||||||
|
<UniqueIdentifier>{6c5ac0df-26ad-40ad-860c-3d0372b81094}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtRcc Include="mainwindow.qrc">
|
<QtRcc Include="mainwindow.qrc">
|
||||||
<Filter>Resource Files</Filter>
|
<Filter>Resource Files</Filter>
|
||||||
</QtRcc>
|
</QtRcc>
|
||||||
<QtUic Include="mainwindow.ui">
|
|
||||||
<Filter>Form Files</Filter>
|
|
||||||
</QtUic>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="main.cpp">
|
<ClCompile Include="main.cpp">
|
||||||
@ -85,21 +120,51 @@
|
|||||||
<ClCompile Include="mainwindow.cpp">
|
<ClCompile Include="mainwindow.cpp">
|
||||||
<Filter>Source Files\Qt Widgets</Filter>
|
<Filter>Source Files\Qt Widgets</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="sceneviewer.cpp">
|
|
||||||
<Filter>Source Files\Qt Widgets</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="modelselector.cpp">
|
|
||||||
<Filter>Source Files\Qt Widgets</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="modelselectable.cpp">
|
|
||||||
<Filter>Source Files\Qt Widgets</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="modelsetter.cpp">
|
|
||||||
<Filter>Source Files\Qt Widgets</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="logger.cpp">
|
<ClCompile Include="logger.cpp">
|
||||||
<Filter>Source Files\Utils</Filter>
|
<Filter>Source Files\Utils</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="editorpage.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\Scene Editor</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="framelesswindow.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="pushbutton.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="scrolllistwidget.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="sidebar.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="pagewidget.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="roundedcornerwidget.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="aboutpage.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\About Page</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="lineeditwidget.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="modelselector.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="modelselectable.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="modelsetter.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\Scene Editor\Object Setter</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="sceneviewer.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\Scene Editor\Scene Viewer</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="modelthumbnailwidget.cpp">
|
||||||
|
<Filter>Source Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="camera.h">
|
<ClInclude Include="camera.h">
|
||||||
@ -117,12 +182,6 @@
|
|||||||
<ClInclude Include="mesh.h">
|
<ClInclude Include="mesh.h">
|
||||||
<Filter>Header Files\OpenGL Abstractions</Filter>
|
<Filter>Header Files\OpenGL Abstractions</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="modelselector.h">
|
|
||||||
<Filter>Header Files\Qt Widgets</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="modelsetter.h">
|
|
||||||
<Filter>Header Files\Qt Widgets</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="vertex.h">
|
<ClInclude Include="vertex.h">
|
||||||
<Filter>Header Files\OpenGL Abstractions</Filter>
|
<Filter>Header Files\OpenGL Abstractions</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -141,20 +200,56 @@
|
|||||||
<ClInclude Include="utils.h">
|
<ClInclude Include="utils.h">
|
||||||
<Filter>Header Files\Utils</Filter>
|
<Filter>Header Files\Utils</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="modelselectable.h">
|
|
||||||
<Filter>Header Files\Qt Widgets</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="logger.h">
|
<ClInclude Include="logger.h">
|
||||||
<Filter>Header Files\Utils</Filter>
|
<Filter>Header Files\Utils</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="modelsetter.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Setter</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtMoc Include="sceneviewer.h">
|
|
||||||
<Filter>Header Files\Qt Widgets</Filter>
|
|
||||||
</QtMoc>
|
|
||||||
<QtMoc Include="mainwindow.h">
|
<QtMoc Include="mainwindow.h">
|
||||||
<Filter>Header Files\Qt Widgets</Filter>
|
<Filter>Header Files\Qt Widgets</Filter>
|
||||||
</QtMoc>
|
</QtMoc>
|
||||||
|
<QtMoc Include="framelesswindow.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="pushbutton.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="pagewidget.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="sidebar.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="editorpage.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\Scene Editor</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="roundedcornerwidget.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="aboutpage.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\About Page</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="lineeditwidget.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="scrolllistwidget.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="sceneviewer.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Scene Viewer</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="modelselector.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="modelselectable.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
|
||||||
|
</QtMoc>
|
||||||
|
<QtMoc Include="modelthumbnailwidget.h">
|
||||||
|
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
|
||||||
|
</QtMoc>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="fragmentshader.fs">
|
<None Include="fragmentshader.fs">
|
||||||
|
|||||||
135
FinalProject/aboutpage.cpp
Normal file
135
FinalProject/aboutpage.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <qlayoutitem.h>
|
||||||
|
|
||||||
|
#include "aboutpage.h"
|
||||||
|
|
||||||
|
AboutPage::AboutPage(QWidget* parent) :
|
||||||
|
PageWidget(parent)
|
||||||
|
{
|
||||||
|
_contentWidget->setMouseTracking(true);
|
||||||
|
|
||||||
|
// Construct title layout
|
||||||
|
_titleLayout = new QVBoxLayout(_contentWidget);
|
||||||
|
_titleLayout->setContentsMargins(28, 46, 28, 28);
|
||||||
|
_titleLayout->setSpacing(18);
|
||||||
|
_titleLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
_contentWidget->setLayout(_titleLayout);
|
||||||
|
|
||||||
|
// Construct title
|
||||||
|
_titleLabel = new QLabel("ABOUT", _contentWidget);
|
||||||
|
_titleLabel->setFont(_titleFont);
|
||||||
|
_titleLayout->addWidget(_titleLabel);
|
||||||
|
_titleLabel->show();
|
||||||
|
|
||||||
|
// Construct main layout
|
||||||
|
_mainWidget = new QWidget(_contentWidget);
|
||||||
|
_mainWidget->setObjectName("mainWidget");
|
||||||
|
_mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
_mainWidget->setStyleSheet("QWidget#mainWidget { background-color: #efefef; border-radius: 8px; }");
|
||||||
|
_mainLayout = new QVBoxLayout(_mainWidget);
|
||||||
|
_mainLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
_mainLayout->setContentsMargins(0, 8, 0, 8);
|
||||||
|
_mainLayout->setSpacing(8);
|
||||||
|
_mainWidget->setLayout(_mainLayout);
|
||||||
|
_titleLayout->addWidget(_mainWidget);
|
||||||
|
_mainWidget->show();
|
||||||
|
|
||||||
|
// Construct contents
|
||||||
|
_authorLabel = new LineEditWidget(_mainWidget);
|
||||||
|
_authorLabel->mainLayout()->insertWidget(0, new QLabel("Author"));
|
||||||
|
_authorLabel->mainLayout()->insertSpacing(1, 8);
|
||||||
|
_authorLabel->setBackgroundColor(QColor(0, 0, 0, 0));
|
||||||
|
_authorLabel->setHoverColor(QColor(0, 0, 0, 10));
|
||||||
|
_authorLabel->setPressedColor(QColor(0, 0, 0, 20));
|
||||||
|
_authorLabel->setText("Linloir");
|
||||||
|
_authorLabel->setEnabled(false);
|
||||||
|
_mainLayout->addWidget(_authorLabel);
|
||||||
|
_authorLabel->show();
|
||||||
|
|
||||||
|
_versionLabel = new LineEditWidget(_mainWidget);
|
||||||
|
_versionLabel->mainLayout()->insertWidget(0, new QLabel("Version"));
|
||||||
|
_versionLabel->mainLayout()->insertSpacing(1, 8);
|
||||||
|
_versionLabel->setBackgroundColor(QColor(0, 0, 0, 0));
|
||||||
|
_versionLabel->setHoverColor(QColor(0, 0, 0, 10));
|
||||||
|
_versionLabel->setPressedColor(QColor(0, 0, 0, 20));
|
||||||
|
_versionLabel->setText("1.0.0");
|
||||||
|
_versionLabel->setEnabled(false);
|
||||||
|
_mainLayout->addWidget(_versionLabel);
|
||||||
|
_versionLabel->show();
|
||||||
|
|
||||||
|
_dateLabel = new LineEditWidget(_mainWidget);
|
||||||
|
_dateLabel->mainLayout()->insertWidget(0, new QLabel("Last Update"));
|
||||||
|
_dateLabel->mainLayout()->insertSpacing(1, 8);
|
||||||
|
_dateLabel->setBackgroundColor(QColor(0, 0, 0, 0));
|
||||||
|
_dateLabel->setHoverColor(QColor(0, 0, 0, 10));
|
||||||
|
_dateLabel->setPressedColor(QColor(0, 0, 0, 20));
|
||||||
|
_dateLabel->setText("2020/12/31");
|
||||||
|
_dateLabel->setEnabled(false);
|
||||||
|
_mainLayout->addWidget(_dateLabel);
|
||||||
|
_dateLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
AboutPage::~AboutPage() {}
|
||||||
|
|
||||||
|
PushButton* AboutPage::getPageIconButton(QWidget* context) {
|
||||||
|
// Check for existed button
|
||||||
|
if (_iconButton != nullptr) {
|
||||||
|
return _iconButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new icon button
|
||||||
|
_iconButton = new PushButton(nullptr, context);
|
||||||
|
_iconButton->setMargin(20, 18, 16, 18);
|
||||||
|
_iconButtonLabel = new QLabel(_iconButton);
|
||||||
|
_iconButtonLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
QFont iconButtonFont("Font Awesome 6 Free Regular", 12);
|
||||||
|
iconButtonFont.setStyleStrategy(QFont::PreferAntialias);
|
||||||
|
_iconButtonLabel->setFont(iconButtonFont);
|
||||||
|
_iconButtonLabel->setText("\uf059");
|
||||||
|
_iconButtonLabel->setAlignment(Qt::AlignLeft);
|
||||||
|
_iconButton->setChildWidget(_iconButtonLabel);
|
||||||
|
|
||||||
|
// Return newly generated icon
|
||||||
|
return _iconButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton* AboutPage::getPageTextButton(QWidget* context) {
|
||||||
|
// Check for existed button
|
||||||
|
if (_textButton != nullptr) {
|
||||||
|
return _textButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new text button
|
||||||
|
_textButton = new PushButton(nullptr, context);
|
||||||
|
_textButton->setMargin(20, 18, 16, 18);
|
||||||
|
_textButtonWidget = new QWidget(_textButton);
|
||||||
|
_textButtonLayout = new QHBoxLayout(_textButtonWidget);
|
||||||
|
_textButtonLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_textButtonLayout->setSpacing(12);
|
||||||
|
_textButtonWidget->setLayout(_textButtonLayout);
|
||||||
|
|
||||||
|
// Generate text button contents
|
||||||
|
_textButtonIcon = new QLabel(_textButtonWidget);
|
||||||
|
QFont textButtonFont("Font Awesome 6 Free Regular", 12);
|
||||||
|
textButtonFont.setStyleStrategy(QFont::PreferQuality);
|
||||||
|
_textButtonIcon->setFont(textButtonFont);
|
||||||
|
_textButtonIcon->setText("\uf059"); // set icon to "pen" icon
|
||||||
|
_textButtonIcon->setAlignment(Qt::AlignLeft);
|
||||||
|
|
||||||
|
_textButtonLabel = new QLabel(_textButtonWidget);
|
||||||
|
_textButtonLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
_textButtonLabel->setText("About");
|
||||||
|
_textButtonLabel->setAlignment(Qt::AlignLeft);
|
||||||
|
|
||||||
|
// Add text button contents to layout
|
||||||
|
_textButtonLayout->addWidget(_textButtonIcon);
|
||||||
|
_textButtonLayout->addWidget(_textButtonLabel);
|
||||||
|
_textButtonIcon->show();
|
||||||
|
_textButtonLabel->show();
|
||||||
|
|
||||||
|
// Set text button child widget
|
||||||
|
_textButton->setChildWidget(_textButtonWidget);
|
||||||
|
_textButtonWidget->show();
|
||||||
|
|
||||||
|
// Return newly generated text button
|
||||||
|
return _textButton;
|
||||||
|
}
|
||||||
41
FinalProject/aboutpage.h
Normal file
41
FinalProject/aboutpage.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
|
||||||
|
#include "pagewidget.h"
|
||||||
|
#include "lineeditwidget.h"
|
||||||
|
|
||||||
|
class AboutPage : public PageWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AboutPage(QWidget* parent = 0);
|
||||||
|
~AboutPage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Push button icons
|
||||||
|
QLabel* _iconButtonLabel = nullptr;
|
||||||
|
QWidget* _textButtonWidget = nullptr;
|
||||||
|
QHBoxLayout* _textButtonLayout = nullptr;
|
||||||
|
QLabel* _textButtonIcon = nullptr;
|
||||||
|
QLabel* _textButtonLabel = nullptr;
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
QVBoxLayout* _titleLayout = nullptr;
|
||||||
|
const QFont _titleFont = QFont("DengXian", 26, QFont::ExtraLight);
|
||||||
|
QLabel* _titleLabel = nullptr;
|
||||||
|
|
||||||
|
QWidget* _mainWidget = nullptr;
|
||||||
|
QVBoxLayout* _mainLayout = nullptr;
|
||||||
|
|
||||||
|
LineEditWidget* _authorLabel = nullptr;
|
||||||
|
LineEditWidget* _versionLabel = nullptr;
|
||||||
|
LineEditWidget* _dateLabel = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual PushButton* getPageIconButton(QWidget* context) override;
|
||||||
|
virtual PushButton* getPageTextButton(QWidget* context) override;
|
||||||
|
};
|
||||||
118
FinalProject/editorpage.cpp
Normal file
118
FinalProject/editorpage.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qfontdatabase.h>
|
||||||
|
|
||||||
|
#include "editorpage.h"
|
||||||
|
|
||||||
|
EditorPage::EditorPage(QWidget* parent) :
|
||||||
|
PageWidget(parent)
|
||||||
|
{
|
||||||
|
_contentWidget->setMouseTracking(true);
|
||||||
|
|
||||||
|
// Construct title layout
|
||||||
|
_titleLayout = new QVBoxLayout(_contentWidget);
|
||||||
|
_titleLayout->setContentsMargins(28, 46, 28, 28);
|
||||||
|
_titleLayout->setSpacing(18);
|
||||||
|
_titleLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
_contentWidget->setLayout(_titleLayout);
|
||||||
|
|
||||||
|
// Construct title
|
||||||
|
_titleLabel = new QLabel("EDITOR", _contentWidget);
|
||||||
|
_titleLabel->setFont(_titleFont);
|
||||||
|
_titleLayout->addWidget(_titleLabel);
|
||||||
|
_titleLabel->show();
|
||||||
|
|
||||||
|
// Construct main layout
|
||||||
|
_mainWidget = new QWidget(_contentWidget);
|
||||||
|
_mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
_mainLayout = new QHBoxLayout(_mainWidget);
|
||||||
|
_mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_mainLayout->setSpacing(16);
|
||||||
|
_mainWidget->setLayout(_mainLayout);
|
||||||
|
_titleLayout->addWidget(_mainWidget);
|
||||||
|
_mainWidget->show();
|
||||||
|
|
||||||
|
// Generate model selector
|
||||||
|
_modelSelector = new ModelSelector(_mainWidget);
|
||||||
|
_mainLayout->addWidget(_modelSelector);
|
||||||
|
_modelSelector->show();
|
||||||
|
|
||||||
|
// Generate scene viewer
|
||||||
|
_sceneViewerContainer = new RoundedCornerWidget(_mainWidget);
|
||||||
|
_sceneViewerContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
_sceneViewerContainerLayout = new QVBoxLayout(_sceneViewerContainer->mainWidget());
|
||||||
|
_sceneViewerContainerLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_sceneViewerContainerLayout->setSpacing(0);
|
||||||
|
_sceneViewerContainer->mainWidget()->setLayout(_sceneViewerContainerLayout);
|
||||||
|
_sceneViewer = new SceneViewer(_sceneViewerContainer->mainWidget());
|
||||||
|
_sceneViewerContainerLayout->addWidget(_sceneViewer);
|
||||||
|
_sceneViewer->show();
|
||||||
|
_mainLayout->addWidget(_sceneViewerContainer);
|
||||||
|
_sceneViewerContainer->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorPage::~EditorPage() {}
|
||||||
|
|
||||||
|
PushButton* EditorPage::getPageIconButton(QWidget* context) {
|
||||||
|
// Check for existed button
|
||||||
|
if (_iconButton != nullptr) {
|
||||||
|
return _iconButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new icon button
|
||||||
|
_iconButton = new PushButton(nullptr, context);
|
||||||
|
_iconButton->setMargin(20, 18, 16, 18);
|
||||||
|
_iconButtonLabel = new QLabel(_iconButton);
|
||||||
|
_iconButtonLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
QFont iconButtonFont("Font Awesome 6 Free Solid", 12);
|
||||||
|
iconButtonFont.setStyleStrategy(QFont::PreferAntialias);
|
||||||
|
_iconButtonLabel->setFont(iconButtonFont);
|
||||||
|
_iconButtonLabel->setText("\uf304"); // set icon to "pen" icon
|
||||||
|
_iconButtonLabel->setAlignment(Qt::AlignLeft);
|
||||||
|
_iconButton->setChildWidget(_iconButtonLabel);
|
||||||
|
|
||||||
|
// Return newly generated icon
|
||||||
|
return _iconButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton* EditorPage::getPageTextButton(QWidget* context) {
|
||||||
|
// Check for existed button
|
||||||
|
if (_textButton != nullptr) {
|
||||||
|
return _textButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new text button
|
||||||
|
_textButton = new PushButton(nullptr, context);
|
||||||
|
_textButton->setMargin(20, 18, 16, 18);
|
||||||
|
_textButtonWidget = new QWidget(_textButton);
|
||||||
|
_textButtonLayout = new QHBoxLayout(_textButtonWidget);
|
||||||
|
_textButtonLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_textButtonLayout->setSpacing(12);
|
||||||
|
_textButtonWidget->setLayout(_textButtonLayout);
|
||||||
|
|
||||||
|
// Generate text button contents
|
||||||
|
_textButtonIcon = new QLabel(_textButtonWidget);
|
||||||
|
QFont textButtonFont("Font Awesome 6 Free Solid", 12);
|
||||||
|
textButtonFont.setStyleStrategy(QFont::PreferQuality);
|
||||||
|
_textButtonIcon->setFont(textButtonFont);
|
||||||
|
_textButtonIcon->setText("\uf304"); // set icon to "pen" icon
|
||||||
|
_textButtonIcon->setAlignment(Qt::AlignLeft);
|
||||||
|
|
||||||
|
_textButtonLabel = new QLabel(_textButtonWidget);
|
||||||
|
_textButtonLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
_textButtonLabel->setText("Editor");
|
||||||
|
_textButtonLabel->setAlignment(Qt::AlignLeft);
|
||||||
|
|
||||||
|
// Add text button contents to layout
|
||||||
|
_textButtonLayout->addWidget(_textButtonIcon);
|
||||||
|
_textButtonLayout->addWidget(_textButtonLabel);
|
||||||
|
_textButtonIcon->show();
|
||||||
|
_textButtonLabel->show();
|
||||||
|
|
||||||
|
// Set text button child widget
|
||||||
|
_textButton->setChildWidget(_textButtonWidget);
|
||||||
|
_textButtonWidget->show();
|
||||||
|
|
||||||
|
// Return newly generated text button
|
||||||
|
return _textButton;
|
||||||
|
}
|
||||||
45
FinalProject/editorpage.h
Normal file
45
FinalProject/editorpage.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
|
||||||
|
#include "pagewidget.h"
|
||||||
|
#include "sceneviewer.h"
|
||||||
|
#include "roundedcornerwidget.h"
|
||||||
|
#include "modelselector.h"
|
||||||
|
|
||||||
|
class EditorPage : public PageWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
EditorPage(QWidget* parent = 0);
|
||||||
|
~EditorPage();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Push button icons
|
||||||
|
QLabel* _iconButtonLabel = nullptr;
|
||||||
|
QWidget* _textButtonWidget = nullptr;
|
||||||
|
QHBoxLayout* _textButtonLayout = nullptr;
|
||||||
|
QLabel* _textButtonIcon = nullptr;
|
||||||
|
QLabel* _textButtonLabel = nullptr;
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
QVBoxLayout* _titleLayout = nullptr;
|
||||||
|
const QFont _titleFont = QFont("DengXian", 26, QFont::ExtraLight);
|
||||||
|
QLabel* _titleLabel = nullptr;
|
||||||
|
|
||||||
|
QWidget* _mainWidget = nullptr;
|
||||||
|
QHBoxLayout* _mainLayout = nullptr;
|
||||||
|
|
||||||
|
ModelSelector* _modelSelector = nullptr;
|
||||||
|
|
||||||
|
RoundedCornerWidget* _sceneViewerContainer = nullptr;
|
||||||
|
QVBoxLayout* _sceneViewerContainerLayout = nullptr;
|
||||||
|
SceneViewer* _sceneViewer = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual PushButton* getPageIconButton(QWidget* context) override;
|
||||||
|
virtual PushButton* getPageTextButton(QWidget* context) override;
|
||||||
|
};
|
||||||
BIN
FinalProject/font_awesome_6_regular_free.otf
Normal file
BIN
FinalProject/font_awesome_6_regular_free.otf
Normal file
Binary file not shown.
BIN
FinalProject/font_awesome_6_solid_free.otf
Normal file
BIN
FinalProject/font_awesome_6_solid_free.otf
Normal file
Binary file not shown.
373
FinalProject/framelesswindow.cpp
Normal file
373
FinalProject/framelesswindow.cpp
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
#include <qapplication.h>
|
||||||
|
#include <qpainterpath.h>
|
||||||
|
#include <qscreen.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
|
||||||
|
#include "framelesswindow.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#define MAX_MOUSE_MOVEMENT 300
|
||||||
|
|
||||||
|
FramelessWindow::FramelessWindow(int cornerRadius, unsigned int attributes, QWidget* parent)
|
||||||
|
: _cornerRadius(cornerRadius), _attributes((LUI_WINDOW_ATTRIBUTES)attributes), QWidget(parent)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
setWindowFlags(Qt::FramelessWindowHint);
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
setMouseTracking(true);
|
||||||
|
setFocus();
|
||||||
|
|
||||||
|
// Create and properly set real displayed window widget
|
||||||
|
_stretchLayout = new QVBoxLayout(this);
|
||||||
|
_stretchLayout->setContentsMargins(30, 30, 30, 30);
|
||||||
|
_windowWidget = new QWidget(this);
|
||||||
|
_windowWidget->setObjectName("windowWidget");
|
||||||
|
_windowWidget->setMouseTracking(true);
|
||||||
|
_stretchLayout->addWidget(_windowWidget);
|
||||||
|
_windowWidget->show();
|
||||||
|
setLayout(_stretchLayout);
|
||||||
|
|
||||||
|
// Set style sheet for window widget
|
||||||
|
QString windowWidgetStyleSheet = "QWidget#windowWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_cornerRadius) + "px;}";
|
||||||
|
_windowWidget->setStyleSheet(windowWidgetStyleSheet);
|
||||||
|
|
||||||
|
// Set shadow for window widget
|
||||||
|
_windowShadow = new QGraphicsDropShadowEffect(_windowWidget);
|
||||||
|
_windowShadow->setBlurRadius(30);
|
||||||
|
_windowShadow->setColor(QColor(0, 0, 0));
|
||||||
|
_windowShadow->setOffset(0, 0);
|
||||||
|
_windowWidget->setGraphicsEffect(_windowShadow);
|
||||||
|
|
||||||
|
// Create window control buttons container widget & its layout
|
||||||
|
_windowBtnWidget = new QWidget(_windowWidget);
|
||||||
|
_windowBtnWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
_windowBtnWidget->setMouseTracking(true);
|
||||||
|
_windowBtnLayout = new QHBoxLayout(_windowBtnWidget);
|
||||||
|
_windowBtnLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_windowBtnLayout->setSpacing(10);
|
||||||
|
_windowBtnLayout->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||||
|
_windowBtnWidget->setLayout(_windowBtnLayout);
|
||||||
|
|
||||||
|
// Create window control buttons
|
||||||
|
_minimizeBtn = new QPushButton(_windowBtnWidget);
|
||||||
|
_maximizeBtn = new QPushButton(_windowBtnWidget);
|
||||||
|
_closeBtn = new QPushButton(_windowBtnWidget);
|
||||||
|
|
||||||
|
_minimizeBtn->setFixedSize(12, 12);
|
||||||
|
_maximizeBtn->setFixedSize(12, 12);
|
||||||
|
_closeBtn->setFixedSize(12, 12);
|
||||||
|
|
||||||
|
_minimizeBtn->setStyleSheet("QPushButton{border-radius: 6px; background-color: #c2c2c2;}"
|
||||||
|
"QPushButton:hover{background-color: #e98b2a;}");
|
||||||
|
_maximizeBtn->setStyleSheet("QPushButton{border-radius: 6px; background-color: #c2c2c2;}"
|
||||||
|
"QPushButton:hover{background-color: #2d6d4b;}");
|
||||||
|
_closeBtn->setStyleSheet("QPushButton{border-radius: 6px; background-color: #c2c2c2;}"
|
||||||
|
"QPushButton:hover{background-color: #ab3b3a;}");
|
||||||
|
|
||||||
|
_windowBtnLayout->addWidget(_minimizeBtn);
|
||||||
|
_windowBtnLayout->addWidget(_maximizeBtn);
|
||||||
|
_windowBtnLayout->addWidget(_closeBtn);
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_MINIMIZE) == 0) {
|
||||||
|
_minimizeBtn->show();
|
||||||
|
}
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_MAXIMIZE) == 0) {
|
||||||
|
_maximizeBtn->show();
|
||||||
|
}
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_CLOSE) == 0) {
|
||||||
|
_closeBtn->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect window control buttons
|
||||||
|
connect(_minimizeBtn, &QPushButton::clicked, this, &QWidget::showMinimized);
|
||||||
|
connect(_maximizeBtn, &QPushButton::clicked, this, &FramelessWindow::controlWindowScale);
|
||||||
|
connect(_closeBtn, &QPushButton::clicked, this, &QWidget::close);
|
||||||
|
}
|
||||||
|
|
||||||
|
FramelessWindow::FramelessWindow(QWidget* parent)
|
||||||
|
: FramelessWindow(0, LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_NO_ATTRIBUTES, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FramelessWindow::FramelessWindow(int cornerRadius, QWidget* parent)
|
||||||
|
: FramelessWindow(cornerRadius, LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_NO_ATTRIBUTES, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FramelessWindow::FramelessWindow(unsigned int attributes, QWidget* parent)
|
||||||
|
: FramelessWindow(0, attributes, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FramelessWindow::~FramelessWindow() {}
|
||||||
|
|
||||||
|
void FramelessWindow::showEvent(QShowEvent* event) {
|
||||||
|
// Initialize window UI after window is shown
|
||||||
|
initializeWindowUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::initializeWindowUI() {
|
||||||
|
if (_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a round cornered mask for window widget
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(_windowWidget->rect(), _cornerRadius - 1, _cornerRadius - 1);
|
||||||
|
QRegion region(path.toFillPolygon().toPolygon());
|
||||||
|
_windowWidget->setMask(region);
|
||||||
|
|
||||||
|
// Create a border for window widget (in order to hide zigzagged edges)
|
||||||
|
_windowBorder = new QWidget(this);
|
||||||
|
_windowBorder->setObjectName("windowBorder");
|
||||||
|
QString windowBorderStyleSheet =
|
||||||
|
"QWidget#windowBorder{background-color:#00FFFFFF;border:1.5px solid " + _borderColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_cornerRadius) + "px;}";
|
||||||
|
_windowBorder->setStyleSheet(windowBorderStyleSheet);
|
||||||
|
_windowBorder->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
_windowBorder->move(_windowWidget->pos() - QPoint(1, 1));
|
||||||
|
_windowBorder->resize(_windowWidget->size() + QSize(2, 2));
|
||||||
|
_windowBorder->show();
|
||||||
|
|
||||||
|
// Move button widget to the top right of the window widget
|
||||||
|
_windowBtnWidget->move(_windowWidget->width() - _windowBtnWidget->width() - 18, 18);
|
||||||
|
_windowBtnWidget->show();
|
||||||
|
_windowBtnWidget->raise();
|
||||||
|
|
||||||
|
// Set initialized state
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::resizeEvent(QResizeEvent* event) {
|
||||||
|
// Resize window border
|
||||||
|
if (_windowBorder != nullptr) {
|
||||||
|
_windowBorder->move(_windowWidget->pos() - QPoint(1, 1));
|
||||||
|
_windowBorder->resize(_windowWidget->size() + QSize(2, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize window mask
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(_windowWidget->rect(), _cornerRadius - 1, _cornerRadius - 1);
|
||||||
|
QRegion region(path.toFillPolygon().toPolygon());
|
||||||
|
_windowWidget->setMask(region);
|
||||||
|
|
||||||
|
// Move button widget to the top right of the window widget
|
||||||
|
_windowBtnWidget->move(_windowWidget->width() - _windowBtnWidget->width() - 18, 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::controlWindowScale() {
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_MAXIMIZE) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_maximized) {
|
||||||
|
_lastWindowGeometry = frameGeometry();
|
||||||
|
|
||||||
|
Logger::debug("Maximizing window:");
|
||||||
|
Logger::debug("[+] current window position: " + std::to_string(x()) + ", " + std::to_string(y()));
|
||||||
|
Logger::debug("[+] current window size: " + std::to_string(width()) + ", " + std::to_string(height()));
|
||||||
|
Logger::debug("[+] current geometry: " + std::to_string(_lastWindowGeometry.x()) + ", " + std::to_string(_lastWindowGeometry.y()) + ", " + std::to_string(_lastWindowGeometry.width()) + ", " + std::to_string(_lastWindowGeometry.height()));
|
||||||
|
Logger::debug("[+] current window widget position: " + std::to_string(_windowWidget->x()) + ", " + std::to_string(_windowWidget->y()));
|
||||||
|
Logger::debug("[+] current window widget size: " + std::to_string(_windowWidget->width()) + ", " + std::to_string(_windowWidget->height()));
|
||||||
|
Logger::debug("[+] current window border position: " + std::to_string(_windowBorder->x()) + ", " + std::to_string(_windowBorder->y()));
|
||||||
|
Logger::debug("[+] current window border size: " + std::to_string(_windowBorder->width()) + ", " + std::to_string(_windowBorder->height()));
|
||||||
|
|
||||||
|
_windowShadow->setEnabled(false);
|
||||||
|
_windowBorder->hide();
|
||||||
|
QString windowWidgetStyleSheet = "QWidget#windowWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";}";
|
||||||
|
_windowWidget->setStyleSheet(windowWidgetStyleSheet);
|
||||||
|
|
||||||
|
_stretchLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
showMaximized();
|
||||||
|
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRect(_windowWidget->rect());
|
||||||
|
QRegion mask(path.toFillPolygon().toPolygon());
|
||||||
|
_windowWidget->setMask(mask);
|
||||||
|
|
||||||
|
_maximized = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_stretchLayout->setContentsMargins(30, 30, 30, 30);
|
||||||
|
|
||||||
|
showNormal();
|
||||||
|
|
||||||
|
resize(_lastWindowGeometry.size());
|
||||||
|
move(_lastWindowGeometry.topLeft());
|
||||||
|
|
||||||
|
_windowShadow->setEnabled(true);
|
||||||
|
_windowBorder->show();
|
||||||
|
QString windowWidgetStyleSheet = "QWidget#windowWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_cornerRadius) + "px;}";
|
||||||
|
_windowWidget->setStyleSheet(windowWidgetStyleSheet);
|
||||||
|
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(_windowWidget->rect(), _cornerRadius - 1, _cornerRadius - 1);
|
||||||
|
QRegion mask(path.toFillPolygon().toPolygon());
|
||||||
|
_windowWidget->setMask(mask);
|
||||||
|
|
||||||
|
Logger::debug("Restoring window:");
|
||||||
|
Logger::debug("[+] current window position: " + std::to_string(x()) + ", " + std::to_string(y()));
|
||||||
|
Logger::debug("[+] current window size: " + std::to_string(width()) + ", " + std::to_string(height()));
|
||||||
|
Logger::debug("[+] current geometry: " + std::to_string(frameGeometry().x()) + ", " + std::to_string(frameGeometry().y()) + ", " + std::to_string(frameGeometry().width()) + ", " + std::to_string(frameGeometry().height()));
|
||||||
|
Logger::debug("[+] current window widget position: " + std::to_string(_windowWidget->x()) + ", " + std::to_string(_windowWidget->y()));
|
||||||
|
Logger::debug("[+] current window widget size: " + std::to_string(_windowWidget->width()) + ", " + std::to_string(_windowWidget->height()));
|
||||||
|
|
||||||
|
_maximized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::updateMouseState(QMouseEvent* event) {
|
||||||
|
_mouseState = MOUSE_STATE_NONE;
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_RESIZE) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_maximized) {
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Set mouse state according to abs distance from window border
|
||||||
|
if (abs(event->globalPos().x() - (_windowWidget->frameGeometry().left() + frameGeometry().left())) < 5) {
|
||||||
|
_mouseState |= MOUSE_STATE_RESIZE_LEFT;
|
||||||
|
}
|
||||||
|
if (abs(event->globalPos().x() - (_windowWidget->frameGeometry().right() + frameGeometry().left())) < 5) {
|
||||||
|
_mouseState |= MOUSE_STATE_RESIZE_RIGHT;
|
||||||
|
}
|
||||||
|
if (abs(event->globalPos().y() - (_windowWidget->frameGeometry().top() + frameGeometry().top())) < 5) {
|
||||||
|
_mouseState |= MOUSE_STATE_RESIZE_TOP;
|
||||||
|
}
|
||||||
|
if (abs(event->globalPos().y() - (_windowWidget->frameGeometry().bottom() + frameGeometry().top())) < 5) {
|
||||||
|
_mouseState |= MOUSE_STATE_RESIZE_BOTTOM;
|
||||||
|
}
|
||||||
|
// Set cursor shape according to mouse state
|
||||||
|
switch (_mouseState) {
|
||||||
|
case MOUSE_STATE_RESIZE_LEFT:
|
||||||
|
case MOUSE_STATE_RESIZE_RIGHT:
|
||||||
|
setCursor(Qt::SizeHorCursor);
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_TOP:
|
||||||
|
case MOUSE_STATE_RESIZE_BOTTOM:
|
||||||
|
setCursor(Qt::SizeVerCursor);
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_TOP:
|
||||||
|
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_BOTTOM:
|
||||||
|
setCursor(Qt::SizeFDiagCursor);
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_BOTTOM:
|
||||||
|
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_TOP:
|
||||||
|
setCursor(Qt::SizeBDiagCursor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::mousePressEvent(QMouseEvent* event) {
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
_mousePressed = true;
|
||||||
|
_lastMousePosition = event->globalPos().toPointF();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
_mousePressed = false;
|
||||||
|
QScreen* screen = QGuiApplication::screenAt(event->globalPos());
|
||||||
|
Logger::debug("Current screen geometry:");
|
||||||
|
Logger::debug("[+] screen position: " + std::to_string(screen->geometry().x()) + ", " + std::to_string(screen->geometry().y()));
|
||||||
|
Logger::debug("[+] screen size: " + std::to_string(screen->geometry().width()) + ", " + std::to_string(screen->geometry().height()));
|
||||||
|
if (abs(event->globalPos().y() - screen->geometry().top()) < 5) {
|
||||||
|
controlWindowScale();
|
||||||
|
}
|
||||||
|
updateMouseState(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
Logger::debug("Detected mouse move");
|
||||||
|
Logger::debug("[+] mouse global position : " + std::to_string(event->globalPos().x()) + ", " + std::to_string(event->globalPos().y()));
|
||||||
|
Logger::debug("[+] window geometry: " + std::to_string(frameGeometry().x()) + ", " + std::to_string(frameGeometry().y()) + ", " + std::to_string(frameGeometry().width()) + ", " + std::to_string(frameGeometry().height()));
|
||||||
|
Logger::debug("[+] widget frame geometry: " + std::to_string(_windowWidget->frameGeometry().x()) + ", " + std::to_string(_windowWidget->frameGeometry().y()));
|
||||||
|
Logger::debug("[+] widget frame size: " + std::to_string(_windowWidget->frameGeometry().width()) + ", " + std::to_string(_windowWidget->frameGeometry().height()));
|
||||||
|
if (event->buttons() == Qt::NoButton) {
|
||||||
|
_mousePressed = false;
|
||||||
|
}
|
||||||
|
if (abs(event->globalPos().x() - _lastMousePosition.x()) > MAX_MOUSE_MOVEMENT) {
|
||||||
|
// Maybe moving window across monitors, avoid window disappear
|
||||||
|
_lastMousePosition = event->globalPos().toPointF();
|
||||||
|
}
|
||||||
|
if (abs(event->globalPos().y() - _lastMousePosition.y()) > MAX_MOUSE_MOVEMENT) {
|
||||||
|
// Maybe moving window across monitors, avoid window disappear
|
||||||
|
_lastMousePosition = event->globalPos().toPointF();
|
||||||
|
}
|
||||||
|
if (!_mousePressed) {
|
||||||
|
updateMouseState(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Resize window according to mouse state
|
||||||
|
switch (_mouseState) {
|
||||||
|
case MOUSE_STATE_RESIZE_LEFT:
|
||||||
|
resize(frameGeometry().width() - event->globalPos().x() + frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height());
|
||||||
|
move(event->globalPos().x() - _windowWidget->frameGeometry().left(), frameGeometry().top());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_RIGHT:
|
||||||
|
resize(event->globalPos().x() - frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_TOP:
|
||||||
|
resize(frameGeometry().width(), frameGeometry().height() - event->globalPos().y() + frameGeometry().top() + _windowWidget->frameGeometry().top());
|
||||||
|
move(frameGeometry().left(), event->globalPos().y() - _windowWidget->frameGeometry().top());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_BOTTOM:
|
||||||
|
resize(frameGeometry().width(), event->globalPos().y() - frameGeometry().top() + _windowWidget->frameGeometry().top());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_TOP:
|
||||||
|
resize(frameGeometry().width() - event->globalPos().x() + frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height() - event->globalPos().y() + frameGeometry().top() + _windowWidget->frameGeometry().top());
|
||||||
|
move(event->globalPos().x() - _windowWidget->frameGeometry().left(), event->globalPos().y() - _windowWidget->frameGeometry().top());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_BOTTOM:
|
||||||
|
resize(frameGeometry().width() - event->globalPos().x() + frameGeometry().left() + _windowWidget->frameGeometry().left(), event->globalPos().y() - frameGeometry().top() + _windowWidget->frameGeometry().top());
|
||||||
|
move(event->globalPos().x() - _windowWidget->frameGeometry().left(), frameGeometry().top());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_TOP:
|
||||||
|
resize(event->globalPos().x() - frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height() - event->globalPos().y() + frameGeometry().top() + _windowWidget->frameGeometry().top());
|
||||||
|
move(frameGeometry().left(), event->globalPos().y() - _windowWidget->frameGeometry().top());
|
||||||
|
break;
|
||||||
|
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_BOTTOM:
|
||||||
|
resize(event->globalPos().x() - frameGeometry().left() + _windowWidget->frameGeometry().left(), event->globalPos().y() - frameGeometry().top() + _windowWidget->frameGeometry().top());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (_maximized) {
|
||||||
|
qreal wRatio = (qreal)event->pos().x() / (qreal)_windowWidget->width();
|
||||||
|
controlWindowScale();
|
||||||
|
move(event->globalPos().x() - _windowWidget->width() * wRatio, event->globalPos().y() - 52);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
move(frameGeometry().left() + event->globalPos().x() - _lastMousePosition.x(), frameGeometry().top() + event->globalPos().y() - _lastMousePosition.y());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_lastMousePosition = event->globalPos().toPointF();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FramelessWindow::LUI_WINDOW_ATTRIBUTES FramelessWindow::getWindowAttributes() {
|
||||||
|
return _attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramelessWindow::setWindowAttributes(unsigned int attributes) {
|
||||||
|
_attributes = (LUI_WINDOW_ATTRIBUTES)attributes;
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_MINIMIZE) == 0) {
|
||||||
|
_minimizeBtn->show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_minimizeBtn->hide();
|
||||||
|
}
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_MAXIMIZE) == 0) {
|
||||||
|
_maximizeBtn->show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_maximizeBtn->hide();
|
||||||
|
}
|
||||||
|
if ((_attributes & LUI_WINDOW_ATTRIBUTES::LUI_WINDOW_DISABLE_CLOSE) == 0) {
|
||||||
|
_closeBtn->show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_closeBtn->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
82
FinalProject/framelesswindow.h
Normal file
82
FinalProject/framelesswindow.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtWidgets/QMainWindow>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qgraphicseffect.h>
|
||||||
|
#include <qpushbutton.h>
|
||||||
|
|
||||||
|
class FramelessWindow : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Window attributes
|
||||||
|
enum LUI_WINDOW_ATTRIBUTES {
|
||||||
|
LUI_WINDOW_NO_ATTRIBUTES = 0,
|
||||||
|
LUI_WINDOW_DISABLE_CLOSE = 1 << 0,
|
||||||
|
LUI_WINDOW_DISABLE_MAXIMIZE = 1 << 1,
|
||||||
|
LUI_WINDOW_DISABLE_MINIMIZE = 1 << 2,
|
||||||
|
LUI_WINDOW_DISABLE_RESIZE = 1 << 3
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
FramelessWindow(QWidget* parent = 0);
|
||||||
|
FramelessWindow(int cornerRadius, QWidget* parent = 0);
|
||||||
|
FramelessWindow(unsigned int attributes, QWidget* parent = 0);
|
||||||
|
FramelessWindow(int cornerRadius, unsigned int attributes, QWidget* parent = 0);
|
||||||
|
~FramelessWindow();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// UI control variables
|
||||||
|
const int _cornerRadius = 0;
|
||||||
|
const QColor _backgroundColor = QColor(251, 251, 251);
|
||||||
|
const QColor _borderColor = QColor(104, 104, 104);
|
||||||
|
|
||||||
|
// Window initialize
|
||||||
|
bool _initialized = false; // prevent double initialization when restore from minimized state
|
||||||
|
void initializeWindowUI();
|
||||||
|
virtual void showEvent(QShowEvent* event) override;
|
||||||
|
|
||||||
|
// Widget list
|
||||||
|
QVBoxLayout* _stretchLayout = nullptr;
|
||||||
|
|
||||||
|
QWidget* _windowWidget = nullptr;
|
||||||
|
QWidget* _windowBorder = nullptr;
|
||||||
|
QGraphicsDropShadowEffect* _windowShadow = nullptr;
|
||||||
|
|
||||||
|
QWidget* _windowBtnWidget = nullptr;
|
||||||
|
QHBoxLayout* _windowBtnLayout = nullptr;
|
||||||
|
QPushButton* _minimizeBtn = nullptr;
|
||||||
|
QPushButton* _maximizeBtn = nullptr;
|
||||||
|
QPushButton* _closeBtn = nullptr;
|
||||||
|
|
||||||
|
// Window size control
|
||||||
|
LUI_WINDOW_ATTRIBUTES _attributes = LUI_WINDOW_NO_ATTRIBUTES;
|
||||||
|
bool _maximized = false;
|
||||||
|
QRect _lastWindowGeometry;
|
||||||
|
|
||||||
|
virtual void resizeEvent(QResizeEvent* event) override;
|
||||||
|
void controlWindowScale();
|
||||||
|
|
||||||
|
// User interaction control
|
||||||
|
enum MOUSE_STATE {
|
||||||
|
MOUSE_STATE_NONE = 0,
|
||||||
|
MOUSE_STATE_RESIZE_LEFT = 1 << 0,
|
||||||
|
MOUSE_STATE_RESIZE_TOP = 1 << 1,
|
||||||
|
MOUSE_STATE_RESIZE_RIGHT = 1 << 2,
|
||||||
|
MOUSE_STATE_RESIZE_BOTTOM = 1 << 3
|
||||||
|
};
|
||||||
|
bool _mousePressed = false;
|
||||||
|
int _mouseState = MOUSE_STATE_NONE;
|
||||||
|
QPointF _lastMousePosition;
|
||||||
|
void updateMouseState(QMouseEvent* event);
|
||||||
|
virtual void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
virtual void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QWidget* windowWidget() const { return _windowWidget; }
|
||||||
|
LUI_WINDOW_ATTRIBUTES getWindowAttributes();
|
||||||
|
void setWindowAttributes(unsigned int attributes);
|
||||||
|
};
|
||||||
427
FinalProject/lineeditwidget.cpp
Normal file
427
FinalProject/lineeditwidget.cpp
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
#include <qpropertyanimation.h>
|
||||||
|
#include <qparallelanimationgroup.h>
|
||||||
|
|
||||||
|
#include "lineeditwidget.h"
|
||||||
|
|
||||||
|
LineEditWidget::LineEditWidget(QWidget* parent) :
|
||||||
|
QWidget(parent)
|
||||||
|
{
|
||||||
|
// Generate colors
|
||||||
|
generateColor(_defaultColorScheme);
|
||||||
|
|
||||||
|
// Initialize ui
|
||||||
|
initializeUI();
|
||||||
|
|
||||||
|
// Connect line edit events
|
||||||
|
connect(_editor, &QLineEdit::returnPressed, this, &LineEditWidget::endEdit);
|
||||||
|
connect(_editor, &QLineEdit::editingFinished, this, &LineEditWidget::endEdit);
|
||||||
|
connect(_editor, &QLineEdit::textChanged, this, &LineEditWidget::onTextChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
LineEditWidget::~LineEditWidget() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::initializeUI() {
|
||||||
|
// Construct and set main layout
|
||||||
|
_mainLayout = new QHBoxLayout(this);
|
||||||
|
_mainLayout->setContentsMargins(12, 0, 12, 0);
|
||||||
|
_mainLayout->setSpacing(8);
|
||||||
|
setLayout(_mainLayout);
|
||||||
|
|
||||||
|
// Construct editor container widget
|
||||||
|
_editorWidget = new QWidget(this);
|
||||||
|
_mainLayout->addWidget(_editorWidget);
|
||||||
|
_editorWidget->show();
|
||||||
|
|
||||||
|
// Construct editor layout to stretch editor widget
|
||||||
|
_editorWidgetLayout = new QHBoxLayout(_editorWidget);
|
||||||
|
_editorWidgetLayout->setContentsMargins(0, 10, 0, 10);
|
||||||
|
_editorWidgetLayout->setSpacing(0);
|
||||||
|
_editorWidget->setLayout(_editorWidgetLayout);
|
||||||
|
|
||||||
|
// Install event filter to editor widget to resize indicator
|
||||||
|
_editorWidget->installEventFilter(this);
|
||||||
|
|
||||||
|
// Construct real text editor
|
||||||
|
_editor = new QLineEdit(_editorWidget);
|
||||||
|
_editor->setText("");
|
||||||
|
_editor->setFont(_defaultFont);
|
||||||
|
_editor->setAlignment(Qt::AlignRight);
|
||||||
|
_editor->setReadOnly(true);
|
||||||
|
_editor->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||||
|
_editor->setStyleSheet("QLineEdit{color:#2c2c2c;background-color:#00ffffff;border-style:none;}");
|
||||||
|
//_editor->setFixedHeight(_editor->fontMetrics().lineSpacing()); // Restrict one line
|
||||||
|
_editor->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
||||||
|
_editorWidgetLayout->addWidget(_editor);
|
||||||
|
_editor->show();
|
||||||
|
|
||||||
|
// Construct indicator widget
|
||||||
|
_indicator = new QWidget(_editorWidget);
|
||||||
|
_indicator->setObjectName("indicator");
|
||||||
|
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number((float)_indicatorWidth / 2) + "px;}");
|
||||||
|
_indicator->resize(_indicatorWidth, _indicatorWidth);
|
||||||
|
_indicator->move(_editorWidget->width() - _indicatorWidth, _editorWidget->height() - _indicatorWidth - _indicatorSpacing);
|
||||||
|
_indicatorEffect = new QGraphicsOpacityEffect(_indicator);
|
||||||
|
_indicatorEffect->setOpacity(0);
|
||||||
|
_indicator->setGraphicsEffect(_indicatorEffect);
|
||||||
|
_indicator->show();
|
||||||
|
|
||||||
|
// Construct background widget
|
||||||
|
_backgroundWidget = new QWidget(this);
|
||||||
|
_backgroundWidget->resize(size());
|
||||||
|
_backgroundWidget->setObjectName("backgroundWidget");
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
_backgroundWidget->lower();
|
||||||
|
_backgroundWidget->show();
|
||||||
|
|
||||||
|
// Set size policy
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::generateColor(QColor colorScheme) {
|
||||||
|
_backgroundColor = colorScheme.lighter(120);
|
||||||
|
_backgroundColor.setAlpha(5);
|
||||||
|
_hoverColor = colorScheme.lighter(120);
|
||||||
|
_hoverColor.setAlpha(40);
|
||||||
|
_pressedColor = colorScheme.lighter(120);
|
||||||
|
_pressedColor.setAlpha(50);
|
||||||
|
_indicatorColor = colorScheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::startEdit() {
|
||||||
|
if (_editing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set editing flag
|
||||||
|
_editing = true;
|
||||||
|
|
||||||
|
// Enable qlineedit widget
|
||||||
|
_editor->setReadOnly(false);
|
||||||
|
_editor->setAttribute(Qt::WA_TransparentForMouseEvents, false);
|
||||||
|
_editor->setFocus();
|
||||||
|
_editor->setCursorPosition(_editor->text().length());
|
||||||
|
|
||||||
|
// Minorly move cursor to update cursor icon
|
||||||
|
QCursor::setPos(QCursor::pos() + QPoint(1, 0));
|
||||||
|
QCursor::setPos(QCursor::pos() + QPoint(-1, 0));
|
||||||
|
|
||||||
|
// Add grow and fade in animation for indicator
|
||||||
|
QParallelAnimationGroup* startEditAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* growAnimation = new QPropertyAnimation(_indicator, "geometry");
|
||||||
|
QPropertyAnimation* fadeInAnimation = new QPropertyAnimation(_indicatorEffect, "opacity");
|
||||||
|
growAnimation->setDuration(200);
|
||||||
|
growAnimation->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
fadeInAnimation->setDuration(200);
|
||||||
|
fadeInAnimation->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
growAnimation->setStartValue(_indicator->geometry());
|
||||||
|
growAnimation->setEndValue(QRect(
|
||||||
|
0,
|
||||||
|
_editorWidget->height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_editorWidget->width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
fadeInAnimation->setStartValue(_indicatorEffect->opacity());
|
||||||
|
fadeInAnimation->setEndValue(0.999);
|
||||||
|
startEditAnimation->addAnimation(growAnimation);
|
||||||
|
startEditAnimation->addAnimation(fadeInAnimation);
|
||||||
|
startEditAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Emit signal
|
||||||
|
emit onStartEditing(_editor->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::endEdit() {
|
||||||
|
if (!_editing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set editing flag
|
||||||
|
_editing = false;
|
||||||
|
|
||||||
|
// Disable qlineedit widget
|
||||||
|
_editor->setReadOnly(true);
|
||||||
|
_editor->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||||
|
_editor->setSelection(0, 0);
|
||||||
|
|
||||||
|
// Add shrink and fade out animation for indicator
|
||||||
|
QParallelAnimationGroup* endEditAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* shrinkAnimation = new QPropertyAnimation(_indicator, "geometry");
|
||||||
|
QPropertyAnimation* fadeOutAnimation = new QPropertyAnimation(_indicatorEffect, "opacity");
|
||||||
|
shrinkAnimation->setDuration(200);
|
||||||
|
shrinkAnimation->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
fadeOutAnimation->setDuration(200);
|
||||||
|
fadeOutAnimation->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
shrinkAnimation->setStartValue(_indicator->geometry());
|
||||||
|
shrinkAnimation->setEndValue(QRect(
|
||||||
|
_editorWidget->width() - _indicatorWidth,
|
||||||
|
_editorWidget->height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_indicatorWidth,
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
fadeOutAnimation->setStartValue(_indicatorEffect->opacity());
|
||||||
|
fadeOutAnimation->setEndValue(0);
|
||||||
|
endEditAnimation->addAnimation(shrinkAnimation);
|
||||||
|
endEditAnimation->addAnimation(fadeOutAnimation);
|
||||||
|
endEditAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Emit signal
|
||||||
|
emit onEndEditing(_editor->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::showEvent(QShowEvent* event) {
|
||||||
|
// Call on parent
|
||||||
|
QWidget::showEvent(event);
|
||||||
|
|
||||||
|
// Check initialize state
|
||||||
|
if (_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize size dependent widgets
|
||||||
|
_backgroundWidget->resize(size());
|
||||||
|
if (_editing) {
|
||||||
|
_indicator->move(0, _editorWidget->height() - _indicatorWidth - _indicatorSpacing);
|
||||||
|
_indicator->resize(_editorWidget->width(), _indicatorWidth);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->move(_editorWidget->width() - _indicatorWidth, _editorWidget->height() - _indicatorWidth - _indicatorSpacing);
|
||||||
|
_indicator->resize(_indicatorWidth, _indicatorWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set initialized flag
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::enterEvent(QEnterEvent* event) {
|
||||||
|
// Check on enabled
|
||||||
|
if (_enabled) {
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change background color
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
|
||||||
|
// Set hover flag
|
||||||
|
_hovered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::leaveEvent(QEvent* event) {
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
|
||||||
|
// Change background color
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
|
||||||
|
// Set hover flag
|
||||||
|
_hovered = false;
|
||||||
|
_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::mousePressEvent(QMouseEvent* event) {
|
||||||
|
// Change background color
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
|
||||||
|
// Set pressed flag
|
||||||
|
_pressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
// Change background color
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
|
||||||
|
// Trigger on click
|
||||||
|
if (_pressed) {
|
||||||
|
if (_enabled) {
|
||||||
|
if (_editing) {
|
||||||
|
endEdit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
startEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_editing) {
|
||||||
|
endEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set pressed flag
|
||||||
|
_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::focusInEvent(QFocusEvent* event) {
|
||||||
|
// Call on parent
|
||||||
|
QWidget::focusInEvent(event);
|
||||||
|
|
||||||
|
// Check on enabled
|
||||||
|
if (!_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change background color
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
|
||||||
|
// Start edit
|
||||||
|
if (!_editing) {
|
||||||
|
startEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::focusOutEvent(QFocusEvent* event) {
|
||||||
|
// Call on parent
|
||||||
|
QWidget::focusOutEvent(event);
|
||||||
|
|
||||||
|
// Change background color
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
|
||||||
|
// End edit
|
||||||
|
if (_editing) {
|
||||||
|
endEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::resizeEvent(QResizeEvent* event) {
|
||||||
|
// Check initialize state
|
||||||
|
if (!_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize background widget
|
||||||
|
_backgroundWidget->resize(size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LineEditWidget::eventFilter(QObject* object, QEvent* event) {
|
||||||
|
// Resize indicator when editor widget size changed
|
||||||
|
if (object == _editorWidget) {
|
||||||
|
if (event->type() == QEvent::Resize) {
|
||||||
|
if (_editing) {
|
||||||
|
_indicator->move(0, _editorWidget->height() - _indicatorWidth - _indicatorSpacing);
|
||||||
|
_indicator->resize(_editorWidget->width(), _indicatorWidth);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->move(_editorWidget->width() - _indicatorWidth, _editorWidget->height() - _indicatorWidth - _indicatorSpacing);
|
||||||
|
_indicator->resize(_indicatorWidth, _indicatorWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call on parent
|
||||||
|
return QWidget::eventFilter(object, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setText(const QString& text) {
|
||||||
|
// Set text
|
||||||
|
_editor->setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setPlaceholderText(const QString& text) {
|
||||||
|
// Set placeholder text
|
||||||
|
_editor->setPlaceholderText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setValidator(const QValidator* validator) {
|
||||||
|
// Set validator
|
||||||
|
_editor->setValidator(validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setEnabled(bool enabled) {
|
||||||
|
// Set enabled
|
||||||
|
_enabled = enabled;
|
||||||
|
|
||||||
|
// Check for current state
|
||||||
|
if (_editing && !_enabled) {
|
||||||
|
endEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setMargins(QMargins margins) {
|
||||||
|
// Set margins
|
||||||
|
_mainLayout->setContentsMargins(margins);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setMargins(int left, int top, int right, int bottom) {
|
||||||
|
// Set margins
|
||||||
|
_mainLayout->setContentsMargins(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setBackgroundColor(QColor color) {
|
||||||
|
// Set background color
|
||||||
|
_backgroundColor = color;
|
||||||
|
|
||||||
|
// Check for current state
|
||||||
|
if (!_hovered && !_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setHoverColor(QColor color) {
|
||||||
|
// Set hover color
|
||||||
|
_hoverColor = color;
|
||||||
|
|
||||||
|
// Check for current state
|
||||||
|
if (_hovered && !_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setPressedColor(QColor color) {
|
||||||
|
// Set pressed color
|
||||||
|
_pressedColor = color;
|
||||||
|
|
||||||
|
// Check for current state
|
||||||
|
if (_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setIndicatorColor(QColor color) {
|
||||||
|
// Set indicator color
|
||||||
|
_indicatorColor = color;
|
||||||
|
|
||||||
|
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_indicatorWidth) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineEditWidget::setColorScheme(QColor primaryColor) {
|
||||||
|
// Generate colors
|
||||||
|
generateColor(primaryColor);
|
||||||
|
|
||||||
|
// Check for current state
|
||||||
|
if (!_hovered && !_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
}
|
||||||
|
else if (_hovered && !_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
}
|
||||||
|
else if (_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_indicatorWidth) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LineEditWidget::text() const {
|
||||||
|
// Return text
|
||||||
|
return _editor->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout* LineEditWidget::mainLayout() const {
|
||||||
|
// Return main layout
|
||||||
|
return _mainLayout;
|
||||||
|
}
|
||||||
95
FinalProject/lineeditwidget.h
Normal file
95
FinalProject/lineeditwidget.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qlineedit.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qgraphicseffect.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
|
||||||
|
class LineEditWidget : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LineEditWidget(QWidget* parent = 0);
|
||||||
|
~LineEditWidget();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// UI control variables
|
||||||
|
int _cornerRadius = 8;
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
QHBoxLayout* _mainLayout = nullptr; // For layout the user added components and the real editor component
|
||||||
|
|
||||||
|
QWidget* _backgroundWidget = nullptr;
|
||||||
|
const QColor _defaultColorScheme = QColor(58, 143, 183);
|
||||||
|
QColor _backgroundColor;
|
||||||
|
QColor _hoverColor;
|
||||||
|
QColor _pressedColor;
|
||||||
|
|
||||||
|
QWidget* _editorWidget = nullptr; // Container widget for the real editor component
|
||||||
|
QHBoxLayout* _editorWidgetLayout = nullptr;
|
||||||
|
|
||||||
|
QLineEdit* _editor = nullptr;
|
||||||
|
const QFont _defaultFont = QFont("DengXian", 10, QFont::Normal);
|
||||||
|
|
||||||
|
QWidget* _indicator = nullptr;
|
||||||
|
const int _indicatorWidth = 4;
|
||||||
|
const int _indicatorSpacing = 4;
|
||||||
|
QColor _indicatorColor;
|
||||||
|
QGraphicsOpacityEffect* _indicatorEffect;
|
||||||
|
|
||||||
|
// Editor state
|
||||||
|
bool _hovered = false;
|
||||||
|
bool _pressed = false;
|
||||||
|
bool _enabled = true;
|
||||||
|
bool _editing = false;
|
||||||
|
bool _initialized = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// UI Util functions
|
||||||
|
void initializeUI();
|
||||||
|
void generateColor(QColor colorScheme);
|
||||||
|
|
||||||
|
// Interaction Util functions
|
||||||
|
void startEdit();
|
||||||
|
void endEdit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Interactions
|
||||||
|
virtual void showEvent(QShowEvent* event) override;
|
||||||
|
virtual void enterEvent(QEnterEvent* event) override;
|
||||||
|
virtual void leaveEvent(QEvent* event) override;
|
||||||
|
virtual void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
virtual void focusInEvent(QFocusEvent* event) override;
|
||||||
|
virtual void focusOutEvent(QFocusEvent* event) override;
|
||||||
|
virtual void resizeEvent(QResizeEvent* event) override;
|
||||||
|
virtual bool eventFilter(QObject* obj, QEvent* event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Public setter APIs for text
|
||||||
|
void setText(const QString& text);
|
||||||
|
void setPlaceholderText(const QString& text);
|
||||||
|
void setValidator(const QValidator* validator);
|
||||||
|
|
||||||
|
// Publics setter APIs for UI
|
||||||
|
void setEnabled(bool enabled = true);
|
||||||
|
void setMargins(QMargins margins);
|
||||||
|
void setMargins(int left, int top, int right, int bottom);
|
||||||
|
void setBackgroundColor(QColor color);
|
||||||
|
void setHoverColor(QColor color);
|
||||||
|
void setPressedColor(QColor color);
|
||||||
|
void setIndicatorColor(QColor color);
|
||||||
|
void setColorScheme(QColor primaryColor);
|
||||||
|
|
||||||
|
// Public getter APIs
|
||||||
|
QString text() const;
|
||||||
|
QHBoxLayout* mainLayout() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// Public signal functions
|
||||||
|
void onStartEditing(const QString& text);
|
||||||
|
void onTextChanged(const QString& text);
|
||||||
|
void onEndEditing(const QString& text);
|
||||||
|
};
|
||||||
@ -1,13 +1,21 @@
|
|||||||
#include "mainwindow.h"
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
|
#include <qfontdatabase.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv); // Create main application instance
|
||||||
|
|
||||||
|
QFontDatabase::addApplicationFont(":/fonts/font_awesome_6_regular_free.otf"); // Add font awesome font to application
|
||||||
|
QFontDatabase::addApplicationFont(":/fonts/font_awesome_6_solid_free.otf"); // Add font awesome font to application
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.setWindowFlag(Qt::FramelessWindowHint);
|
|
||||||
w.setAttribute(Qt::WA_TranslucentBackground);
|
|
||||||
w.setMouseTracking(true);
|
w.setMouseTracking(true);
|
||||||
|
w.resize(900, 600);
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,318 +1,97 @@
|
|||||||
#include <qpainterpath.h>
|
|
||||||
#include <qscreen.h>
|
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "sceneviewer.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
#define MAX_MOUSE_MOVEMENT 300
|
#define MAX_MOUSE_MOVEMENT 300
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: FramelessWindow(20, parent)
|
||||||
{
|
{
|
||||||
ui.setupUi(this);
|
// Create main layout for page and sidebar
|
||||||
ui.centralWidget->setMouseTracking(true);
|
_mainLayout = new QHBoxLayout(_windowWidget);
|
||||||
|
_mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
// Create and properly set real displayed window widget
|
_mainLayout->setSpacing(0);
|
||||||
_stretchLayout = new QVBoxLayout(this);
|
_windowWidget->setLayout(_mainLayout);
|
||||||
_stretchLayout->setContentsMargins(30, 30, 30, 30);
|
|
||||||
_windowWidget = new QWidget(this);
|
// Create placeholder widget for pages
|
||||||
_windowWidget->setObjectName("windowWidget");
|
_placeHolderWidget = new QWidget(_windowWidget);
|
||||||
_windowWidget->setMouseTracking(true);
|
_placeHolderWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
_windowLayout = new QVBoxLayout(_windowWidget);
|
_placeHolderWidget->setMouseTracking(true);
|
||||||
_windowLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
_windowLayout->setSpacing(0);
|
|
||||||
_windowLayout->setAlignment(Qt::AlignTop);
|
|
||||||
_windowWidget->setLayout(_windowLayout);
|
|
||||||
_stretchLayout->addWidget(_windowWidget);
|
|
||||||
_windowWidget->show();
|
|
||||||
ui.centralWidget->setLayout(_stretchLayout);
|
|
||||||
|
|
||||||
// Set style sheet for window widget
|
// Connect the resize event of the placeholder widget to the resizePages function using event filter
|
||||||
QString windowWidgetStyleSheet = "QWidget#windowWidget{background-color:" + _backgroundColor.name() + ";border-radius:" + QString::number(_cornerRadius) + "px;}";
|
_placeHolderWidget->installEventFilter(this);
|
||||||
_windowWidget->setStyleSheet(windowWidgetStyleSheet);
|
|
||||||
|
|
||||||
// Set shadow for window widget
|
|
||||||
_windowShadow = new QGraphicsDropShadowEffect(_windowWidget);
|
|
||||||
_windowShadow->setBlurRadius(30);
|
|
||||||
_windowShadow->setColor(QColor(0, 0, 0));
|
|
||||||
_windowShadow->setOffset(0, 0);
|
|
||||||
_windowWidget->setGraphicsEffect(_windowShadow);
|
|
||||||
|
|
||||||
// Create title bar widget
|
|
||||||
_titleBar = new QWidget(_windowWidget);
|
|
||||||
_titleBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
_titleBar->setMouseTracking(true);
|
|
||||||
_titleBarLayout = new QHBoxLayout(_titleBar);
|
|
||||||
_titleBarLayout->setContentsMargins(18, 18, 18, 18);
|
|
||||||
_titleBarLayout->setSpacing(0);
|
|
||||||
_titleBarLayout->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
||||||
_titleBar->setLayout(_titleBarLayout);
|
|
||||||
_windowLayout->addWidget(_titleBar);
|
|
||||||
_titleBar->show();
|
|
||||||
|
|
||||||
// Create window control buttons container widget & its layout
|
|
||||||
_windowBtnWidget = new QWidget(_titleBar);
|
|
||||||
_windowBtnWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
||||||
_windowBtnLayout = new QHBoxLayout(_windowBtnWidget);
|
|
||||||
_windowBtnLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
_windowBtnLayout->setSpacing(8);
|
|
||||||
_windowBtnWidget->setLayout(_windowBtnLayout);
|
|
||||||
_titleBarLayout->addWidget(_windowBtnWidget);
|
|
||||||
_windowBtnWidget->show();
|
|
||||||
|
|
||||||
// Create window control buttons
|
// Create sidebar
|
||||||
_minimizeBtn = new QPushButton(_windowBtnWidget);
|
_sideBar = new SideBar(_windowWidget);
|
||||||
_maximizeBtn = new QPushButton(_windowBtnWidget);
|
connect(_sideBar, &SideBar::onPageChanged, this, [=](PageWidget* previousPage, PageWidget* currentPage) {
|
||||||
_closeBtn = new QPushButton(_windowBtnWidget);
|
// Check for input validity
|
||||||
|
if (previousPage == currentPage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (previousPage != nullptr) {
|
||||||
|
previousPage->offStage();
|
||||||
|
}
|
||||||
|
if (currentPage != nullptr) {
|
||||||
|
currentPage->onStage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_sideBar->setMouseTracking(true);
|
||||||
|
|
||||||
|
// Add sidebar and placeholder widget to main layout
|
||||||
|
_mainLayout->addWidget(_sideBar);
|
||||||
|
_mainLayout->addWidget(_placeHolderWidget);
|
||||||
|
|
||||||
_minimizeBtn->setFixedSize(12, 12);
|
// Create editor page and connect to side bar
|
||||||
_maximizeBtn->setFixedSize(12, 12);
|
_editorPage = new EditorPage(_placeHolderWidget);
|
||||||
_closeBtn->setFixedSize(12, 12);
|
_editorPage->setMouseTracking(true);
|
||||||
|
_sideBar->addPage(_editorPage);
|
||||||
|
|
||||||
_minimizeBtn->setStyleSheet("QPushButton{border-radius: 6px; background-color: #828282;}"
|
// Create about page and connect to side bar
|
||||||
"QPushButton:hover{background-color: #e98b2a;}");
|
_aboutPage = new AboutPage(_placeHolderWidget);
|
||||||
_maximizeBtn->setStyleSheet("QPushButton{border-radius: 6px; background-color: #828282;}"
|
_aboutPage->setMouseTracking(true);
|
||||||
"QPushButton:hover{background-color: #2d6d4b;}");
|
_sideBar->addPage(_aboutPage);
|
||||||
_closeBtn->setStyleSheet("QPushButton{border-radius: 6px; background-color: #828282;}"
|
|
||||||
"QPushButton:hover{background-color: #ab3b3a;}");
|
|
||||||
|
|
||||||
_windowBtnLayout->addWidget(_minimizeBtn);
|
|
||||||
_windowBtnLayout->addWidget(_maximizeBtn);
|
|
||||||
_windowBtnLayout->addWidget(_closeBtn);
|
|
||||||
_minimizeBtn->show();
|
|
||||||
_maximizeBtn->show();
|
|
||||||
_closeBtn->show();
|
|
||||||
|
|
||||||
// Connect window control buttons
|
|
||||||
connect(_minimizeBtn, &QPushButton::clicked, this, &MainWindow::showMinimized);
|
|
||||||
connect(_maximizeBtn, &QPushButton::clicked, this, [=]() {controlWindowScale(); });
|
|
||||||
connect(_closeBtn, &QPushButton::clicked, qApp, &QApplication::quit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() {
|
MainWindow::~MainWindow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showEvent(QShowEvent* event) {
|
void MainWindow::resizePages(QResizeEvent* event) {
|
||||||
// Initialize window UI after window is shown
|
// Check for input validity
|
||||||
initializeWindowUI();
|
if (event == nullptr) {
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::initializeWindowUI() {
|
|
||||||
// Create a round cornered mask for window widget
|
|
||||||
QPainterPath path;
|
|
||||||
path.addRoundedRect(_windowWidget->rect(), _cornerRadius - 1, _cornerRadius - 1);
|
|
||||||
QRegion region(path.toFillPolygon().toPolygon());
|
|
||||||
_windowWidget->setMask(region);
|
|
||||||
|
|
||||||
// Create a border for window widget (in order to hide zigzagged edges)
|
|
||||||
_windowBorder = new QWidget(this);
|
|
||||||
_windowBorder->setObjectName("windowBorder");
|
|
||||||
QString windowBorderStyleSheet =
|
|
||||||
"QWidget#windowBorder{background-color:#00FFFFFF;border:1.5px solid " + _borderColor.name() + ";border-radius:" + QString::number(_cornerRadius) + "px;}";
|
|
||||||
_windowBorder->setStyleSheet(windowBorderStyleSheet);
|
|
||||||
_windowBorder->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
_windowBorder->move(_windowWidget->pos() - QPoint(1, 1));
|
|
||||||
_windowBorder->resize(_windowWidget->size() + QSize(2, 2));
|
|
||||||
_windowBorder->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::resizeEvent(QResizeEvent* event) {
|
|
||||||
// Resize window border
|
|
||||||
if (_windowBorder != nullptr) {
|
|
||||||
_windowBorder->move(_windowWidget->pos() - QPoint(1, 1));
|
|
||||||
_windowBorder->resize(_windowWidget->size() + QSize(2, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize window mask
|
|
||||||
QPainterPath path;
|
|
||||||
path.addRoundedRect(_windowWidget->rect(), _cornerRadius - 1, _cornerRadius - 1);
|
|
||||||
QRegion region(path.toFillPolygon().toPolygon());
|
|
||||||
_windowWidget->setMask(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::controlWindowScale() {
|
|
||||||
if (!_maximized) {
|
|
||||||
_lastWindowGeometry = frameGeometry();
|
|
||||||
|
|
||||||
Logger::debug("Maximizing window:");
|
|
||||||
Logger::debug("[+] current window position: " + std::to_string(x()) + ", " + std::to_string(y()));
|
|
||||||
Logger::debug("[+] current window size: " + std::to_string(width()) + ", " + std::to_string(height()));
|
|
||||||
Logger::debug("[+] current geometry: " + std::to_string(_lastWindowGeometry.x()) + ", " + std::to_string(_lastWindowGeometry.y()) + ", " + std::to_string(_lastWindowGeometry.width()) + ", " + std::to_string(_lastWindowGeometry.height()));
|
|
||||||
Logger::debug("[+] current window widget position: " + std::to_string(_windowWidget->x()) + ", " + std::to_string(_windowWidget->y()));
|
|
||||||
Logger::debug("[+] current window widget size: " + std::to_string(_windowWidget->width()) + ", " + std::to_string(_windowWidget->height()));
|
|
||||||
Logger::debug("[+] current window border position: " + std::to_string(_windowBorder->x()) + ", " + std::to_string(_windowBorder->y()));
|
|
||||||
Logger::debug("[+] current window border size: " + std::to_string(_windowBorder->width()) + ", " + std::to_string(_windowBorder->height()));
|
|
||||||
|
|
||||||
_windowShadow->setEnabled(false);
|
|
||||||
_windowBorder->hide();
|
|
||||||
QString windowWidgetStyleSheet = "QWidget#windowWidget{background-color:" + _backgroundColor.name() + ";}";
|
|
||||||
_windowWidget->setStyleSheet(windowWidgetStyleSheet);
|
|
||||||
|
|
||||||
_stretchLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
|
|
||||||
showMaximized();
|
|
||||||
|
|
||||||
QPainterPath path;
|
|
||||||
path.addRect(_windowWidget->rect());
|
|
||||||
QRegion mask(path.toFillPolygon().toPolygon());
|
|
||||||
_windowWidget->setMask(mask);
|
|
||||||
|
|
||||||
_maximized = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_stretchLayout->setContentsMargins(30, 30, 30, 30);
|
|
||||||
|
|
||||||
showNormal();
|
|
||||||
|
|
||||||
resize(_lastWindowGeometry.size());
|
|
||||||
move(_lastWindowGeometry.topLeft());
|
|
||||||
|
|
||||||
_windowShadow->setEnabled(true);
|
|
||||||
_windowBorder->show();
|
|
||||||
QString windowWidgetStyleSheet = "QWidget#windowWidget{background-color:" + _backgroundColor.name() + ";border-radius:" + QString::number(_cornerRadius) + "px;}";
|
|
||||||
_windowWidget->setStyleSheet(windowWidgetStyleSheet);
|
|
||||||
|
|
||||||
QPainterPath path;
|
|
||||||
path.addRoundedRect(_windowWidget->rect(), _cornerRadius - 1, _cornerRadius - 1);
|
|
||||||
QRegion mask(path.toFillPolygon().toPolygon());
|
|
||||||
_windowWidget->setMask(mask);
|
|
||||||
|
|
||||||
Logger::debug("Restoring window:");
|
|
||||||
Logger::debug("[+] current window position: " + std::to_string(x()) + ", " + std::to_string(y()));
|
|
||||||
Logger::debug("[+] current window size: " + std::to_string(width()) + ", " + std::to_string(height()));
|
|
||||||
Logger::debug("[+] current geometry: " + std::to_string(frameGeometry().x()) + ", " + std::to_string(frameGeometry().y()) + ", " + std::to_string(frameGeometry().width()) + ", " + std::to_string(frameGeometry().height()));
|
|
||||||
Logger::debug("[+] current window widget position: " + std::to_string(_windowWidget->x()) + ", " + std::to_string(_windowWidget->y()));
|
|
||||||
Logger::debug("[+] current window widget size: " + std::to_string(_windowWidget->width()) + ", " + std::to_string(_windowWidget->height()));
|
|
||||||
|
|
||||||
_maximized = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::updateMouseState(QMouseEvent* event) {
|
|
||||||
_mouseState = MOUSE_STATE_NONE;
|
|
||||||
if (_maximized) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Set mouse state according to abs distance from window border
|
|
||||||
if (abs(event->globalPos().x() - (_windowWidget->frameGeometry().left() + frameGeometry().left())) < 5) {
|
// Get the size of the placeholder widget
|
||||||
_mouseState |= MOUSE_STATE_RESIZE_LEFT;
|
QSize size = event->size();
|
||||||
}
|
|
||||||
if (abs(event->globalPos().x() - (_windowWidget->frameGeometry().right() + frameGeometry().left())) < 5) {
|
// Resize the editor page
|
||||||
_mouseState |= MOUSE_STATE_RESIZE_RIGHT;
|
_editorPage->resize(size);
|
||||||
}
|
_aboutPage->resize(size);
|
||||||
if (abs(event->globalPos().y() - (_windowWidget->frameGeometry().top() + frameGeometry().top())) < 5) {
|
|
||||||
_mouseState |= MOUSE_STATE_RESIZE_TOP;
|
|
||||||
}
|
|
||||||
if (abs(event->globalPos().y() - (_windowWidget->frameGeometry().bottom() + frameGeometry().top())) < 5) {
|
|
||||||
_mouseState |= MOUSE_STATE_RESIZE_BOTTOM;
|
|
||||||
}
|
|
||||||
// Set cursor shape according to mouse state
|
|
||||||
switch (_mouseState) {
|
|
||||||
case MOUSE_STATE_RESIZE_LEFT:
|
|
||||||
case MOUSE_STATE_RESIZE_RIGHT:
|
|
||||||
setCursor(Qt::SizeHorCursor);
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_TOP:
|
|
||||||
case MOUSE_STATE_RESIZE_BOTTOM:
|
|
||||||
setCursor(Qt::SizeVerCursor);
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_TOP:
|
|
||||||
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_BOTTOM:
|
|
||||||
setCursor(Qt::SizeFDiagCursor);
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_BOTTOM:
|
|
||||||
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_TOP:
|
|
||||||
setCursor(Qt::SizeBDiagCursor);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setCursor(Qt::ArrowCursor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::mousePressEvent(QMouseEvent* event) {
|
void MainWindow::showEvent(QShowEvent* event) {
|
||||||
if (event->button() == Qt::LeftButton) {
|
// Call parent show event
|
||||||
_mousePressed = true;
|
FramelessWindow::showEvent(event);
|
||||||
_lastMousePosition = event->globalPos().toPointF();
|
|
||||||
}
|
// Resize all the pages based on the placeholder widget
|
||||||
|
_editorPage->resize(_placeHolderWidget->size());
|
||||||
|
_aboutPage->resize(_placeHolderWidget->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::mouseReleaseEvent(QMouseEvent* event) {
|
bool MainWindow::eventFilter(QObject* object, QEvent* event) {
|
||||||
_mousePressed = false;
|
// Check for input validity
|
||||||
QScreen* screen = QGuiApplication::screenAt(event->globalPos());
|
if (object == nullptr || event == nullptr) {
|
||||||
Logger::debug("Current screen geometry:");
|
return false;
|
||||||
Logger::debug("[+] screen position: " + std::to_string(screen->geometry().x()) + ", " + std::to_string(screen->geometry().y()));
|
|
||||||
Logger::debug("[+] screen size: " + std::to_string(screen->geometry().width()) + ", " + std::to_string(screen->geometry().height()));
|
|
||||||
if (abs(event->globalPos().y() - screen->geometry().top()) < 5) {
|
|
||||||
controlWindowScale();
|
|
||||||
}
|
}
|
||||||
updateMouseState(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::mouseMoveEvent(QMouseEvent* event) {
|
// Check if the object is the placeholder widget
|
||||||
Logger::debug("Detected mouse move");
|
if (object == _placeHolderWidget) {
|
||||||
Logger::debug("[+] mouse global position : " + std::to_string(event->globalPos().x()) + ", " + std::to_string(event->globalPos().y()));
|
// Check if the event is a resize event
|
||||||
Logger::debug("[+] window geometry: " + std::to_string(frameGeometry().x()) + ", " + std::to_string(frameGeometry().y()) + ", " + std::to_string(frameGeometry().width()) + ", " + std::to_string(frameGeometry().height()));
|
if (event->type() == QEvent::Resize) {
|
||||||
Logger::debug("[+] widget frame geometry: " + std::to_string(_windowWidget->frameGeometry().x()) + ", " + std::to_string(_windowWidget->frameGeometry().y()));
|
// Resize all the pages
|
||||||
Logger::debug("[+] widget frame size: " + std::to_string(_windowWidget->frameGeometry().width()) + ", " + std::to_string(_windowWidget->frameGeometry().height()));
|
resizePages(static_cast<QResizeEvent*>(event));
|
||||||
; if (event->buttons() == Qt::NoButton) {
|
|
||||||
_mousePressed = false;
|
|
||||||
}
|
|
||||||
if (abs(event->globalPos().x() - _lastMousePosition.x()) > MAX_MOUSE_MOVEMENT) {
|
|
||||||
// Maybe moving window across monitors, avoid window disappear
|
|
||||||
_lastMousePosition = event->globalPos().toPointF();
|
|
||||||
}
|
|
||||||
if (abs(event->globalPos().y() - _lastMousePosition.y()) > MAX_MOUSE_MOVEMENT) {
|
|
||||||
// Maybe moving window across monitors, avoid window disappear
|
|
||||||
_lastMousePosition = event->globalPos().toPointF();
|
|
||||||
}
|
|
||||||
if (!_mousePressed) {
|
|
||||||
updateMouseState(event);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Resize window according to mouse state
|
|
||||||
switch (_mouseState) {
|
|
||||||
case MOUSE_STATE_RESIZE_LEFT:
|
|
||||||
resize(frameGeometry().width() - event->globalPos().x() + frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height());
|
|
||||||
move(event->globalPos().x() - _windowWidget->frameGeometry().left(), frameGeometry().top());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_RIGHT:
|
|
||||||
resize(event->globalPos().x() - frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_TOP:
|
|
||||||
resize(frameGeometry().width(), frameGeometry().height() - event->globalPos().y() + frameGeometry().top() + _windowWidget->frameGeometry().top());
|
|
||||||
move(frameGeometry().left(), event->globalPos().y() - _windowWidget->frameGeometry().top());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_BOTTOM:
|
|
||||||
resize(frameGeometry().width(), event->globalPos().y() - frameGeometry().top() + _windowWidget->frameGeometry().top());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_TOP:
|
|
||||||
resize(frameGeometry().width() - event->globalPos().x() + frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height() - event->globalPos().y() + frameGeometry().top() + _windowWidget->frameGeometry().top());
|
|
||||||
move(event->globalPos().x() - _windowWidget->frameGeometry().left(), event->globalPos().y() - _windowWidget->frameGeometry().top());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_LEFT | MOUSE_STATE_RESIZE_BOTTOM:
|
|
||||||
resize(frameGeometry().width() - event->globalPos().x() + frameGeometry().left() + _windowWidget->frameGeometry().left(), event->globalPos().y() + frameGeometry().top() - _windowWidget->frameGeometry().top());
|
|
||||||
move(event->globalPos().x() - _windowWidget->frameGeometry().left(), frameGeometry().top());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_TOP:
|
|
||||||
resize(event->globalPos().x() - frameGeometry().left() + _windowWidget->frameGeometry().left(), frameGeometry().height() - event->globalPos().y() + frameGeometry().top() + _windowWidget->frameGeometry().top());
|
|
||||||
move(frameGeometry().left(), event->globalPos().y() - _windowWidget->frameGeometry().top());
|
|
||||||
break;
|
|
||||||
case MOUSE_STATE_RESIZE_RIGHT | MOUSE_STATE_RESIZE_BOTTOM:
|
|
||||||
resize(event->globalPos().x() - frameGeometry().left() + _windowWidget->frameGeometry().left(), event->globalPos().y() - frameGeometry().top() + _windowWidget->frameGeometry().top());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (_maximized) {
|
|
||||||
qreal wRatio = (qreal)event->pos().x() / (qreal)_windowWidget->width();
|
|
||||||
controlWindowScale();
|
|
||||||
move(event->globalPos().x() - _windowWidget->width() * wRatio, event->globalPos().y() - 52);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
move(frameGeometry().left() + event->globalPos().x() - _lastMousePosition.x(), frameGeometry().top() + event->globalPos().y() - _lastMousePosition.y());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
_lastMousePosition = event->globalPos().toPointF();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Call parent event filter
|
||||||
|
return FramelessWindow::eventFilter(object, event);
|
||||||
|
}
|
||||||
@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtWidgets/QMainWindow>
|
#include <qevent.h>
|
||||||
#include <qboxlayout.h>
|
|
||||||
#include <qgraphicseffect.h>
|
|
||||||
#include <qpushbutton.h>
|
|
||||||
#include "ui_mainwindow.h"
|
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
#include "framelesswindow.h"
|
||||||
|
#include "sidebar.h"
|
||||||
|
#include "editorpage.h"
|
||||||
|
#include "aboutpage.h"
|
||||||
|
|
||||||
|
class MainWindow : public FramelessWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -15,54 +16,21 @@ public:
|
|||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindowClass ui;
|
// Main ui layout
|
||||||
|
QHBoxLayout* _mainLayout = nullptr;
|
||||||
|
|
||||||
|
// Side bar and corresponding pages
|
||||||
|
SideBar* _sideBar = nullptr;
|
||||||
|
EditorPage* _editorPage = nullptr;
|
||||||
|
AboutPage* _aboutPage = nullptr;
|
||||||
|
|
||||||
|
// Place holder widget for resizing pages
|
||||||
|
QWidget* _placeHolderWidget = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// UI control variables
|
void resizePages(QResizeEvent* event);
|
||||||
const int _cornerRadius = 20;
|
|
||||||
const QColor _backgroundColor = QColor(251, 251, 251);
|
|
||||||
const QColor _borderColor = QColor(104, 104, 104);
|
|
||||||
|
|
||||||
// Window initialize
|
private:
|
||||||
void initializeWindowUI();
|
|
||||||
virtual void showEvent(QShowEvent* event) override;
|
virtual void showEvent(QShowEvent* event) override;
|
||||||
|
virtual bool eventFilter(QObject* object, QEvent* event) override;
|
||||||
// Widget list
|
|
||||||
QVBoxLayout* _stretchLayout = nullptr;
|
|
||||||
QWidget* _windowWidget = nullptr;
|
|
||||||
QWidget* _windowBorder = nullptr;
|
|
||||||
QGraphicsDropShadowEffect* _windowShadow = nullptr;
|
|
||||||
QVBoxLayout* _windowLayout = nullptr;
|
|
||||||
QWidget* _titleBar = nullptr;
|
|
||||||
QHBoxLayout* _titleBarLayout = nullptr;
|
|
||||||
QWidget* _windowBtnWidget = nullptr;
|
|
||||||
QHBoxLayout* _windowBtnLayout = nullptr;
|
|
||||||
QPushButton* _minimizeBtn = nullptr;
|
|
||||||
QPushButton* _maximizeBtn = nullptr;
|
|
||||||
QPushButton* _closeBtn = nullptr;
|
|
||||||
QWidget* _objectList = nullptr;
|
|
||||||
QWidget* _settingsPannel = nullptr;
|
|
||||||
|
|
||||||
// Window size control
|
|
||||||
bool _maximized = false;
|
|
||||||
QRect _lastWindowGeometry;
|
|
||||||
|
|
||||||
virtual void resizeEvent(QResizeEvent* event) override;
|
|
||||||
void controlWindowScale();
|
|
||||||
|
|
||||||
// User interaction control
|
|
||||||
enum MOUSE_STATE {
|
|
||||||
MOUSE_STATE_NONE = 0,
|
|
||||||
MOUSE_STATE_RESIZE_LEFT = 1 << 0,
|
|
||||||
MOUSE_STATE_RESIZE_TOP = 1 << 1,
|
|
||||||
MOUSE_STATE_RESIZE_RIGHT = 1 << 2,
|
|
||||||
MOUSE_STATE_RESIZE_BOTTOM = 1 << 3
|
|
||||||
};
|
|
||||||
bool _mousePressed = false;
|
|
||||||
int _mouseState = MOUSE_STATE_NONE;
|
|
||||||
QPointF _lastMousePosition;
|
|
||||||
void updateMouseState(QMouseEvent* event);
|
|
||||||
virtual void mousePressEvent(QMouseEvent* event) override;
|
|
||||||
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
|
||||||
virtual void mouseMoveEvent(QMouseEvent* event) override;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,4 +3,8 @@
|
|||||||
<file>fragmentshader.fs</file>
|
<file>fragmentshader.fs</file>
|
||||||
<file>vertexshader.vs</file>
|
<file>vertexshader.vs</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
<qresource prefix="/fonts">
|
||||||
|
<file>font_awesome_6_regular_free.otf</file>
|
||||||
|
<file>font_awesome_6_solid_free.otf</file>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>MainWindowClass</class>
|
|
||||||
<widget class="QMainWindow" name="MainWindowClass">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>600</width>
|
|
||||||
<height>400</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>MainWindow</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralWidget"/>
|
|
||||||
</widget>
|
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
|
||||||
<resources>
|
|
||||||
<include location="mainwindow.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
@ -13,7 +13,13 @@ Model::~Model() {
|
|||||||
// TODO: Maybe delete all meshes?
|
// TODO: Maybe delete all meshes?
|
||||||
}
|
}
|
||||||
|
|
||||||
// file path is ...\\...\\.obj, and processnode & processmesh have been called here
|
Model::Model(std::vector<Mesh>&& meshes, std::vector<Texture>&& textures, std::string directory) {
|
||||||
|
_meshes = std::move(meshes);
|
||||||
|
_texturesLoaded = std::move(textures);
|
||||||
|
_directory = directory;
|
||||||
|
_status = LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
void Model::loadModel(std::string path) {
|
void Model::loadModel(std::string path) {
|
||||||
Logger::info("Loading model from path: " + path);
|
Logger::info("Loading model from path: " + path);
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
@ -34,7 +40,7 @@ void Model::loadModel(std::string path) {
|
|||||||
processNode(scene->mRootNode, scene);
|
processNode(scene->mRootNode, scene);
|
||||||
_status = LOADED;
|
_status = LOADED;
|
||||||
Logger::info("Model loaded");
|
Logger::info("Model loaded");
|
||||||
// 仅检查一次即可
|
// 仅检查一次即可
|
||||||
//check_boundary();
|
//check_boundary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +73,7 @@ Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene) {
|
|||||||
glm::vec3 vertexBitangent = glm::vec3(0.0f);
|
glm::vec3 vertexBitangent = glm::vec3(0.0f);
|
||||||
|
|
||||||
// Process vertex positions
|
// Process vertex positions
|
||||||
//使用循环避免代码重复,如果可行的话,可以在此循环中确定法向量等信息
|
//使用循环避免代码重复,如果可行的话,可以在此循环中确定法向量等信息
|
||||||
for (int j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
vertexPosition[j] = mesh->mVertices[i][j];
|
vertexPosition[j] = mesh->mVertices[i][j];
|
||||||
_left_down_back[j] = _left_down_back[j] < vertexPosition[j] ? _left_down_back[j] : vertexPosition[j];
|
_left_down_back[j] = _left_down_back[j] < vertexPosition[j] ? _left_down_back[j] : vertexPosition[j];
|
||||||
@ -200,5 +206,26 @@ void Model::check_boundary() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
Model* Model::copyToCurrentContext() const {
|
||||||
|
// Reload all textures
|
||||||
|
std::vector<Texture> newTextures;
|
||||||
|
for (unsigned int i = 0; i < _texturesLoaded.size(); i++) {
|
||||||
|
// Load texture
|
||||||
|
Texture newTexture = Texture(_texturesLoaded[i].type(), _directory + '/' + _texturesLoaded[i].path());
|
||||||
|
newTextures.push_back(newTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all meshes
|
||||||
|
std::vector<Mesh> newMeshes;
|
||||||
|
for (unsigned int i = 0; i < _meshes.size(); i++) {
|
||||||
|
// Copy mesh
|
||||||
|
Mesh newMesh = Mesh(_meshes[i].vertices(), _meshes[i].indices(), newTextures);
|
||||||
|
newMeshes.push_back(newMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new model
|
||||||
|
Model* newModel = new Model(std::move(newMeshes), std::move(newTextures), _directory);
|
||||||
|
return newModel;
|
||||||
|
}
|
||||||
|
|||||||
@ -28,8 +28,16 @@ public:
|
|||||||
Model(std::string path);
|
Model(std::string path);
|
||||||
~Model();
|
~Model();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model(std::vector<Mesh>&& meshes, std::vector<Texture>&& textures, std::string directory);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline MODELSTATUS status() const { return _status; }
|
inline MODELSTATUS status() const { return _status; }
|
||||||
|
inline int meshCount() const { return _meshes.size(); }
|
||||||
|
inline int textureCount() const { return _texturesLoaded.size(); }
|
||||||
|
inline std::string directory() const { return _directory; }
|
||||||
|
|
||||||
|
Model* copyToCurrentContext() const;
|
||||||
|
|
||||||
|
|
||||||
// maybe we can check if boundary has not been set yet
|
// maybe we can check if boundary has not been set yet
|
||||||
|
|||||||
@ -1 +1,83 @@
|
|||||||
#pragma once
|
#include <qlabel.h>
|
||||||
|
|
||||||
|
#include "modelselectable.h"
|
||||||
|
#include "sceneviewer.h"
|
||||||
|
|
||||||
|
ModelSelectable::ModelSelectable(Model* model, QWidget* parent) :
|
||||||
|
QWidget(parent), _model(model)
|
||||||
|
{
|
||||||
|
// Set size
|
||||||
|
setFixedHeight(150);
|
||||||
|
setSizeIncrement(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
// Create stretch layout to hold the main button
|
||||||
|
_stretchLayout = new QHBoxLayout(this);
|
||||||
|
_stretchLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_stretchLayout->setSpacing(0);
|
||||||
|
setLayout(_stretchLayout);
|
||||||
|
|
||||||
|
// Create main button widget
|
||||||
|
_mainBtn = new PushButton(nullptr, this);
|
||||||
|
_mainBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
_mainBtn->setMargin(0, 0, 0, 0);
|
||||||
|
_mainBtn->setRadius(10);
|
||||||
|
_mainBtn->setBackgroundColor(QColor(58, 143, 183, 15));
|
||||||
|
_stretchLayout->addWidget(_mainBtn);
|
||||||
|
_mainBtn->show();
|
||||||
|
|
||||||
|
// Create widget to hold the button content
|
||||||
|
_mainBtnChild = new QWidget(_mainBtn);
|
||||||
|
_mainBtnChild->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
//_mainBtnChild->setObjectName("mainBtnChild");
|
||||||
|
//_mainBtnChild->setStyleSheet("QWidget#mainBtnChild{border: 3px solid " + _borderColor.name(QColor::HexArgb) + ";"
|
||||||
|
// "border-radius:" + QString::number(_cornerRadius) + "px;}");
|
||||||
|
_mainBtn->setChildWidget(_mainBtnChild);
|
||||||
|
_mainBtnChild->show();
|
||||||
|
|
||||||
|
// Create layout to hold the button content
|
||||||
|
_mainLayout = new QHBoxLayout(_mainBtnChild);
|
||||||
|
_mainLayout->setContentsMargins(16, 12, 16, 12);
|
||||||
|
_mainLayout->setSpacing(12);
|
||||||
|
_mainBtnChild->setLayout(_mainLayout);
|
||||||
|
|
||||||
|
// Create model thumbnail widget
|
||||||
|
_thumbnailContainer = new RoundedCornerWidget(_mainBtnChild);
|
||||||
|
_thumbnailContainer->setCornerRadius(_cornerRadius);
|
||||||
|
_thumbnailContainer->setBorderColor(QColor(255, 255, 255, 0));
|
||||||
|
_thumbnailContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
_mainLayout->addWidget(_thumbnailContainer);
|
||||||
|
_thumbnailContainer->show();
|
||||||
|
|
||||||
|
_thumbnailWidget = new ModelThumbnailWidget(_model, _mainBtnChild);
|
||||||
|
_thumbnailWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
_thumbnailContainerLayout = new QHBoxLayout(_thumbnailContainer->mainWidget());
|
||||||
|
_thumbnailContainerLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_thumbnailContainerLayout->setSpacing(0);
|
||||||
|
_thumbnailContainer->mainWidget()->setLayout(_thumbnailContainerLayout);
|
||||||
|
_thumbnailContainerLayout->addWidget(_thumbnailWidget);
|
||||||
|
_thumbnailWidget->show();
|
||||||
|
|
||||||
|
// Create delete button
|
||||||
|
_deleteButton = new PushButton(nullptr, _mainBtnChild);
|
||||||
|
_deleteButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
_deleteIcon = new QLabel(_deleteButton);
|
||||||
|
_deleteIcon->setFont(QFont("Font Awesome 6 Free Regular", 12));
|
||||||
|
_deleteIcon->setText("\uf2ed");
|
||||||
|
_deleteIcon->setAlignment(Qt::AlignCenter);
|
||||||
|
_deleteButton->setChildWidget(_deleteIcon);
|
||||||
|
_deleteButton->setColorScheme(QColor(171, 59, 58));
|
||||||
|
_deleteButton->setIndicatorColor(QColor(171, 59, 58, 0));
|
||||||
|
_deleteIcon->show();
|
||||||
|
_mainLayout->addWidget(_deleteButton);
|
||||||
|
_deleteButton->show();
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
connect(_mainBtn, &PushButton::onClick, this, &ModelSelectable::onSelected);
|
||||||
|
connect(_deleteButton, &PushButton::onClick, this, &ModelSelectable::onRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelSelectable::~ModelSelectable()
|
||||||
|
{
|
||||||
|
delete _model;
|
||||||
|
}
|
||||||
@ -1,6 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "model.h"
|
|
||||||
|
|
||||||
#include <qwidget.h>
|
#include <qwidget.h>
|
||||||
|
#include <qlayout.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
|
||||||
|
#include "model.h"
|
||||||
|
#include "pushbutton.h"
|
||||||
|
#include "roundedcornerwidget.h"
|
||||||
|
#include "modelthumbnailwidget.h"
|
||||||
|
#include "lineeditwidget.h"
|
||||||
|
|
||||||
|
class ModelSelectable : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModelSelectable(Model* model, QWidget* parent = 0);
|
||||||
|
~ModelSelectable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Data
|
||||||
|
Model* _model;
|
||||||
|
|
||||||
|
// UI control variables
|
||||||
|
const QColor _borderColor = QColor(58, 143, 183);
|
||||||
|
const int _cornerRadius = 10;
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
QHBoxLayout* _stretchLayout = nullptr;
|
||||||
|
PushButton* _mainBtn = nullptr;
|
||||||
|
|
||||||
|
QWidget* _mainBtnChild = nullptr;
|
||||||
|
QHBoxLayout* _mainLayout = nullptr;
|
||||||
|
|
||||||
|
RoundedCornerWidget* _thumbnailContainer = nullptr;
|
||||||
|
QHBoxLayout* _thumbnailContainerLayout = nullptr;
|
||||||
|
ModelThumbnailWidget* _thumbnailWidget = nullptr;
|
||||||
|
|
||||||
|
PushButton* _deleteButton = nullptr;
|
||||||
|
QLabel* _deleteIcon = nullptr;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onSelected();
|
||||||
|
void onRemoved();
|
||||||
|
};
|
||||||
|
|||||||
@ -1 +1,83 @@
|
|||||||
#pragma once
|
#include <qfiledialog.h>
|
||||||
|
|
||||||
|
#include "modelselector.h"
|
||||||
|
|
||||||
|
ModelSelector::ModelSelector(QWidget* parent) :
|
||||||
|
QWidget(parent)
|
||||||
|
{
|
||||||
|
// Set maximum width
|
||||||
|
setMaximumWidth(240);
|
||||||
|
|
||||||
|
// Set up the main layout
|
||||||
|
_stretchLayout = new QVBoxLayout(this);
|
||||||
|
_stretchLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_stretchLayout->setSpacing(8);
|
||||||
|
setLayout(_stretchLayout);
|
||||||
|
|
||||||
|
// Create and add the 'add new' button
|
||||||
|
_addNewObjectBtn = new PushButton(nullptr, this);
|
||||||
|
_addNewObjectBtn->setChildWidget(new QLabel("Add New", _addNewObjectBtn));
|
||||||
|
_addNewObjectBtn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
_addNewObjectBtn->setMargin(32, 24, 32, 24);
|
||||||
|
_addNewObjectBtn->setRadius(10);
|
||||||
|
_addNewObjectBtn->setBackgroundColor(QColor(58, 143, 183, 20));
|
||||||
|
_stretchLayout->addWidget(_addNewObjectBtn);
|
||||||
|
_addNewObjectBtn->show();
|
||||||
|
|
||||||
|
// Create the selection list widget
|
||||||
|
_objectList = new ScrollListWidget(this);
|
||||||
|
_stretchLayout->addWidget(_objectList);
|
||||||
|
_objectList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
_objectList->show();
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
connect(_addNewObjectBtn, &PushButton::onClick, this, &ModelSelector::addNewObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelSelector::~ModelSelector() {}
|
||||||
|
|
||||||
|
void ModelSelector::addNewObject() {
|
||||||
|
QString path = getNewObjectPath();
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* model = loadObject(path);
|
||||||
|
ModelSelectable* newSelectable = new ModelSelectable(model, this);
|
||||||
|
|
||||||
|
_objectSelectables.push_back(newSelectable);
|
||||||
|
_objectList->addWidget(newSelectable);
|
||||||
|
|
||||||
|
connect(newSelectable, &ModelSelectable::onSelected, this, [=]() {
|
||||||
|
emit onObjectSelected(model);
|
||||||
|
});
|
||||||
|
connect(newSelectable, &ModelSelectable::onRemoved, this, [=]() {
|
||||||
|
removeObject(newSelectable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ModelSelector::getNewObjectPath() {
|
||||||
|
QString path = QFileDialog::getOpenFileName(this, "Select Model", "", "Model Files (*.obj)");
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* ModelSelector::loadObject(const QString& path) {
|
||||||
|
Model* model = new Model(path.toStdString());
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelSelector::removeObject(ModelSelectable* selectable) {
|
||||||
|
// Check if selectable is still in list
|
||||||
|
if (!_objectSelectables.contains(selectable)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the selectable from the list
|
||||||
|
_objectSelectables.removeAll(selectable);
|
||||||
|
|
||||||
|
// Remove the selectable from the list widget
|
||||||
|
_objectList->removeWidget(selectable);
|
||||||
|
|
||||||
|
// Delete the selectable
|
||||||
|
delete selectable;
|
||||||
|
}
|
||||||
|
|||||||
@ -1 +1,40 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qlist.h>
|
||||||
|
|
||||||
|
#include "scrolllistwidget.h"
|
||||||
|
#include "pushbutton.h"
|
||||||
|
#include "modelselectable.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
class ModelSelector : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModelSelector(QWidget* parent = 0);
|
||||||
|
~ModelSelector();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// UI elements
|
||||||
|
QVBoxLayout* _stretchLayout = nullptr;
|
||||||
|
PushButton* _addNewObjectBtn = nullptr;
|
||||||
|
ScrollListWidget* _objectList = nullptr;
|
||||||
|
|
||||||
|
// Object selection storage
|
||||||
|
QList<ModelSelectable*> _objectSelectables;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Slot functions
|
||||||
|
void addNewObject();
|
||||||
|
|
||||||
|
// Util functions
|
||||||
|
QString getNewObjectPath();
|
||||||
|
Model* loadObject(const QString& path);
|
||||||
|
void removeObject(ModelSelectable* selectable);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onObjectSelected(Model* selectedModel);
|
||||||
|
};
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
|||||||
75
FinalProject/modelthumbnailwidget.cpp
Normal file
75
FinalProject/modelthumbnailwidget.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include <qfile.h>
|
||||||
|
#include <qdir.h>
|
||||||
|
|
||||||
|
#include "modelthumbnailwidget.h"
|
||||||
|
|
||||||
|
ModelThumbnailWidget::ModelThumbnailWidget(Model* model, QWidget* parent) :
|
||||||
|
QOpenGLWidget(parent), _model(model)
|
||||||
|
{
|
||||||
|
// OpenGL initialize
|
||||||
|
QSurfaceFormat format;
|
||||||
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
format.setVersion(4, 3);
|
||||||
|
setFormat(format);
|
||||||
|
|
||||||
|
// Create a folder
|
||||||
|
QDir dir("./temp/shaders");
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkpath(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the shaders to the folder
|
||||||
|
if (QFile::exists("./temp/shaders/vertexshader.vs")) {
|
||||||
|
QFile::remove("./temp/shaders/vertexshader.vs");
|
||||||
|
}
|
||||||
|
QFile::copy(":/shaders/vertexshader.vs", "./temp/shaders/vertexshader.vs");
|
||||||
|
QFile::setPermissions("./temp/shaders/vertexshader.vs", QFileDevice::ReadOwner | QFileDevice::WriteOwner);
|
||||||
|
if (QFile::exists("./temp/shaders/fragmentshader.fs")) {
|
||||||
|
QFile::remove("./temp/shaders/fragmentshader.fs");
|
||||||
|
}
|
||||||
|
QFile::copy(":/shaders/fragmentshader.fs", "./temp/shaders/fragmentshader.fs");
|
||||||
|
QFile::setPermissions("./temp/shaders/fragmentshader.fs", QFile::ReadOwner | QFile::WriteOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelThumbnailWidget::~ModelThumbnailWidget() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelThumbnailWidget::initializeGL() {
|
||||||
|
initializeOpenGLFunctions();
|
||||||
|
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
_shaderProgram.ensureInitialized();
|
||||||
|
|
||||||
|
VertexShader vertexShader("./temp/shaders/vertexshader.vs");
|
||||||
|
FragmentShader fragmentShader("./temp/shaders/fragmentshader.fs");
|
||||||
|
_shaderProgram.attachShader(vertexShader);
|
||||||
|
_shaderProgram.attachShader(fragmentShader);
|
||||||
|
vertexShader.dispose();
|
||||||
|
fragmentShader.dispose();
|
||||||
|
|
||||||
|
_object.setModel(_model->copyToCurrentContext());
|
||||||
|
_camera.setPosition(glm::vec3(0.0f, 0.0f, 7.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelThumbnailWidget::paintGL() {
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
_shaderProgram.bind();
|
||||||
|
|
||||||
|
glm::mat4 view = _camera.viewMatrix();
|
||||||
|
glm::mat4 projection = glm::perspective(glm::radians(_camera.zoomVal()), (float)width() / (float)height(), 0.1f, 100.0f);
|
||||||
|
_shaderProgram.setUniform("view", view);
|
||||||
|
_shaderProgram.setUniform("projection", projection);
|
||||||
|
|
||||||
|
_object.render(_shaderProgram);
|
||||||
|
|
||||||
|
_shaderProgram.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelThumbnailWidget::resizeGL(int w, int h) {
|
||||||
|
glViewport(0, 0, w, h);
|
||||||
|
}
|
||||||
30
FinalProject/modelthumbnailwidget.h
Normal file
30
FinalProject/modelthumbnailwidget.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtOpenGLWidgets/qopenglwidget.h>
|
||||||
|
#include <qopenglfunctions.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
|
||||||
|
#include "model.h"
|
||||||
|
#include "camera.h"
|
||||||
|
#include "shader.h"
|
||||||
|
#include "renderable.h"
|
||||||
|
|
||||||
|
class ModelThumbnailWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModelThumbnailWidget(Model* model, QWidget* parent = 0);
|
||||||
|
~ModelThumbnailWidget();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model* _model = nullptr;
|
||||||
|
Renderable _object = Renderable::empty();
|
||||||
|
ShaderProgram _shaderProgram = ShaderProgram::empty();
|
||||||
|
Camera _camera;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void initializeGL() override;
|
||||||
|
virtual void paintGL() override;
|
||||||
|
virtual void resizeGL(int w, int h) override;
|
||||||
|
};
|
||||||
72
FinalProject/pagewidget.cpp
Normal file
72
FinalProject/pagewidget.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include <qpropertyanimation.h>
|
||||||
|
#include <qparallelanimationgroup.h>
|
||||||
|
|
||||||
|
#include "pagewidget.h"
|
||||||
|
|
||||||
|
PageWidget::PageWidget(QWidget* parent) : QWidget(parent) {
|
||||||
|
// Construct and set main layout
|
||||||
|
_stretchLayout = new QVBoxLayout(this);
|
||||||
|
_stretchLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_stretchLayout->setSpacing(0);
|
||||||
|
setLayout(_stretchLayout);
|
||||||
|
|
||||||
|
// Construct content widget
|
||||||
|
_contentWidget = new QWidget(this);
|
||||||
|
_stretchLayout->addWidget(_contentWidget);
|
||||||
|
_contentWidget->show();
|
||||||
|
|
||||||
|
// Add opacity effect to real content
|
||||||
|
_pageOpacityEffect = new QGraphicsOpacityEffect(_contentWidget);
|
||||||
|
_pageOpacityEffect->setOpacity(0);
|
||||||
|
_contentWidget->setGraphicsEffect(_pageOpacityEffect);
|
||||||
|
|
||||||
|
// Move offstage
|
||||||
|
move(_originPagePosition + QPoint(0, 150));
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
PageWidget::~PageWidget() {}
|
||||||
|
|
||||||
|
void PageWidget::onStage() {
|
||||||
|
// Move up and fade in
|
||||||
|
QParallelAnimationGroup* onStageAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* moveAnimation = new QPropertyAnimation(this, "pos");
|
||||||
|
QPropertyAnimation* fadeInAnimation = new QPropertyAnimation(_pageOpacityEffect, "opacity");
|
||||||
|
moveAnimation->setDuration(600);
|
||||||
|
moveAnimation->setEasingCurve(QEasingCurve::OutExpo);
|
||||||
|
moveAnimation->setStartValue(pos());
|
||||||
|
moveAnimation->setEndValue(_originPagePosition);
|
||||||
|
fadeInAnimation->setDuration(500);
|
||||||
|
fadeInAnimation->setEasingCurve(QEasingCurve::InQuad);
|
||||||
|
fadeInAnimation->setStartValue(_pageOpacityEffect->opacity());
|
||||||
|
fadeInAnimation->setEndValue(0.999);
|
||||||
|
onStageAnimation->addAnimation(moveAnimation);
|
||||||
|
onStageAnimation->addAnimation(fadeInAnimation);
|
||||||
|
onStageAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Show page
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageWidget::offStage() {
|
||||||
|
// Move down and fade out
|
||||||
|
QParallelAnimationGroup* offStageAnimation = new QParallelAnimationGroup(this);
|
||||||
|
//QPropertyAnimation* moveAnimation = new QPropertyAnimation(_contentWidget, "pos");
|
||||||
|
QPropertyAnimation* fadeOutAnimation = new QPropertyAnimation(_pageOpacityEffect, "opacity");
|
||||||
|
//moveAnimation->setDuration(300);
|
||||||
|
//moveAnimation->setEasingCurve(QEasingCurve::OutCubic);
|
||||||
|
//moveAnimation->setStartValue(_contentWidget->pos());
|
||||||
|
//moveAnimation->setEndValue(_originPagePosition - QPoint(0, 100));
|
||||||
|
fadeOutAnimation->setDuration(200);
|
||||||
|
fadeOutAnimation->setStartValue(_pageOpacityEffect->opacity());
|
||||||
|
fadeOutAnimation->setEndValue(0);
|
||||||
|
//offStageAnimation->addAnimation(moveAnimation);
|
||||||
|
offStageAnimation->addAnimation(fadeOutAnimation);
|
||||||
|
offStageAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Connect animation finished signal to hide page
|
||||||
|
connect(offStageAnimation, &QParallelAnimationGroup::finished, [=]() {
|
||||||
|
move(_originPagePosition + QPoint(0, 150));
|
||||||
|
hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
39
FinalProject/pagewidget.h
Normal file
39
FinalProject/pagewidget.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qgraphicseffect.h>
|
||||||
|
|
||||||
|
#include "pushbutton.h"
|
||||||
|
|
||||||
|
class PageWidget : public QWidget
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PageWidget(QWidget* parent = 0);
|
||||||
|
~PageWidget();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Page layout and content widget (which holds the actual page elements)
|
||||||
|
QVBoxLayout* _stretchLayout = nullptr;
|
||||||
|
QWidget* _contentWidget = nullptr;
|
||||||
|
|
||||||
|
// Button widgets for side bar
|
||||||
|
PushButton* _iconButton = nullptr;
|
||||||
|
PushButton* _textButton = nullptr;
|
||||||
|
|
||||||
|
// Opacity effects
|
||||||
|
QGraphicsOpacityEffect* _pageOpacityEffect = nullptr;
|
||||||
|
|
||||||
|
// Page position memory
|
||||||
|
QPoint _originPagePosition = QPoint(0, 0);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual PushButton* getPageIconButton(QWidget* context) = 0; // provide a push button with only an icon
|
||||||
|
virtual PushButton* getPageTextButton(QWidget* context) = 0; // provide a push button with an icon and a description text
|
||||||
|
|
||||||
|
public:
|
||||||
|
void onStage(); // provide an on stage animation when the page is selected
|
||||||
|
void offStage(); // provide an off stage animation when the page is deselected
|
||||||
|
};
|
||||||
811
FinalProject/pushbutton.cpp
Normal file
811
FinalProject/pushbutton.cpp
Normal file
@ -0,0 +1,811 @@
|
|||||||
|
#include <qanimationgroup.h>
|
||||||
|
#include <qparallelanimationgroup.h>
|
||||||
|
#include <qsequentialanimationgroup.h>
|
||||||
|
#include <qregularexpression.h>
|
||||||
|
|
||||||
|
#include "pushbutton.h"
|
||||||
|
|
||||||
|
PushButton::PushButton(QWidget* child, QWidget* parent)
|
||||||
|
: QWidget(parent), _childWidget(child)
|
||||||
|
{
|
||||||
|
initializeUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
PushButton::~PushButton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::initializeUI() {
|
||||||
|
generateColor(_defaultColorScheme);
|
||||||
|
|
||||||
|
// Add margin for the child widget
|
||||||
|
_stretchLayout = new QHBoxLayout(this);
|
||||||
|
_stretchLayout->setContentsMargins(_contentMargin);
|
||||||
|
_stretchLayout->setSpacing(0);
|
||||||
|
_stretchLayout->setAlignment(Qt::AlignCenter);
|
||||||
|
setLayout(_stretchLayout);
|
||||||
|
if (_childWidget) {
|
||||||
|
// prevent adding a null widget
|
||||||
|
_stretchLayout->addWidget(_childWidget);
|
||||||
|
_childWidget->show();
|
||||||
|
_childWidgetOriginalGeometry = _childWidget->geometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize background widget
|
||||||
|
_backgroundWidget = new QWidget(this);
|
||||||
|
_backgroundWidget->resize(size());
|
||||||
|
_backgroundWidget->setObjectName("backgroundWidget");
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
_backgroundWidget->lower();
|
||||||
|
_backgroundWidget->show();
|
||||||
|
|
||||||
|
// Initialize indicator
|
||||||
|
_indicator = new QWidget(this);
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
_indicator->resize(_indicatorWidth, _activatedLengthRatio * height());
|
||||||
|
_indicator->move(_indicatorSpacing, (0.5 - _activatedLengthRatio / 2) * height());
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
_indicator->resize(_indicatorWidth, _activatedLengthRatio * height());
|
||||||
|
_indicator->move(width() - _indicatorWidth - _indicatorSpacing, (0.5 - _activatedLengthRatio / 2) * height());
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
_indicator->resize(_activatedLengthRatio * width(), _indicatorWidth);
|
||||||
|
_indicator->move((0.5 - _activatedLengthRatio / 2) * width(), _indicatorSpacing);
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
_indicator->resize(_activatedLengthRatio * width(), _indicatorWidth);
|
||||||
|
_indicator->move((0.5 - _activatedLengthRatio / 2) * width(), height() - _indicatorWidth - _indicatorSpacing);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_indicator->setObjectName("indicator");
|
||||||
|
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number((float)_indicatorWidth / 2) + "px;}");
|
||||||
|
_indicatorEffect = new QGraphicsOpacityEffect(_indicator);
|
||||||
|
_indicatorEffect->setOpacity(0);
|
||||||
|
_indicator->setGraphicsEffect(_indicatorEffect);
|
||||||
|
_indicator->show();
|
||||||
|
|
||||||
|
// Enable mouse tracking
|
||||||
|
setMouseTracking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::generateColor(QColor colorScheme) {
|
||||||
|
_backgroundColor = colorScheme.lighter(120);
|
||||||
|
_backgroundColor.setAlpha(0);
|
||||||
|
_hoverColor = colorScheme.lighter(120);
|
||||||
|
_hoverColor.setAlpha(40);
|
||||||
|
_pressedColor = colorScheme.lighter(120);
|
||||||
|
_pressedColor.setAlpha(50);
|
||||||
|
_selectedColor = colorScheme.lighter(120);
|
||||||
|
_selectedColor.setAlpha(35);
|
||||||
|
_indicatorColor = colorScheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::enterEvent(QEnterEvent* event) {
|
||||||
|
setCursor(Qt::PointingHandCursor);
|
||||||
|
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
|
||||||
|
QParallelAnimationGroup* indicatorEnterAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* indicatorGrowLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
QPropertyAnimation* indicatorFadeIn = new QPropertyAnimation(_indicatorEffect, "opacity", this);
|
||||||
|
indicatorGrowLength->setDuration(150);
|
||||||
|
indicatorGrowLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorFadeIn->setDuration(100);
|
||||||
|
indicatorFadeIn->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorGrowLength->setStartValue(_indicator->geometry());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indicatorFadeIn->setStartValue(_indicatorEffect->opacity());
|
||||||
|
indicatorFadeIn->setEndValue(0.999);
|
||||||
|
indicatorEnterAnimation->addAnimation(indicatorGrowLength);
|
||||||
|
indicatorEnterAnimation->addAnimation(indicatorFadeIn);
|
||||||
|
indicatorEnterAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
_hovered = true;
|
||||||
|
emit onHover();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::leaveEvent(QEvent* event) {
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
|
||||||
|
if (_selected) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _selectedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
QParallelAnimationGroup* indicatorLeaveAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* indicatorShrinkLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
QPropertyAnimation* indicatorFadeOut = new QPropertyAnimation(_indicatorEffect, "opacity", this);
|
||||||
|
indicatorShrinkLength->setDuration(150);
|
||||||
|
indicatorShrinkLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorFadeOut->setDuration(100);
|
||||||
|
indicatorFadeOut->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorShrinkLength->setStartValue(_indicator->geometry());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indicatorFadeOut->setStartValue(_indicatorEffect->opacity());
|
||||||
|
indicatorFadeOut->setEndValue(_selected ? 0.999 : 0);
|
||||||
|
indicatorLeaveAnimation->addAnimation(indicatorShrinkLength);
|
||||||
|
indicatorLeaveAnimation->addAnimation(indicatorFadeOut);
|
||||||
|
indicatorLeaveAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
_pressed = false;
|
||||||
|
_hovered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::mousePressEvent(QMouseEvent* event) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
|
||||||
|
QPropertyAnimation* indicatorShrinkLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
indicatorShrinkLength->setDuration(100);
|
||||||
|
indicatorShrinkLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorShrinkLength->setStartValue(_indicator->geometry());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indicatorShrinkLength->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
_pressed = true;
|
||||||
|
|
||||||
|
emit onPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
if (!_pressed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
|
||||||
|
QPropertyAnimation* indicatorGrowLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
indicatorGrowLength->setDuration(100);
|
||||||
|
indicatorGrowLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorGrowLength->setStartValue(_indicator->geometry());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indicatorGrowLength->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
if (_pressed) {
|
||||||
|
// prevent double trigger if mouse is first left and then released
|
||||||
|
emit onClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::resizeEvent(QResizeEvent* event) {
|
||||||
|
_backgroundWidget->setGeometry(0, 0, width(), height());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(QRect(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::select() {
|
||||||
|
if (_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _selectedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// First shrink then length the indicator, also fade in
|
||||||
|
QSequentialAnimationGroup* indicatorSelectAnimation = new QSequentialAnimationGroup(this);
|
||||||
|
QParallelAnimationGroup* indicatorShrinkAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* indicatorFadeIn = new QPropertyAnimation(_indicatorEffect, "opacity", this);
|
||||||
|
QPropertyAnimation* indicatorShrinkLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
QPropertyAnimation* indicatorGrowLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
indicatorFadeIn->setDuration(100);
|
||||||
|
indicatorFadeIn->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorShrinkLength->setDuration(100);
|
||||||
|
indicatorShrinkLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorGrowLength->setDuration(100);
|
||||||
|
indicatorGrowLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorFadeIn->setStartValue(_indicatorEffect->opacity());
|
||||||
|
indicatorFadeIn->setEndValue(0.999);
|
||||||
|
indicatorShrinkLength->setStartValue(_indicator->geometry());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setStartValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setStartValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setStartValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setStartValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
indicatorGrowLength->setEndValue(QRect(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indicatorShrinkAnimation->addAnimation(indicatorShrinkLength);
|
||||||
|
indicatorShrinkAnimation->addAnimation(indicatorFadeIn);
|
||||||
|
indicatorSelectAnimation->addAnimation(indicatorShrinkAnimation);
|
||||||
|
indicatorSelectAnimation->addAnimation(indicatorGrowLength);
|
||||||
|
indicatorSelectAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Set selected state
|
||||||
|
_selected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::deselect() {
|
||||||
|
if (!_selected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
|
||||||
|
// Cursor is currently not in the button, shrink and fade out the indicator
|
||||||
|
QParallelAnimationGroup* indicatorDeselectAnimation = new QParallelAnimationGroup(this);
|
||||||
|
QPropertyAnimation* indicatorFadeOut = new QPropertyAnimation(_indicatorEffect, "opacity", this);
|
||||||
|
QPropertyAnimation* indicatorShrinkLength = new QPropertyAnimation(_indicator, "geometry", this);
|
||||||
|
indicatorFadeOut->setDuration(100);
|
||||||
|
indicatorFadeOut->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorShrinkLength->setDuration(100);
|
||||||
|
indicatorShrinkLength->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
indicatorFadeOut->setStartValue(_indicatorEffect->opacity());
|
||||||
|
indicatorFadeOut->setEndValue(0);
|
||||||
|
indicatorShrinkLength->setStartValue(_indicator->geometry());
|
||||||
|
switch (_indicatorPosition) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
indicatorShrinkLength->setEndValue(QRect(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
indicatorDeselectAnimation->addAnimation(indicatorFadeOut);
|
||||||
|
indicatorDeselectAnimation->addAnimation(indicatorShrinkLength);
|
||||||
|
indicatorDeselectAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set selected state
|
||||||
|
_selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setRadius(int radius) {
|
||||||
|
// get current style sheet
|
||||||
|
QString styleSheet = _backgroundWidget->styleSheet();
|
||||||
|
// remove old border radius
|
||||||
|
styleSheet.remove(QRegularExpression("border-radius:\\d+px;"));
|
||||||
|
// add new border radius
|
||||||
|
styleSheet.append("border-radius: " + QString::number(radius) + "px;");
|
||||||
|
// set new style sheet
|
||||||
|
_backgroundWidget->setStyleSheet(styleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setBackgroundColor(QColor color) {
|
||||||
|
_backgroundColor = color;
|
||||||
|
if (!_selected && !_hovered && !_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setHoverColor(QColor color) {
|
||||||
|
_hoverColor = color;
|
||||||
|
if (_hovered && !_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setPressedColor(QColor color) {
|
||||||
|
_pressedColor = color;
|
||||||
|
if (_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setSelectedColor(QColor color) {
|
||||||
|
_selectedColor = color;
|
||||||
|
if (_selected && !_pressed && !_hovered) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _selectedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setIndicatorColor(QColor color) {
|
||||||
|
_indicatorColor = color;
|
||||||
|
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number((float)_indicatorWidth / 2) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setColorScheme(QColor color) {
|
||||||
|
generateColor(color);
|
||||||
|
if (_pressed) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else if (_selected) {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _selectedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
|
||||||
|
}
|
||||||
|
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number((float)_indicatorWidth / 2) + "px;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
QHBoxLayout* PushButton::mainLayout() const {
|
||||||
|
return _stretchLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setAlignment(Qt::Alignment alignment) {
|
||||||
|
_stretchLayout->setAlignment(alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setMargin(QMargins margin) {
|
||||||
|
_stretchLayout->setContentsMargins(margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setMargin(int left, int top, int right, int bottom) {
|
||||||
|
_stretchLayout->setContentsMargins(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setIndicatorPosition(LUI_BTN_INDICATOR_POS pos) {
|
||||||
|
_indicatorPosition = pos;
|
||||||
|
switch (pos) {
|
||||||
|
case LUI_BTN_POS_LEFT:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
_indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_RIGHT:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_pressedLengthRatio * height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_hoveredLengthRatio * height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
width() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * height(),
|
||||||
|
_indicatorWidth,
|
||||||
|
_activatedLengthRatio * height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_TOP:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
_indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUI_BTN_POS_BOTTOM:
|
||||||
|
if (_pressed) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
(0.5 - _pressedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_pressedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (_hovered) {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
(0.5 - _hoveredLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_hoveredLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_indicator->setGeometry(
|
||||||
|
(0.5 - _activatedLengthRatio / 2) * width(),
|
||||||
|
height() - _indicatorWidth - _indicatorSpacing,
|
||||||
|
_activatedLengthRatio * width(),
|
||||||
|
_indicatorWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* PushButton::childWidget() {
|
||||||
|
return _childWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushButton::setChildWidget(QWidget* widget) {
|
||||||
|
_childWidget = widget;
|
||||||
|
for (int i = 0; i < _stretchLayout->count(); i++) {
|
||||||
|
_stretchLayout->removeItem(_stretchLayout->itemAt(i));
|
||||||
|
}
|
||||||
|
if (_childWidget != nullptr) {
|
||||||
|
_stretchLayout->addWidget(_childWidget);
|
||||||
|
_childWidget->show();
|
||||||
|
_childWidgetOriginalGeometry = _childWidget->geometry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PushButton::isSelected() const {
|
||||||
|
return _selected;
|
||||||
|
}
|
||||||
102
FinalProject/pushbutton.h
Normal file
102
FinalProject/pushbutton.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qgraphicseffect.h>
|
||||||
|
#include <qpropertyanimation.h>
|
||||||
|
|
||||||
|
class PushButton : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum LUI_BTN_INDICATOR_POS {
|
||||||
|
LUI_BTN_POS_LEFT,
|
||||||
|
LUI_BTN_POS_RIGHT,
|
||||||
|
LUI_BTN_POS_TOP,
|
||||||
|
LUI_BTN_POS_BOTTOM
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
PushButton(QWidget* child, QWidget* parent);
|
||||||
|
~PushButton();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Button Layout
|
||||||
|
QWidget* _childWidget;
|
||||||
|
QRect _childWidgetOriginalGeometry;
|
||||||
|
const float _childWidgetShrinkRatio = 0.9;
|
||||||
|
QHBoxLayout* _stretchLayout;
|
||||||
|
QMargins _contentMargin = QMargins(12, 12, 12, 12);
|
||||||
|
|
||||||
|
// Button ui
|
||||||
|
int _radius = 8;
|
||||||
|
|
||||||
|
QWidget* _backgroundWidget;
|
||||||
|
const QColor _defaultColorScheme = QColor(58, 143, 183);
|
||||||
|
QColor _backgroundColor;
|
||||||
|
QColor _hoverColor;
|
||||||
|
QColor _pressedColor;
|
||||||
|
QColor _selectedColor;
|
||||||
|
|
||||||
|
QWidget* _indicator;
|
||||||
|
LUI_BTN_INDICATOR_POS _indicatorPosition = LUI_BTN_POS_LEFT;
|
||||||
|
const int _indicatorWidth = 6;
|
||||||
|
const int _indicatorSpacing = 4;
|
||||||
|
const float _activatedLengthRatio = 0.4;
|
||||||
|
const float _hoveredLengthRatio = 0.5;
|
||||||
|
const float _pressedLengthRatio = 0.2;
|
||||||
|
QColor _indicatorColor;
|
||||||
|
QGraphicsOpacityEffect* _indicatorEffect;
|
||||||
|
|
||||||
|
// Button state
|
||||||
|
bool _hovered = false;
|
||||||
|
bool _pressed = false;
|
||||||
|
bool _selected = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// UI util functions
|
||||||
|
void initializeUI();
|
||||||
|
void generateColor(QColor colorScheme);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Interactions
|
||||||
|
virtual void enterEvent(QEnterEvent* event) override;
|
||||||
|
virtual void leaveEvent(QEvent* event) override;
|
||||||
|
virtual void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
virtual void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Operation APIs
|
||||||
|
void select();
|
||||||
|
void deselect();
|
||||||
|
|
||||||
|
// Attribute setter APIs
|
||||||
|
void setRadius(int radius);
|
||||||
|
|
||||||
|
void setBackgroundColor(QColor color);
|
||||||
|
void setHoverColor(QColor color);
|
||||||
|
void setPressedColor(QColor color);
|
||||||
|
void setSelectedColor(QColor color);
|
||||||
|
void setIndicatorColor(QColor color);
|
||||||
|
void setColorScheme(QColor primaryColor);
|
||||||
|
|
||||||
|
QHBoxLayout* mainLayout() const;
|
||||||
|
void setAlignment(Qt::Alignment alignment);
|
||||||
|
void setMargin(QMargins margin);
|
||||||
|
void setMargin(int left, int top, int right, int bottom);
|
||||||
|
|
||||||
|
void setIndicatorPosition(LUI_BTN_INDICATOR_POS position);
|
||||||
|
|
||||||
|
QWidget* childWidget();
|
||||||
|
void setChildWidget(QWidget* widget);
|
||||||
|
|
||||||
|
bool isSelected() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onClick();
|
||||||
|
void onHover();
|
||||||
|
void onPressed();
|
||||||
|
};
|
||||||
@ -8,6 +8,10 @@ Renderable::Renderable(Model* model) : _model(model) {}
|
|||||||
|
|
||||||
Renderable::Renderable(Model* model, glm::vec3 position) : _model(model), _position(position) {}
|
Renderable::Renderable(Model* model, glm::vec3 position) : _model(model), _position(position) {}
|
||||||
|
|
||||||
|
void Renderable::setModel(Model* model) {
|
||||||
|
_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
void Renderable::move(glm::vec3 deltaVec) {
|
void Renderable::move(glm::vec3 deltaVec) {
|
||||||
_position += deltaVec;
|
_position += deltaVec;
|
||||||
}
|
}
|
||||||
@ -33,6 +37,11 @@ void Renderable::setScale(float scale) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderable::render(ShaderProgram shader) {
|
void Renderable::render(ShaderProgram shader) {
|
||||||
|
// Check if initialized
|
||||||
|
if (_model == nullptr) {
|
||||||
|
Logger::error("Tries to render an uninitialized renderable object");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Set model matrix
|
// Set model matrix
|
||||||
shader.setUniform("model", modelMatrix());
|
shader.setUniform("model", modelMatrix());
|
||||||
// Render
|
// Render
|
||||||
|
|||||||
@ -7,8 +7,16 @@
|
|||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
class Renderable {
|
class Renderable {
|
||||||
|
public:
|
||||||
|
static Renderable empty() {
|
||||||
|
return Renderable();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Model* _model;
|
Renderable() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model* _model = nullptr;
|
||||||
glm::vec3 _position = glm::vec3(0.0f);
|
glm::vec3 _position = glm::vec3(0.0f);
|
||||||
glm::mat4 _rotation = glm::mat4(1.0f);
|
glm::mat4 _rotation = glm::mat4(1.0f);
|
||||||
glm::vec3 _scale = glm::vec3(1.0f);
|
glm::vec3 _scale = glm::vec3(1.0f);
|
||||||
@ -21,6 +29,7 @@ public:
|
|||||||
Renderable(Model* model, glm::vec3 position);
|
Renderable(Model* model, glm::vec3 position);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void setModel(Model* model);
|
||||||
void move(glm::vec3 deltaVec);
|
void move(glm::vec3 deltaVec);
|
||||||
void setPosition(glm::vec3 position);
|
void setPosition(glm::vec3 position);
|
||||||
void rotate(glm::vec3 axis, float deltaAngle);
|
void rotate(glm::vec3 axis, float deltaAngle);
|
||||||
|
|||||||
106
FinalProject/roundedcornerwidget.cpp
Normal file
106
FinalProject/roundedcornerwidget.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include <qpainterpath.h>
|
||||||
|
#include <qregularexpression.h>
|
||||||
|
|
||||||
|
#include "roundedcornerwidget.h"
|
||||||
|
|
||||||
|
RoundedCornerWidget::RoundedCornerWidget(QWidget* parent) : QWidget(parent) {
|
||||||
|
// Create main layout and main widget
|
||||||
|
_mainLayout = new QVBoxLayout(this);
|
||||||
|
_mainLayout->setContentsMargins(0, 1, 1, 1);
|
||||||
|
_mainLayout->setSpacing(0);
|
||||||
|
_mainWidget = new QWidget(this);
|
||||||
|
_mainWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
_mainLayout->addWidget(_mainWidget);
|
||||||
|
_mainWidget->show();
|
||||||
|
setLayout(_mainLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundedCornerWidget::~RoundedCornerWidget() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundedCornerWidget::showEvent(QShowEvent* event) {
|
||||||
|
// Call parent show event
|
||||||
|
QWidget::showEvent(event);
|
||||||
|
|
||||||
|
if (_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize widget UI
|
||||||
|
initializeWidgetUI();
|
||||||
|
|
||||||
|
// Set initialized state
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundedCornerWidget::initializeWidgetUI() {
|
||||||
|
// Set up border widget
|
||||||
|
_borderWidget = new QWidget(this);
|
||||||
|
_borderWidget->setObjectName("borderWidget");
|
||||||
|
QString borderWidgetStyleSheet =
|
||||||
|
"QWidget#borderWidget{background-color:#00FFFFFF;border:2px solid " + _borderColor.name(QColor::HexArgb) + ";"
|
||||||
|
"border-radius:" + QString::number(_cornerRadius) + "px;}";
|
||||||
|
_borderWidget->setStyleSheet(borderWidgetStyleSheet);
|
||||||
|
_borderWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
_borderWidget->move(0, 0);
|
||||||
|
_borderWidget->resize(width(), height());
|
||||||
|
_borderWidget->show();
|
||||||
|
|
||||||
|
// Create a round cornered mask
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(_mainWidget->rect(), _cornerRadius, _cornerRadius);
|
||||||
|
QRegion region(path.toFillPolygon().toPolygon());
|
||||||
|
_mainWidget->setMask(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundedCornerWidget::resizeEvent(QResizeEvent* event) {
|
||||||
|
// Resize widget border
|
||||||
|
if (_borderWidget != nullptr) {
|
||||||
|
_borderWidget->move(0, 0);
|
||||||
|
_borderWidget->resize(width(), height());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize window mask
|
||||||
|
if (_mainWidget != nullptr) {
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(_mainWidget->rect(), _cornerRadius, _cornerRadius);
|
||||||
|
QRegion region(path.toFillPolygon().toPolygon());
|
||||||
|
_mainWidget->setMask(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundedCornerWidget::setCornerRadius(int radius) {
|
||||||
|
// Set corner radius
|
||||||
|
_cornerRadius = radius;
|
||||||
|
|
||||||
|
// Modify the corner radius in the current style sheet of the border widget
|
||||||
|
if (_borderWidget != nullptr) {
|
||||||
|
QString styleSheet = _borderWidget->styleSheet();
|
||||||
|
styleSheet.replace(QRegularExpression("border-radius:\\d+px;"),
|
||||||
|
QString("border-radius:%1px;").arg(_cornerRadius));
|
||||||
|
_borderWidget->setStyleSheet(styleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the mask of the main widget
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(_mainWidget->rect(), _cornerRadius, _cornerRadius);
|
||||||
|
QRegion region(path.toFillPolygon().toPolygon());
|
||||||
|
_mainWidget->setMask(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoundedCornerWidget::setBorderColor(QColor color) {
|
||||||
|
// Set color
|
||||||
|
_borderColor = color;
|
||||||
|
|
||||||
|
// Modify the border color in the current style sheet of the border widget
|
||||||
|
if (_borderWidget != nullptr) {
|
||||||
|
QString styleSheet = _borderWidget->styleSheet();
|
||||||
|
styleSheet.replace(QRegularExpression("border:2px solid #\\w+;"),
|
||||||
|
QString("border:2px solid %1;").arg(_borderColor.name(QColor::HexArgb)));
|
||||||
|
_borderWidget->setStyleSheet(styleSheet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* RoundedCornerWidget::mainWidget() const {
|
||||||
|
return _mainWidget;
|
||||||
|
}
|
||||||
38
FinalProject/roundedcornerwidget.h
Normal file
38
FinalProject/roundedcornerwidget.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
|
||||||
|
class RoundedCornerWidget : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
RoundedCornerWidget(QWidget* parent = 0);
|
||||||
|
~RoundedCornerWidget();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// UI settings
|
||||||
|
int _cornerRadius = 15;
|
||||||
|
QColor _borderColor = QColor(255, 255, 255);
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
QWidget* _mainWidget = nullptr;
|
||||||
|
QVBoxLayout* _mainLayout = nullptr;
|
||||||
|
QWidget* _borderWidget = nullptr;
|
||||||
|
|
||||||
|
// Initialization mark
|
||||||
|
bool _initialized = false;
|
||||||
|
void initializeWidgetUI();
|
||||||
|
|
||||||
|
// UI events
|
||||||
|
virtual void showEvent(QShowEvent* event) override;
|
||||||
|
virtual void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Public APIs
|
||||||
|
void setCornerRadius(int radius);
|
||||||
|
void setBorderColor(QColor color);
|
||||||
|
QWidget* mainWidget() const;
|
||||||
|
};
|
||||||
@ -17,6 +17,7 @@ using std::vector;
|
|||||||
SceneViewer::SceneViewer(QWidget* parent)
|
SceneViewer::SceneViewer(QWidget* parent)
|
||||||
: QOpenGLWidget(parent)
|
: QOpenGLWidget(parent)
|
||||||
{
|
{
|
||||||
|
// OpenGL initialize
|
||||||
QSurfaceFormat format;
|
QSurfaceFormat format;
|
||||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
format.setVersion(4, 3);
|
format.setVersion(4, 3);
|
||||||
@ -64,15 +65,8 @@ void SceneViewer::initializeGL() {
|
|||||||
_shaderProgram.attachShader(fragmentShader);
|
_shaderProgram.attachShader(fragmentShader);
|
||||||
vertexShader.dispose();
|
vertexShader.dispose();
|
||||||
fragmentShader.dispose();
|
fragmentShader.dispose();
|
||||||
|
|
||||||
Model* backpackModel = new Model("D:/code/ComputerGraphic/SceneEditor/obj/nanosuit/nanosuit.obj");
|
|
||||||
Logger::info("Model loaded");
|
|
||||||
Renderable backpack(backpackModel);
|
|
||||||
_objects.push_back(backpack);
|
|
||||||
|
|
||||||
|
_camera.setPosition(glm::vec3(0.0f, 0.0f, 10.0f));
|
||||||
_camera.setPosition(glm::vec3(0.0f, 0.0f, 5.0f));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneViewer::resizeGL(int w, int h) {
|
void SceneViewer::resizeGL(int w, int h) {
|
||||||
@ -80,6 +74,8 @@ void SceneViewer::resizeGL(int w, int h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SceneViewer::paintGL() {
|
void SceneViewer::paintGL() {
|
||||||
|
Logger::debug("Repainting");
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
_shaderProgram.bind();
|
_shaderProgram.bind();
|
||||||
@ -108,7 +104,9 @@ void SceneViewer::mousePressEvent(QMouseEvent* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
|
void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
Logger::debug("Mouse moved with offset: " + std::to_string(event->x() - _lastMousePosition.x()) + ", " + std::to_string(event->y() - _lastMousePosition.y()));
|
if (event->buttons() != Qt::NoButton) {
|
||||||
|
Logger::debug("Mouse moved with offset: " + std::to_string(event->x() - _lastMousePosition.x()) + ", " + std::to_string(event->y() - _lastMousePosition.y()));
|
||||||
|
}
|
||||||
// Check the type of button pressed
|
// Check the type of button pressed
|
||||||
switch (event->buttons()) {
|
switch (event->buttons()) {
|
||||||
case Qt::LeftButton: {
|
case Qt::LeftButton: {
|
||||||
@ -154,7 +152,7 @@ void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
|
|||||||
// Update the last mouse position
|
// Update the last mouse position
|
||||||
_lastMousePosition = event->pos();
|
_lastMousePosition = event->pos();
|
||||||
// Update the view
|
// Update the view
|
||||||
update();
|
parentWidget()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneViewer::wheelEvent(QWheelEvent* event) {
|
void SceneViewer::wheelEvent(QWheelEvent* event) {
|
||||||
@ -167,5 +165,31 @@ void SceneViewer::wheelEvent(QWheelEvent* event) {
|
|||||||
Logger::debug("New camera position: " + std::to_string(_camera.position().x) + ", " + std::to_string(_camera.position().y) + ", " + std::to_string(_camera.position().z));
|
Logger::debug("New camera position: " + std::to_string(_camera.position().x) + ", " + std::to_string(_camera.position().y) + ", " + std::to_string(_camera.position().z));
|
||||||
Logger::debug("New center position: " + std::to_string(_rotateCenter.x) + ", " + std::to_string(_rotateCenter.y) + ", " + std::to_string(_rotateCenter.z));
|
Logger::debug("New center position: " + std::to_string(_rotateCenter.x) + ", " + std::to_string(_rotateCenter.y) + ", " + std::to_string(_rotateCenter.z));
|
||||||
// Update the view
|
// Update the view
|
||||||
update();
|
parentWidget()->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneViewer::showEvent(QShowEvent* event) {
|
||||||
|
// Call show event of super class
|
||||||
|
QOpenGLWidget::showEvent(event);
|
||||||
|
|
||||||
|
if (_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Create mask for rounded corner
|
||||||
|
//QPainterPath mask;
|
||||||
|
//mask.addRoundedRect(rect(), _cornerRadius, _cornerRadius);
|
||||||
|
//setMask(mask.toFillPolygon().toPolygon());
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneViewer::resizeEvent(QResizeEvent* event) {
|
||||||
|
// Call resize event of super class
|
||||||
|
QOpenGLWidget::resizeEvent(event);
|
||||||
|
|
||||||
|
//// Create mask for rounded corner
|
||||||
|
//QPainterPath mask;
|
||||||
|
//mask.addRoundedRect(rect(), _cornerRadius, _cornerRadius);
|
||||||
|
//setMask(mask.toFillPolygon().toPolygon());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,10 @@ private:
|
|||||||
// User Interaction flags section---------------------
|
// User Interaction flags section---------------------
|
||||||
QPoint _lastMousePosition;
|
QPoint _lastMousePosition;
|
||||||
Renderable* _selectedObject = nullptr;
|
Renderable* _selectedObject = nullptr;
|
||||||
|
|
||||||
|
// UI interface control
|
||||||
|
const int _cornerRadius = 10;
|
||||||
|
bool _initialized = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SceneViewer(QWidget* parent = 0);
|
SceneViewer(QWidget* parent = 0);
|
||||||
@ -50,4 +54,7 @@ protected:
|
|||||||
virtual void mouseMoveEvent(QMouseEvent* event) override;
|
virtual void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
virtual void wheelEvent(QWheelEvent* event) override;
|
virtual void wheelEvent(QWheelEvent* event) override;
|
||||||
|
|
||||||
|
// UI update events
|
||||||
|
virtual void showEvent(QShowEvent* event) override;
|
||||||
|
virtual void resizeEvent(QResizeEvent* event) override;
|
||||||
};
|
};
|
||||||
422
FinalProject/scrolllistwidget.cpp
Normal file
422
FinalProject/scrolllistwidget.cpp
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
#include "scrolllistwidget.h"
|
||||||
|
|
||||||
|
ScrollListWidget::ScrollListWidget(QWidget* parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
//initialize list container and timer
|
||||||
|
container = new ScrollListContainer(this);
|
||||||
|
container->move(0, 0);
|
||||||
|
container->resize(this->width(), 3);
|
||||||
|
getCord = new QTimer;
|
||||||
|
getCord->setSingleShot(true);
|
||||||
|
rfrshView = new QTimer;
|
||||||
|
getCord->setSingleShot(true);
|
||||||
|
|
||||||
|
indicator = new ScrollListIndicator(this);
|
||||||
|
indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height()));
|
||||||
|
indicator->move(this->width() - indicator->width() - 3, 0);
|
||||||
|
|
||||||
|
this->setMouseTracking(true);
|
||||||
|
container->setMouseTracking(true);
|
||||||
|
indicator->setMouseTracking(true);
|
||||||
|
|
||||||
|
bounce = new QPropertyAnimation(container, "pos");
|
||||||
|
|
||||||
|
QObject::connect(getCord, SIGNAL(timeout()), this, SLOT(updateSpd()));
|
||||||
|
QObject::connect(rfrshView, SIGNAL(timeout()), this, SLOT(scrollContainer()));
|
||||||
|
QObject::connect(indicator, SIGNAL(scrollPage(int)), this, SLOT(scrollIndicator(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::paintEvent(QPaintEvent* event) {
|
||||||
|
container->resize(this->width(), container->height());
|
||||||
|
if (container->height() > this->height() && container->y() < this->height() - container->height() && curSpd == 0 && bounce->state() == QAbstractAnimation::Stopped)
|
||||||
|
container->move(container->x(), this->height() - container->height());
|
||||||
|
if (container->height() <= this->height()) {
|
||||||
|
container->move(container->x(), 0);
|
||||||
|
indicator->hide();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indicator->show();
|
||||||
|
}
|
||||||
|
indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height()));
|
||||||
|
indicator->move(this->width() - indicator->width() - 3, -container->y() * this->height() / container->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::mousePressEvent(QMouseEvent* event) {
|
||||||
|
if (container->height() > this->height()) {
|
||||||
|
if (container->y() <= 0 && container->y() + container->height() >= this->height())
|
||||||
|
pressed = true;
|
||||||
|
lastY = event->pos().y();
|
||||||
|
}
|
||||||
|
getCord->stop();
|
||||||
|
rfrshView->stop();
|
||||||
|
curSpd = 0;
|
||||||
|
outOfEdge = false;
|
||||||
|
moveStored = 0;
|
||||||
|
nextMove = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
if (pressed) {
|
||||||
|
//start scroll
|
||||||
|
if (!getCord->isActive() && event->pos().y() - lastY != 0) {
|
||||||
|
//start 30ms timer
|
||||||
|
getCord->start(30);
|
||||||
|
strtY = event->pos().y();
|
||||||
|
}
|
||||||
|
if (container->y() <= 0 && container->y() + container->height() >= this->height())
|
||||||
|
container->move(container->x(), container->y() + event->pos().y() - lastY);
|
||||||
|
else {
|
||||||
|
if (!outOfEdge) {
|
||||||
|
bfEdgeY = event->pos().y();
|
||||||
|
container->move(container->x(), container->y() + event->pos().y() - lastY);
|
||||||
|
outOfEdge = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int pos = container->y() >= 0 ? 1 : -1;
|
||||||
|
int dp = event->pos().y() - bfEdgeY;
|
||||||
|
if (dp == 0) {
|
||||||
|
outOfEdge = false;
|
||||||
|
nextMove = 1;
|
||||||
|
moveStored = 0;
|
||||||
|
if (container->y() >= 0)
|
||||||
|
container->move(container->x(), 0);
|
||||||
|
else
|
||||||
|
container->move(container->x(), this->height() - container->height());
|
||||||
|
}
|
||||||
|
else if (dp / abs(dp) != pos) {
|
||||||
|
outOfEdge = false;
|
||||||
|
container->move(container->x(), this->y() + event->pos().y() - bfEdgeY);
|
||||||
|
nextMove = 1;
|
||||||
|
moveStored = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (abs(moveStored) + nextMove <= abs(event->pos().y() - bfEdgeY)) {
|
||||||
|
moveStored += nextMove * pos;
|
||||||
|
container->move(container->x(), container->y() + pos);
|
||||||
|
nextMove++;
|
||||||
|
}
|
||||||
|
while (nextMove > 1 && abs(moveStored) > abs(event->pos().y() - bfEdgeY)) {
|
||||||
|
nextMove--;
|
||||||
|
moveStored -= nextMove * pos;
|
||||||
|
container->move(container->x(), container->y() - pos);
|
||||||
|
}
|
||||||
|
if (moveStored == 0) {
|
||||||
|
outOfEdge = false;
|
||||||
|
if (container->y() >= 0)
|
||||||
|
container->move(container->x(), 0);
|
||||||
|
else
|
||||||
|
container->move(container->x(), this->height() - container->height());
|
||||||
|
nextMove = 1;
|
||||||
|
moveStored = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastY = event->pos().y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
//start scrolling
|
||||||
|
if (container->y() > 0 || container->y() + container->height() < this->height())
|
||||||
|
bounceBack();
|
||||||
|
else
|
||||||
|
rfrshView->start(30);
|
||||||
|
pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::bounceBack() {
|
||||||
|
rfrshView->stop();
|
||||||
|
getCord->stop();
|
||||||
|
bounce->setDuration(500);
|
||||||
|
bounce->setStartValue(container->pos());
|
||||||
|
if (container->y() > 0)
|
||||||
|
bounce->setEndValue(QPoint(container->x(), 0));
|
||||||
|
else
|
||||||
|
bounce->setEndValue(QPoint(container->x(), this->height() - container->height()));
|
||||||
|
bounce->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
bounce->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::scrollContainer() {
|
||||||
|
//scroll
|
||||||
|
if (curSpd > 0) {
|
||||||
|
if (curSpd > MAXSPEED && !ignoreMaxSpeed)
|
||||||
|
curSpd = MAXSPEED;
|
||||||
|
else if (curSpd <= MAXSPEED) ignoreMaxSpeed = false;
|
||||||
|
int dp = scrollDown ? curSpd : -curSpd;
|
||||||
|
container->move(container->x(), container->y() + dp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
if (container->y() <= 0 && container->y() + container->height() >= this->height()) {
|
||||||
|
curSpd -= damp;
|
||||||
|
curSpd = curSpd < 0 ? 0 : curSpd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
curSpd /= 2;
|
||||||
|
if (curSpd == 0 && (container->y() > 0 || container->y() + container->height() < this->height()))
|
||||||
|
bounceBack();
|
||||||
|
else
|
||||||
|
rfrshView->start(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::updateSpd() {
|
||||||
|
int spd = lastY - strtY;
|
||||||
|
scrollDown = spd >= 0;
|
||||||
|
strtY = lastY;
|
||||||
|
curSpd = abs(spd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::addWidget(QWidget* newWidget, bool setAnimation) {
|
||||||
|
newWidget->setParent(container);
|
||||||
|
container->AddWidget(newWidget, setAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::removeWidget(QWidget* w) {
|
||||||
|
container->RemoveWidget(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::scrollToTop() {
|
||||||
|
curSpd = sqrt(8 * (-container->pos().y()) + 2) / 2;
|
||||||
|
scrollDown = true;
|
||||||
|
getCord->stop();
|
||||||
|
rfrshView->stop();
|
||||||
|
outOfEdge = false;
|
||||||
|
moveStored = 0;
|
||||||
|
nextMove = 1;
|
||||||
|
ignoreMaxSpeed = true;
|
||||||
|
rfrshView->start(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::updateHeight() {
|
||||||
|
container->updateHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::clear() {
|
||||||
|
container->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::scrollIndicator(int dp) {
|
||||||
|
int newY = container->y() - dp * container->height() / this->height();
|
||||||
|
if (newY > 0)
|
||||||
|
newY = 0;
|
||||||
|
else if (newY < this->height() - container->height())
|
||||||
|
newY = this->height() - container->height();
|
||||||
|
container->move(container->x(), newY);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListWidget::wheelEvent(QWheelEvent* event) {
|
||||||
|
if (container->y() > 0 || container->y() + container->height() < this->height())
|
||||||
|
return;
|
||||||
|
curSpd += 5;
|
||||||
|
bool newDirection = event->angleDelta().y() > 0;
|
||||||
|
if (newDirection != scrollDown)
|
||||||
|
curSpd = 5;
|
||||||
|
if (curSpd > MAXSPEED)
|
||||||
|
curSpd = MAXSPEED;
|
||||||
|
scrollDown = newDirection;
|
||||||
|
if (!rfrshView->isActive())
|
||||||
|
rfrshView->start(30);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollListContainer::ScrollListContainer(QWidget* parent) : QWidget(parent) {}
|
||||||
|
|
||||||
|
void ScrollListContainer::paintEvent(QPaintEvent* event) {
|
||||||
|
for (int i = 0; i < widgets.size(); i++) {
|
||||||
|
widgets[i]->resize(this->width(), widgets[i]->height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListContainer::AddWidget(QWidget* widget, bool setAnimation) {
|
||||||
|
//Add animation for all widgets current
|
||||||
|
this->resize(this->width(), this->height() + widget->height() + spacing);
|
||||||
|
widgets.push_back(widget);
|
||||||
|
size++;
|
||||||
|
ys.push_back(0);
|
||||||
|
widget->resize(this->width(), widget->height());
|
||||||
|
widget->show();
|
||||||
|
|
||||||
|
if (setAnimation) {
|
||||||
|
QGraphicsOpacityEffect* widgetOpac = new QGraphicsOpacityEffect(widget);
|
||||||
|
widgetOpac->setOpacity(0);
|
||||||
|
widget->setGraphicsEffect(widgetOpac);
|
||||||
|
QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup;
|
||||||
|
QSequentialAnimationGroup* newWidgetFadeIn = new QSequentialAnimationGroup;
|
||||||
|
for (int i = 0; i < size - 1; i++) {
|
||||||
|
ys[i] += widget->height() + spacing;
|
||||||
|
QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos");
|
||||||
|
move->setDuration(750);
|
||||||
|
move->setStartValue(widgets[i]->pos());
|
||||||
|
move->setEndValue(QPoint(widgets[i]->x(), ys[i]));
|
||||||
|
move->setEasingCurve(QEasingCurve::InOutQuart);
|
||||||
|
dpGroup->addAnimation(move);
|
||||||
|
}
|
||||||
|
newWidgetFadeIn->addPause(300);
|
||||||
|
QPropertyAnimation* fade = new QPropertyAnimation(widgetOpac, "opacity", widget);
|
||||||
|
fade->setDuration(300);
|
||||||
|
fade->setStartValue(0);
|
||||||
|
fade->setEndValue(0.99);
|
||||||
|
newWidgetFadeIn->addAnimation(fade);
|
||||||
|
dpGroup->addAnimation(newWidgetFadeIn);
|
||||||
|
dpGroup->start();
|
||||||
|
connect(dpGroup, &QPropertyAnimation::stateChanged, [=]() {
|
||||||
|
if (dpGroup->state() == QAbstractAnimation::Stopped) {
|
||||||
|
if (widgetOpac->opacity() != 0.99) {
|
||||||
|
fade->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
connect(fade, &QPropertyAnimation::finished, [=]() {widgetOpac->deleteLater(); });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dpGroup->deleteLater();
|
||||||
|
widgetOpac->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < size - 1; i++) {
|
||||||
|
ys[i] += widget->height() + spacing;
|
||||||
|
widgets[i]->move(QPoint(widgets[i]->pos().x(), ys[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListContainer::RemoveWidget(QWidget* widget) {
|
||||||
|
int index;
|
||||||
|
if (widget == nullptr) {
|
||||||
|
index = size - 1;
|
||||||
|
if (index != -1)
|
||||||
|
widget = widgets[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
index = widgets.indexOf(widget);
|
||||||
|
if (index == -1 || widget == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->resize(this->width(), this->height() - widget->height() - spacing);
|
||||||
|
this->parentWidget()->update();
|
||||||
|
widget->hide();
|
||||||
|
widget->setParent(nullptr);
|
||||||
|
QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup;
|
||||||
|
for (int i = index - 1; i >= 0; i--) {
|
||||||
|
ys[i] -= (widget->height() + spacing);
|
||||||
|
QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos");
|
||||||
|
move->setDuration(750);
|
||||||
|
move->setStartValue(widgets[i]->pos());
|
||||||
|
move->setEndValue(QPoint(widgets[i]->x(), ys[i]));
|
||||||
|
move->setEasingCurve(QEasingCurve::InOutQuart);
|
||||||
|
dpGroup->addAnimation(move);
|
||||||
|
}
|
||||||
|
dpGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
widgets.remove(index);
|
||||||
|
size--;
|
||||||
|
ys.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListContainer::updateHeight() {
|
||||||
|
for (int i = size - 2; i >= 0; i--) {
|
||||||
|
ys[i] = ys[i + 1] + widgets[i + 1]->height() + spacing;
|
||||||
|
widgets[i]->move(widgets[i]->pos().x(), ys[i]);
|
||||||
|
}
|
||||||
|
this->resize(this->width(), ys[0] + widgets[0]->height() + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListContainer::clear() {
|
||||||
|
int n = size;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
RemoveWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollListIndicator::ScrollListIndicator(QWidget* parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
this->resize(defaultWidth, 0);
|
||||||
|
hovTimer = new QTimer(this);
|
||||||
|
hovTimer->setSingleShot(true);
|
||||||
|
aniPause = new QTimer(this);
|
||||||
|
aniPause->setSingleShot(true);
|
||||||
|
QObject::connect(hovTimer, SIGNAL(timeout()), this, SLOT(setHoverActive()));
|
||||||
|
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
this->curColor = defaultColor;
|
||||||
|
|
||||||
|
this->setMouseTracking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::paintEvent(QPaintEvent* event) {
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(curColor);
|
||||||
|
painter.drawRect(this->rect());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::enterEvent(QEnterEvent* event) {
|
||||||
|
if (!pressed) {
|
||||||
|
hovTimer->start(100);
|
||||||
|
curColor = hoverColor;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::leaveEvent(QEvent* event) {
|
||||||
|
hovTimer->stop();
|
||||||
|
curColor = defaultColor;
|
||||||
|
QPropertyAnimation* narrow = new QPropertyAnimation(this, "geometry");
|
||||||
|
narrow->setDuration(300);
|
||||||
|
narrow->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
|
||||||
|
narrow->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidth, this->y(), defaultWidth, this->height()));
|
||||||
|
narrow->setEasingCurve(QEasingCurve::InOutQuad);
|
||||||
|
narrow->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
aniPause->start(300);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::mousePressEvent(QMouseEvent* event) {
|
||||||
|
curColor = pressColor;
|
||||||
|
pressed = true;
|
||||||
|
//>note: globalPos -> globalPosition here due to deprecation
|
||||||
|
//> may cause issues
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||||
|
lastY = event->globalPosition().y();
|
||||||
|
#else
|
||||||
|
lastY = event->globalPos().y();
|
||||||
|
#endif
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
if (pressed && !aniPause->isActive()) {
|
||||||
|
//>note: globalPos -> globalPosition here due to deprecation
|
||||||
|
//> may cause issues
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||||
|
int dp = event->globalPosition().y() - lastY;
|
||||||
|
#else
|
||||||
|
int dp = event->globalPos().y() - lastY;
|
||||||
|
#endif
|
||||||
|
emit scrollPage(dp);
|
||||||
|
//>note: globalPos -> globalPosition here due to deprecation
|
||||||
|
//> may cause issues
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
||||||
|
lastY = event->globalPosition().y();
|
||||||
|
#else
|
||||||
|
lastY = event->globalPos().y();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
pressed = false;
|
||||||
|
curColor = hoverColor;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollListIndicator::setHoverActive() {
|
||||||
|
QPropertyAnimation* widen = new QPropertyAnimation(this, "geometry");
|
||||||
|
widen->setDuration(300);
|
||||||
|
widen->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
|
||||||
|
widen->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidthAtFocus, this->y(), defaultWidthAtFocus, this->height()));
|
||||||
|
widen->setEasingCurve(QEasingCurve::InOutQuad);
|
||||||
|
widen->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
aniPause->start(300);
|
||||||
|
}
|
||||||
142
FinalProject/scrolllistwidget.h
Normal file
142
FinalProject/scrolllistwidget.h
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/* This Module has not yet been rewritten */
|
||||||
|
/* Behavior and performance is not guaranteed*/
|
||||||
|
/* @Linloir */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qpainter.h>
|
||||||
|
#include <qpropertyanimation.h>
|
||||||
|
#include <qparallelanimationgroup.h>
|
||||||
|
#include <qsequentialanimationgroup.h>
|
||||||
|
#include <qgraphicseffect.h>
|
||||||
|
#include <qvector.h>
|
||||||
|
#include <qevent.h>
|
||||||
|
#include <qtimer.h>
|
||||||
|
#include <qmath.h>
|
||||||
|
|
||||||
|
#define MAXSPEED 70
|
||||||
|
|
||||||
|
class ScrollListWidget;
|
||||||
|
class ScrollListContainer;
|
||||||
|
class ScrollListIndicator;
|
||||||
|
|
||||||
|
class ScrollListWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer* getCord;
|
||||||
|
QTimer* rfrshView;
|
||||||
|
|
||||||
|
ScrollListContainer* container;
|
||||||
|
ScrollListIndicator* indicator;
|
||||||
|
|
||||||
|
QPropertyAnimation* bounce;
|
||||||
|
|
||||||
|
bool pressed = false;
|
||||||
|
bool scrollDown = true;
|
||||||
|
bool outOfEdge = false;
|
||||||
|
bool ignoreMaxSpeed = false;
|
||||||
|
|
||||||
|
int strtY;
|
||||||
|
int lastY;
|
||||||
|
int bfEdgeY; //last y value before out of edge
|
||||||
|
|
||||||
|
int curSpd = 0;
|
||||||
|
int damp = 1;
|
||||||
|
int moveStored = 0;
|
||||||
|
int nextMove = 1;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
void wheelEvent(QWheelEvent* event);
|
||||||
|
void bounceBack();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ScrollListWidget(QWidget* parent = nullptr);
|
||||||
|
void addWidget(QWidget* newWidget, bool setAnimation = true);
|
||||||
|
void addWidgets(QVector<QWidget*> widgets) { for (int i = 0; i < widgets.size(); i++)addWidget(widgets[i], false); }
|
||||||
|
void removeWidget(QWidget* w = nullptr);
|
||||||
|
void scrollToTop();
|
||||||
|
void updateHeight();
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void scrollContainer();
|
||||||
|
void updateSpd();
|
||||||
|
void scrollIndicator(int dp);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScrollListContainer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ScrollListContainer(QWidget* parent = nullptr);
|
||||||
|
void AddWidget(QWidget* widget, bool setAnimation = true);
|
||||||
|
void RemoveWidget(QWidget* widget = nullptr);
|
||||||
|
void updateHeight();
|
||||||
|
void clear();
|
||||||
|
//void RemoveWidget(QWidget* widget);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//QTimer* newWidgetFade;
|
||||||
|
int spacing = 3;
|
||||||
|
QVector<QWidget*> widgets;
|
||||||
|
int size = 0;
|
||||||
|
QVector<int> ys;
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScrollListIndicator : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
QColor curColor;
|
||||||
|
QColor defaultColor = QColor(100, 100, 100, 130);
|
||||||
|
QColor hoverColor = QColor(70, 70, 70, 150);
|
||||||
|
QColor pressColor = QColor(50, 50, 50, 170);
|
||||||
|
|
||||||
|
QTimer* hovTimer;
|
||||||
|
QTimer* aniPause;
|
||||||
|
|
||||||
|
int lastY;
|
||||||
|
|
||||||
|
int defaultWidth = 2;
|
||||||
|
int defaultWidthAtFocus = 9;
|
||||||
|
int margin = 3;
|
||||||
|
|
||||||
|
bool pressed = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ScrollListIndicator(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent* event);
|
||||||
|
void enterEvent(QEnterEvent* event);
|
||||||
|
void leaveEvent(QEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void scrollPage(int);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void setHoverActive();
|
||||||
|
|
||||||
|
};
|
||||||
286
FinalProject/sidebar.cpp
Normal file
286
FinalProject/sidebar.cpp
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qfontdatabase.h>
|
||||||
|
#include <qpropertyanimation.h>
|
||||||
|
#include <qparallelanimationgroup.h>
|
||||||
|
#include <qlayoutitem.h>
|
||||||
|
|
||||||
|
#include "sidebar.h"
|
||||||
|
|
||||||
|
SideBar::SideBar(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_StyledBackground, true);
|
||||||
|
setMaximumWidth(_collapsedWidth);
|
||||||
|
|
||||||
|
// Create stylesheet
|
||||||
|
setObjectName("sideBar");
|
||||||
|
QString sideBarStyleSheet = "QWidget#sideBar{background-color:" + _backgroundColor.name(QColor::HexArgb) + "; }";
|
||||||
|
setStyleSheet(sideBarStyleSheet);
|
||||||
|
|
||||||
|
// Create main layout
|
||||||
|
_mainLayout = new QVBoxLayout(this);
|
||||||
|
_mainLayout->setSpacing(8);
|
||||||
|
_mainLayout->setContentsMargins(16, 16, 16, 16);
|
||||||
|
_mainLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
_mainLayout->addSpacing(8); // Add the top spacing between the expand button and the window edge
|
||||||
|
|
||||||
|
// Create expand button
|
||||||
|
_expandButton = new PushButton(nullptr, this);
|
||||||
|
_expandButton->setMargin(18, 16, 18, 16);
|
||||||
|
_expandButton->setIndicatorColor(QColor(255, 255, 255, 0)); // Set indicator to transparent
|
||||||
|
_expandButton->setHoverColor(QColor(0, 0, 0, 10));
|
||||||
|
_expandButton->setPressedColor(QColor(0, 0, 0, 20));
|
||||||
|
int buttonSize = _collapsedWidth - _mainLayout->contentsMargins().left() - _mainLayout->contentsMargins().right();
|
||||||
|
int buttonSizeMax = _expandedWidth - _mainLayout->contentsMargins().left() - _mainLayout->contentsMargins().right();
|
||||||
|
_expandButton->setMinimumSize(buttonSize, buttonSize);
|
||||||
|
_expandButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
|
||||||
|
_expandButtonIcon = new QLabel(_expandButton);
|
||||||
|
_expandButtonIcon->setFont(QFont("Font Awesome 6 Free Solid", 14));
|
||||||
|
_expandButtonIcon->setText("\uf0c9");
|
||||||
|
_expandButton->setChildWidget(_expandButtonIcon);
|
||||||
|
|
||||||
|
// Connect the expand button event to expand / collapse event
|
||||||
|
connect(_expandButton, &PushButton::onClick, this, [=]() {
|
||||||
|
if (_expanded) {
|
||||||
|
collapse();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expand();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add expand button to main layout
|
||||||
|
_mainLayout->addWidget(_expandButton);
|
||||||
|
_expandButton->show();
|
||||||
|
|
||||||
|
// Create the page icon button container widget
|
||||||
|
_pageIconButtonWidget = new QWidget(this);
|
||||||
|
_pageIconButtonWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
_pageIconButtonLayout = new QVBoxLayout(_pageIconButtonWidget);
|
||||||
|
_pageIconButtonLayout->setSpacing(8);
|
||||||
|
_pageIconButtonLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_pageIconButtonLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
_pageIconButtonWidget->setLayout(_pageIconButtonLayout);
|
||||||
|
|
||||||
|
// Create the page text button container widget
|
||||||
|
_pageTextButtonWidget = new QWidget(this);
|
||||||
|
_pageTextButtonWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
_pageTextButtonLayout = new QVBoxLayout(_pageTextButtonWidget);
|
||||||
|
_pageTextButtonLayout->setSpacing(8);
|
||||||
|
_pageTextButtonLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
_pageTextButtonLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
_pageTextButtonWidget->setLayout(_pageTextButtonLayout);
|
||||||
|
|
||||||
|
// Add page icon and text button container widgets to main layout
|
||||||
|
_mainLayout->addWidget(_pageIconButtonWidget);
|
||||||
|
_mainLayout->addWidget(_pageTextButtonWidget);
|
||||||
|
|
||||||
|
// Display the icon buttons
|
||||||
|
_pageIconButtonWidget->show();
|
||||||
|
_pageTextButtonWidget->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
SideBar::~SideBar() {}
|
||||||
|
|
||||||
|
void SideBar::expand() {
|
||||||
|
// Add animation to expand the side bar
|
||||||
|
QPropertyAnimation* expandAnimation = new QPropertyAnimation(this, "maximumWidth");
|
||||||
|
expandAnimation->setDuration(650);
|
||||||
|
expandAnimation->setEasingCurve(QEasingCurve::OutExpo);
|
||||||
|
expandAnimation->setStartValue(width());
|
||||||
|
expandAnimation->setEndValue(_expandedWidth);
|
||||||
|
expandAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Show the page text buttons
|
||||||
|
_pageIconButtonWidget->hide();
|
||||||
|
_pageTextButtonWidget->show();
|
||||||
|
|
||||||
|
// Set the expand state
|
||||||
|
_expanded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::collapse() {
|
||||||
|
// Add animation to collapse the side bar
|
||||||
|
QPropertyAnimation* collapseAnimation = new QPropertyAnimation(this, "maximumWidth");
|
||||||
|
collapseAnimation->setDuration(650);
|
||||||
|
collapseAnimation->setEasingCurve(QEasingCurve::OutExpo);
|
||||||
|
collapseAnimation->setStartValue(width());
|
||||||
|
collapseAnimation->setEndValue(_collapsedWidth);
|
||||||
|
collapseAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
|
||||||
|
// Show the page icon buttons
|
||||||
|
_pageIconButtonWidget->show();
|
||||||
|
_pageTextButtonWidget->hide();
|
||||||
|
|
||||||
|
// Set the expand state
|
||||||
|
_expanded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::setBackgroundColor(QColor color) {
|
||||||
|
_backgroundColor = color;
|
||||||
|
QString sideBarStyleSheet = "QWidget#sideBar{background-color:" + _backgroundColor.name(QColor::HexArgb) + "; }";
|
||||||
|
setStyleSheet(sideBarStyleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::setExpandedWidth(int width) {
|
||||||
|
if (width <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_expandedWidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::setCollapsedWidth(int width) {
|
||||||
|
if (width <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_collapsedWidth = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::selectPage(PageWidget* page) {
|
||||||
|
// Check for input validity
|
||||||
|
if (page == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deselect current page if there is one
|
||||||
|
if (_currentPage != nullptr) {
|
||||||
|
// Find the buttons of the current page
|
||||||
|
int index = _pageList.indexOf(_currentPage);
|
||||||
|
PushButton* currentPageIconButton = _pageButtonList.at(index).first;
|
||||||
|
PushButton* currentPageTextButton = _pageButtonList.at(index).second;
|
||||||
|
|
||||||
|
// Deselect both the buttons
|
||||||
|
currentPageIconButton->deselect();
|
||||||
|
currentPageTextButton->deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily store the current page
|
||||||
|
PageWidget* previousPage = _currentPage;
|
||||||
|
|
||||||
|
// Select the new page
|
||||||
|
int index = _pageList.indexOf(page);
|
||||||
|
PushButton* newPageIconButton = _pageButtonList.at(index).first;
|
||||||
|
PushButton* newPageTextButton = _pageButtonList.at(index).second;
|
||||||
|
newPageIconButton->select();
|
||||||
|
newPageTextButton->select();
|
||||||
|
_currentPage = page;
|
||||||
|
|
||||||
|
// Emit the page selected signal
|
||||||
|
emit onPageChanged(previousPage, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::addPage(PageWidget* page) {
|
||||||
|
// Call on the page's get button method to get icon button & text button
|
||||||
|
PushButton* iconButton = page->getPageIconButton(_pageIconButtonWidget);
|
||||||
|
PushButton* textButton = page->getPageTextButton(_pageTextButtonWidget);
|
||||||
|
|
||||||
|
// Store the page in the page list
|
||||||
|
_pageList.append(page);
|
||||||
|
|
||||||
|
// Store the corresponding buttons
|
||||||
|
_pageButtonList.append(QPair<PushButton*, PushButton*>(iconButton, textButton));
|
||||||
|
|
||||||
|
// Add the icon button to the icon button layout
|
||||||
|
_pageIconButtonLayout->addWidget(iconButton);
|
||||||
|
iconButton->show();
|
||||||
|
|
||||||
|
// Add the text button to the text button layout
|
||||||
|
_pageTextButtonLayout->addWidget(textButton);
|
||||||
|
textButton->show();
|
||||||
|
|
||||||
|
// Resize the buttons and set size policy to fixed
|
||||||
|
int buttonSize = _collapsedWidth - _mainLayout->contentsMargins().left() - _mainLayout->contentsMargins().right();
|
||||||
|
int buttonSizeMax = _expandedWidth - _mainLayout->contentsMargins().left() - _mainLayout->contentsMargins().right();
|
||||||
|
iconButton->setMinimumSize(buttonSize, buttonSize);
|
||||||
|
textButton->setMinimumSize(buttonSize, buttonSize);
|
||||||
|
iconButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
textButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
// Connect the button click event with page selection
|
||||||
|
connect(iconButton, &PushButton::onClick, this, [=]() {
|
||||||
|
selectPage(page);
|
||||||
|
});
|
||||||
|
connect(textButton, &PushButton::onClick, this, [=]() {
|
||||||
|
selectPage(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Select the page if there are no pages
|
||||||
|
if (_currentPage == nullptr) {
|
||||||
|
selectPage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::insertPage(PageWidget* page, int index) {
|
||||||
|
// Call on the page's get button method to get icon button & text button
|
||||||
|
PushButton* iconButton = page->getPageIconButton(_pageIconButtonWidget);
|
||||||
|
PushButton* textButton = page->getPageTextButton(_pageTextButtonWidget);
|
||||||
|
|
||||||
|
// Store the page
|
||||||
|
_pageList.insert(index, page);
|
||||||
|
|
||||||
|
// Store the corresponding buttons
|
||||||
|
_pageButtonList.insert(index, QPair<PushButton*, PushButton*>(iconButton, textButton));
|
||||||
|
|
||||||
|
// Add the icon button to the icon button layout
|
||||||
|
_pageIconButtonLayout->insertWidget(index, iconButton);
|
||||||
|
iconButton->show();
|
||||||
|
|
||||||
|
// Add the text button to the text button layout
|
||||||
|
_pageTextButtonLayout->insertWidget(index, textButton);
|
||||||
|
textButton->show();
|
||||||
|
|
||||||
|
// Resize the buttons and set size policy to fixed
|
||||||
|
int buttonSize = _collapsedWidth - _mainLayout->contentsMargins().left() - _mainLayout->contentsMargins().right();
|
||||||
|
int buttonSizeMax = _expandedWidth - _mainLayout->contentsMargins().left() - _mainLayout->contentsMargins().right();
|
||||||
|
iconButton->setMinimumSize(buttonSize, buttonSize);
|
||||||
|
textButton->setMinimumSize(buttonSize, buttonSize);
|
||||||
|
iconButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
textButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
// Connect the button click event with page selection
|
||||||
|
connect(iconButton, &PushButton::onClick, this, [=]() {
|
||||||
|
selectPage(page);
|
||||||
|
});
|
||||||
|
connect(textButton, &PushButton::onClick, this, [=]() {
|
||||||
|
selectPage(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Select the page if there are no pages
|
||||||
|
if (_currentPage == nullptr) {
|
||||||
|
selectPage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SideBar::removePage(PageWidget* page) {
|
||||||
|
// Get the index of the page from the page list
|
||||||
|
int index = _pageList.indexOf(page);
|
||||||
|
|
||||||
|
// Get the corresponding buttons
|
||||||
|
PushButton* iconButton = _pageButtonList.at(index).first;
|
||||||
|
PushButton* textButton = _pageButtonList.at(index).second;
|
||||||
|
|
||||||
|
// Remove the page from the list
|
||||||
|
_pageList.removeAt(index);
|
||||||
|
|
||||||
|
// Remove the icon and text buttons from the list
|
||||||
|
_pageButtonList.removeAt(index);
|
||||||
|
|
||||||
|
// Remove the icon button from the icon button layout
|
||||||
|
_pageIconButtonLayout->removeWidget(iconButton);
|
||||||
|
iconButton->hide();
|
||||||
|
|
||||||
|
// Remove the text button from the text button layout
|
||||||
|
_pageTextButtonLayout->removeWidget(textButton);
|
||||||
|
textButton->hide();
|
||||||
|
|
||||||
|
// Select the first page if the current page is the page being removed
|
||||||
|
if (_currentPage == page) {
|
||||||
|
if (_pageList.size() > 0) {
|
||||||
|
selectPage(_pageList.first());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_currentPage = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
FinalProject/sidebar.h
Normal file
63
FinalProject/sidebar.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qcolor.h>
|
||||||
|
#include <qmap.h>
|
||||||
|
#include <qlist.h>
|
||||||
|
|
||||||
|
#include "pushbutton.h"
|
||||||
|
#include "pagewidget.h"
|
||||||
|
|
||||||
|
class SideBar : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SideBar(QWidget* parent = 0);
|
||||||
|
~SideBar();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Initialized flag
|
||||||
|
bool _initialized = false;
|
||||||
|
|
||||||
|
// UI control variables
|
||||||
|
QColor _backgroundColor = QColor(230, 230, 230);
|
||||||
|
int _collapsedWidth = 86;
|
||||||
|
int _expandedWidth = 200;
|
||||||
|
|
||||||
|
// UI widgets
|
||||||
|
PushButton* _expandButton;
|
||||||
|
QLabel* _expandButtonIcon;
|
||||||
|
QVBoxLayout* _mainLayout = nullptr; // Layout expand icon and page selection buttons
|
||||||
|
QWidget* _pageIconButtonWidget = nullptr; // Container for page icon buttons
|
||||||
|
QVBoxLayout* _pageIconButtonLayout = nullptr; // Layout page icon buttons
|
||||||
|
QWidget* _pageTextButtonWidget = nullptr; // Container for page text buttons
|
||||||
|
QVBoxLayout* _pageTextButtonLayout = nullptr; // Layout page text buttons
|
||||||
|
|
||||||
|
// Interaction controls
|
||||||
|
bool _expanded = false;
|
||||||
|
PageWidget* _currentPage = nullptr;
|
||||||
|
|
||||||
|
// State storage
|
||||||
|
// QMap<PageWidget*, QPair<PushButton*, PushButton*>> _pageButtonMap;
|
||||||
|
QList<PageWidget*> _pageList;
|
||||||
|
QList<QPair<PushButton*, PushButton*>> _pageButtonList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void expand();
|
||||||
|
void collapse();
|
||||||
|
void selectPage(PageWidget* page);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setBackgroundColor(QColor color);
|
||||||
|
void setCollapsedWidth(int width);
|
||||||
|
void setExpandedWidth(int width);
|
||||||
|
void addPage(PageWidget* page);
|
||||||
|
void insertPage(PageWidget* page, int index);
|
||||||
|
void removePage(PageWidget* page);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onPageChanged(PageWidget* previousPage, PageWidget* currentPage);
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user