diff --git a/bin/app/data/gui/code_view/code_view.css b/bin/app/data/gui/code_view/code_view.css index a66141b8..230dc1c4 100644 --- a/bin/app/data/gui/code_view/code_view.css +++ b/bin/app/data/gui/code_view/code_view.css @@ -82,8 +82,6 @@ background-color: ; border: 2px solid ; border-radius: 12px; - border-top-left-radius: 14px; - border-top-right-radius: 14px; font-size: px; padding-bottom: 7px; } @@ -93,7 +91,6 @@ border-top-left-radius: 7px; border-top-right-radius: 7px; font-size: px; - padding-right: 5px; } #code_file #title_label, #single_file_title_bar #file_title { @@ -106,7 +103,7 @@ } #code_file #title_label { - margin: 1px 8px 3px; + margin: 1px 8px; } #single_file_title_bar #file_title { @@ -181,34 +178,16 @@ selection-background-color: ; } -#code_file #maximize_button, #code_file #snippet_button, #code_file #minimize_button { +#code_file #file_button { + background: transparent; + border: none; margin: 3px; max-height: 16px; max-width: 16px; } -#code_file #maximize_button { - border-image: url(code_view/images/maximize_inactive.png); -} - -#code_file #maximize_button:enabled { - border-image: url(code_view/images/maximize_active.png); -} - -#code_file #snippet_button { - border-image: url(code_view/images/snippet_inactive.png); -} - -#code_file #snippet_button:enabled { - border-image: url(code_view/images/snippet_active.png); -} - -#code_file #minimize_button { - border-image: url(code_view/images/minimize_inactive.png); -} - -#code_file #minimize_button:enabled { - border-image: url(code_view/images/minimize_active.png); +#code_file #file_button:enabled { + border-image: url(code_view/images/button_background.png); } #single_file_title_bar { diff --git a/bin/app/data/gui/code_view/images/button_background.png b/bin/app/data/gui/code_view/images/button_background.png new file mode 100644 index 00000000..a130b01b Binary files /dev/null and b/bin/app/data/gui/code_view/images/button_background.png differ diff --git a/src/lib_gui/qt/element/QtCodeFile.cpp b/src/lib_gui/qt/element/QtCodeFile.cpp index 5e26671f..92b494b8 100644 --- a/src/lib_gui/qt/element/QtCodeFile.cpp +++ b/src/lib_gui/qt/element/QtCodeFile.cpp @@ -5,6 +5,7 @@ #include #include "utility/messaging/type/MessageChangeFileView.h" +#include "utility/ResourcePaths.h" #include "data/location/SourceLocationFile.h" #include "qt/element/QtCodeFileTitleButton.h" @@ -28,11 +29,14 @@ QtCodeFile::QtCodeFile(const FilePath& filePath, QtCodeNavigator* navigator) layout->setAlignment(Qt::AlignTop); setLayout(layout); - m_titleBar = new QPushButton(this); + m_titleBar = new QtHoverButton(this); m_titleBar->setObjectName("title_widget"); m_titleBar->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac layout->addWidget(m_titleBar); + connect(dynamic_cast(m_titleBar), SIGNAL(hoveredIn(QPushButton*)), this, SLOT(enteredTitleBar(QPushButton*))); + connect(dynamic_cast(m_titleBar), SIGNAL(hoveredOut(QPushButton*)), this, SLOT(leftTitleBar(QPushButton*))); + QHBoxLayout* titleLayout = new QHBoxLayout(); titleLayout->setMargin(0); titleLayout->setSpacing(0); @@ -56,24 +60,39 @@ QtCodeFile::QtCodeFile(const FilePath& filePath, QtCodeNavigator* navigator) titleLayout->addStretch(3); - m_minimizeButton = new QPushButton(this); - m_minimizeButton->setObjectName("minimize_button"); + m_minimizeButton = new QtIconStateButton(this); + m_minimizeButton->addState(QtIconStateButton::STATE_DEFAULT, (ResourcePaths::getGuiPath().str() + "code_view/images/minimize_active.png").c_str()); + m_minimizeButton->addState(QtIconStateButton::STATE_HOVERED, (ResourcePaths::getGuiPath().str() + "code_view/images/minimize_inactive.png").c_str(), "#5E5D5D"); + m_minimizeButton->addState(QtIconStateButton::STATE_DISABLED, (ResourcePaths::getGuiPath().str() + "code_view/images/minimize_inactive.png").c_str()); + m_minimizeButton->setObjectName("file_button"); m_minimizeButton->setToolTip("minimize"); - m_minimizeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac titleLayout->addWidget(m_minimizeButton); - m_snippetButton = new QPushButton(this); - m_snippetButton->setObjectName("snippet_button"); + m_snippetButton = new QtIconStateButton(this); + m_snippetButton->addState(QtIconStateButton::STATE_DEFAULT, (ResourcePaths::getGuiPath().str() + "code_view/images/snippet_active.png").c_str()); + m_snippetButton->addState(QtIconStateButton::STATE_HOVERED, (ResourcePaths::getGuiPath().str() + "code_view/images/snippet_inactive.png").c_str(), "#5E5D5D"); + m_snippetButton->addState(QtIconStateButton::STATE_DISABLED, (ResourcePaths::getGuiPath().str() + "code_view/images/snippet_inactive.png").c_str()); + m_snippetButton->setObjectName("file_button"); m_snippetButton->setToolTip("show snippets"); - m_snippetButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac titleLayout->addWidget(m_snippetButton); - m_maximizeButton = new QPushButton(this); - m_maximizeButton->setObjectName("maximize_button"); + m_maximizeButton = new QtIconStateButton(this); + m_maximizeButton->addState(QtIconStateButton::STATE_DEFAULT, (ResourcePaths::getGuiPath().str() + "code_view/images/maximize_active.png").c_str()); + m_maximizeButton->addState(QtIconStateButton::STATE_HOVERED, (ResourcePaths::getGuiPath().str() + "code_view/images/maximize_inactive.png").c_str(), "#5E5D5D"); + m_maximizeButton->addState(QtIconStateButton::STATE_DISABLED, (ResourcePaths::getGuiPath().str() + "code_view/images/maximize_inactive.png").c_str()); + m_maximizeButton->setObjectName("file_button"); m_maximizeButton->setToolTip("maximize"); - m_maximizeButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac titleLayout->addWidget(m_maximizeButton); + connect(m_minimizeButton, SIGNAL(hoveredIn(QPushButton*)), this, SLOT(leftTitleBar(QPushButton*))); + connect(m_minimizeButton, SIGNAL(hoveredOut(QPushButton*)), this, SLOT(enteredTitleBar(QPushButton*))); + connect(m_snippetButton, SIGNAL(hoveredIn(QPushButton*)), this, SLOT(leftTitleBar(QPushButton*))); + connect(m_snippetButton, SIGNAL(hoveredOut(QPushButton*)), this, SLOT(enteredTitleBar(QPushButton*))); + connect(m_maximizeButton, SIGNAL(hoveredIn(QPushButton*)), this, SLOT(leftTitleBar(QPushButton*))); + connect(m_maximizeButton, SIGNAL(hoveredOut(QPushButton*)), this, SLOT(enteredTitleBar(QPushButton*))); + + titleLayout->addSpacing(3); + m_minimizeButton->setEnabled(false); m_snippetButton->setEnabled(false); m_maximizeButton->setEnabled(false); @@ -112,13 +131,12 @@ std::string QtCodeFile::getFileName() const QtCodeSnippet* QtCodeFile::addCodeSnippet(const CodeSnippetParams& params) { - m_isCollapsed = false; - std::shared_ptr snippet(new QtCodeSnippet(params, m_navigator, this)); if (params.reduced) { m_title->setProject(params.title); + m_isCollapsed = false; } m_snippetLayout->addWidget(snippet.get()); @@ -141,6 +159,10 @@ QtCodeSnippet* QtCodeFile::addCodeSnippet(const CodeSnippetParams& params) return m_fileSnippet.get(); } + else + { + m_isCollapsed = false; + } m_snippets.push_back(snippet); @@ -310,6 +332,12 @@ void QtCodeFile::setMinimized() m_minimizeButton->setEnabled(false); m_snippetButton->setEnabled(m_snippets.size() || (isCollapsed() && !m_isWholeFile)); m_maximizeButton->setEnabled(true); + + m_minimizeButton->hoverOut(); + m_snippetButton->hoverOut(); + m_maximizeButton->hoverOut(); + + setStyleSheet("#code_file { padding-bottom: 0; } #code_file #title_widget { border-radius: 7px; }"); } void QtCodeFile::setSnippets() @@ -327,6 +355,12 @@ void QtCodeFile::setSnippets() m_minimizeButton->setEnabled(true); m_snippetButton->setEnabled(false); m_maximizeButton->setEnabled(true); + + m_minimizeButton->hoverOut(); + m_snippetButton->hoverOut(); + m_maximizeButton->hoverOut(); + + setStyleSheet(""); } void QtCodeFile::setMaximized() @@ -342,8 +376,14 @@ void QtCodeFile::setMaximized() } m_minimizeButton->setEnabled(true); - m_snippetButton->setEnabled(m_snippets.size()); + m_snippetButton->setEnabled(m_snippets.size() || (isCollapsed() && !m_isWholeFile)); m_maximizeButton->setEnabled(false); + + m_minimizeButton->hoverOut(); + m_snippetButton->hoverOut(); + m_maximizeButton->hoverOut(); + + setStyleSheet(""); } bool QtCodeFile::hasSnippets() const @@ -385,8 +425,15 @@ void QtCodeFile::updateTitleBar() m_title->updateTexts(); } -void QtCodeFile::clickedMinimizeButton() const +void QtCodeFile::clickedMinimizeButton() { + // overview stats + if (m_filePath.empty()) + { + setMinimized(); + return; + } + MessageChangeFileView( m_filePath, MessageChangeFileView::FILE_MINIMIZED, @@ -395,7 +442,7 @@ void QtCodeFile::clickedMinimizeButton() const ).dispatch(); } -void QtCodeFile::clickedSnippetButton() const +void QtCodeFile::clickedSnippetButton() { MessageChangeFileView( m_filePath, @@ -405,8 +452,15 @@ void QtCodeFile::clickedSnippetButton() const ).dispatch(); } -void QtCodeFile::clickedMaximizeButton() const +void QtCodeFile::clickedMaximizeButton() { + // overview stats + if (m_filePath.empty()) + { + setMaximized(); + return; + } + MessageChangeFileView( m_filePath, MessageChangeFileView::FILE_MAXIMIZED, @@ -415,6 +469,56 @@ void QtCodeFile::clickedMaximizeButton() const ).dispatch(); } +void QtCodeFile::enteredTitleBar(QPushButton* button) +{ + if (m_minimizeButton->isEnabled()) + { + if (m_minimizeButton != button) + { + m_minimizeButton->hoverIn(); + } + } + else if (m_snippetButton->isEnabled()) + { + if (m_snippetButton != button) + { + m_snippetButton->hoverIn(); + } + } + else if (m_maximizeButton->isEnabled()) + { + if (m_maximizeButton != button) + { + m_maximizeButton->hoverIn(); + } + } +} + +void QtCodeFile::leftTitleBar(QPushButton* button) +{ + if (m_minimizeButton->isEnabled()) + { + if (m_minimizeButton != button) + { + m_minimizeButton->hoverOut(); + } + } + else if (m_snippetButton->isEnabled()) + { + if (m_snippetButton != button) + { + m_snippetButton->hoverOut(); + } + } + else if (m_maximizeButton->isEnabled()) + { + if (m_maximizeButton != button) + { + m_maximizeButton->hoverOut(); + } + } +} + void QtCodeFile::clickedTitleBar() { if (m_minimizeButton->isEnabled()) diff --git a/src/lib_gui/qt/element/QtCodeFile.h b/src/lib_gui/qt/element/QtCodeFile.h index 0af62f94..aca9af17 100644 --- a/src/lib_gui/qt/element/QtCodeFile.h +++ b/src/lib_gui/qt/element/QtCodeFile.h @@ -7,9 +7,11 @@ #include -#include "component/view/helper/CodeSnippetParams.h" #include "utility/file/FilePath.h" +#include "component/view/helper/CodeSnippetParams.h" +#include "qt/element/QtIconButton.h" + class QLabel; class QPushButton; class QtCodeFileTitleButton; @@ -58,9 +60,12 @@ public: void updateTitleBar(); public slots: - void clickedMinimizeButton() const; - void clickedSnippetButton() const; - void clickedMaximizeButton() const; + void clickedMinimizeButton(); + void clickedSnippetButton(); + void clickedMaximizeButton(); + + void enteredTitleBar(QPushButton* button); + void leftTitleBar(QPushButton* button); private slots: void clickedTitleBar(); @@ -74,9 +79,9 @@ private: QtCodeFileTitleButton* m_title; QLabel* m_referenceCount; - QPushButton* m_minimizeButton; - QPushButton* m_snippetButton; - QPushButton* m_maximizeButton; + QtIconStateButton* m_minimizeButton; + QtIconStateButton* m_snippetButton; + QtIconStateButton* m_maximizeButton; QVBoxLayout* m_snippetLayout; std::vector> m_snippets; diff --git a/src/lib_gui/qt/element/QtIconButton.cpp b/src/lib_gui/qt/element/QtIconButton.cpp index 9038a3b7..229b438c 100644 --- a/src/lib_gui/qt/element/QtIconButton.cpp +++ b/src/lib_gui/qt/element/QtIconButton.cpp @@ -1,7 +1,34 @@ #include "qt/element/QtIconButton.h" +#include + #include "qt/utility/utilityQt.h" + +QtHoverButton::QtHoverButton(QWidget* parent) + : QPushButton("", parent) +{ + setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac + setMouseTracking(true); +} + +void QtHoverButton::enterEvent(QEvent *event) +{ + if (isEnabled()) + { + emit hoveredIn(this); + } +} + +void QtHoverButton::leaveEvent(QEvent *event) +{ + if (isEnabled()) + { + emit hoveredOut(this); + } +} + + QtIconButton::QtIconButton(QString iconPath, QString hoveredIconPath, QWidget* parent) : QPushButton("", parent) , m_iconPath(iconPath) @@ -50,3 +77,106 @@ void QtIconButton::setIconFromPath(QString path) setIcon(QIcon(pixmap)); } + + +QtIconStateButton::QtIconStateButton(QWidget* parent) + : QPushButton("", parent) +{ + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac + setMouseTracking(true); + + setObjectName("iconStateButton"); + + leaveEvent(nullptr); +} + +void QtIconStateButton::addState(ButtonState buttonState, QString iconPath, QColor color) +{ + State state; + state.iconPath = iconPath; + state.color = color; + m_states.emplace(buttonState, state); + + if (buttonState == STATE_DEFAULT) + { + leaveEvent(nullptr); + } +} + +void QtIconStateButton::hoverIn() +{ + enterEvent(nullptr); +} + +void QtIconStateButton::hoverOut() +{ + leaveEvent(nullptr); +} + +void QtIconStateButton::changeEvent(QEvent *event) +{ + if (event->type() != QEvent::EnabledChange) + { + return; + } + + auto it = m_states.find(isEnabled() ? STATE_DEFAULT : STATE_DISABLED); + if (it != m_states.end()) + { + setState(it->second); + } +} + +void QtIconStateButton::enterEvent(QEvent *event) +{ + if (!isEnabled()) + { + return; + } + + auto it = m_states.find(STATE_HOVERED); + if (it != m_states.end()) + { + setState(it->second); + + if (event) + { + emit hoveredIn(this); + } + } +} + +void QtIconStateButton::leaveEvent(QEvent *event) +{ + if (!isEnabled()) + { + return; + } + + auto it = m_states.find(STATE_DEFAULT); + if (it != m_states.end()) + { + setState(it->second); + + if (event) + { + emit hoveredOut(this); + } + } +} + +void QtIconStateButton::setState(State state) +{ + QPixmap pixmap = QPixmap(state.iconPath); + + if (state.color != Qt::transparent) + { + pixmap = utility::colorizePixmap(pixmap, state.color); + } + + QIcon icon(pixmap); + icon.addPixmap(pixmap, QIcon::Disabled); + + setIcon(icon); +} diff --git a/src/lib_gui/qt/element/QtIconButton.h b/src/lib_gui/qt/element/QtIconButton.h index 2cf8e489..8ae1bfe4 100644 --- a/src/lib_gui/qt/element/QtIconButton.h +++ b/src/lib_gui/qt/element/QtIconButton.h @@ -3,6 +3,24 @@ #include +class QtHoverButton + : public QPushButton +{ + Q_OBJECT + +public: + QtHoverButton(QWidget* parent = nullptr); + +signals: + void hoveredIn(QPushButton*); + void hoveredOut(QPushButton*); + +protected: + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); +}; + + class QtIconButton : public QPushButton { @@ -24,4 +42,46 @@ private: QColor m_color; }; + +class QtIconStateButton + : public QPushButton +{ + Q_OBJECT + +public: + enum ButtonState + { + STATE_DEFAULT, + STATE_HOVERED, + STATE_DISABLED + }; + + struct State + { + QString iconPath; + QColor color; + }; + + QtIconStateButton(QWidget* parent = nullptr); + + void addState(ButtonState buttonState, QString iconPath, QColor color = Qt::transparent); + + void hoverIn(); + void hoverOut(); + +signals: + void hoveredIn(QPushButton*); + void hoveredOut(QPushButton*); + +protected: + void changeEvent(QEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + +private: + void setState(State state); + + std::map m_states; +}; + #endif // QT_ICON_BUTTON_H