From 32d6d68c83c89a2bcbf87fff57c473bff8ed0149 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Fri, 17 Jun 2016 16:16:42 +0200 Subject: [PATCH] refs #674, code for hover/drop indicator * item delegate for callback to view for hover * proxy style for draw drop indicator as primitive * added functions to view base for hover / callbacks * highlight hover row in model --- src/blackgui/models/listmodelbase.cpp | 29 +++++++++++-- src/blackgui/models/listmodelbase.h | 6 +++ src/blackgui/views/viewbase.cpp | 33 +++++++++++++++ src/blackgui/views/viewbase.h | 18 +++++++-- src/blackgui/views/viewbaseitemdelegate.cpp | 34 ++++++++++++++++ src/blackgui/views/viewbaseitemdelegate.h | 44 ++++++++++++++++++++ src/blackgui/views/viewbaseproxystyle.cpp | 38 +++++++++++++++++ src/blackgui/views/viewbaseproxystyle.h | 45 +++++++++++++++++++++ 8 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 src/blackgui/views/viewbaseitemdelegate.cpp create mode 100644 src/blackgui/views/viewbaseitemdelegate.h create mode 100644 src/blackgui/views/viewbaseproxystyle.cpp create mode 100644 src/blackgui/views/viewbaseproxystyle.h diff --git a/src/blackgui/models/listmodelbase.cpp b/src/blackgui/models/listmodelbase.cpp index 53bac3c5b..cdcdf7e89 100644 --- a/src/blackgui/models/listmodelbase.cpp +++ b/src/blackgui/models/listmodelbase.cpp @@ -163,7 +163,6 @@ namespace BlackGui // drag and drop f = f | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; - return f; } @@ -198,6 +197,19 @@ namespace BlackGui return m_modelDestroyed; } + void CListModelBaseNonTemplate::setHoveredRow(int row) + { + if (this->m_hoverRow == row) { return; } + this->m_hoverRow = row; + const int columns = columnCount(); + if (columns < 1) { return; } + if (row < 0) { return; } + + const QModelIndex topLeft(createIndex(row, 0)); + const QModelIndex bottomRight(createIndex(row, columns - 1)); + emit this->dataChanged(topLeft, bottomRight); + } + void CListModelBaseNonTemplate::emitDataChanged(int startRowIndex, int endRowIndex) { BLACK_VERIFY_X(startRowIndex <= endRowIndex, Q_FUNC_INFO, "check rows"); @@ -228,6 +240,13 @@ namespace BlackGui connect(this, &CListModelBaseNonTemplate::dataChanged, this, &CListModelBaseNonTemplate::ps_onDataChanged); } + bool CListModelBaseNonTemplate::isHoveredRow(int row) const + { + if (this->m_hoverRow < 0) { return false; } + if (row < 0) { return false; } + return row == this->m_hoverRow; + } + bool CListModelBaseNonTemplate::isHoveredRow(const QModelIndex &modelIndex) const { if (this->m_hoverRow < 0) { return false; } @@ -292,11 +311,13 @@ namespace BlackGui { // check / init if (!this->isValidIndex(index)) { return QVariant(); } + const int row = index.row(); + const int col = index.column(); // Hover effect if (role == Qt::BackgroundRole) { - if (this->isHoveredRow(index)) + if (this->isHoveredRow(row)) { return QBrush(Qt::red); } @@ -311,8 +332,8 @@ namespace BlackGui if (!formatter || !formatter->supportsRole(role)) { return CListModelBaseNonTemplate::data(index, role); } // Formatted data - const ObjectType obj = this->containerOrFilteredContainer()[index.row()]; - BlackMisc::CPropertyIndex propertyIndex = this->columnToPropertyIndex(index.column()); + const ObjectType obj = this->containerOrFilteredContainer()[row]; + BlackMisc::CPropertyIndex propertyIndex = this->columnToPropertyIndex(col); return formatter->data(role, obj.propertyByIndex(propertyIndex)).getQVariant(); } diff --git a/src/blackgui/models/listmodelbase.h b/src/blackgui/models/listmodelbase.h index eb805af07..a7d1b3bf0 100644 --- a/src/blackgui/models/listmodelbase.h +++ b/src/blackgui/models/listmodelbase.h @@ -108,6 +108,9 @@ namespace BlackGui //! Model about to be destroyed? bool isModelDestroyed(); + //! Hovered role + void setHoveredRow(int row); + //! Drop actions void setDropActions(Qt::DropActions dropActions) { this->m_dropActions = dropActions; } @@ -161,6 +164,9 @@ namespace BlackGui //! Helper method with template free signature virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort) = 0; + //! Row to be hovered? + bool isHoveredRow(int row) const; + //! Row to be hovered? bool isHoveredRow(const QModelIndex &modelIndex) const; diff --git a/src/blackgui/views/viewbase.cpp b/src/blackgui/views/viewbase.cpp index 4dda99725..0f60a44ec 100644 --- a/src/blackgui/views/viewbase.cpp +++ b/src/blackgui/views/viewbase.cpp @@ -19,6 +19,8 @@ #include "blackgui/menus/menudelegate.h" #include "blackgui/shortcut.h" #include "blackgui/views/viewbase.h" +#include "blackgui/views/viewbaseproxystyle.h" +#include "blackgui/views/viewbaseitemdelegate.h" #include "blackmisc/aviation/aircrafticaocode.h" #include "blackmisc/aviation/aircrafticaocodelist.h" #include "blackmisc/aviation/airlineicaocode.h" @@ -95,6 +97,11 @@ namespace BlackGui CViewBaseNonTemplate::CViewBaseNonTemplate(QWidget *parent) : QTableView(parent) { + // this->viewport()->setAttribute(Qt::WA_Hover, true); + // this->viewport()->setMouseTracking(true); + // this->setStyle(new CViewBaseProxyStyle(this, this->style())); + // this->setItemDelegate(new CViewBaseItemDelegate(this)); + this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &QWidget::customContextMenuRequested, this, &CViewBaseNonTemplate::ps_customMenuRequested); connect(this, &QTableView::clicked, this, &CViewBaseNonTemplate::ps_clicked); @@ -683,6 +690,12 @@ namespace BlackGui event->accept(); } + void CViewBaseNonTemplate::dropEvent(QDropEvent *event) + { + if (!event) { return; } + QTableView::dropEvent(event); + } + template CViewBase::CViewBase(QWidget *parent, ModelClass *model) : CViewBaseNonTemplate(parent), m_model(model) { @@ -1136,6 +1149,26 @@ namespace BlackGui } } + template + void CViewBase::mouseOverCallback(const QModelIndex &index, bool mouseOver) + { + if (mouseOver && index.isValid()) + { + const int row = index.row(); + this->m_model->setHoveredRow(row); + } + else + { + // this->m_model->setHoveredRow(-1); + } + } + + template + void CViewBase::drawDropIndicator(bool indicator) + { + this->m_dropIndicator = indicator; + } + template CStatusMessage CViewBase::modifyLoadedJsonData(ContainerType &data) const { diff --git a/src/blackgui/views/viewbase.h b/src/blackgui/views/viewbase.h index 6b2b9207a..238398e1a 100644 --- a/src/blackgui/views/viewbase.h +++ b/src/blackgui/views/viewbase.h @@ -56,14 +56,13 @@ namespace BlackGui class CDockWidgetInfoArea; class CLoadIndicator; + namespace Menus { class IMenuDelegate; } namespace Filters { class CFilterDialog; class CFilterWidget; } - namespace Menus { class IMenuDelegate; } - namespace Views { //! Non templated base class, allows Q_OBJECT and signals / slots to be used @@ -76,6 +75,9 @@ namespace BlackGui //! Load indicator property allows using in stylesheet Q_PROPERTY(bool isShowingLoadIndicator READ isShowingLoadIndicator NOTIFY loadIndicatorVisibilityChanged) + friend class CViewBaseItemDelegate; + friend class CViewBaseProxyStyle; + public: //! Resize mode, when to resize rows / columns //! \remarks Using own resizing (other than QHeaderView::ResizeMode) @@ -117,7 +119,7 @@ namespace BlackGui MenuDefaultDbViews = MenuToggleSelectionMode | MenuBackend, // special menus, should be in derived classes, but enums cannot be inherited // maybe shifted in the future to elsewhere - MenuHighlightDbData = 1 << 10, //!< highlight DB data + MenuHighlightDbData = 1 << 10, //!< highlight DB data MenuHighlightStashed = 1 << 11, //!< highlight stashed models MenuCanStashModels = 1 << 12, //!< stash models MenuStashing = MenuHighlightStashed | MenuCanStashModels, @@ -324,6 +326,7 @@ namespace BlackGui virtual void dragEnterEvent(QDragEnterEvent *event) override; virtual void dragMoveEvent(QDragMoveEvent *event) override; virtual void dragLeaveEvent(QDragLeaveEvent *event) override; + virtual void dropEvent(QDropEvent *event) override; //! @} //! Perform resizing (no presizing) / non slot method for template @@ -360,6 +363,12 @@ namespace BlackGui //! Set the sort indicator to the current sort column virtual void updateSortIndicator() = 0; + //! From delegate indicating we are in mouse over state + virtual void mouseOverCallback(const QModelIndex &index, bool mouseOver) = 0; + + //! Draw drop indicator + virtual void drawDropIndicator(bool indicator) = 0; + QString m_saveFileName; //!< save file name (JSON) ResizeMode m_resizeMode = PresizeSubset; //!< mode RowsResizeMode m_rowResizeMode = Interactive; //!< row resize mode for row height @@ -375,6 +384,7 @@ namespace BlackGui bool m_acceptDoubleClickSelection = false; //!< double clicked bool m_displayAutomatically = true; //!< display directly when loaded bool m_enableDeleteSelectedRows = false; //!< selected rows can be deleted + bool m_dropIndicator = false; //!< draw indicator QWidget *m_filterWidget = nullptr; //!< filter widget or dialog Menu m_menus = MenuDefault; //!< Default menu settings BlackGui::Menus::IMenuDelegate *m_menu = nullptr; //!< custom menu if any @@ -597,6 +607,8 @@ namespace BlackGui virtual void performModeBasedResizeToContent() override; virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize) override; virtual void updateSortIndicator() override; + virtual void mouseOverCallback(const QModelIndex &index, bool mouseOver) override; + virtual void drawDropIndicator(bool indicator) override; //! @} //! Modify JSON data loaded in BlackGui::Views::CViewBaseNonTemplate::ps_loadJson diff --git a/src/blackgui/views/viewbaseitemdelegate.cpp b/src/blackgui/views/viewbaseitemdelegate.cpp new file mode 100644 index 000000000..46ed82b6d --- /dev/null +++ b/src/blackgui/views/viewbaseitemdelegate.cpp @@ -0,0 +1,34 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "viewbaseitemdelegate.h" +#include "viewbase.h" + +namespace BlackGui +{ + namespace Views + { + void CViewBaseItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const + { + const bool isMouseOver = option.state & QStyle::State_MouseOver; + viewBase()->mouseOverCallback(index, isMouseOver); + QStyledItemDelegate::paint(painter, option, index); + } + + QSize CViewBaseItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const + { + return QStyledItemDelegate::sizeHint(option, index); + } + + CViewBaseNonTemplate *CViewBaseItemDelegate::viewBase() const + { + return qobject_cast(this->parent()); + } + } // namespace +} // namespace diff --git a/src/blackgui/views/viewbaseitemdelegate.h b/src/blackgui/views/viewbaseitemdelegate.h new file mode 100644 index 000000000..1fec6f817 --- /dev/null +++ b/src/blackgui/views/viewbaseitemdelegate.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_VIEWBASE_ITEMDELEGATE_H +#define BLACKGUI_VIEWBASE_ITEMDELEGATE_H + +#include + +namespace BlackGui +{ + namespace Views + { + class CViewBaseNonTemplate; + + /*! + * Delegate for our view items + */ + class CViewBaseItemDelegate : public QStyledItemDelegate + { + public: + //! Constructor + CViewBaseItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} + + //! \name QStyledItemDelegate overrides + //! @{ + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + //! @} + + private: + //! Related CViewBaseNonTemplate + CViewBaseNonTemplate *viewBase() const; + }; + } // namespace +} // namespace +#endif // guard diff --git a/src/blackgui/views/viewbaseproxystyle.cpp b/src/blackgui/views/viewbaseproxystyle.cpp new file mode 100644 index 000000000..699531337 --- /dev/null +++ b/src/blackgui/views/viewbaseproxystyle.cpp @@ -0,0 +1,38 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "viewbaseproxystyle.h" +#include "viewbase.h" + +namespace BlackGui +{ + namespace Views + { + CViewBaseProxyStyle::CViewBaseProxyStyle(CViewBaseNonTemplate *view, QStyle *style) : QProxyStyle(style), m_view(view) {} + + void CViewBaseProxyStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const + { + const bool indicator = (element == QStyle::PE_IndicatorItemViewItemDrop); + if (indicator) + { + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); + QPainter viewPainter(this->m_view->viewport()); + QPoint point = this->m_view->mapFromGlobal(QCursor::pos()); + if (!point.isNull()) + { + const QPoint topLeft(0, point.y()); + const QPoint topRight(this->m_view->width(), point.y()); + viewPainter.drawLine(topLeft, topRight); + } + } + } + } // namespace +} // namespace diff --git a/src/blackgui/views/viewbaseproxystyle.h b/src/blackgui/views/viewbaseproxystyle.h new file mode 100644 index 000000000..235c8c96d --- /dev/null +++ b/src/blackgui/views/viewbaseproxystyle.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_VIEWBASE_PROXYSTYLE_H +#define BLACKGUI_VIEWBASE_PROXYSTYLE_H + +#include +#include +#include +#include + +namespace BlackGui +{ + namespace Views + { + class CViewBaseNonTemplate; + + /*! + * Proxy for style of our views + */ + class CViewBaseProxyStyle : public QProxyStyle + { + public: + //! Constructor + CViewBaseProxyStyle(CViewBaseNonTemplate *view, QStyle *style = nullptr); + + //! \name Proxy style overrides + //! @{ + virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; + //! @} + + private: + CViewBaseNonTemplate *m_view = nullptr; //!< "parent view" + }; + } // namespace +} // namespace +#endif // guard