Fix group mouse interaction issues

This commit is contained in:
Petr Mrázek 2014-02-02 14:27:43 +01:00
parent b2bf50a6d7
commit eb0ed082d8
4 changed files with 109 additions and 33 deletions

View File

@ -9,9 +9,9 @@
Group::Group(const QString &text, GroupView *view) : view(view), text(text), collapsed(false) Group::Group(const QString &text, GroupView *view) : view(view), text(text), collapsed(false)
{ {
} }
Group::Group(const Group *other) Group::Group(const Group *other)
: view(other->view), text(other->text), collapsed(other->collapsed), : view(other->view), text(other->text), collapsed(other->collapsed)
iconRect(other->iconRect), textRect(other->textRect)
{ {
} }
@ -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) void Group::drawHeader(QPainter *painter, const int y)
{ {
painter->save(); painter->save();
@ -35,7 +66,7 @@ void Group::drawHeader(QPainter *painter, const int y)
int collapseSize = height; int collapseSize = height;
// the icon // 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->setPen(QPen(Qt::black, 1));
painter->drawRect(iconRect); painter->drawRect(iconRect);
static const int margin = 2; static const int margin = 2;
@ -50,7 +81,7 @@ void Group::drawHeader(QPainter *painter, const int y)
// the text // the text
int textWidth = painter->fontMetrics().width(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()); painter->setBrush(view->viewOptions().palette.text());
view->style()->drawItemText(painter, textRect, Qt::AlignHCenter | Qt::AlignVCenter, view->style()->drawItemText(painter, textRect, Qt::AlignHCenter | Qt::AlignVCenter,
view->viewport()->palette(), true, text); view->viewport()->palette(), true, text);

16
Group.h
View File

@ -15,8 +15,6 @@ struct Group
GroupView *view; GroupView *view;
QString text; QString text;
bool collapsed; bool collapsed;
QRect iconRect;
QRect textRect;
QVector<int> rowHeights; QVector<int> rowHeights;
int firstRow; int firstRow;
@ -29,8 +27,22 @@ struct Group
int numRows() const; int numRows() const;
int top() 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<QModelIndex> items() const; QList<QModelIndex> items() const;
int numItems() const; int numItems() const;
QModelIndex firstItem() const; QModelIndex firstItem() const;
QModelIndex lastItem() const; QModelIndex lastItem() const;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(Group::HitResults)

View File

@ -36,7 +36,7 @@ GroupView::GroupView(QWidget *parent)
// setWordWrap(true); // setWordWrap(true);
// setDragDropMode(QListView::InternalMove); // setDragDropMode(QListView::InternalMove);
setAcceptDrops(true); setAcceptDrops(true);
// setSpacing(10); m_spacing = 5;
} }
GroupView::~GroupView() GroupView::~GroupView()
@ -145,31 +145,31 @@ Group *GroupView::category(const QModelIndex &index) const
Group *GroupView::category(const QString &cat) 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 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 int GroupView::itemsPerRow() const
{ {
return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + /* spacing */ 10)); return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
} }
int GroupView::contentWidth() const int GroupView::contentWidth() const
@ -261,7 +261,7 @@ void GroupView::mousePressEvent(QMouseEvent *event)
m_pressedIndex = index; m_pressedIndex = index;
m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex); m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex);
QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); QItemSelectionModel::SelectionFlags selection_flags = selectionCommand(index, event);
m_pressedPosition = pos; m_pressedPosition = pos;
m_pressedCategory = categoryAt(m_pressedPosition); m_pressedCategory = categoryAt(m_pressedPosition);
@ -428,9 +428,8 @@ void GroupView::mouseDoubleClickEvent(QMouseEvent *event)
void GroupView::paintEvent(QPaintEvent *event) void GroupView::paintEvent(QPaintEvent *event)
{ {
QPainter painter(this->viewport()); QPainter painter(this->viewport());
painter.translate(-offset());
int y = 0; int y = -verticalOffset();
for (int i = 0; i < m_categories.size(); ++i) for (int i = 0; i < m_categories.size(); ++i)
{ {
Group *category = m_categories.at(i); Group *category = m_categories.at(i);
@ -502,7 +501,7 @@ void GroupView::resizeEvent(QResizeEvent *event)
// if (m_categoryEditor) // if (m_categoryEditor)
// { // {
// m_categoryEditor->resize(qMax(contentWidth() / 2, // m_categoryEditor->resize(qMax(contentWidth() / 2,
//m_editedCategory->textRect.width()), // m_editedCategory->textRect.width()),
// m_categoryEditor->height()); // m_categoryEditor->height());
// } // }
@ -618,6 +617,11 @@ void GroupView::startDrag(Qt::DropActions supportedActions)
} }
QRect GroupView::visualRect(const QModelIndex &index) const 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) if (!index.isValid() || isIndexHidden(index) || index.column() > 0)
{ {
@ -627,15 +631,16 @@ QRect GroupView::visualRect(const QModelIndex &index) const
const Group *cat = category(index); const Group *cat = category(index);
QPair<int, int> pos = categoryInternalPosition(index); QPair<int, int> pos = categoryInternalPosition(index);
int x = pos.first; int x = pos.first;
int y = pos.second; // int y = pos.second;
QRect out; QRect out;
out.setTop(cat->top() + cat->headerHeight() + 5 + categoryInternalRowTop(index)); 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)); out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
return out; return out;
} }
/* /*
void CategorizedView::startCategoryEditor(Category *category) void CategorizedView::startCategoryEditor(Category *category)
{ {
@ -680,7 +685,7 @@ QModelIndex GroupView::indexAt(const QPoint &point) const
for (int i = 0; i < model()->rowCount(); ++i) for (int i = 0; i < model()->rowCount(); ++i)
{ {
QModelIndex index = model()->index(i, 0); QModelIndex index = model()->index(i, 0);
if (visualRect(index).contains(point)) if (geometryRect(index).contains(point))
{ {
return index; return index;
} }
@ -694,7 +699,7 @@ void GroupView::setSelection(const QRect &rect,
for (int i = 0; i < model()->rowCount(); ++i) for (int i = 0; i < model()->rowCount(); ++i)
{ {
QModelIndex index = model()->index(i, 0); QModelIndex index = model()->index(i, 0);
if (visualRect(index).intersects(rect)) if (geometryRect(index).intersects(rect))
{ {
selectionModel()->select(index, commands); selectionModel()->select(index, commands);
} }
@ -734,7 +739,7 @@ QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelInde
for (int i = 0; i < indices.count(); ++i) for (int i = 0; i < indices.count(); ++i)
{ {
const QModelIndex &index = indices.at(i); const QModelIndex &index = indices.at(i);
const QRect current = visualRect(index); const QRect current = geometryRect(index);
if (current.intersects(viewportRect)) if (current.intersects(viewportRect))
{ {
ret += qMakePair(current, index); ret += qMakePair(current, index);
@ -857,3 +862,24 @@ QPoint GroupView::offset() const
{ {
return QPoint(horizontalOffset(), verticalOffset()); 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;
}

View File

@ -2,6 +2,7 @@
#include <QListView> #include <QListView>
#include <QLineEdit> #include <QLineEdit>
#include <QScrollBar>
struct CategorizedViewRoles struct CategorizedViewRoles
{ {
@ -23,7 +24,8 @@ public:
GroupView(QWidget *parent = 0); GroupView(QWidget *parent = 0);
~GroupView(); ~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; QModelIndex indexAt(const QPoint &point) const;
void setSelection(const QRect &rect, void setSelection(const QRect &rect,
const QItemSelectionModel::SelectionFlags commands) override; const QItemSelectionModel::SelectionFlags commands) override;
@ -34,12 +36,18 @@ public:
virtual int horizontalOffset() const override virtual int horizontalOffset() const override
{ {
return 0; return horizontalScrollBar()->value();
} }
virtual int verticalOffset() const override 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 virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override
@ -53,10 +61,7 @@ public:
return QModelIndex(); return QModelIndex();
} }
virtual QRegion visualRegionForSelection(const QItemSelection &) const override virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
{
return QRegion();
}
/* /*
* End of BS * End of BS
@ -116,14 +121,16 @@ private:
private slots: private slots:
void endCategoryEditor();*/ void endCategoryEditor();*/
private: private: /* variables */
QPoint m_pressedPosition; QPoint m_pressedPosition;
QPersistentModelIndex m_pressedIndex; QPersistentModelIndex m_pressedIndex;
bool m_pressedAlreadySelected; bool m_pressedAlreadySelected;
Group *m_pressedCategory; Group *m_pressedCategory;
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag; QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
QPoint m_lastDragPosition; QPoint m_lastDragPosition;
int m_spacing = 5;
private: /* methods */
QPair<int, int> categoryInternalPosition(const QModelIndex &index) const; QPair<int, int> categoryInternalPosition(const QModelIndex &index) const;
int categoryInternalRowTop(const QModelIndex &index) const; int categoryInternalRowTop(const QModelIndex &index) const;
int itemHeightForCategoryRow(const Group *category, const int internalRow) const; int itemHeightForCategoryRow(const Group *category, const int internalRow) const;