Fix group mouse interaction issues
This commit is contained in:
		
							
								
								
									
										39
									
								
								Group.cpp
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								Group.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Group.h
									
									
									
									
									
								
							@@ -15,8 +15,6 @@ struct Group
 | 
			
		||||
	GroupView *view;
 | 
			
		||||
	QString text;
 | 
			
		||||
	bool collapsed;
 | 
			
		||||
	QRect iconRect;
 | 
			
		||||
	QRect textRect;
 | 
			
		||||
	QVector<int> 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<QModelIndex> items() const;
 | 
			
		||||
	int numItems() const;
 | 
			
		||||
	QModelIndex firstItem() const;
 | 
			
		||||
	QModelIndex lastItem() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Group::HitResults)
 | 
			
		||||
 
 | 
			
		||||
@@ -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<int, int> 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<QPair<QRect, QModelIndex>> 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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								GroupView.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								GroupView.h
									
									
									
									
									
								
							@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
#include <QListView>
 | 
			
		||||
#include <QLineEdit>
 | 
			
		||||
#include <QScrollBar>
 | 
			
		||||
 | 
			
		||||
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<int, int> categoryInternalPosition(const QModelIndex &index) const;
 | 
			
		||||
	int categoryInternalRowTop(const QModelIndex &index) const;
 | 
			
		||||
	int itemHeightForCategoryRow(const Group *category, const int internalRow) const;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user