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
This commit is contained in:
Klaus Basan
2016-06-17 16:16:42 +02:00
parent ce7362a9d9
commit 32d6d68c83
8 changed files with 240 additions and 7 deletions

View File

@@ -163,7 +163,6 @@ namespace BlackGui
// drag and drop // drag and drop
f = f | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; f = f | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
return f; return f;
} }
@@ -198,6 +197,19 @@ namespace BlackGui
return m_modelDestroyed; 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) void CListModelBaseNonTemplate::emitDataChanged(int startRowIndex, int endRowIndex)
{ {
BLACK_VERIFY_X(startRowIndex <= endRowIndex, Q_FUNC_INFO, "check rows"); BLACK_VERIFY_X(startRowIndex <= endRowIndex, Q_FUNC_INFO, "check rows");
@@ -228,6 +240,13 @@ namespace BlackGui
connect(this, &CListModelBaseNonTemplate::dataChanged, this, &CListModelBaseNonTemplate::ps_onDataChanged); 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 bool CListModelBaseNonTemplate::isHoveredRow(const QModelIndex &modelIndex) const
{ {
if (this->m_hoverRow < 0) { return false; } if (this->m_hoverRow < 0) { return false; }
@@ -292,11 +311,13 @@ namespace BlackGui
{ {
// check / init // check / init
if (!this->isValidIndex(index)) { return QVariant(); } if (!this->isValidIndex(index)) { return QVariant(); }
const int row = index.row();
const int col = index.column();
// Hover effect // Hover effect
if (role == Qt::BackgroundRole) if (role == Qt::BackgroundRole)
{ {
if (this->isHoveredRow(index)) if (this->isHoveredRow(row))
{ {
return QBrush(Qt::red); return QBrush(Qt::red);
} }
@@ -311,8 +332,8 @@ namespace BlackGui
if (!formatter || !formatter->supportsRole(role)) { return CListModelBaseNonTemplate::data(index, role); } if (!formatter || !formatter->supportsRole(role)) { return CListModelBaseNonTemplate::data(index, role); }
// Formatted data // Formatted data
const ObjectType obj = this->containerOrFilteredContainer()[index.row()]; const ObjectType obj = this->containerOrFilteredContainer()[row];
BlackMisc::CPropertyIndex propertyIndex = this->columnToPropertyIndex(index.column()); BlackMisc::CPropertyIndex propertyIndex = this->columnToPropertyIndex(col);
return formatter->data(role, obj.propertyByIndex(propertyIndex)).getQVariant(); return formatter->data(role, obj.propertyByIndex(propertyIndex)).getQVariant();
} }

View File

@@ -108,6 +108,9 @@ namespace BlackGui
//! Model about to be destroyed? //! Model about to be destroyed?
bool isModelDestroyed(); bool isModelDestroyed();
//! Hovered role
void setHoveredRow(int row);
//! Drop actions //! Drop actions
void setDropActions(Qt::DropActions dropActions) { this->m_dropActions = dropActions; } void setDropActions(Qt::DropActions dropActions) { this->m_dropActions = dropActions; }
@@ -161,6 +164,9 @@ namespace BlackGui
//! Helper method with template free signature //! Helper method with template free signature
virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort) = 0; virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort) = 0;
//! Row to be hovered?
bool isHoveredRow(int row) const;
//! Row to be hovered? //! Row to be hovered?
bool isHoveredRow(const QModelIndex &modelIndex) const; bool isHoveredRow(const QModelIndex &modelIndex) const;

View File

@@ -19,6 +19,8 @@
#include "blackgui/menus/menudelegate.h" #include "blackgui/menus/menudelegate.h"
#include "blackgui/shortcut.h" #include "blackgui/shortcut.h"
#include "blackgui/views/viewbase.h" #include "blackgui/views/viewbase.h"
#include "blackgui/views/viewbaseproxystyle.h"
#include "blackgui/views/viewbaseitemdelegate.h"
#include "blackmisc/aviation/aircrafticaocode.h" #include "blackmisc/aviation/aircrafticaocode.h"
#include "blackmisc/aviation/aircrafticaocodelist.h" #include "blackmisc/aviation/aircrafticaocodelist.h"
#include "blackmisc/aviation/airlineicaocode.h" #include "blackmisc/aviation/airlineicaocode.h"
@@ -95,6 +97,11 @@ namespace BlackGui
CViewBaseNonTemplate::CViewBaseNonTemplate(QWidget *parent) : CViewBaseNonTemplate::CViewBaseNonTemplate(QWidget *parent) :
QTableView(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); this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &QWidget::customContextMenuRequested, this, &CViewBaseNonTemplate::ps_customMenuRequested); connect(this, &QWidget::customContextMenuRequested, this, &CViewBaseNonTemplate::ps_customMenuRequested);
connect(this, &QTableView::clicked, this, &CViewBaseNonTemplate::ps_clicked); connect(this, &QTableView::clicked, this, &CViewBaseNonTemplate::ps_clicked);
@@ -683,6 +690,12 @@ namespace BlackGui
event->accept(); event->accept();
} }
void CViewBaseNonTemplate::dropEvent(QDropEvent *event)
{
if (!event) { return; }
QTableView::dropEvent(event);
}
template <class ModelClass, class ContainerType, class ObjectType> template <class ModelClass, class ContainerType, class ObjectType>
CViewBase<ModelClass, ContainerType, ObjectType>::CViewBase(QWidget *parent, ModelClass *model) : CViewBaseNonTemplate(parent), m_model(model) CViewBase<ModelClass, ContainerType, ObjectType>::CViewBase(QWidget *parent, ModelClass *model) : CViewBaseNonTemplate(parent), m_model(model)
{ {
@@ -1136,6 +1149,26 @@ namespace BlackGui
} }
} }
template <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::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 <class ModelClass, class ContainerType, class ObjectType>
void CViewBase<ModelClass, ContainerType, ObjectType>::drawDropIndicator(bool indicator)
{
this->m_dropIndicator = indicator;
}
template <class ModelClass, class ContainerType, class ObjectType> template <class ModelClass, class ContainerType, class ObjectType>
CStatusMessage CViewBase<ModelClass, ContainerType, ObjectType>::modifyLoadedJsonData(ContainerType &data) const CStatusMessage CViewBase<ModelClass, ContainerType, ObjectType>::modifyLoadedJsonData(ContainerType &data) const
{ {

View File

@@ -56,14 +56,13 @@ namespace BlackGui
class CDockWidgetInfoArea; class CDockWidgetInfoArea;
class CLoadIndicator; class CLoadIndicator;
namespace Menus { class IMenuDelegate; }
namespace Filters namespace Filters
{ {
class CFilterDialog; class CFilterDialog;
class CFilterWidget; class CFilterWidget;
} }
namespace Menus { class IMenuDelegate; }
namespace Views namespace Views
{ {
//! Non templated base class, allows Q_OBJECT and signals / slots to be used //! 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 //! Load indicator property allows using in stylesheet
Q_PROPERTY(bool isShowingLoadIndicator READ isShowingLoadIndicator NOTIFY loadIndicatorVisibilityChanged) Q_PROPERTY(bool isShowingLoadIndicator READ isShowingLoadIndicator NOTIFY loadIndicatorVisibilityChanged)
friend class CViewBaseItemDelegate;
friend class CViewBaseProxyStyle;
public: public:
//! Resize mode, when to resize rows / columns //! Resize mode, when to resize rows / columns
//! \remarks Using own resizing (other than QHeaderView::ResizeMode) //! \remarks Using own resizing (other than QHeaderView::ResizeMode)
@@ -117,7 +119,7 @@ namespace BlackGui
MenuDefaultDbViews = MenuToggleSelectionMode | MenuBackend, MenuDefaultDbViews = MenuToggleSelectionMode | MenuBackend,
// special menus, should be in derived classes, but enums cannot be inherited // special menus, should be in derived classes, but enums cannot be inherited
// maybe shifted in the future to elsewhere // 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 MenuHighlightStashed = 1 << 11, //!< highlight stashed models
MenuCanStashModels = 1 << 12, //!< stash models MenuCanStashModels = 1 << 12, //!< stash models
MenuStashing = MenuHighlightStashed | MenuCanStashModels, MenuStashing = MenuHighlightStashed | MenuCanStashModels,
@@ -324,6 +326,7 @@ namespace BlackGui
virtual void dragEnterEvent(QDragEnterEvent *event) override; virtual void dragEnterEvent(QDragEnterEvent *event) override;
virtual void dragMoveEvent(QDragMoveEvent *event) override; virtual void dragMoveEvent(QDragMoveEvent *event) override;
virtual void dragLeaveEvent(QDragLeaveEvent *event) override; virtual void dragLeaveEvent(QDragLeaveEvent *event) override;
virtual void dropEvent(QDropEvent *event) override;
//! @} //! @}
//! Perform resizing (no presizing) / non slot method for template //! Perform resizing (no presizing) / non slot method for template
@@ -360,6 +363,12 @@ namespace BlackGui
//! Set the sort indicator to the current sort column //! Set the sort indicator to the current sort column
virtual void updateSortIndicator() = 0; 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) QString m_saveFileName; //!< save file name (JSON)
ResizeMode m_resizeMode = PresizeSubset; //!< mode ResizeMode m_resizeMode = PresizeSubset; //!< mode
RowsResizeMode m_rowResizeMode = Interactive; //!< row resize mode for row height RowsResizeMode m_rowResizeMode = Interactive; //!< row resize mode for row height
@@ -375,6 +384,7 @@ namespace BlackGui
bool m_acceptDoubleClickSelection = false; //!< double clicked bool m_acceptDoubleClickSelection = false; //!< double clicked
bool m_displayAutomatically = true; //!< display directly when loaded bool m_displayAutomatically = true; //!< display directly when loaded
bool m_enableDeleteSelectedRows = false; //!< selected rows can be deleted bool m_enableDeleteSelectedRows = false; //!< selected rows can be deleted
bool m_dropIndicator = false; //!< draw indicator
QWidget *m_filterWidget = nullptr; //!< filter widget or dialog QWidget *m_filterWidget = nullptr; //!< filter widget or dialog
Menu m_menus = MenuDefault; //!< Default menu settings Menu m_menus = MenuDefault; //!< Default menu settings
BlackGui::Menus::IMenuDelegate *m_menu = nullptr; //!< custom menu if any BlackGui::Menus::IMenuDelegate *m_menu = nullptr; //!< custom menu if any
@@ -597,6 +607,8 @@ namespace BlackGui
virtual void performModeBasedResizeToContent() override; virtual void performModeBasedResizeToContent() override;
virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize) override; virtual int performUpdateContainer(const BlackMisc::CVariant &variant, bool sort, bool resize) override;
virtual void updateSortIndicator() 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 //! Modify JSON data loaded in BlackGui::Views::CViewBaseNonTemplate::ps_loadJson

View File

@@ -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<CViewBaseNonTemplate *>(this->parent());
}
} // namespace
} // namespace

View File

@@ -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 <QStyledItemDelegate>
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

View File

@@ -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

View File

@@ -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 <QProxyStyle>
#include <QPen>
#include <QPainter>
#include <QStyleOptionViewItem>
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