From eb0ed082d877156f543324736cbf4ab85a9ec3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 2 Feb 2014 14:27:43 +0100 Subject: [PATCH] Fix group mouse interaction issues --- Group.cpp | 39 +++++++++++++++++++++++++++---- Group.h | 16 +++++++++++-- GroupView.cpp | 64 ++++++++++++++++++++++++++++++++++++--------------- GroupView.h | 23 +++++++++++------- 4 files changed, 109 insertions(+), 33 deletions(-) diff --git a/Group.cpp b/Group.cpp index a62f592b..c92132ca 100644 --- a/Group.cpp +++ b/Group.cpp @@ -9,9 +9,9 @@ Group::Group(const QString &text, GroupView *view) : view(view), text(text), collapsed(false) { } + Group::Group(const Group *other) - : view(other->view), text(other->text), collapsed(other->collapsed), - iconRect(other->iconRect), textRect(other->textRect) + : view(other->view), text(other->text), collapsed(other->collapsed) { } @@ -27,6 +27,37 @@ void Group::update() } } +Group::HitResults Group::pointIntersect(const QPoint &pos) const +{ + Group::HitResults results = Group::NoHit; + int y_start = top(); + int body_start = y_start + headerHeight(); + int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5? + int y = pos.y(); + // int x = pos.x(); + if(y < y_start) + { + results = Group::NoHit; + } + else if(y < body_start) + { + results = Group::HeaderHit; + int collapseSize = headerHeight() - 4; + + // the icon + QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize); + if(iconRect.contains(pos)) + { + results |= Group::CheckboxHit; + } + } + else if (y < body_end) + { + results |= Group::BodyHit; + } + return results; +} + void Group::drawHeader(QPainter *painter, const int y) { painter->save(); @@ -35,7 +66,7 @@ void Group::drawHeader(QPainter *painter, const int y) int collapseSize = height; // the icon - iconRect = QRect(view->m_rightMargin + 2, 2 + y, collapseSize, collapseSize); + QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y, collapseSize, collapseSize); painter->setPen(QPen(Qt::black, 1)); painter->drawRect(iconRect); static const int margin = 2; @@ -50,7 +81,7 @@ void Group::drawHeader(QPainter *painter, const int y) // the text int textWidth = painter->fontMetrics().width(text); - textRect = QRect(iconRect.right() + 4, y, textWidth, headerHeight()); + QRect textRect = QRect(iconRect.right() + 4, y, textWidth, headerHeight()); painter->setBrush(view->viewOptions().palette.text()); view->style()->drawItemText(painter, textRect, Qt::AlignHCenter | Qt::AlignVCenter, view->viewport()->palette(), true, text); diff --git a/Group.h b/Group.h index 6a8fadeb..51e0470d 100644 --- a/Group.h +++ b/Group.h @@ -15,8 +15,6 @@ struct Group GroupView *view; QString text; bool collapsed; - QRect iconRect; - QRect textRect; QVector rowHeights; int firstRow; @@ -29,8 +27,22 @@ struct Group int numRows() const; int top() const; + enum HitResult + { + NoHit = 0x0, + TextHit = 0x1, + CheckboxHit = 0x2, + HeaderHit = 0x4, + BodyHit = 0x8 + }; + Q_DECLARE_FLAGS(HitResults, HitResult) + + HitResults pointIntersect (const QPoint &pos) const; + QList items() const; int numItems() const; QModelIndex firstItem() const; QModelIndex lastItem() const; }; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Group::HitResults) diff --git a/GroupView.cpp b/GroupView.cpp index 50d19f52..1f0a51e7 100644 --- a/GroupView.cpp +++ b/GroupView.cpp @@ -36,7 +36,7 @@ GroupView::GroupView(QWidget *parent) // setWordWrap(true); // setDragDropMode(QListView::InternalMove); setAcceptDrops(true); - // setSpacing(10); + m_spacing = 5; } GroupView::~GroupView() @@ -145,31 +145,31 @@ Group *GroupView::category(const QModelIndex &index) const Group *GroupView::category(const QString &cat) const { - for (int i = 0; i < m_categories.size(); ++i) + for (auto group : m_categories) { - if (m_categories.at(i)->text == cat) + if (group->text == cat) { - return m_categories.at(i); + return group; } } - return 0; + return nullptr; } Group *GroupView::categoryAt(const QPoint &pos) const { - for (int i = 0; i < m_categories.size(); ++i) + for (auto group : m_categories) { - if (m_categories.at(i)->iconRect.contains(pos)) + if(group->pointIntersect(pos) & Group::CheckboxHit) { - return m_categories.at(i); + return group; } } - return 0; + return nullptr; } int GroupView::itemsPerRow() const { - return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + /* spacing */ 10)); + return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing)); } int GroupView::contentWidth() const @@ -261,7 +261,7 @@ void GroupView::mousePressEvent(QMouseEvent *event) m_pressedIndex = index; m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex); - QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); + QItemSelectionModel::SelectionFlags selection_flags = selectionCommand(index, event); m_pressedPosition = pos; m_pressedCategory = categoryAt(m_pressedPosition); @@ -428,9 +428,8 @@ void GroupView::mouseDoubleClickEvent(QMouseEvent *event) void GroupView::paintEvent(QPaintEvent *event) { QPainter painter(this->viewport()); - painter.translate(-offset()); - int y = 0; + int y = -verticalOffset(); for (int i = 0; i < m_categories.size(); ++i) { Group *category = m_categories.at(i); @@ -502,7 +501,7 @@ void GroupView::resizeEvent(QResizeEvent *event) // if (m_categoryEditor) // { // m_categoryEditor->resize(qMax(contentWidth() / 2, - //m_editedCategory->textRect.width()), + // m_editedCategory->textRect.width()), // m_categoryEditor->height()); // } @@ -618,6 +617,11 @@ void GroupView::startDrag(Qt::DropActions supportedActions) } QRect GroupView::visualRect(const QModelIndex &index) const +{ + return geometryRect(index).translated(-offset()); +} + +QRect GroupView::geometryRect(const QModelIndex &index) const { if (!index.isValid() || isIndexHidden(index) || index.column() > 0) { @@ -627,15 +631,16 @@ QRect GroupView::visualRect(const QModelIndex &index) const const Group *cat = category(index); QPair pos = categoryInternalPosition(index); int x = pos.first; - int y = pos.second; + // int y = pos.second; QRect out; out.setTop(cat->top() + cat->headerHeight() + 5 + categoryInternalRowTop(index)); - out.setLeft(/*spacing*/ 10 + x * itemWidth() + x * /*spacing()*/ 10); + out.setLeft(m_spacing + x * (itemWidth() + m_spacing)); out.setSize(itemDelegate()->sizeHint(viewOptions(), index)); return out; } + /* void CategorizedView::startCategoryEditor(Category *category) { @@ -680,7 +685,7 @@ QModelIndex GroupView::indexAt(const QPoint &point) const for (int i = 0; i < model()->rowCount(); ++i) { QModelIndex index = model()->index(i, 0); - if (visualRect(index).contains(point)) + if (geometryRect(index).contains(point)) { return index; } @@ -694,7 +699,7 @@ void GroupView::setSelection(const QRect &rect, for (int i = 0; i < model()->rowCount(); ++i) { QModelIndex index = model()->index(i, 0); - if (visualRect(index).intersects(rect)) + if (geometryRect(index).intersects(rect)) { selectionModel()->select(index, commands); } @@ -734,7 +739,7 @@ QList> GroupView::draggablePaintPairs(const QModelInde for (int i = 0; i < indices.count(); ++i) { const QModelIndex &index = indices.at(i); - const QRect current = visualRect(index); + const QRect current = geometryRect(index); if (current.intersects(viewportRect)) { ret += qMakePair(current, index); @@ -857,3 +862,24 @@ QPoint GroupView::offset() const { return QPoint(horizontalOffset(), verticalOffset()); } + +QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) const +{ + QRegion region; + for (auto &range : selection) + { + int start_row = range.top(); + int end_row = range.bottom(); + for (int row = start_row; row <= end_row; ++row) + { + int start_column = range.left(); + int end_column = range.right(); + for (int column = start_column; column <= end_column; ++column) + { + QModelIndex index = model()->index(row, column, rootIndex()); + region += visualRect(index); // OK + } + } + } + return region; +} diff --git a/GroupView.h b/GroupView.h index bf911794..2c60f0e9 100644 --- a/GroupView.h +++ b/GroupView.h @@ -2,6 +2,7 @@ #include #include +#include struct CategorizedViewRoles { @@ -23,7 +24,8 @@ public: GroupView(QWidget *parent = 0); ~GroupView(); - virtual QRect visualRect(const QModelIndex &index) const; + virtual QRect geometryRect(const QModelIndex &index) const; + virtual QRect visualRect(const QModelIndex &index) const override; QModelIndex indexAt(const QPoint &point) const; void setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands) override; @@ -34,12 +36,18 @@ public: virtual int horizontalOffset() const override { - return 0; + return horizontalScrollBar()->value(); } virtual int verticalOffset() const override { - return 0; + return verticalScrollBar()->value(); + } + + virtual void scrollContentsBy(int dx, int dy) override + { + scrollDirtyRegion(dx, dy); + viewport()->scroll(dx, dy); } virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override @@ -53,10 +61,7 @@ public: return QModelIndex(); } - virtual QRegion visualRegionForSelection(const QItemSelection &) const override - { - return QRegion(); - } + virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override; /* * End of BS @@ -116,14 +121,16 @@ private: private slots: void endCategoryEditor();*/ -private: +private: /* variables */ QPoint m_pressedPosition; QPersistentModelIndex m_pressedIndex; bool m_pressedAlreadySelected; Group *m_pressedCategory; QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag; QPoint m_lastDragPosition; + int m_spacing = 5; +private: /* methods */ QPair categoryInternalPosition(const QModelIndex &index) const; int categoryInternalRowTop(const QModelIndex &index) const; int itemHeightForCategoryRow(const Group *category, const int internalRow) const;