diff --git a/README.md b/README.md index 17aa909..558e3a6 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,39 @@ # CustomTitlebar -CustomTitlebar é um projeto cuja classe principal (NMainWindow) deriva da classe QMainWindow da biblioteca Qt. -Ao derivar a janela principal da classe NMainWindow, você poderá desenvolver programas que usarão bordas personalizadas (não geradas pelo SO) - veja as capturas de tela para maiores detalhes. +CustomTitlebar is a project where the main class (QCustomWindow) inherits its properties from QMainWindow, part of Qt Library. +Inheriting the main window from the QCustomWindow class, will allow you to develop programs which will use customized borders (not generated by the OS) - have a look at the screenshots for major details. -## Suporte e Documentação +

+ +

-Você poderá obter o suporte e documentação para o uso deste projeto em sua [página no site da Nintersoft](https://www.nintersoft.com/portfolio/custom-titlebar/) ou ainda em sua [página de documentação](https://docwiki.nintersoft.com/custom-titlebar/). - -## Características: -- Redimensionável (100% funcional) -- Botões personalizáveis -- Atualização do título da janela (QMainWindow::setWindowTitle(QString)) funcionando; - -Código aberto CustomTitlebar -- Você poderá baixar e fazer suas modificações à vontade, conforme a Licença Pública Mozilla (MPL) v2.0. -- A licença está disponível na raiz da pasta do projeto. - -Caso importe este repositório para seu Git, por favor coloque um link para nossa página e as referências cabíveis à nossa equipe, além de manter o README original. +## Support and Documentation -Atenciosamente, -Mauro Mascarenhas - Nintersoft. +Docs elaboration is still in progress :( ... +Should you have any doubts, do not hesitate in contacting me through [my email](mailto:mauro.mascarenhas@nintersoft.com). -## EN +## Features: -# CustomTitlebar +- Customized stylesheet (light theme); +- Resizeable (100% functional); +- Window title update (QMainWindow::setWindowTitle(QString)) working properly; +- Better performance (when compared to previous versions); +- QTabWidgets and QDockWidgets working properly; +- QMenuBar/menu widget can be through QCustomWindow methods (DO NOT CALL IT THROUGH ITS PARENT (QMAINWINDOW) METHODS); +- Available as a Dynamically Linked Library (DLL). -CustomTitlebar is a project where the main class (NMainWindow) inherits its properties from QMainWindow, which is part of Qt Library. -Inheriting the main window from the NMainWindow class, will allow you to develop programs which will use customized borders (not generated by the OS) - have a look at the screenshots for major details. +## Limitations: -## Support and Documentation +- It is not recommended to change QToolBar's stylesheet (after it has been added to the QCustomWindow's layout), since the auto-generated one plays and important role in the layout disposition; +- Setting the menu bar/widget through QMainWindow's methods will possibly crash the application (so, it is not possible to generate it through Qt Designer). Should you do that, the window's titlebar is going to be removed and every reference to it is going to break (since the widget gets deleted); -You are able to get the proper support and documentation in order to use this project on its [page at Nintersoft's website](https://www.nintersoft.com/en/portfolio/custom-titlebar/) or yet on its [documentation page](https://docwiki.nintersoft.com/en/custom-titlebar/). +## Distribution (available versions): -## Features: -- Resizeable (100% functional) -- BotõesCustomizable buttons -- Window title update (QMainWindow::setWindowTitle(QString)) working properly; +- [x] DLL + LIB + headers; +- [x] Stactic linking/source files; +- [ ] Qt Creator/Designer plugin; ## CustomTitlebar open source code -- You can download and make some modifications in the source code, according to Mozilla Public Licence v2.0. -- The licence is available in the root of the project folder. - -If you clone this directory into yours, please insert a linkback to our webpage and the correct references to our team, also leaving the original README in your repository. -Graciously, -Mauro Mascarenhas - Nintersoft. +- You can download and make modifications in the source code, accordingly to Mozilla Public Licence v2.0 terms. +- The licence is available in the root of the project folder and must be always shipped with it. diff --git a/sample/CustomFrame-Dynamic/CustomFrameTestIn.pro b/sample/CustomFrame-Dynamic/CustomFrameTestIn.pro index d23231d..539c2f7 100644 --- a/sample/CustomFrame-Dynamic/CustomFrameTestIn.pro +++ b/sample/CustomFrame-Dynamic/CustomFrameTestIn.pro @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -43,5 +43,5 @@ HEADERS += testwindow.h FORMS += testwindow.ui -win32:CONFIG(release, debug|release): LIBS += -L$$PWD/customtitlebar/ -lCustomTitlebar -else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/customtitlebar/ -lCustomTitlebar +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/customtitlebar/ -lQCustomTitlebar +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/customtitlebar/ -lQCustomTitlebar diff --git a/sample/CustomFrame-Dynamic/customtitlebar/CustomTitlebar.dll b/sample/CustomFrame-Dynamic/customtitlebar/CustomTitlebar.dll deleted file mode 100644 index 393d2a2..0000000 Binary files a/sample/CustomFrame-Dynamic/customtitlebar/CustomTitlebar.dll and /dev/null differ diff --git a/sample/CustomFrame-Dynamic/customtitlebar/CustomTitlebar.lib b/sample/CustomFrame-Dynamic/customtitlebar/CustomTitlebar.lib deleted file mode 100644 index 842282b..0000000 Binary files a/sample/CustomFrame-Dynamic/customtitlebar/CustomTitlebar.lib and /dev/null differ diff --git a/sample/CustomFrame-Dynamic/customtitlebar/nmainwindow.h b/sample/CustomFrame-Dynamic/customtitlebar/nmainwindow.h deleted file mode 100644 index 55ea5cb..0000000 --- a/sample/CustomFrame-Dynamic/customtitlebar/nmainwindow.h +++ /dev/null @@ -1,86 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef NMAINWINDOW_H -#define NMAINWINDOW_H - -#include - -#if defined(CUSTOMTITLEBAR_LIBRARY) -# define CUSTOMTITLEBARSHARED_EXPORT Q_DECL_EXPORT -#else -# define CUSTOMTITLEBARSHARED_EXPORT Q_DECL_IMPORT -#endif - -#include -#include -#include -#include - -#include "titlebar.h" - -namespace Ui { -class NMainWindow; -} - -class CUSTOMTITLEBARSHARED_EXPORT NMainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit NMainWindow(QWidget *parent = nullptr); - ~NMainWindow(); - - void setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar); - void setNewCentralWidget(QWidget *newCentralWidget); - void setCustomStatusBar(QStatusBar *newStatusBar); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - - void setTitlebarStylesheet(const QString &styleSheet); - QString titlebarStylesheet() const; - -protected: - void closeEvent(QCloseEvent *event); - - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void undefMouseMoveEvent(QObject *object, QMouseEvent* event); - bool eventFilter(QObject *watched, QEvent *event); - - enum LockMoveType{ - Left, - Right, - Top, - Bottom, - TopLeft, - TopRight, - BottomLeft, - BottomRight, - None - }; - -private: - Ui::NMainWindow *ui; - const int RESIZE_LIMIT; - - QPoint posCursor; - LockMoveType locked; -}; - -#endif // NMAINWINDOW_H diff --git a/sample/CustomFrame-Dynamic/customtitlebar/qcustomwindow.h b/sample/CustomFrame-Dynamic/customtitlebar/qcustomwindow.h new file mode 100644 index 0000000..84cb2de --- /dev/null +++ b/sample/CustomFrame-Dynamic/customtitlebar/qcustomwindow.h @@ -0,0 +1,92 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 24 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QCUSTOMWINDOW_H +#define QCUSTOMWINDOW_H + +#include + +#if defined(QCUSTOMTITLEBAR_LIBRARY) +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_EXPORT +#else +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_IMPORT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qtitlebar.h" + +class QCUSTOMTITLEBARSHARED_EXPORT QCustomWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit QCustomWindow(QWidget *parent = nullptr); + ~QCustomWindow() override; + + QMenu * createPopupMenu() override; + + void setMenuBar(QMenuBar *menuBar); + QMenuBar * menuBar() const; + + void setMenuWidget(QWidget *widget); + QWidget * menuWidget() const; + + inline QTitleBar& titleBar() const { return *this->m_titleBar; } + +protected: + const int RESIZE_LIMIT; + + bool event(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; + + void customMouseMoveEvent(QMouseEvent* event); + +private: + bool init; + + QWidget *m_titleBarW; + QWidget *m_menuWidget; + QMenuBar *m_menuBar; + QTitleBar *m_titleBar; + + QToolBar *m_leftBorder; + QToolBar *m_rightBorder; + QToolBar *m_bottomBorder; + + Qt::Edges m_lock; + QPoint m_posCursor; + + QToolBar * generateBorder(Qt::ToolBarArea area, Qt::Orientation orientation); +}; + +#endif // QCUSTOMWINDOW_H diff --git a/sample/CustomFrame-Dynamic/customtitlebar/qtitlebar.h b/sample/CustomFrame-Dynamic/customtitlebar/qtitlebar.h new file mode 100644 index 0000000..58f4d0e --- /dev/null +++ b/sample/CustomFrame-Dynamic/customtitlebar/qtitlebar.h @@ -0,0 +1,97 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 24 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QTITLEBAR_H +#define QTITLEBAR_H + +#include + +#if defined(QCUSTOMTITLEBAR_LIBRARY) +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_EXPORT +#else +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_IMPORT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace QCustomAttrs { + enum WindowButton { + Minimize = 0x01, + Maximize = 0x02, + Close = 0x04, + All = Minimize | Maximize | Close + }; + + Q_DECLARE_FLAGS(WindowButtons, WindowButton) + Q_DECLARE_OPERATORS_FOR_FLAGS(WindowButtons) +} + +class QCUSTOMTITLEBARSHARED_EXPORT QTitleBar : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QCustomAttrs::WindowButtons windowButtons READ windowButtons WRITE setWindowButtons) + Q_CLASSINFO("custom_obj_type", "QTitleBar") +public: + explicit QTitleBar(QMainWindow *parent = nullptr); + + void setWindowButtons(QCustomAttrs::WindowButtons btns); + inline QCustomAttrs::WindowButtons windowButtons() const { return this->m_frameButtons; } + + void setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled = true); + +protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + +private: + bool canMove; + bool maximizing; + + QPoint m_pCursor; + const QSize FRAME_BUTTON_SIZE; + + QWidget *m_parentWindow; + + QCustomAttrs::WindowButtons m_frameButtons; + + QLabel lbl_windowTitle; + QHBoxLayout m_layout; + QPushButton btn_minimize; + QPushButton btn_maximize; + QPushButton btn_close; + +signals: + void requestClose(); + void requestMaximize(); + void requestMinimize(); +}; + +#endif // QTITLEBAR_H diff --git a/sample/CustomFrame-Dynamic/customtitlebar/titlebar.h b/sample/CustomFrame-Dynamic/customtitlebar/titlebar.h deleted file mode 100644 index 2c170d4..0000000 --- a/sample/CustomFrame-Dynamic/customtitlebar/titlebar.h +++ /dev/null @@ -1,65 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef TITLEBAR_H -#define TITLEBAR_H - -#include -#include -#include -#include - -namespace Ui { -class TitleBar; -} - -class TitleBar : public QWidget -{ - Q_OBJECT - -public: - explicit TitleBar(QWidget *parent = nullptr); - ~TitleBar(); - - void setMainWindow(QWidget *mainWindow); - QWidget* mainWindow(); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - -private: - bool canMove; - - Ui::TitleBar *ui; - QWidget *parent; - QPoint m_pCursor; - -protected: - void paintEvent(QPaintEvent *); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - -protected slots: - void maximizeParent(); - void onCloseRequest(); - -signals: - void closeRequest(); -}; - -#endif // TITLEBAR_H diff --git a/sample/CustomFrame-Dynamic/main.cpp b/sample/CustomFrame-Dynamic/main.cpp index 153b157..6154b5e 100644 --- a/sample/CustomFrame-Dynamic/main.cpp +++ b/sample/CustomFrame-Dynamic/main.cpp @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # diff --git a/sample/CustomFrame-Dynamic/testwindow.cpp b/sample/CustomFrame-Dynamic/testwindow.cpp index 9493aa2..d71831a 100644 --- a/sample/CustomFrame-Dynamic/testwindow.cpp +++ b/sample/CustomFrame-Dynamic/testwindow.cpp @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -18,19 +18,24 @@ #include "ui_testwindow.h" TestWindow::TestWindow(QWidget *parent) : - NMainWindow(parent), + QCustomWindow(parent), ui(new Ui::TestWindow) { ui->setupUi(this); + // A simple test to check if QTitleBar has been successfully exported + this->titleBar().setWindowButtonEnabled(QCustomAttrs::Maximize, false); - // Sets the custom Widgets on the parent Class - // Otherwise, the window resizing feature will not work - NMainWindow::setCustomWidgets(ui->centralWidget, ui->statusBar); + /* + * QMenuBar should never be inserted using Qt Designer. + * Insert them manually instead setMenuBar(QMenuBar*) + * and setMenuWidget(QWidget*) have been reimplemented. + */ clicks = 0; connect(ui->pushButton, &QPushButton::clicked, [this]{ setWindowTitle("Number of clicks : " + QString::number(++clicks)); }); + this->setMinimumSize(500, 400); } TestWindow::~TestWindow() diff --git a/sample/CustomFrame-Dynamic/testwindow.h b/sample/CustomFrame-Dynamic/testwindow.h index 40c7d03..cdba79e 100644 --- a/sample/CustomFrame-Dynamic/testwindow.h +++ b/sample/CustomFrame-Dynamic/testwindow.h @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -19,13 +19,14 @@ #include -#include "nmainwindow.h" +#include "qtitlebar.h" +#include "qcustomwindow.h" namespace Ui { class TestWindow; } -class TestWindow : public NMainWindow +class TestWindow : public QCustomWindow { Q_OBJECT diff --git a/sample/CustomFrame-Static/CustomFrameTestIn.pro b/sample/CustomFrame-Static/CustomFrameTestIn.pro index fc4fd77..838876c 100644 --- a/sample/CustomFrame-Static/CustomFrameTestIn.pro +++ b/sample/CustomFrame-Static/CustomFrameTestIn.pro @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -36,17 +36,14 @@ INCLUDEPATH += $$PWD/customtitlebar DEPENDPATH += $$PWD/customtitlebar SOURCES += \ - customtitlebar/nmainwindow.cpp \ - customtitlebar/titlebar.cpp \ + customtitlebar/qcustomwindow.cpp \ + customtitlebar/qtitlebar.cpp \ testwindow.cpp \ main.cpp HEADERS += \ - customtitlebar/nmainwindow.h \ - customtitlebar/titlebar.h \ + customtitlebar/qcustomwindow.h \ + customtitlebar/qtitlebar.h \ testwindow.h -FORMS += \ - customtitlebar/nmainwindow.ui \ - customtitlebar/titlebar.ui \ - testwindow.ui +FORMS += testwindow.ui diff --git a/sample/CustomFrame-Static/customtitlebar/nmainwindow.cpp b/sample/CustomFrame-Static/customtitlebar/nmainwindow.cpp deleted file mode 100644 index 68ac9dd..0000000 --- a/sample/CustomFrame-Static/customtitlebar/nmainwindow.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#include "nmainwindow.h" -#include "ui_nmainwindow.h" - -NMainWindow::NMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::NMainWindow), - RESIZE_LIMIT(2) -{ - ui->setupUi(this); - setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); - centralWidget()->installEventFilter(this); - ui->titleBar->installEventFilter(this); - ui->statusBar->installEventFilter(this); - - centralWidget()->setMouseTracking(true); - ui->titleBar->setMouseTracking(true); - ui->statusBar->setMouseTracking(true); - - setWindowTitle("Custom Window Border"); - locked = LockMoveType::None; - - ui->headerWidget->setTitleBarWidget(ui->titleBar); - if (ui->titleBar->mainWindow() != this) - ui->titleBar->setMainWindow(this); - - if (this->maximumSize() == this->minimumSize()) - setMaximizeButtonEnabled(false); - - connect(ui->titleBar, &TitleBar::closeRequest, this, &NMainWindow::close); -} - -NMainWindow::~NMainWindow() -{ - delete ui; -} - -void NMainWindow::setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar){ - setCustomStatusBar(newStatusBar); - setNewCentralWidget(newCentralWidget); -} - -void NMainWindow::setCustomStatusBar(QStatusBar *newStatusBar){ - if (!newStatusBar) return; - newStatusBar->installEventFilter(this); - newStatusBar->setMouseTracking(true); -} - -void NMainWindow::setNewCentralWidget(QWidget *newCentralWidget){ - if (!newCentralWidget) return; - newCentralWidget->installEventFilter(this); - newCentralWidget->setMouseTracking(true); - - if (newCentralWidget->layout()) - newCentralWidget->layout()->setContentsMargins(10, 0, 10, 0); -} - -void NMainWindow::setCloseButtonEnabled(bool enable){ - ui->titleBar->setCloseButtonEnabled(enable); -} - -void NMainWindow::setMaximizeButtonEnabled(bool enable){ - ui->titleBar->setMaximizeButtonEnabled(enable); -} - -void NMainWindow::setMinimizeButtonEnabled(bool enable){ - ui->titleBar->setMinimizeButtonEnabled(enable); -} - -void NMainWindow::setTitlebarStylesheet(const QString &styleSheet){ - ui->titleBar->setStyleSheet(styleSheet); -} - -QString NMainWindow::titlebarStylesheet() const { - return ui->titleBar->styleSheet(); -} - -void NMainWindow::closeEvent(QCloseEvent *event){ - if (event->isAccepted()) QMainWindow::closeEvent(event); - else event->ignore(); -} - -/* - * GUI Protected Methods (do not change them, unless it's really necessary) - */ - -void NMainWindow::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - int x = event->x(), y = event->y(), bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; - if (x < RESIZE_LIMIT && y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topLeft(); - locked = LockMoveType::TopLeft; - } - else if (x < RESIZE_LIMIT && y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomLeft(); - locked = LockMoveType::BottomLeft; - } - else if (x > right && y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topRight(); - locked = LockMoveType::TopRight; - } - else if (x > right && y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomRight(); - locked = LockMoveType::BottomRight; - } - else if (x < RESIZE_LIMIT || y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topLeft(); - locked = x < RESIZE_LIMIT ? LockMoveType::Left : LockMoveType::Top; - } - else if (x > right || y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomRight(); - locked = x > right ? LockMoveType::Right : LockMoveType::Bottom; - } - event->accept(); - } -} - -void NMainWindow::undefMouseMoveEvent(QObject* object, QMouseEvent* event){ - if (locked != LockMoveType::None){ - switch (locked) { - case LockMoveType::TopLeft: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), event->globalPos().y() - posCursor.y()), - this->geometry().bottomRight())); - break; - case LockMoveType::TopRight: - this->setGeometry(QRect(QPoint(this->geometry().left(), event->globalPos().y() - posCursor.y()), - QPoint(event->globalPos().x() - posCursor.x(), this->geometry().bottom()))); - break; - case LockMoveType::BottomLeft: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), this->geometry().top()), - QPoint(this->geometry().right(), event->globalPos().y() - posCursor.y()))); - break; - case LockMoveType::BottomRight: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(event->globalPos().x() - posCursor.x(), event->globalPos().y() - posCursor.y()))); - break; - case LockMoveType::Left: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), this->geometry().top()), - this->geometry().bottomRight())); - break; - case LockMoveType::Right: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(event->globalPos().x() - posCursor.x(), this->geometry().bottom()))); - break; - case LockMoveType::Top: - this->setGeometry(QRect(QPoint(this->geometry().left(), event->globalPos().y() - posCursor.y()), - this->geometry().bottomRight())); - break; - default: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(this->geometry().right(), event->globalPos().y() - posCursor.y()))); - break; - } - return; - } - - int x = event->x(), y = event->y(), right = this->width() - RESIZE_LIMIT; - if (object->objectName() == "statusBar"){ - if (x < RESIZE_LIMIT && y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeBDiagCursor)); - return; - } - else if (x > right && y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeFDiagCursor)); - return; - } - else if (y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeVerCursor)); - return; - } - } - else if (object->objectName() == "titleBar"){ - if (x < RESIZE_LIMIT && y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeFDiagCursor)); - return; - } - if (x > right && y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeBDiagCursor)); - return; - } - else if (y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeVerCursor)); - return; - } - } - - this->setCursor(QCursor(x < RESIZE_LIMIT || x > right ? Qt::SizeHorCursor : Qt::ArrowCursor)); -} - -void NMainWindow::mouseReleaseEvent(QMouseEvent *event){ - locked = LockMoveType::None; - event->accept(); -} - -bool NMainWindow::eventFilter(QObject* object, QEvent* event) -{ - if(event->type() == QEvent::MouseMove) - undefMouseMoveEvent(object, static_cast(event)); - else if (event->type() == QEvent::MouseButtonPress && object->objectName() == "titleBar") - mousePressEvent(static_cast(event)); - return false; -} diff --git a/sample/CustomFrame-Static/customtitlebar/nmainwindow.h b/sample/CustomFrame-Static/customtitlebar/nmainwindow.h deleted file mode 100644 index 6e06456..0000000 --- a/sample/CustomFrame-Static/customtitlebar/nmainwindow.h +++ /dev/null @@ -1,78 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef NMAINWINDOW_H -#define NMAINWINDOW_H - -#include -#include -#include -#include - -#include "titlebar.h" - -namespace Ui { -class NMainWindow; -} - -class NMainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit NMainWindow(QWidget *parent = nullptr); - ~NMainWindow(); - - void setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar); - void setNewCentralWidget(QWidget *newCentralWidget); - void setCustomStatusBar(QStatusBar *newStatusBar); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - - void setTitlebarStylesheet(const QString &styleSheet); - QString titlebarStylesheet() const; - -protected: - void closeEvent(QCloseEvent *event); - - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void undefMouseMoveEvent(QObject *object, QMouseEvent* event); - bool eventFilter(QObject *watched, QEvent *event); - - enum LockMoveType{ - Left, - Right, - Top, - Bottom, - TopLeft, - TopRight, - BottomLeft, - BottomRight, - None - }; - -private: - Ui::NMainWindow *ui; - const int RESIZE_LIMIT; - - QPoint posCursor; - LockMoveType locked; -}; - -#endif // NMAINWINDOW_H diff --git a/sample/CustomFrame-Static/customtitlebar/nmainwindow.ui b/sample/CustomFrame-Static/customtitlebar/nmainwindow.ui deleted file mode 100644 index bdc7d03..0000000 --- a/sample/CustomFrame-Static/customtitlebar/nmainwindow.ui +++ /dev/null @@ -1,144 +0,0 @@ - - - NMainWindow - - - - 0 - 0 - 400 - 300 - - - - ArrowCursor - - - NMainWindow - - - QWidget#titleBar{ - background-color: #FFF; - border-top: 1px solid orange; - border-left: 1px solid orange; - border-right: 1px solid orange; - color: #000; -} - -QDockWidget#headerWidget, QDockWidget#headerWidget::title{ - background-color: #FFF; - border-top: 1px solid orange; - border-left: 1px solid orange; - border-right: 1px solid orange; - color: #000; -} - -QWidget#centralWidget, QWidget#headerWidgetContents, QStatusBar{ - background-color: #FFF; - border-left: 1px solid orange; - border-right: 1px solid orange; -} - -QMainWindow::separator { - background-color: #FFF; - background: #FFF; - border-left: 1px solid orange; - border-right: 1px solid orange; - height: 0px; -} - -QStatusBar{ - border-bottom: 1px solid orange; -} - - - - - 10 - - - 0 - - - 10 - - - 0 - - - 0 - - - - - - - - 36 - 35 - - - - - 524287 - 35 - - - - QDockWidget::NoDockWidgetFeatures - - - Qt::TopDockWidgetArea - - - 4 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 35 - - - - - 16777215 - 35 - - - - - - - - - - - - TitleBar - QWidget -
titlebar.h
- 1 -
-
- - -
diff --git a/sample/CustomFrame-Static/customtitlebar/qcustomwindow.cpp b/sample/CustomFrame-Static/customtitlebar/qcustomwindow.cpp new file mode 100644 index 0000000..88611d2 --- /dev/null +++ b/sample/CustomFrame-Static/customtitlebar/qcustomwindow.cpp @@ -0,0 +1,276 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#include "qcustomwindow.h" + +QCustomWindow::QCustomWindow(QWidget *parent) : + QMainWindow(parent), RESIZE_LIMIT(4) +{ + setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); + + this->setMinimumSize(QSize(256, 64)); + this->setStyleSheet(QStringLiteral( + "\nQCustomWindow {\n" + " background : white;\n" + " border : 1px solid orange;\n" + "}\n" + "QStatusBar {\n" + " background : white;\n" + " border-bottom: 1px solid orange;\n" + " border-left: 1px solid orange;\n" + " border-right: 1px solid orange;\n" + "}\n" + "QToolBar {\n" + " margin : 1px;\n" + "}" + )); + + this->m_titleBar = new QTitleBar(this); + connect(this->m_titleBar, &QTitleBar::requestClose, + this, &QCustomWindow::close); + connect(this->m_titleBar, &QTitleBar::requestMaximize, [this]{ + if (this->isMaximized()) this->showNormal(); + else this->showMaximized(); + }); + connect(this->m_titleBar, &QTitleBar::requestMinimize, + this, &QCustomWindow::showMinimized); + connect(this, &QMainWindow::windowTitleChanged, this->m_titleBar, + &QWidget::setWindowTitle); + + this->m_titleBarW = new QWidget(); + this->m_titleBarW->setMouseTracking(true); + this->m_titleBarW->installEventFilter(this); + + QVBoxLayout *titleLayout = new QVBoxLayout(); + titleLayout->setContentsMargins(6, 6, 6, 0); + titleLayout->setSpacing(0); + titleLayout->addWidget(this->m_titleBar); + + this->m_titleBarW->setLayout(titleLayout); + QMainWindow::setMenuWidget(this->m_titleBarW); + + this->m_leftBorder = generateBorder(Qt::LeftToolBarArea, Qt::Vertical); + this->m_rightBorder = generateBorder(Qt::RightToolBarArea, Qt::Vertical); + this->m_bottomBorder = generateBorder(Qt::BottomToolBarArea, Qt::Horizontal); + + this->m_menuBar = nullptr; + this->m_menuWidget = nullptr; +} + +QCustomWindow::~QCustomWindow(){ + delete this->m_titleBar; + delete this->m_leftBorder; + delete this->m_rightBorder; + delete this->m_bottomBorder; + + if (this->m_menuBar) delete this->m_menuBar; + else if (this->m_menuWidget) delete this->m_menuWidget; +} + +QToolBar *QCustomWindow::generateBorder(Qt::ToolBarArea area, + Qt::Orientation orientation){ + QToolBar *border = new QToolBar("___border___"); + border->setStyleSheet( + "\nQToolBar {\n" + " margin : 1px;\n" + " border : 0px;\n" + " background : transparent;\n" + "}" + ); + + if (orientation & Qt::Horizontal){ + border->setMinimumHeight(6); + border->setMaximumHeight(6); + } + else { + border->setMinimumWidth(6); + border->setMaximumWidth(6); + } + border->setMovable(false); + border->setFloatable(false); + border->setAllowedAreas(area); + border->setMouseTracking(true); + border->installEventFilter(this); + + this->addToolBar(area, border); + return border; +} + +QMenu * QCustomWindow::createPopupMenu(){ + QMenu *menu = QMainWindow::createPopupMenu(); + QList removal; + foreach (QAction *a, menu->actions()) + if (a->text() == "___border___") removal.append(a); + foreach (QAction *a, removal) menu->removeAction(a); + return menu; +} + +void QCustomWindow::setMenuBar(QMenuBar *menuBar){ + if (this->m_menuBar == menuBar) return; + + if (this->m_menuBar) { + if (this->m_menuBar != this->m_menuWidget && this->m_menuWidget){ + this->m_menuWidget->setParent(nullptr); + this->m_menuWidget->deleteLater(); + } + + this->m_menuBar->hide(); + this->m_menuBar->setParent(nullptr); + this->m_menuBar->deleteLater(); + } + + this->m_menuBar = menuBar; + this->m_menuWidget = qobject_cast(menuBar); + + if (menuBar){ + menuBar->setParent(this); + this->m_titleBarW->layout()->addWidget(menuBar); + } +} + +QMenuBar* QCustomWindow::menuBar() const{ + return this->m_menuBar; +} + +void QCustomWindow::setMenuWidget(QWidget *widget){ + if (this->m_menuWidget == widget) return; + + widget->setParent(this); + + if (this->m_menuWidget){ + this->m_menuWidget->hide(); + this->m_menuWidget->setParent(nullptr); + this->m_menuWidget->deleteLater(); + } + + this->m_menuBar = nullptr; + this->m_menuWidget = widget; + + if (this->m_menuWidget){ + this->m_menuWidget->setParent(this); + this->m_titleBarW->layout()->addWidget(widget); + } +} + +QWidget * QCustomWindow::menuWidget() const{ + return this->m_menuWidget; +} + +bool QCustomWindow::eventFilter(QObject*, QEvent *event){ + if (event->type() == QEvent::MouseMove) + customMouseMoveEvent(static_cast(event)); + else if (event->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(event)); + return false; +} + +bool QCustomWindow::event(QEvent *event){ + if (event->type() == QEvent::ChildRemoved){ + QChildEvent *evt = static_cast(event); + if (evt->child()->isWidgetType()) evt->child()->removeEventFilter(this); + } + else if (event->type() == QEvent::ChildAdded){ + QChildEvent *evt = static_cast(event); + if (evt->child()->isWidgetType()){ + QWidget *child = qobject_cast(evt->child()); + + child->setMouseTracking(true); + child->installEventFilter(this); + + if (child->metaObject()->indexOfClassInfo("custom_obj_type") == -1){ + child->setStyleSheet(child->styleSheet() + + "\nQToolBar {\n" + " margin : 1px;\n" + " padding: 0px 6px 0px 6px;\n" + " border: 1px transparent solid;" + "}\n" + "QToolBar:top:first, QToolBar:bottom:first, QToolBar:left:first {\n" + " margin : 0px 0px 0px 6px;\n" + "}\n" + "QToolBar:top:only-one, QToolBar:bottom:only-one {\n" + " margin : 0px 6px 0px 6px;\n" + "}\n" + "QToolBar:top:last, QToolBar:bottom:last, QToolBar:right:last {\n" + " margin : 0px 6px 0px 0px;\n" + "}\n"); + } + } + } + return QMainWindow::event(event); +} + +void QCustomWindow::mousePressEvent(QMouseEvent *event){ + if (event->button() & Qt::LeftButton){ + int x = event->x(), y = event->y(); + int bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; + + QPoint posCursor = event->globalPos(); + Qt::Edges nFlags = {}; + if (x < RESIZE_LIMIT) { + nFlags |= Qt::LeftEdge; + posCursor.rx() -= this->x(); + } + if (y < RESIZE_LIMIT) { + nFlags |= Qt::TopEdge; + posCursor.ry() -= this->y(); + } + if (x > right) { + nFlags |= Qt::RightEdge; + posCursor.rx() -= (this->x() + this->width()); + } + if (y > bottom) { + nFlags |= Qt::BottomEdge; + posCursor.ry() -= (this->y() + this->height()); + } + this->m_lock = nFlags; + this->m_posCursor = posCursor; + } + QMainWindow::mousePressEvent(event); +} + +void QCustomWindow::mouseReleaseEvent(QMouseEvent *event){ + this->m_lock = {}; + this->unsetCursor(); + QMainWindow::mouseMoveEvent(event); +} + +void QCustomWindow::customMouseMoveEvent(QMouseEvent *event){ + if (this->m_lock){ + QPoint tL = this->geometry().topLeft(), bR = this->geometry().bottomRight(); + if (this->m_lock & Qt::TopEdge) tL.ry() = event->globalY() - this->m_posCursor.y(); + if (this->m_lock & Qt::BottomEdge) bR.ry() = event->globalY() - this->m_posCursor.y(); + if (this->m_lock & Qt::LeftEdge) tL.rx() = event->globalX() - this->m_posCursor.x(); + if (this->m_lock & Qt::RightEdge) bR.rx() = event->globalX() - this->m_posCursor.x(); + this->setGeometry(QRect(tL, bR)); + return; + } + + int x = event->globalX() - this->x(), y = event->globalY() - this->y(); + int bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; + + if (x < RESIZE_LIMIT){ + if (y < RESIZE_LIMIT) this->setCursor(QCursor(Qt::SizeFDiagCursor)); + else if (y > bottom) this->setCursor(QCursor(Qt::SizeBDiagCursor)); + else this->setCursor(QCursor(Qt::SizeHorCursor)); + } + else if (x > right){ + if (y < RESIZE_LIMIT) this->setCursor(QCursor(Qt::SizeBDiagCursor)); + else if (y > bottom) this->setCursor(QCursor(Qt::SizeFDiagCursor)); + else this->setCursor(QCursor(Qt::SizeHorCursor)); + } + else if (y < RESIZE_LIMIT || y > bottom) this->setCursor(Qt::SizeVerCursor); + else this->unsetCursor(); +} diff --git a/sample/CustomFrame-Static/customtitlebar/qcustomwindow.h b/sample/CustomFrame-Static/customtitlebar/qcustomwindow.h new file mode 100644 index 0000000..00d8909 --- /dev/null +++ b/sample/CustomFrame-Static/customtitlebar/qcustomwindow.h @@ -0,0 +1,84 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QCUSTOMWINDOW_H +#define QCUSTOMWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qtitlebar.h" + +class QCustomWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit QCustomWindow(QWidget *parent = nullptr); + ~QCustomWindow() override; + + QMenu * createPopupMenu() override; + + void setMenuBar(QMenuBar *menuBar); + QMenuBar * menuBar() const; + + void setMenuWidget(QWidget *widget); + QWidget * menuWidget() const; + + inline QTitleBar& titleBar() const { return *this->m_titleBar; } + +protected: + const int RESIZE_LIMIT; + + bool event(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; + + void customMouseMoveEvent(QMouseEvent* event); + +private: + bool init; + + QWidget *m_titleBarW; + QWidget *m_menuWidget; + QMenuBar *m_menuBar; + QTitleBar *m_titleBar; + + QToolBar *m_leftBorder; + QToolBar *m_rightBorder; + QToolBar *m_bottomBorder; + + Qt::Edges m_lock; + QPoint m_posCursor; + + QToolBar * generateBorder(Qt::ToolBarArea area, Qt::Orientation orientation); +}; + +#endif // QCUSTOMWINDOW_H diff --git a/sample/CustomFrame-Static/customtitlebar/qtitlebar.cpp b/sample/CustomFrame-Static/customtitlebar/qtitlebar.cpp new file mode 100644 index 0000000..7cfb340 --- /dev/null +++ b/sample/CustomFrame-Static/customtitlebar/qtitlebar.cpp @@ -0,0 +1,127 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#include "qtitlebar.h" + +QTitleBar::QTitleBar(QMainWindow *parent) : + QWidget(parent), FRAME_BUTTON_SIZE(24, 24) +{ + this->canMove = false; + this->maximizing = false; + this->m_frameButtons = QCustomAttrs::All; + + this->setStyleSheet(QStringLiteral( + "QPushButton {\n" + " border : 0.5px solid gray;\n" + " border-radius: 3px;\n" + " min-height: 20px;\n" + " margin: 1px;\n" + " background: white;\n" + " color: gray;\n" + "}\n" + "QPushButton::hover {\n" + " background: darkorange;\n" + " border : 0.5px solid darkorange;\n" + " color: white;\n" + "}\n" + "QPushButton::pressed, QPushButton::!enabled {\n" + " background: orange;\n" + " border : 0.5px solid orange;\n" + " color: white;\n" + "}\n" + "QTitleBar { background: white; }\n" + )); + + if (!parent) throw std::exception("Parent must be a QCustomWindow object (cannot be null)."); + this->m_parentWindow = parent; + + this->lbl_windowTitle.setText("QCustomWindow"); + this->lbl_windowTitle.setAlignment(Qt::AlignCenter); + + this->btn_close.setText("X"); + this->btn_maximize.setText("+"); + this->btn_minimize.setText("-"); + + this->btn_close.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_close.setMinimumSize(FRAME_BUTTON_SIZE); + this->btn_maximize.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_maximize.setMinimumSize(FRAME_BUTTON_SIZE); + this->btn_minimize.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_minimize.setMinimumSize(FRAME_BUTTON_SIZE); + + this->m_layout.addWidget(&this->lbl_windowTitle, 1); + this->m_layout.addWidget(&this->btn_minimize); + this->m_layout.addWidget(&this->btn_maximize); + this->m_layout.addWidget(&this->btn_close); + this->m_layout.setContentsMargins(0, 0, 0, 4); + this->m_layout.setSpacing(0); + + this->setLayout(&this->m_layout); + + connect(&this->btn_close, &QPushButton::clicked, [this]{ emit this->requestClose(); }); + connect(&this->btn_minimize, &QPushButton::clicked, [this]{ emit this->requestMinimize(); }); + connect(&this->btn_maximize, &QPushButton::clicked, [this]{ emit this->requestMaximize(); }); + + connect(this, &QWidget::windowTitleChanged, &this->lbl_windowTitle, &QLabel::setText); + + this->setMaximumHeight(35); + this->setMinimumHeight(35); +} + +void QTitleBar::setWindowButtons(QCustomAttrs::WindowButtons btns){ + this->m_frameButtons = btns; + this->btn_close.setVisible(btns & QCustomAttrs::Close); + this->btn_maximize.setVisible(btns & QCustomAttrs::Maximize); + this->btn_minimize.setVisible(btns & QCustomAttrs::Minimize); +} + +void QTitleBar::setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled){ + if (btn & QCustomAttrs::Close) this->btn_close.setEnabled(enabled); + if (btn & QCustomAttrs::Maximize) this->btn_maximize.setEnabled(enabled); + if (btn & QCustomAttrs::Minimize) this->btn_minimize.setEnabled(enabled); +} + +void QTitleBar::paintEvent(QPaintEvent *event){ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + QWidget::paintEvent(event); +} + +void QTitleBar::mousePressEvent(QMouseEvent *event){ + if (event->button() & Qt::LeftButton){ + this->canMove = (event->x() > 5 && event->y() > 5 && event->x() < (this->m_parentWindow->width() - 5)); + this->m_pCursor = event->globalPos() - this->m_parentWindow->geometry().topLeft(); + } + QWidget::mousePressEvent(event); +} + +void QTitleBar::mouseMoveEvent(QMouseEvent *event){ + if (!this->maximizing && canMove && event->buttons() & Qt::LeftButton + && !this->m_parentWindow->isMaximized()) this->m_parentWindow->move(event->globalPos() - m_pCursor); + this->maximizing = false; + QWidget::mouseMoveEvent(event); +} + +void QTitleBar::mouseDoubleClickEvent(QMouseEvent *event){ + if (m_frameButtons & QCustomAttrs::Maximize && btn_maximize.isEnabled() + && event->buttons() & Qt::LeftButton) { + this->maximizing = true; + emit requestMaximize(); + } + QWidget::mouseDoubleClickEvent(event); +} diff --git a/sample/CustomFrame-Static/customtitlebar/qtitlebar.h b/sample/CustomFrame-Static/customtitlebar/qtitlebar.h new file mode 100644 index 0000000..caff740 --- /dev/null +++ b/sample/CustomFrame-Static/customtitlebar/qtitlebar.h @@ -0,0 +1,89 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QTITLEBAR_H +#define QTITLEBAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace QCustomAttrs { + enum WindowButton { + Minimize = 0x01, + Maximize = 0x02, + Close = 0x04, + All = Minimize | Maximize | Close + }; + + Q_DECLARE_FLAGS(WindowButtons, WindowButton) + Q_DECLARE_OPERATORS_FOR_FLAGS(WindowButtons) +} + +class QTitleBar : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QCustomAttrs::WindowButtons windowButtons READ windowButtons WRITE setWindowButtons) + Q_CLASSINFO("custom_obj_type", "QTitleBar") +public: + explicit QTitleBar(QMainWindow *parent = nullptr); + + void setWindowButtons(QCustomAttrs::WindowButtons btns); + inline QCustomAttrs::WindowButtons windowButtons() const { return this->m_frameButtons; } + + void setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled = true); + +protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + +private: + bool canMove; + bool maximizing; + + QPoint m_pCursor; + const QSize FRAME_BUTTON_SIZE; + + QWidget *m_parentWindow; + + QCustomAttrs::WindowButtons m_frameButtons; + + QLabel lbl_windowTitle; + QHBoxLayout m_layout; + QPushButton btn_minimize; + QPushButton btn_maximize; + QPushButton btn_close; + +signals: + void requestClose(); + void requestMaximize(); + void requestMinimize(); +}; + +#endif // QTITLEBAR_H diff --git a/sample/CustomFrame-Static/customtitlebar/titlebar.cpp b/sample/CustomFrame-Static/customtitlebar/titlebar.cpp deleted file mode 100644 index 831009a..0000000 --- a/sample/CustomFrame-Static/customtitlebar/titlebar.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#include "titlebar.h" -#include "ui_titlebar.h" - -TitleBar::TitleBar(QWidget *parent) : - QWidget(parent), - ui(new Ui::TitleBar) -{ - ui->setupUi(this); - setMainWindow(parent->parentWidget() ? parent->parentWidget() : parent); - - canMove = false; -} - -TitleBar::~TitleBar() -{ - delete ui; -} - -void TitleBar::setMainWindow(QWidget *mainWindow){ - this->parent = mainWindow; - - disconnect(ui->btClose, &QPushButton::clicked, this, &TitleBar::onCloseRequest); - disconnect(ui->btMinimize, &QPushButton::clicked, this->parent, &QWidget::showMinimized); - disconnect(ui->btMaximize, &QPushButton::clicked, this, &TitleBar::maximizeParent); - - disconnect(this->parent, &QWidget::windowTitleChanged, ui->lblFormTitle, &QLabel::setText); - - connect(ui->btClose, &QPushButton::clicked, this, &TitleBar::onCloseRequest); - connect(ui->btMinimize, &QPushButton::clicked, this->parent, &QWidget::showMinimized); - connect(ui->btMaximize, &QPushButton::clicked, this, &TitleBar::maximizeParent); - - connect(this->parent, &QWidget::windowTitleChanged, ui->lblFormTitle, &QLabel::setText); -} - -void TitleBar::maximizeParent(){ - if (parent->isMaximized()) parent->showNormal(); - else parent->showMaximized(); -} - -void TitleBar::onCloseRequest(){ - emit closeRequest(); -} - -QWidget* TitleBar::mainWindow(){ - return this->parent; -} - -void TitleBar::setCloseButtonEnabled(bool enable){ - ui->btClose->setEnabled(enable); -} - -void TitleBar::setMaximizeButtonEnabled(bool enable){ - ui->btMaximize->setEnabled(enable); -} - -void TitleBar::setMinimizeButtonEnabled(bool enable){ - ui->btMinimize->setEnabled(enable); -} - -void TitleBar::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - canMove = !(event->x() < 5 || event->x() > (parent->width() - 5) || event->y() < 5); - m_pCursor = event->globalPos() - parent->geometry().topLeft(); - event->accept(); - } -} - -void TitleBar::mouseMoveEvent(QMouseEvent *event) -{ - if (!canMove){ - event->accept(); - return; - } - if (event->buttons() & Qt::LeftButton){ - if (parent->isMaximized()){ - event->accept(); - return; - } - parent->move(event->globalPos() - m_pCursor); - event->accept(); - } -} - -void TitleBar::mouseDoubleClickEvent(QMouseEvent *event){ - if (!ui->btMaximize->isEnabled()){ - event->accept(); - return; - } - if (event->button() == Qt::LeftButton) maximizeParent(); -} - -void TitleBar::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/sample/CustomFrame-Static/customtitlebar/titlebar.h b/sample/CustomFrame-Static/customtitlebar/titlebar.h deleted file mode 100644 index 2c170d4..0000000 --- a/sample/CustomFrame-Static/customtitlebar/titlebar.h +++ /dev/null @@ -1,65 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef TITLEBAR_H -#define TITLEBAR_H - -#include -#include -#include -#include - -namespace Ui { -class TitleBar; -} - -class TitleBar : public QWidget -{ - Q_OBJECT - -public: - explicit TitleBar(QWidget *parent = nullptr); - ~TitleBar(); - - void setMainWindow(QWidget *mainWindow); - QWidget* mainWindow(); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - -private: - bool canMove; - - Ui::TitleBar *ui; - QWidget *parent; - QPoint m_pCursor; - -protected: - void paintEvent(QPaintEvent *); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - -protected slots: - void maximizeParent(); - void onCloseRequest(); - -signals: - void closeRequest(); -}; - -#endif // TITLEBAR_H diff --git a/sample/CustomFrame-Static/customtitlebar/titlebar.ui b/sample/CustomFrame-Static/customtitlebar/titlebar.ui deleted file mode 100644 index c397b65..0000000 --- a/sample/CustomFrame-Static/customtitlebar/titlebar.ui +++ /dev/null @@ -1,148 +0,0 @@ - - - TitleBar - - - - 0 - 0 - 721 - 35 - - - - - 0 - 35 - - - - - 16777215 - 35 - - - - Form - - - QPushButton{ - border : 0.5px solid gray; - border-radius: 3px; - min-height: 20px; - margin: 1px; - background: white; - color: gray; -} - -QPushButton::hover{ - background: darkorange; - border : 0.5px solid darkorange; - color: white; -} - -QPushButton::pressed, QPushButton::!enabled{ - background: orange; - border : 0.5px solid orange; - color: white; -} - -QWidget::lblFormTitle{ - background-color: white; -} - -QPushButton#lblFormTitle{ - background: transparent; - border-radius: 0px; - border: transparent; - color: black; -} - - - - 0 - - - 6 - - - 6 - - - 6 - - - 0 - - - - - frmTitle - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - 25 - 16777215 - - - - _ - - - - - - - - 24 - 24 - - - - - 25 - 16777215 - - - - + - - - - - - - - 24 - 24 - - - - - 30 - 16777215 - - - - x - - - - - - - - diff --git a/sample/CustomFrame-Static/main.cpp b/sample/CustomFrame-Static/main.cpp index 153b157..6154b5e 100644 --- a/sample/CustomFrame-Static/main.cpp +++ b/sample/CustomFrame-Static/main.cpp @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # diff --git a/sample/CustomFrame-Static/testwindow.cpp b/sample/CustomFrame-Static/testwindow.cpp index 9493aa2..91fbf98 100644 --- a/sample/CustomFrame-Static/testwindow.cpp +++ b/sample/CustomFrame-Static/testwindow.cpp @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -18,19 +18,22 @@ #include "ui_testwindow.h" TestWindow::TestWindow(QWidget *parent) : - NMainWindow(parent), + QCustomWindow(parent), ui(new Ui::TestWindow) { ui->setupUi(this); - // Sets the custom Widgets on the parent Class - // Otherwise, the window resizing feature will not work - NMainWindow::setCustomWidgets(ui->centralWidget, ui->statusBar); + /* + * QMenuBar should never be inserted using Qt Designer. + * Insert them manually instead setMenuBar(QMenuBar*) + * and setMenuWidget(QWidget*) have been reimplemented. + */ clicks = 0; connect(ui->pushButton, &QPushButton::clicked, [this]{ setWindowTitle("Number of clicks : " + QString::number(++clicks)); }); + this->setMinimumSize(500, 400); } TestWindow::~TestWindow() diff --git a/sample/CustomFrame-Static/testwindow.h b/sample/CustomFrame-Static/testwindow.h index 40c7d03..c20556c 100644 --- a/sample/CustomFrame-Static/testwindow.h +++ b/sample/CustomFrame-Static/testwindow.h @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -19,13 +19,13 @@ #include -#include "nmainwindow.h" +#include "qcustomwindow.h" namespace Ui { class TestWindow; } -class TestWindow : public NMainWindow +class TestWindow : public QCustomWindow { Q_OBJECT diff --git a/sample/CustomFrame-Static/testwindow.ui b/sample/CustomFrame-Static/testwindow.ui index 430ef59..cad0629 100644 --- a/sample/CustomFrame-Static/testwindow.ui +++ b/sample/CustomFrame-Static/testwindow.ui @@ -6,7 +6,7 @@ 0 0 - 358 + 368 200 @@ -24,6 +24,9 @@ + + + Click me diff --git a/src/CustomTitlebar-Dynamic/CustomTitlebar.pro b/src/CustomTitlebar-Dynamic/CustomTitlebar.pro index 280c1ea..0879fb5 100644 --- a/src/CustomTitlebar-Dynamic/CustomTitlebar.pro +++ b/src/CustomTitlebar-Dynamic/CustomTitlebar.pro @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -18,11 +18,11 @@ QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -TARGET = CustomTitlebar +TARGET = QCustomTitlebar TEMPLATE = lib win32 { - VERSION = 1.0.0.4 + VERSION = 2.0.0.7 QMAKE_TARGET_COMPANY = Nintersoft QMAKE_TARGET_PRODUCT = Custom Titlebar @@ -32,11 +32,11 @@ win32 { CONFIG += skip_target_version_ext } else { - VERSION = 1.0.0 + VERSION = 2.0.0 CONFIG += unversioned_libname } -DEFINES += CUSTOMTITLEBAR_LIBRARY +DEFINES += QCUSTOMTITLEBAR_LIBRARY # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked as deprecated (the exact warnings @@ -51,16 +51,12 @@ DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ - titlebar.cpp \ - nmainwindow.cpp + qtitlebar.cpp \ + qcustomwindow.cpp HEADERS += \ - titlebar.h \ - nmainwindow.h - -FORMS += \ - titlebar.ui \ - nmainwindow.ui + qtitlebar.h \ + qcustomwindow.h unix { target.path = /usr/lib diff --git a/src/CustomTitlebar-Dynamic/nmainwindow.cpp b/src/CustomTitlebar-Dynamic/nmainwindow.cpp deleted file mode 100644 index 68ac9dd..0000000 --- a/src/CustomTitlebar-Dynamic/nmainwindow.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#include "nmainwindow.h" -#include "ui_nmainwindow.h" - -NMainWindow::NMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::NMainWindow), - RESIZE_LIMIT(2) -{ - ui->setupUi(this); - setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); - centralWidget()->installEventFilter(this); - ui->titleBar->installEventFilter(this); - ui->statusBar->installEventFilter(this); - - centralWidget()->setMouseTracking(true); - ui->titleBar->setMouseTracking(true); - ui->statusBar->setMouseTracking(true); - - setWindowTitle("Custom Window Border"); - locked = LockMoveType::None; - - ui->headerWidget->setTitleBarWidget(ui->titleBar); - if (ui->titleBar->mainWindow() != this) - ui->titleBar->setMainWindow(this); - - if (this->maximumSize() == this->minimumSize()) - setMaximizeButtonEnabled(false); - - connect(ui->titleBar, &TitleBar::closeRequest, this, &NMainWindow::close); -} - -NMainWindow::~NMainWindow() -{ - delete ui; -} - -void NMainWindow::setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar){ - setCustomStatusBar(newStatusBar); - setNewCentralWidget(newCentralWidget); -} - -void NMainWindow::setCustomStatusBar(QStatusBar *newStatusBar){ - if (!newStatusBar) return; - newStatusBar->installEventFilter(this); - newStatusBar->setMouseTracking(true); -} - -void NMainWindow::setNewCentralWidget(QWidget *newCentralWidget){ - if (!newCentralWidget) return; - newCentralWidget->installEventFilter(this); - newCentralWidget->setMouseTracking(true); - - if (newCentralWidget->layout()) - newCentralWidget->layout()->setContentsMargins(10, 0, 10, 0); -} - -void NMainWindow::setCloseButtonEnabled(bool enable){ - ui->titleBar->setCloseButtonEnabled(enable); -} - -void NMainWindow::setMaximizeButtonEnabled(bool enable){ - ui->titleBar->setMaximizeButtonEnabled(enable); -} - -void NMainWindow::setMinimizeButtonEnabled(bool enable){ - ui->titleBar->setMinimizeButtonEnabled(enable); -} - -void NMainWindow::setTitlebarStylesheet(const QString &styleSheet){ - ui->titleBar->setStyleSheet(styleSheet); -} - -QString NMainWindow::titlebarStylesheet() const { - return ui->titleBar->styleSheet(); -} - -void NMainWindow::closeEvent(QCloseEvent *event){ - if (event->isAccepted()) QMainWindow::closeEvent(event); - else event->ignore(); -} - -/* - * GUI Protected Methods (do not change them, unless it's really necessary) - */ - -void NMainWindow::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - int x = event->x(), y = event->y(), bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; - if (x < RESIZE_LIMIT && y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topLeft(); - locked = LockMoveType::TopLeft; - } - else if (x < RESIZE_LIMIT && y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomLeft(); - locked = LockMoveType::BottomLeft; - } - else if (x > right && y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topRight(); - locked = LockMoveType::TopRight; - } - else if (x > right && y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomRight(); - locked = LockMoveType::BottomRight; - } - else if (x < RESIZE_LIMIT || y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topLeft(); - locked = x < RESIZE_LIMIT ? LockMoveType::Left : LockMoveType::Top; - } - else if (x > right || y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomRight(); - locked = x > right ? LockMoveType::Right : LockMoveType::Bottom; - } - event->accept(); - } -} - -void NMainWindow::undefMouseMoveEvent(QObject* object, QMouseEvent* event){ - if (locked != LockMoveType::None){ - switch (locked) { - case LockMoveType::TopLeft: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), event->globalPos().y() - posCursor.y()), - this->geometry().bottomRight())); - break; - case LockMoveType::TopRight: - this->setGeometry(QRect(QPoint(this->geometry().left(), event->globalPos().y() - posCursor.y()), - QPoint(event->globalPos().x() - posCursor.x(), this->geometry().bottom()))); - break; - case LockMoveType::BottomLeft: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), this->geometry().top()), - QPoint(this->geometry().right(), event->globalPos().y() - posCursor.y()))); - break; - case LockMoveType::BottomRight: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(event->globalPos().x() - posCursor.x(), event->globalPos().y() - posCursor.y()))); - break; - case LockMoveType::Left: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), this->geometry().top()), - this->geometry().bottomRight())); - break; - case LockMoveType::Right: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(event->globalPos().x() - posCursor.x(), this->geometry().bottom()))); - break; - case LockMoveType::Top: - this->setGeometry(QRect(QPoint(this->geometry().left(), event->globalPos().y() - posCursor.y()), - this->geometry().bottomRight())); - break; - default: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(this->geometry().right(), event->globalPos().y() - posCursor.y()))); - break; - } - return; - } - - int x = event->x(), y = event->y(), right = this->width() - RESIZE_LIMIT; - if (object->objectName() == "statusBar"){ - if (x < RESIZE_LIMIT && y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeBDiagCursor)); - return; - } - else if (x > right && y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeFDiagCursor)); - return; - } - else if (y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeVerCursor)); - return; - } - } - else if (object->objectName() == "titleBar"){ - if (x < RESIZE_LIMIT && y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeFDiagCursor)); - return; - } - if (x > right && y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeBDiagCursor)); - return; - } - else if (y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeVerCursor)); - return; - } - } - - this->setCursor(QCursor(x < RESIZE_LIMIT || x > right ? Qt::SizeHorCursor : Qt::ArrowCursor)); -} - -void NMainWindow::mouseReleaseEvent(QMouseEvent *event){ - locked = LockMoveType::None; - event->accept(); -} - -bool NMainWindow::eventFilter(QObject* object, QEvent* event) -{ - if(event->type() == QEvent::MouseMove) - undefMouseMoveEvent(object, static_cast(event)); - else if (event->type() == QEvent::MouseButtonPress && object->objectName() == "titleBar") - mousePressEvent(static_cast(event)); - return false; -} diff --git a/src/CustomTitlebar-Dynamic/nmainwindow.h b/src/CustomTitlebar-Dynamic/nmainwindow.h deleted file mode 100644 index 55ea5cb..0000000 --- a/src/CustomTitlebar-Dynamic/nmainwindow.h +++ /dev/null @@ -1,86 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef NMAINWINDOW_H -#define NMAINWINDOW_H - -#include - -#if defined(CUSTOMTITLEBAR_LIBRARY) -# define CUSTOMTITLEBARSHARED_EXPORT Q_DECL_EXPORT -#else -# define CUSTOMTITLEBARSHARED_EXPORT Q_DECL_IMPORT -#endif - -#include -#include -#include -#include - -#include "titlebar.h" - -namespace Ui { -class NMainWindow; -} - -class CUSTOMTITLEBARSHARED_EXPORT NMainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit NMainWindow(QWidget *parent = nullptr); - ~NMainWindow(); - - void setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar); - void setNewCentralWidget(QWidget *newCentralWidget); - void setCustomStatusBar(QStatusBar *newStatusBar); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - - void setTitlebarStylesheet(const QString &styleSheet); - QString titlebarStylesheet() const; - -protected: - void closeEvent(QCloseEvent *event); - - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void undefMouseMoveEvent(QObject *object, QMouseEvent* event); - bool eventFilter(QObject *watched, QEvent *event); - - enum LockMoveType{ - Left, - Right, - Top, - Bottom, - TopLeft, - TopRight, - BottomLeft, - BottomRight, - None - }; - -private: - Ui::NMainWindow *ui; - const int RESIZE_LIMIT; - - QPoint posCursor; - LockMoveType locked; -}; - -#endif // NMAINWINDOW_H diff --git a/src/CustomTitlebar-Dynamic/nmainwindow.ui b/src/CustomTitlebar-Dynamic/nmainwindow.ui deleted file mode 100644 index bdc7d03..0000000 --- a/src/CustomTitlebar-Dynamic/nmainwindow.ui +++ /dev/null @@ -1,144 +0,0 @@ - - - NMainWindow - - - - 0 - 0 - 400 - 300 - - - - ArrowCursor - - - NMainWindow - - - QWidget#titleBar{ - background-color: #FFF; - border-top: 1px solid orange; - border-left: 1px solid orange; - border-right: 1px solid orange; - color: #000; -} - -QDockWidget#headerWidget, QDockWidget#headerWidget::title{ - background-color: #FFF; - border-top: 1px solid orange; - border-left: 1px solid orange; - border-right: 1px solid orange; - color: #000; -} - -QWidget#centralWidget, QWidget#headerWidgetContents, QStatusBar{ - background-color: #FFF; - border-left: 1px solid orange; - border-right: 1px solid orange; -} - -QMainWindow::separator { - background-color: #FFF; - background: #FFF; - border-left: 1px solid orange; - border-right: 1px solid orange; - height: 0px; -} - -QStatusBar{ - border-bottom: 1px solid orange; -} - - - - - 10 - - - 0 - - - 10 - - - 0 - - - 0 - - - - - - - - 36 - 35 - - - - - 524287 - 35 - - - - QDockWidget::NoDockWidgetFeatures - - - Qt::TopDockWidgetArea - - - 4 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 35 - - - - - 16777215 - 35 - - - - - - - - - - - - TitleBar - QWidget -
titlebar.h
- 1 -
-
- - -
diff --git a/src/CustomTitlebar-Dynamic/qcustomwindow.cpp b/src/CustomTitlebar-Dynamic/qcustomwindow.cpp new file mode 100644 index 0000000..88611d2 --- /dev/null +++ b/src/CustomTitlebar-Dynamic/qcustomwindow.cpp @@ -0,0 +1,276 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#include "qcustomwindow.h" + +QCustomWindow::QCustomWindow(QWidget *parent) : + QMainWindow(parent), RESIZE_LIMIT(4) +{ + setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); + + this->setMinimumSize(QSize(256, 64)); + this->setStyleSheet(QStringLiteral( + "\nQCustomWindow {\n" + " background : white;\n" + " border : 1px solid orange;\n" + "}\n" + "QStatusBar {\n" + " background : white;\n" + " border-bottom: 1px solid orange;\n" + " border-left: 1px solid orange;\n" + " border-right: 1px solid orange;\n" + "}\n" + "QToolBar {\n" + " margin : 1px;\n" + "}" + )); + + this->m_titleBar = new QTitleBar(this); + connect(this->m_titleBar, &QTitleBar::requestClose, + this, &QCustomWindow::close); + connect(this->m_titleBar, &QTitleBar::requestMaximize, [this]{ + if (this->isMaximized()) this->showNormal(); + else this->showMaximized(); + }); + connect(this->m_titleBar, &QTitleBar::requestMinimize, + this, &QCustomWindow::showMinimized); + connect(this, &QMainWindow::windowTitleChanged, this->m_titleBar, + &QWidget::setWindowTitle); + + this->m_titleBarW = new QWidget(); + this->m_titleBarW->setMouseTracking(true); + this->m_titleBarW->installEventFilter(this); + + QVBoxLayout *titleLayout = new QVBoxLayout(); + titleLayout->setContentsMargins(6, 6, 6, 0); + titleLayout->setSpacing(0); + titleLayout->addWidget(this->m_titleBar); + + this->m_titleBarW->setLayout(titleLayout); + QMainWindow::setMenuWidget(this->m_titleBarW); + + this->m_leftBorder = generateBorder(Qt::LeftToolBarArea, Qt::Vertical); + this->m_rightBorder = generateBorder(Qt::RightToolBarArea, Qt::Vertical); + this->m_bottomBorder = generateBorder(Qt::BottomToolBarArea, Qt::Horizontal); + + this->m_menuBar = nullptr; + this->m_menuWidget = nullptr; +} + +QCustomWindow::~QCustomWindow(){ + delete this->m_titleBar; + delete this->m_leftBorder; + delete this->m_rightBorder; + delete this->m_bottomBorder; + + if (this->m_menuBar) delete this->m_menuBar; + else if (this->m_menuWidget) delete this->m_menuWidget; +} + +QToolBar *QCustomWindow::generateBorder(Qt::ToolBarArea area, + Qt::Orientation orientation){ + QToolBar *border = new QToolBar("___border___"); + border->setStyleSheet( + "\nQToolBar {\n" + " margin : 1px;\n" + " border : 0px;\n" + " background : transparent;\n" + "}" + ); + + if (orientation & Qt::Horizontal){ + border->setMinimumHeight(6); + border->setMaximumHeight(6); + } + else { + border->setMinimumWidth(6); + border->setMaximumWidth(6); + } + border->setMovable(false); + border->setFloatable(false); + border->setAllowedAreas(area); + border->setMouseTracking(true); + border->installEventFilter(this); + + this->addToolBar(area, border); + return border; +} + +QMenu * QCustomWindow::createPopupMenu(){ + QMenu *menu = QMainWindow::createPopupMenu(); + QList removal; + foreach (QAction *a, menu->actions()) + if (a->text() == "___border___") removal.append(a); + foreach (QAction *a, removal) menu->removeAction(a); + return menu; +} + +void QCustomWindow::setMenuBar(QMenuBar *menuBar){ + if (this->m_menuBar == menuBar) return; + + if (this->m_menuBar) { + if (this->m_menuBar != this->m_menuWidget && this->m_menuWidget){ + this->m_menuWidget->setParent(nullptr); + this->m_menuWidget->deleteLater(); + } + + this->m_menuBar->hide(); + this->m_menuBar->setParent(nullptr); + this->m_menuBar->deleteLater(); + } + + this->m_menuBar = menuBar; + this->m_menuWidget = qobject_cast(menuBar); + + if (menuBar){ + menuBar->setParent(this); + this->m_titleBarW->layout()->addWidget(menuBar); + } +} + +QMenuBar* QCustomWindow::menuBar() const{ + return this->m_menuBar; +} + +void QCustomWindow::setMenuWidget(QWidget *widget){ + if (this->m_menuWidget == widget) return; + + widget->setParent(this); + + if (this->m_menuWidget){ + this->m_menuWidget->hide(); + this->m_menuWidget->setParent(nullptr); + this->m_menuWidget->deleteLater(); + } + + this->m_menuBar = nullptr; + this->m_menuWidget = widget; + + if (this->m_menuWidget){ + this->m_menuWidget->setParent(this); + this->m_titleBarW->layout()->addWidget(widget); + } +} + +QWidget * QCustomWindow::menuWidget() const{ + return this->m_menuWidget; +} + +bool QCustomWindow::eventFilter(QObject*, QEvent *event){ + if (event->type() == QEvent::MouseMove) + customMouseMoveEvent(static_cast(event)); + else if (event->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(event)); + return false; +} + +bool QCustomWindow::event(QEvent *event){ + if (event->type() == QEvent::ChildRemoved){ + QChildEvent *evt = static_cast(event); + if (evt->child()->isWidgetType()) evt->child()->removeEventFilter(this); + } + else if (event->type() == QEvent::ChildAdded){ + QChildEvent *evt = static_cast(event); + if (evt->child()->isWidgetType()){ + QWidget *child = qobject_cast(evt->child()); + + child->setMouseTracking(true); + child->installEventFilter(this); + + if (child->metaObject()->indexOfClassInfo("custom_obj_type") == -1){ + child->setStyleSheet(child->styleSheet() + + "\nQToolBar {\n" + " margin : 1px;\n" + " padding: 0px 6px 0px 6px;\n" + " border: 1px transparent solid;" + "}\n" + "QToolBar:top:first, QToolBar:bottom:first, QToolBar:left:first {\n" + " margin : 0px 0px 0px 6px;\n" + "}\n" + "QToolBar:top:only-one, QToolBar:bottom:only-one {\n" + " margin : 0px 6px 0px 6px;\n" + "}\n" + "QToolBar:top:last, QToolBar:bottom:last, QToolBar:right:last {\n" + " margin : 0px 6px 0px 0px;\n" + "}\n"); + } + } + } + return QMainWindow::event(event); +} + +void QCustomWindow::mousePressEvent(QMouseEvent *event){ + if (event->button() & Qt::LeftButton){ + int x = event->x(), y = event->y(); + int bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; + + QPoint posCursor = event->globalPos(); + Qt::Edges nFlags = {}; + if (x < RESIZE_LIMIT) { + nFlags |= Qt::LeftEdge; + posCursor.rx() -= this->x(); + } + if (y < RESIZE_LIMIT) { + nFlags |= Qt::TopEdge; + posCursor.ry() -= this->y(); + } + if (x > right) { + nFlags |= Qt::RightEdge; + posCursor.rx() -= (this->x() + this->width()); + } + if (y > bottom) { + nFlags |= Qt::BottomEdge; + posCursor.ry() -= (this->y() + this->height()); + } + this->m_lock = nFlags; + this->m_posCursor = posCursor; + } + QMainWindow::mousePressEvent(event); +} + +void QCustomWindow::mouseReleaseEvent(QMouseEvent *event){ + this->m_lock = {}; + this->unsetCursor(); + QMainWindow::mouseMoveEvent(event); +} + +void QCustomWindow::customMouseMoveEvent(QMouseEvent *event){ + if (this->m_lock){ + QPoint tL = this->geometry().topLeft(), bR = this->geometry().bottomRight(); + if (this->m_lock & Qt::TopEdge) tL.ry() = event->globalY() - this->m_posCursor.y(); + if (this->m_lock & Qt::BottomEdge) bR.ry() = event->globalY() - this->m_posCursor.y(); + if (this->m_lock & Qt::LeftEdge) tL.rx() = event->globalX() - this->m_posCursor.x(); + if (this->m_lock & Qt::RightEdge) bR.rx() = event->globalX() - this->m_posCursor.x(); + this->setGeometry(QRect(tL, bR)); + return; + } + + int x = event->globalX() - this->x(), y = event->globalY() - this->y(); + int bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; + + if (x < RESIZE_LIMIT){ + if (y < RESIZE_LIMIT) this->setCursor(QCursor(Qt::SizeFDiagCursor)); + else if (y > bottom) this->setCursor(QCursor(Qt::SizeBDiagCursor)); + else this->setCursor(QCursor(Qt::SizeHorCursor)); + } + else if (x > right){ + if (y < RESIZE_LIMIT) this->setCursor(QCursor(Qt::SizeBDiagCursor)); + else if (y > bottom) this->setCursor(QCursor(Qt::SizeFDiagCursor)); + else this->setCursor(QCursor(Qt::SizeHorCursor)); + } + else if (y < RESIZE_LIMIT || y > bottom) this->setCursor(Qt::SizeVerCursor); + else this->unsetCursor(); +} diff --git a/src/CustomTitlebar-Dynamic/qcustomwindow.h b/src/CustomTitlebar-Dynamic/qcustomwindow.h new file mode 100644 index 0000000..78c62d8 --- /dev/null +++ b/src/CustomTitlebar-Dynamic/qcustomwindow.h @@ -0,0 +1,92 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QCUSTOMWINDOW_H +#define QCUSTOMWINDOW_H + +#include + +#if defined(QCUSTOMTITLEBAR_LIBRARY) +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_EXPORT +#else +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_IMPORT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qtitlebar.h" + +class QCUSTOMTITLEBARSHARED_EXPORT QCustomWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit QCustomWindow(QWidget *parent = nullptr); + ~QCustomWindow() override; + + QMenu * createPopupMenu() override; + + void setMenuBar(QMenuBar *menuBar); + QMenuBar * menuBar() const; + + void setMenuWidget(QWidget *widget); + QWidget * menuWidget() const; + + inline QTitleBar& titleBar() const { return *this->m_titleBar; } + +protected: + const int RESIZE_LIMIT; + + bool event(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; + + void customMouseMoveEvent(QMouseEvent* event); + +private: + bool init; + + QWidget *m_titleBarW; + QWidget *m_menuWidget; + QMenuBar *m_menuBar; + QTitleBar *m_titleBar; + + QToolBar *m_leftBorder; + QToolBar *m_rightBorder; + QToolBar *m_bottomBorder; + + Qt::Edges m_lock; + QPoint m_posCursor; + + QToolBar * generateBorder(Qt::ToolBarArea area, Qt::Orientation orientation); +}; + +#endif // QCUSTOMWINDOW_H diff --git a/src/CustomTitlebar-Dynamic/qtitlebar.cpp b/src/CustomTitlebar-Dynamic/qtitlebar.cpp new file mode 100644 index 0000000..7cfb340 --- /dev/null +++ b/src/CustomTitlebar-Dynamic/qtitlebar.cpp @@ -0,0 +1,127 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#include "qtitlebar.h" + +QTitleBar::QTitleBar(QMainWindow *parent) : + QWidget(parent), FRAME_BUTTON_SIZE(24, 24) +{ + this->canMove = false; + this->maximizing = false; + this->m_frameButtons = QCustomAttrs::All; + + this->setStyleSheet(QStringLiteral( + "QPushButton {\n" + " border : 0.5px solid gray;\n" + " border-radius: 3px;\n" + " min-height: 20px;\n" + " margin: 1px;\n" + " background: white;\n" + " color: gray;\n" + "}\n" + "QPushButton::hover {\n" + " background: darkorange;\n" + " border : 0.5px solid darkorange;\n" + " color: white;\n" + "}\n" + "QPushButton::pressed, QPushButton::!enabled {\n" + " background: orange;\n" + " border : 0.5px solid orange;\n" + " color: white;\n" + "}\n" + "QTitleBar { background: white; }\n" + )); + + if (!parent) throw std::exception("Parent must be a QCustomWindow object (cannot be null)."); + this->m_parentWindow = parent; + + this->lbl_windowTitle.setText("QCustomWindow"); + this->lbl_windowTitle.setAlignment(Qt::AlignCenter); + + this->btn_close.setText("X"); + this->btn_maximize.setText("+"); + this->btn_minimize.setText("-"); + + this->btn_close.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_close.setMinimumSize(FRAME_BUTTON_SIZE); + this->btn_maximize.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_maximize.setMinimumSize(FRAME_BUTTON_SIZE); + this->btn_minimize.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_minimize.setMinimumSize(FRAME_BUTTON_SIZE); + + this->m_layout.addWidget(&this->lbl_windowTitle, 1); + this->m_layout.addWidget(&this->btn_minimize); + this->m_layout.addWidget(&this->btn_maximize); + this->m_layout.addWidget(&this->btn_close); + this->m_layout.setContentsMargins(0, 0, 0, 4); + this->m_layout.setSpacing(0); + + this->setLayout(&this->m_layout); + + connect(&this->btn_close, &QPushButton::clicked, [this]{ emit this->requestClose(); }); + connect(&this->btn_minimize, &QPushButton::clicked, [this]{ emit this->requestMinimize(); }); + connect(&this->btn_maximize, &QPushButton::clicked, [this]{ emit this->requestMaximize(); }); + + connect(this, &QWidget::windowTitleChanged, &this->lbl_windowTitle, &QLabel::setText); + + this->setMaximumHeight(35); + this->setMinimumHeight(35); +} + +void QTitleBar::setWindowButtons(QCustomAttrs::WindowButtons btns){ + this->m_frameButtons = btns; + this->btn_close.setVisible(btns & QCustomAttrs::Close); + this->btn_maximize.setVisible(btns & QCustomAttrs::Maximize); + this->btn_minimize.setVisible(btns & QCustomAttrs::Minimize); +} + +void QTitleBar::setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled){ + if (btn & QCustomAttrs::Close) this->btn_close.setEnabled(enabled); + if (btn & QCustomAttrs::Maximize) this->btn_maximize.setEnabled(enabled); + if (btn & QCustomAttrs::Minimize) this->btn_minimize.setEnabled(enabled); +} + +void QTitleBar::paintEvent(QPaintEvent *event){ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + QWidget::paintEvent(event); +} + +void QTitleBar::mousePressEvent(QMouseEvent *event){ + if (event->button() & Qt::LeftButton){ + this->canMove = (event->x() > 5 && event->y() > 5 && event->x() < (this->m_parentWindow->width() - 5)); + this->m_pCursor = event->globalPos() - this->m_parentWindow->geometry().topLeft(); + } + QWidget::mousePressEvent(event); +} + +void QTitleBar::mouseMoveEvent(QMouseEvent *event){ + if (!this->maximizing && canMove && event->buttons() & Qt::LeftButton + && !this->m_parentWindow->isMaximized()) this->m_parentWindow->move(event->globalPos() - m_pCursor); + this->maximizing = false; + QWidget::mouseMoveEvent(event); +} + +void QTitleBar::mouseDoubleClickEvent(QMouseEvent *event){ + if (m_frameButtons & QCustomAttrs::Maximize && btn_maximize.isEnabled() + && event->buttons() & Qt::LeftButton) { + this->maximizing = true; + emit requestMaximize(); + } + QWidget::mouseDoubleClickEvent(event); +} diff --git a/src/CustomTitlebar-Dynamic/qtitlebar.h b/src/CustomTitlebar-Dynamic/qtitlebar.h new file mode 100644 index 0000000..a1e12cb --- /dev/null +++ b/src/CustomTitlebar-Dynamic/qtitlebar.h @@ -0,0 +1,97 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QTITLEBAR_H +#define QTITLEBAR_H + +#include + +#if defined(QCUSTOMTITLEBAR_LIBRARY) +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_EXPORT +#else +# define QCUSTOMTITLEBARSHARED_EXPORT Q_DECL_IMPORT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace QCustomAttrs { + enum WindowButton { + Minimize = 0x01, + Maximize = 0x02, + Close = 0x04, + All = Minimize | Maximize | Close + }; + + Q_DECLARE_FLAGS(WindowButtons, WindowButton) + Q_DECLARE_OPERATORS_FOR_FLAGS(WindowButtons) +} + +class QCUSTOMTITLEBARSHARED_EXPORT QTitleBar : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QCustomAttrs::WindowButtons windowButtons READ windowButtons WRITE setWindowButtons) + Q_CLASSINFO("custom_obj_type", "QTitleBar") +public: + explicit QTitleBar(QMainWindow *parent = nullptr); + + void setWindowButtons(QCustomAttrs::WindowButtons btns); + inline QCustomAttrs::WindowButtons windowButtons() const { return this->m_frameButtons; } + + void setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled = true); + +protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + +private: + bool canMove; + bool maximizing; + + QPoint m_pCursor; + const QSize FRAME_BUTTON_SIZE; + + QWidget *m_parentWindow; + + QCustomAttrs::WindowButtons m_frameButtons; + + QLabel lbl_windowTitle; + QHBoxLayout m_layout; + QPushButton btn_minimize; + QPushButton btn_maximize; + QPushButton btn_close; + +signals: + void requestClose(); + void requestMaximize(); + void requestMinimize(); +}; + +#endif // QTITLEBAR_H diff --git a/src/CustomTitlebar-Dynamic/titlebar.cpp b/src/CustomTitlebar-Dynamic/titlebar.cpp deleted file mode 100644 index 831009a..0000000 --- a/src/CustomTitlebar-Dynamic/titlebar.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#include "titlebar.h" -#include "ui_titlebar.h" - -TitleBar::TitleBar(QWidget *parent) : - QWidget(parent), - ui(new Ui::TitleBar) -{ - ui->setupUi(this); - setMainWindow(parent->parentWidget() ? parent->parentWidget() : parent); - - canMove = false; -} - -TitleBar::~TitleBar() -{ - delete ui; -} - -void TitleBar::setMainWindow(QWidget *mainWindow){ - this->parent = mainWindow; - - disconnect(ui->btClose, &QPushButton::clicked, this, &TitleBar::onCloseRequest); - disconnect(ui->btMinimize, &QPushButton::clicked, this->parent, &QWidget::showMinimized); - disconnect(ui->btMaximize, &QPushButton::clicked, this, &TitleBar::maximizeParent); - - disconnect(this->parent, &QWidget::windowTitleChanged, ui->lblFormTitle, &QLabel::setText); - - connect(ui->btClose, &QPushButton::clicked, this, &TitleBar::onCloseRequest); - connect(ui->btMinimize, &QPushButton::clicked, this->parent, &QWidget::showMinimized); - connect(ui->btMaximize, &QPushButton::clicked, this, &TitleBar::maximizeParent); - - connect(this->parent, &QWidget::windowTitleChanged, ui->lblFormTitle, &QLabel::setText); -} - -void TitleBar::maximizeParent(){ - if (parent->isMaximized()) parent->showNormal(); - else parent->showMaximized(); -} - -void TitleBar::onCloseRequest(){ - emit closeRequest(); -} - -QWidget* TitleBar::mainWindow(){ - return this->parent; -} - -void TitleBar::setCloseButtonEnabled(bool enable){ - ui->btClose->setEnabled(enable); -} - -void TitleBar::setMaximizeButtonEnabled(bool enable){ - ui->btMaximize->setEnabled(enable); -} - -void TitleBar::setMinimizeButtonEnabled(bool enable){ - ui->btMinimize->setEnabled(enable); -} - -void TitleBar::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - canMove = !(event->x() < 5 || event->x() > (parent->width() - 5) || event->y() < 5); - m_pCursor = event->globalPos() - parent->geometry().topLeft(); - event->accept(); - } -} - -void TitleBar::mouseMoveEvent(QMouseEvent *event) -{ - if (!canMove){ - event->accept(); - return; - } - if (event->buttons() & Qt::LeftButton){ - if (parent->isMaximized()){ - event->accept(); - return; - } - parent->move(event->globalPos() - m_pCursor); - event->accept(); - } -} - -void TitleBar::mouseDoubleClickEvent(QMouseEvent *event){ - if (!ui->btMaximize->isEnabled()){ - event->accept(); - return; - } - if (event->button() == Qt::LeftButton) maximizeParent(); -} - -void TitleBar::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/CustomTitlebar-Dynamic/titlebar.h b/src/CustomTitlebar-Dynamic/titlebar.h deleted file mode 100644 index 2c170d4..0000000 --- a/src/CustomTitlebar-Dynamic/titlebar.h +++ /dev/null @@ -1,65 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef TITLEBAR_H -#define TITLEBAR_H - -#include -#include -#include -#include - -namespace Ui { -class TitleBar; -} - -class TitleBar : public QWidget -{ - Q_OBJECT - -public: - explicit TitleBar(QWidget *parent = nullptr); - ~TitleBar(); - - void setMainWindow(QWidget *mainWindow); - QWidget* mainWindow(); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - -private: - bool canMove; - - Ui::TitleBar *ui; - QWidget *parent; - QPoint m_pCursor; - -protected: - void paintEvent(QPaintEvent *); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - -protected slots: - void maximizeParent(); - void onCloseRequest(); - -signals: - void closeRequest(); -}; - -#endif // TITLEBAR_H diff --git a/src/CustomTitlebar-Dynamic/titlebar.ui b/src/CustomTitlebar-Dynamic/titlebar.ui deleted file mode 100644 index c397b65..0000000 --- a/src/CustomTitlebar-Dynamic/titlebar.ui +++ /dev/null @@ -1,148 +0,0 @@ - - - TitleBar - - - - 0 - 0 - 721 - 35 - - - - - 0 - 35 - - - - - 16777215 - 35 - - - - Form - - - QPushButton{ - border : 0.5px solid gray; - border-radius: 3px; - min-height: 20px; - margin: 1px; - background: white; - color: gray; -} - -QPushButton::hover{ - background: darkorange; - border : 0.5px solid darkorange; - color: white; -} - -QPushButton::pressed, QPushButton::!enabled{ - background: orange; - border : 0.5px solid orange; - color: white; -} - -QWidget::lblFormTitle{ - background-color: white; -} - -QPushButton#lblFormTitle{ - background: transparent; - border-radius: 0px; - border: transparent; - color: black; -} - - - - 0 - - - 6 - - - 6 - - - 6 - - - 0 - - - - - frmTitle - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - 25 - 16777215 - - - - _ - - - - - - - - 24 - 24 - - - - - 25 - 16777215 - - - - + - - - - - - - - 24 - 24 - - - - - 30 - 16777215 - - - - x - - - - - - - - diff --git a/src/CustomTitlebar-Static/CustomTitlebar.pro b/src/CustomTitlebar-Static/CustomTitlebar.pro index 64c07eb..ef4e194 100644 --- a/src/CustomTitlebar-Static/CustomTitlebar.pro +++ b/src/CustomTitlebar-Static/CustomTitlebar.pro @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 +# 25 of August of 2020 # # Licence notice # @@ -35,13 +35,9 @@ DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ main.cpp \ - titlebar.cpp \ - nmainwindow.cpp + qcustomwindow.cpp \ + qtitlebar.cpp HEADERS += \ - titlebar.h \ - nmainwindow.h - -FORMS += \ - titlebar.ui \ - nmainwindow.ui + qcustomwindow.h \ + qtitlebar.h diff --git a/src/CustomTitlebar-Static/main.cpp b/src/CustomTitlebar-Static/main.cpp index 8b6848e..b9a6789 100644 --- a/src/CustomTitlebar-Static/main.cpp +++ b/src/CustomTitlebar-Static/main.cpp @@ -4,7 +4,7 @@ # Developer: Mauro Mascarenhas de Araújo # Contact: mauro.mascarenhas@nintersoft.com # Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 +# Date: 25 of August of 2020 # # Licence notice # @@ -14,13 +14,13 @@ # ------------------------------------------------- */ -#include "nmainwindow.h" +#include "qcustomwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); - NMainWindow w; + QCustomWindow w; w.show(); return a.exec(); diff --git a/src/CustomTitlebar-Static/nmainwindow.cpp b/src/CustomTitlebar-Static/nmainwindow.cpp deleted file mode 100644 index 68ac9dd..0000000 --- a/src/CustomTitlebar-Static/nmainwindow.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 25 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#include "nmainwindow.h" -#include "ui_nmainwindow.h" - -NMainWindow::NMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::NMainWindow), - RESIZE_LIMIT(2) -{ - ui->setupUi(this); - setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); - centralWidget()->installEventFilter(this); - ui->titleBar->installEventFilter(this); - ui->statusBar->installEventFilter(this); - - centralWidget()->setMouseTracking(true); - ui->titleBar->setMouseTracking(true); - ui->statusBar->setMouseTracking(true); - - setWindowTitle("Custom Window Border"); - locked = LockMoveType::None; - - ui->headerWidget->setTitleBarWidget(ui->titleBar); - if (ui->titleBar->mainWindow() != this) - ui->titleBar->setMainWindow(this); - - if (this->maximumSize() == this->minimumSize()) - setMaximizeButtonEnabled(false); - - connect(ui->titleBar, &TitleBar::closeRequest, this, &NMainWindow::close); -} - -NMainWindow::~NMainWindow() -{ - delete ui; -} - -void NMainWindow::setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar){ - setCustomStatusBar(newStatusBar); - setNewCentralWidget(newCentralWidget); -} - -void NMainWindow::setCustomStatusBar(QStatusBar *newStatusBar){ - if (!newStatusBar) return; - newStatusBar->installEventFilter(this); - newStatusBar->setMouseTracking(true); -} - -void NMainWindow::setNewCentralWidget(QWidget *newCentralWidget){ - if (!newCentralWidget) return; - newCentralWidget->installEventFilter(this); - newCentralWidget->setMouseTracking(true); - - if (newCentralWidget->layout()) - newCentralWidget->layout()->setContentsMargins(10, 0, 10, 0); -} - -void NMainWindow::setCloseButtonEnabled(bool enable){ - ui->titleBar->setCloseButtonEnabled(enable); -} - -void NMainWindow::setMaximizeButtonEnabled(bool enable){ - ui->titleBar->setMaximizeButtonEnabled(enable); -} - -void NMainWindow::setMinimizeButtonEnabled(bool enable){ - ui->titleBar->setMinimizeButtonEnabled(enable); -} - -void NMainWindow::setTitlebarStylesheet(const QString &styleSheet){ - ui->titleBar->setStyleSheet(styleSheet); -} - -QString NMainWindow::titlebarStylesheet() const { - return ui->titleBar->styleSheet(); -} - -void NMainWindow::closeEvent(QCloseEvent *event){ - if (event->isAccepted()) QMainWindow::closeEvent(event); - else event->ignore(); -} - -/* - * GUI Protected Methods (do not change them, unless it's really necessary) - */ - -void NMainWindow::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - int x = event->x(), y = event->y(), bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; - if (x < RESIZE_LIMIT && y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topLeft(); - locked = LockMoveType::TopLeft; - } - else if (x < RESIZE_LIMIT && y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomLeft(); - locked = LockMoveType::BottomLeft; - } - else if (x > right && y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topRight(); - locked = LockMoveType::TopRight; - } - else if (x > right && y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomRight(); - locked = LockMoveType::BottomRight; - } - else if (x < RESIZE_LIMIT || y < RESIZE_LIMIT){ - posCursor = event->globalPos() - this->geometry().topLeft(); - locked = x < RESIZE_LIMIT ? LockMoveType::Left : LockMoveType::Top; - } - else if (x > right || y > bottom){ - posCursor = event->globalPos() - this->geometry().bottomRight(); - locked = x > right ? LockMoveType::Right : LockMoveType::Bottom; - } - event->accept(); - } -} - -void NMainWindow::undefMouseMoveEvent(QObject* object, QMouseEvent* event){ - if (locked != LockMoveType::None){ - switch (locked) { - case LockMoveType::TopLeft: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), event->globalPos().y() - posCursor.y()), - this->geometry().bottomRight())); - break; - case LockMoveType::TopRight: - this->setGeometry(QRect(QPoint(this->geometry().left(), event->globalPos().y() - posCursor.y()), - QPoint(event->globalPos().x() - posCursor.x(), this->geometry().bottom()))); - break; - case LockMoveType::BottomLeft: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), this->geometry().top()), - QPoint(this->geometry().right(), event->globalPos().y() - posCursor.y()))); - break; - case LockMoveType::BottomRight: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(event->globalPos().x() - posCursor.x(), event->globalPos().y() - posCursor.y()))); - break; - case LockMoveType::Left: - this->setGeometry(QRect(QPoint(event->globalPos().x() - posCursor.x(), this->geometry().top()), - this->geometry().bottomRight())); - break; - case LockMoveType::Right: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(event->globalPos().x() - posCursor.x(), this->geometry().bottom()))); - break; - case LockMoveType::Top: - this->setGeometry(QRect(QPoint(this->geometry().left(), event->globalPos().y() - posCursor.y()), - this->geometry().bottomRight())); - break; - default: - this->setGeometry(QRect(this->geometry().topLeft(), - QPoint(this->geometry().right(), event->globalPos().y() - posCursor.y()))); - break; - } - return; - } - - int x = event->x(), y = event->y(), right = this->width() - RESIZE_LIMIT; - if (object->objectName() == "statusBar"){ - if (x < RESIZE_LIMIT && y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeBDiagCursor)); - return; - } - else if (x > right && y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeFDiagCursor)); - return; - } - else if (y > (19 - RESIZE_LIMIT)){ - this->setCursor(QCursor(Qt::SizeVerCursor)); - return; - } - } - else if (object->objectName() == "titleBar"){ - if (x < RESIZE_LIMIT && y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeFDiagCursor)); - return; - } - if (x > right && y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeBDiagCursor)); - return; - } - else if (y < RESIZE_LIMIT){ - this->setCursor(QCursor(Qt::SizeVerCursor)); - return; - } - } - - this->setCursor(QCursor(x < RESIZE_LIMIT || x > right ? Qt::SizeHorCursor : Qt::ArrowCursor)); -} - -void NMainWindow::mouseReleaseEvent(QMouseEvent *event){ - locked = LockMoveType::None; - event->accept(); -} - -bool NMainWindow::eventFilter(QObject* object, QEvent* event) -{ - if(event->type() == QEvent::MouseMove) - undefMouseMoveEvent(object, static_cast(event)); - else if (event->type() == QEvent::MouseButtonPress && object->objectName() == "titleBar") - mousePressEvent(static_cast(event)); - return false; -} diff --git a/src/CustomTitlebar-Static/nmainwindow.h b/src/CustomTitlebar-Static/nmainwindow.h deleted file mode 100644 index 6e06456..0000000 --- a/src/CustomTitlebar-Static/nmainwindow.h +++ /dev/null @@ -1,78 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef NMAINWINDOW_H -#define NMAINWINDOW_H - -#include -#include -#include -#include - -#include "titlebar.h" - -namespace Ui { -class NMainWindow; -} - -class NMainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit NMainWindow(QWidget *parent = nullptr); - ~NMainWindow(); - - void setCustomWidgets(QWidget *newCentralWidget, QStatusBar *newStatusBar); - void setNewCentralWidget(QWidget *newCentralWidget); - void setCustomStatusBar(QStatusBar *newStatusBar); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - - void setTitlebarStylesheet(const QString &styleSheet); - QString titlebarStylesheet() const; - -protected: - void closeEvent(QCloseEvent *event); - - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void undefMouseMoveEvent(QObject *object, QMouseEvent* event); - bool eventFilter(QObject *watched, QEvent *event); - - enum LockMoveType{ - Left, - Right, - Top, - Bottom, - TopLeft, - TopRight, - BottomLeft, - BottomRight, - None - }; - -private: - Ui::NMainWindow *ui; - const int RESIZE_LIMIT; - - QPoint posCursor; - LockMoveType locked; -}; - -#endif // NMAINWINDOW_H diff --git a/src/CustomTitlebar-Static/nmainwindow.ui b/src/CustomTitlebar-Static/nmainwindow.ui deleted file mode 100644 index bdc7d03..0000000 --- a/src/CustomTitlebar-Static/nmainwindow.ui +++ /dev/null @@ -1,144 +0,0 @@ - - - NMainWindow - - - - 0 - 0 - 400 - 300 - - - - ArrowCursor - - - NMainWindow - - - QWidget#titleBar{ - background-color: #FFF; - border-top: 1px solid orange; - border-left: 1px solid orange; - border-right: 1px solid orange; - color: #000; -} - -QDockWidget#headerWidget, QDockWidget#headerWidget::title{ - background-color: #FFF; - border-top: 1px solid orange; - border-left: 1px solid orange; - border-right: 1px solid orange; - color: #000; -} - -QWidget#centralWidget, QWidget#headerWidgetContents, QStatusBar{ - background-color: #FFF; - border-left: 1px solid orange; - border-right: 1px solid orange; -} - -QMainWindow::separator { - background-color: #FFF; - background: #FFF; - border-left: 1px solid orange; - border-right: 1px solid orange; - height: 0px; -} - -QStatusBar{ - border-bottom: 1px solid orange; -} - - - - - 10 - - - 0 - - - 10 - - - 0 - - - 0 - - - - - - - - 36 - 35 - - - - - 524287 - 35 - - - - QDockWidget::NoDockWidgetFeatures - - - Qt::TopDockWidgetArea - - - 4 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 35 - - - - - 16777215 - 35 - - - - - - - - - - - - TitleBar - QWidget -
titlebar.h
- 1 -
-
- - -
diff --git a/src/CustomTitlebar-Static/qcustomwindow.cpp b/src/CustomTitlebar-Static/qcustomwindow.cpp new file mode 100644 index 0000000..88611d2 --- /dev/null +++ b/src/CustomTitlebar-Static/qcustomwindow.cpp @@ -0,0 +1,276 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#include "qcustomwindow.h" + +QCustomWindow::QCustomWindow(QWidget *parent) : + QMainWindow(parent), RESIZE_LIMIT(4) +{ + setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); + + this->setMinimumSize(QSize(256, 64)); + this->setStyleSheet(QStringLiteral( + "\nQCustomWindow {\n" + " background : white;\n" + " border : 1px solid orange;\n" + "}\n" + "QStatusBar {\n" + " background : white;\n" + " border-bottom: 1px solid orange;\n" + " border-left: 1px solid orange;\n" + " border-right: 1px solid orange;\n" + "}\n" + "QToolBar {\n" + " margin : 1px;\n" + "}" + )); + + this->m_titleBar = new QTitleBar(this); + connect(this->m_titleBar, &QTitleBar::requestClose, + this, &QCustomWindow::close); + connect(this->m_titleBar, &QTitleBar::requestMaximize, [this]{ + if (this->isMaximized()) this->showNormal(); + else this->showMaximized(); + }); + connect(this->m_titleBar, &QTitleBar::requestMinimize, + this, &QCustomWindow::showMinimized); + connect(this, &QMainWindow::windowTitleChanged, this->m_titleBar, + &QWidget::setWindowTitle); + + this->m_titleBarW = new QWidget(); + this->m_titleBarW->setMouseTracking(true); + this->m_titleBarW->installEventFilter(this); + + QVBoxLayout *titleLayout = new QVBoxLayout(); + titleLayout->setContentsMargins(6, 6, 6, 0); + titleLayout->setSpacing(0); + titleLayout->addWidget(this->m_titleBar); + + this->m_titleBarW->setLayout(titleLayout); + QMainWindow::setMenuWidget(this->m_titleBarW); + + this->m_leftBorder = generateBorder(Qt::LeftToolBarArea, Qt::Vertical); + this->m_rightBorder = generateBorder(Qt::RightToolBarArea, Qt::Vertical); + this->m_bottomBorder = generateBorder(Qt::BottomToolBarArea, Qt::Horizontal); + + this->m_menuBar = nullptr; + this->m_menuWidget = nullptr; +} + +QCustomWindow::~QCustomWindow(){ + delete this->m_titleBar; + delete this->m_leftBorder; + delete this->m_rightBorder; + delete this->m_bottomBorder; + + if (this->m_menuBar) delete this->m_menuBar; + else if (this->m_menuWidget) delete this->m_menuWidget; +} + +QToolBar *QCustomWindow::generateBorder(Qt::ToolBarArea area, + Qt::Orientation orientation){ + QToolBar *border = new QToolBar("___border___"); + border->setStyleSheet( + "\nQToolBar {\n" + " margin : 1px;\n" + " border : 0px;\n" + " background : transparent;\n" + "}" + ); + + if (orientation & Qt::Horizontal){ + border->setMinimumHeight(6); + border->setMaximumHeight(6); + } + else { + border->setMinimumWidth(6); + border->setMaximumWidth(6); + } + border->setMovable(false); + border->setFloatable(false); + border->setAllowedAreas(area); + border->setMouseTracking(true); + border->installEventFilter(this); + + this->addToolBar(area, border); + return border; +} + +QMenu * QCustomWindow::createPopupMenu(){ + QMenu *menu = QMainWindow::createPopupMenu(); + QList removal; + foreach (QAction *a, menu->actions()) + if (a->text() == "___border___") removal.append(a); + foreach (QAction *a, removal) menu->removeAction(a); + return menu; +} + +void QCustomWindow::setMenuBar(QMenuBar *menuBar){ + if (this->m_menuBar == menuBar) return; + + if (this->m_menuBar) { + if (this->m_menuBar != this->m_menuWidget && this->m_menuWidget){ + this->m_menuWidget->setParent(nullptr); + this->m_menuWidget->deleteLater(); + } + + this->m_menuBar->hide(); + this->m_menuBar->setParent(nullptr); + this->m_menuBar->deleteLater(); + } + + this->m_menuBar = menuBar; + this->m_menuWidget = qobject_cast(menuBar); + + if (menuBar){ + menuBar->setParent(this); + this->m_titleBarW->layout()->addWidget(menuBar); + } +} + +QMenuBar* QCustomWindow::menuBar() const{ + return this->m_menuBar; +} + +void QCustomWindow::setMenuWidget(QWidget *widget){ + if (this->m_menuWidget == widget) return; + + widget->setParent(this); + + if (this->m_menuWidget){ + this->m_menuWidget->hide(); + this->m_menuWidget->setParent(nullptr); + this->m_menuWidget->deleteLater(); + } + + this->m_menuBar = nullptr; + this->m_menuWidget = widget; + + if (this->m_menuWidget){ + this->m_menuWidget->setParent(this); + this->m_titleBarW->layout()->addWidget(widget); + } +} + +QWidget * QCustomWindow::menuWidget() const{ + return this->m_menuWidget; +} + +bool QCustomWindow::eventFilter(QObject*, QEvent *event){ + if (event->type() == QEvent::MouseMove) + customMouseMoveEvent(static_cast(event)); + else if (event->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(event)); + return false; +} + +bool QCustomWindow::event(QEvent *event){ + if (event->type() == QEvent::ChildRemoved){ + QChildEvent *evt = static_cast(event); + if (evt->child()->isWidgetType()) evt->child()->removeEventFilter(this); + } + else if (event->type() == QEvent::ChildAdded){ + QChildEvent *evt = static_cast(event); + if (evt->child()->isWidgetType()){ + QWidget *child = qobject_cast(evt->child()); + + child->setMouseTracking(true); + child->installEventFilter(this); + + if (child->metaObject()->indexOfClassInfo("custom_obj_type") == -1){ + child->setStyleSheet(child->styleSheet() + + "\nQToolBar {\n" + " margin : 1px;\n" + " padding: 0px 6px 0px 6px;\n" + " border: 1px transparent solid;" + "}\n" + "QToolBar:top:first, QToolBar:bottom:first, QToolBar:left:first {\n" + " margin : 0px 0px 0px 6px;\n" + "}\n" + "QToolBar:top:only-one, QToolBar:bottom:only-one {\n" + " margin : 0px 6px 0px 6px;\n" + "}\n" + "QToolBar:top:last, QToolBar:bottom:last, QToolBar:right:last {\n" + " margin : 0px 6px 0px 0px;\n" + "}\n"); + } + } + } + return QMainWindow::event(event); +} + +void QCustomWindow::mousePressEvent(QMouseEvent *event){ + if (event->button() & Qt::LeftButton){ + int x = event->x(), y = event->y(); + int bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; + + QPoint posCursor = event->globalPos(); + Qt::Edges nFlags = {}; + if (x < RESIZE_LIMIT) { + nFlags |= Qt::LeftEdge; + posCursor.rx() -= this->x(); + } + if (y < RESIZE_LIMIT) { + nFlags |= Qt::TopEdge; + posCursor.ry() -= this->y(); + } + if (x > right) { + nFlags |= Qt::RightEdge; + posCursor.rx() -= (this->x() + this->width()); + } + if (y > bottom) { + nFlags |= Qt::BottomEdge; + posCursor.ry() -= (this->y() + this->height()); + } + this->m_lock = nFlags; + this->m_posCursor = posCursor; + } + QMainWindow::mousePressEvent(event); +} + +void QCustomWindow::mouseReleaseEvent(QMouseEvent *event){ + this->m_lock = {}; + this->unsetCursor(); + QMainWindow::mouseMoveEvent(event); +} + +void QCustomWindow::customMouseMoveEvent(QMouseEvent *event){ + if (this->m_lock){ + QPoint tL = this->geometry().topLeft(), bR = this->geometry().bottomRight(); + if (this->m_lock & Qt::TopEdge) tL.ry() = event->globalY() - this->m_posCursor.y(); + if (this->m_lock & Qt::BottomEdge) bR.ry() = event->globalY() - this->m_posCursor.y(); + if (this->m_lock & Qt::LeftEdge) tL.rx() = event->globalX() - this->m_posCursor.x(); + if (this->m_lock & Qt::RightEdge) bR.rx() = event->globalX() - this->m_posCursor.x(); + this->setGeometry(QRect(tL, bR)); + return; + } + + int x = event->globalX() - this->x(), y = event->globalY() - this->y(); + int bottom = this->height() - RESIZE_LIMIT, right = this->width() - RESIZE_LIMIT; + + if (x < RESIZE_LIMIT){ + if (y < RESIZE_LIMIT) this->setCursor(QCursor(Qt::SizeFDiagCursor)); + else if (y > bottom) this->setCursor(QCursor(Qt::SizeBDiagCursor)); + else this->setCursor(QCursor(Qt::SizeHorCursor)); + } + else if (x > right){ + if (y < RESIZE_LIMIT) this->setCursor(QCursor(Qt::SizeBDiagCursor)); + else if (y > bottom) this->setCursor(QCursor(Qt::SizeFDiagCursor)); + else this->setCursor(QCursor(Qt::SizeHorCursor)); + } + else if (y < RESIZE_LIMIT || y > bottom) this->setCursor(Qt::SizeVerCursor); + else this->unsetCursor(); +} diff --git a/src/CustomTitlebar-Static/qcustomwindow.h b/src/CustomTitlebar-Static/qcustomwindow.h new file mode 100644 index 0000000..00d8909 --- /dev/null +++ b/src/CustomTitlebar-Static/qcustomwindow.h @@ -0,0 +1,84 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QCUSTOMWINDOW_H +#define QCUSTOMWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qtitlebar.h" + +class QCustomWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit QCustomWindow(QWidget *parent = nullptr); + ~QCustomWindow() override; + + QMenu * createPopupMenu() override; + + void setMenuBar(QMenuBar *menuBar); + QMenuBar * menuBar() const; + + void setMenuWidget(QWidget *widget); + QWidget * menuWidget() const; + + inline QTitleBar& titleBar() const { return *this->m_titleBar; } + +protected: + const int RESIZE_LIMIT; + + bool event(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + bool eventFilter(QObject *watched, QEvent *event) override; + + void customMouseMoveEvent(QMouseEvent* event); + +private: + bool init; + + QWidget *m_titleBarW; + QWidget *m_menuWidget; + QMenuBar *m_menuBar; + QTitleBar *m_titleBar; + + QToolBar *m_leftBorder; + QToolBar *m_rightBorder; + QToolBar *m_bottomBorder; + + Qt::Edges m_lock; + QPoint m_posCursor; + + QToolBar * generateBorder(Qt::ToolBarArea area, Qt::Orientation orientation); +}; + +#endif // QCUSTOMWINDOW_H diff --git a/src/CustomTitlebar-Static/qtitlebar.cpp b/src/CustomTitlebar-Static/qtitlebar.cpp new file mode 100644 index 0000000..7cfb340 --- /dev/null +++ b/src/CustomTitlebar-Static/qtitlebar.cpp @@ -0,0 +1,127 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#include "qtitlebar.h" + +QTitleBar::QTitleBar(QMainWindow *parent) : + QWidget(parent), FRAME_BUTTON_SIZE(24, 24) +{ + this->canMove = false; + this->maximizing = false; + this->m_frameButtons = QCustomAttrs::All; + + this->setStyleSheet(QStringLiteral( + "QPushButton {\n" + " border : 0.5px solid gray;\n" + " border-radius: 3px;\n" + " min-height: 20px;\n" + " margin: 1px;\n" + " background: white;\n" + " color: gray;\n" + "}\n" + "QPushButton::hover {\n" + " background: darkorange;\n" + " border : 0.5px solid darkorange;\n" + " color: white;\n" + "}\n" + "QPushButton::pressed, QPushButton::!enabled {\n" + " background: orange;\n" + " border : 0.5px solid orange;\n" + " color: white;\n" + "}\n" + "QTitleBar { background: white; }\n" + )); + + if (!parent) throw std::exception("Parent must be a QCustomWindow object (cannot be null)."); + this->m_parentWindow = parent; + + this->lbl_windowTitle.setText("QCustomWindow"); + this->lbl_windowTitle.setAlignment(Qt::AlignCenter); + + this->btn_close.setText("X"); + this->btn_maximize.setText("+"); + this->btn_minimize.setText("-"); + + this->btn_close.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_close.setMinimumSize(FRAME_BUTTON_SIZE); + this->btn_maximize.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_maximize.setMinimumSize(FRAME_BUTTON_SIZE); + this->btn_minimize.setMaximumSize(FRAME_BUTTON_SIZE); + this->btn_minimize.setMinimumSize(FRAME_BUTTON_SIZE); + + this->m_layout.addWidget(&this->lbl_windowTitle, 1); + this->m_layout.addWidget(&this->btn_minimize); + this->m_layout.addWidget(&this->btn_maximize); + this->m_layout.addWidget(&this->btn_close); + this->m_layout.setContentsMargins(0, 0, 0, 4); + this->m_layout.setSpacing(0); + + this->setLayout(&this->m_layout); + + connect(&this->btn_close, &QPushButton::clicked, [this]{ emit this->requestClose(); }); + connect(&this->btn_minimize, &QPushButton::clicked, [this]{ emit this->requestMinimize(); }); + connect(&this->btn_maximize, &QPushButton::clicked, [this]{ emit this->requestMaximize(); }); + + connect(this, &QWidget::windowTitleChanged, &this->lbl_windowTitle, &QLabel::setText); + + this->setMaximumHeight(35); + this->setMinimumHeight(35); +} + +void QTitleBar::setWindowButtons(QCustomAttrs::WindowButtons btns){ + this->m_frameButtons = btns; + this->btn_close.setVisible(btns & QCustomAttrs::Close); + this->btn_maximize.setVisible(btns & QCustomAttrs::Maximize); + this->btn_minimize.setVisible(btns & QCustomAttrs::Minimize); +} + +void QTitleBar::setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled){ + if (btn & QCustomAttrs::Close) this->btn_close.setEnabled(enabled); + if (btn & QCustomAttrs::Maximize) this->btn_maximize.setEnabled(enabled); + if (btn & QCustomAttrs::Minimize) this->btn_minimize.setEnabled(enabled); +} + +void QTitleBar::paintEvent(QPaintEvent *event){ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + QWidget::paintEvent(event); +} + +void QTitleBar::mousePressEvent(QMouseEvent *event){ + if (event->button() & Qt::LeftButton){ + this->canMove = (event->x() > 5 && event->y() > 5 && event->x() < (this->m_parentWindow->width() - 5)); + this->m_pCursor = event->globalPos() - this->m_parentWindow->geometry().topLeft(); + } + QWidget::mousePressEvent(event); +} + +void QTitleBar::mouseMoveEvent(QMouseEvent *event){ + if (!this->maximizing && canMove && event->buttons() & Qt::LeftButton + && !this->m_parentWindow->isMaximized()) this->m_parentWindow->move(event->globalPos() - m_pCursor); + this->maximizing = false; + QWidget::mouseMoveEvent(event); +} + +void QTitleBar::mouseDoubleClickEvent(QMouseEvent *event){ + if (m_frameButtons & QCustomAttrs::Maximize && btn_maximize.isEnabled() + && event->buttons() & Qt::LeftButton) { + this->maximizing = true; + emit requestMaximize(); + } + QWidget::mouseDoubleClickEvent(event); +} diff --git a/src/CustomTitlebar-Static/qtitlebar.h b/src/CustomTitlebar-Static/qtitlebar.h new file mode 100644 index 0000000..caff740 --- /dev/null +++ b/src/CustomTitlebar-Static/qtitlebar.h @@ -0,0 +1,89 @@ +/*------------------------------------------------- +# +# Project developed by Nintersoft team +# Developer: Mauro Mascarenhas de Araújo +# Contact: mauro.mascarenhas@nintersoft.com +# Licence: Mozilla Public Licence 2.0 +# Date: 25 of August of 2020 +# +# Licence notice +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +------------------------------------------------- */ + +#ifndef QTITLEBAR_H +#define QTITLEBAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace QCustomAttrs { + enum WindowButton { + Minimize = 0x01, + Maximize = 0x02, + Close = 0x04, + All = Minimize | Maximize | Close + }; + + Q_DECLARE_FLAGS(WindowButtons, WindowButton) + Q_DECLARE_OPERATORS_FOR_FLAGS(WindowButtons) +} + +class QTitleBar : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QCustomAttrs::WindowButtons windowButtons READ windowButtons WRITE setWindowButtons) + Q_CLASSINFO("custom_obj_type", "QTitleBar") +public: + explicit QTitleBar(QMainWindow *parent = nullptr); + + void setWindowButtons(QCustomAttrs::WindowButtons btns); + inline QCustomAttrs::WindowButtons windowButtons() const { return this->m_frameButtons; } + + void setWindowButtonEnabled(QCustomAttrs::WindowButton btn, bool enabled = true); + +protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + +private: + bool canMove; + bool maximizing; + + QPoint m_pCursor; + const QSize FRAME_BUTTON_SIZE; + + QWidget *m_parentWindow; + + QCustomAttrs::WindowButtons m_frameButtons; + + QLabel lbl_windowTitle; + QHBoxLayout m_layout; + QPushButton btn_minimize; + QPushButton btn_maximize; + QPushButton btn_close; + +signals: + void requestClose(); + void requestMaximize(); + void requestMinimize(); +}; + +#endif // QTITLEBAR_H diff --git a/src/CustomTitlebar-Static/titlebar.cpp b/src/CustomTitlebar-Static/titlebar.cpp deleted file mode 100644 index 831009a..0000000 --- a/src/CustomTitlebar-Static/titlebar.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#include "titlebar.h" -#include "ui_titlebar.h" - -TitleBar::TitleBar(QWidget *parent) : - QWidget(parent), - ui(new Ui::TitleBar) -{ - ui->setupUi(this); - setMainWindow(parent->parentWidget() ? parent->parentWidget() : parent); - - canMove = false; -} - -TitleBar::~TitleBar() -{ - delete ui; -} - -void TitleBar::setMainWindow(QWidget *mainWindow){ - this->parent = mainWindow; - - disconnect(ui->btClose, &QPushButton::clicked, this, &TitleBar::onCloseRequest); - disconnect(ui->btMinimize, &QPushButton::clicked, this->parent, &QWidget::showMinimized); - disconnect(ui->btMaximize, &QPushButton::clicked, this, &TitleBar::maximizeParent); - - disconnect(this->parent, &QWidget::windowTitleChanged, ui->lblFormTitle, &QLabel::setText); - - connect(ui->btClose, &QPushButton::clicked, this, &TitleBar::onCloseRequest); - connect(ui->btMinimize, &QPushButton::clicked, this->parent, &QWidget::showMinimized); - connect(ui->btMaximize, &QPushButton::clicked, this, &TitleBar::maximizeParent); - - connect(this->parent, &QWidget::windowTitleChanged, ui->lblFormTitle, &QLabel::setText); -} - -void TitleBar::maximizeParent(){ - if (parent->isMaximized()) parent->showNormal(); - else parent->showMaximized(); -} - -void TitleBar::onCloseRequest(){ - emit closeRequest(); -} - -QWidget* TitleBar::mainWindow(){ - return this->parent; -} - -void TitleBar::setCloseButtonEnabled(bool enable){ - ui->btClose->setEnabled(enable); -} - -void TitleBar::setMaximizeButtonEnabled(bool enable){ - ui->btMaximize->setEnabled(enable); -} - -void TitleBar::setMinimizeButtonEnabled(bool enable){ - ui->btMinimize->setEnabled(enable); -} - -void TitleBar::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - canMove = !(event->x() < 5 || event->x() > (parent->width() - 5) || event->y() < 5); - m_pCursor = event->globalPos() - parent->geometry().topLeft(); - event->accept(); - } -} - -void TitleBar::mouseMoveEvent(QMouseEvent *event) -{ - if (!canMove){ - event->accept(); - return; - } - if (event->buttons() & Qt::LeftButton){ - if (parent->isMaximized()){ - event->accept(); - return; - } - parent->move(event->globalPos() - m_pCursor); - event->accept(); - } -} - -void TitleBar::mouseDoubleClickEvent(QMouseEvent *event){ - if (!ui->btMaximize->isEnabled()){ - event->accept(); - return; - } - if (event->button() == Qt::LeftButton) maximizeParent(); -} - -void TitleBar::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/CustomTitlebar-Static/titlebar.h b/src/CustomTitlebar-Static/titlebar.h deleted file mode 100644 index 2c170d4..0000000 --- a/src/CustomTitlebar-Static/titlebar.h +++ /dev/null @@ -1,65 +0,0 @@ -/*------------------------------------------------- -# -# Project developed by Nintersoft team -# Developer: Mauro Mascarenhas de Araújo -# Contact: mauro.mascarenhas@nintersoft.com -# Licence: Mozilla Public Licence 2.0 -# Date: 21 of December of 2019 -# -# Licence notice -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -# -------------------------------------------------- */ - -#ifndef TITLEBAR_H -#define TITLEBAR_H - -#include -#include -#include -#include - -namespace Ui { -class TitleBar; -} - -class TitleBar : public QWidget -{ - Q_OBJECT - -public: - explicit TitleBar(QWidget *parent = nullptr); - ~TitleBar(); - - void setMainWindow(QWidget *mainWindow); - QWidget* mainWindow(); - - void setCloseButtonEnabled(bool enable); - void setMaximizeButtonEnabled(bool enable); - void setMinimizeButtonEnabled(bool enable); - -private: - bool canMove; - - Ui::TitleBar *ui; - QWidget *parent; - QPoint m_pCursor; - -protected: - void paintEvent(QPaintEvent *); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - -protected slots: - void maximizeParent(); - void onCloseRequest(); - -signals: - void closeRequest(); -}; - -#endif // TITLEBAR_H diff --git a/src/CustomTitlebar-Static/titlebar.ui b/src/CustomTitlebar-Static/titlebar.ui deleted file mode 100644 index c397b65..0000000 --- a/src/CustomTitlebar-Static/titlebar.ui +++ /dev/null @@ -1,148 +0,0 @@ - - - TitleBar - - - - 0 - 0 - 721 - 35 - - - - - 0 - 35 - - - - - 16777215 - 35 - - - - Form - - - QPushButton{ - border : 0.5px solid gray; - border-radius: 3px; - min-height: 20px; - margin: 1px; - background: white; - color: gray; -} - -QPushButton::hover{ - background: darkorange; - border : 0.5px solid darkorange; - color: white; -} - -QPushButton::pressed, QPushButton::!enabled{ - background: orange; - border : 0.5px solid orange; - color: white; -} - -QWidget::lblFormTitle{ - background-color: white; -} - -QPushButton#lblFormTitle{ - background: transparent; - border-radius: 0px; - border: transparent; - color: black; -} - - - - 0 - - - 6 - - - 6 - - - 6 - - - 0 - - - - - frmTitle - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - 25 - 16777215 - - - - _ - - - - - - - - 24 - 24 - - - - - 25 - 16777215 - - - - + - - - - - - - - 24 - 24 - - - - - 30 - 16777215 - - - - x - - - - - - - -