Group view gets keyboard navigation back.
And a bunch of fixes.
This commit is contained in:
parent
d570037331
commit
cc6968e9a3
@ -366,14 +366,14 @@ SET(MULTIMC_SOURCES
|
|||||||
|
|
||||||
|
|
||||||
# GUI - instance group view
|
# GUI - instance group view
|
||||||
gui/groupview/Group.cpp
|
|
||||||
gui/groupview/Group.h
|
|
||||||
gui/groupview/GroupedProxyModel.cpp
|
gui/groupview/GroupedProxyModel.cpp
|
||||||
gui/groupview/GroupedProxyModel.h
|
gui/groupview/GroupedProxyModel.h
|
||||||
gui/groupview/GroupView.cpp
|
gui/groupview/GroupView.cpp
|
||||||
gui/groupview/GroupView.h
|
gui/groupview/GroupView.h
|
||||||
gui/groupview/InstanceDelegate.cpp
|
gui/groupview/InstanceDelegate.cpp
|
||||||
gui/groupview/InstanceDelegate.h
|
gui/groupview/InstanceDelegate.h
|
||||||
|
gui/groupview/VisualGroup.cpp
|
||||||
|
gui/groupview/VisualGroup.h
|
||||||
|
|
||||||
# LOGIC - Base classes and infrastructure
|
# LOGIC - Base classes and infrastructure
|
||||||
logic/BaseVersion.h
|
logic/BaseVersion.h
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include <QCache>
|
#include <QCache>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
|
||||||
#include "Group.h"
|
#include "VisualGroup.h"
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
|
template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
|
||||||
@ -27,17 +27,12 @@ template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GroupView::GroupView(QWidget *parent)
|
GroupView::GroupView(QWidget *parent)
|
||||||
: QAbstractItemView(parent), m_leftMargin(5), m_rightMargin(5), m_bottomMargin(5),
|
: QAbstractItemView(parent)
|
||||||
m_categoryMargin(5) //, m_updatesDisabled(false), m_categoryEditor(0), m_editedCategory(0)
|
|
||||||
{
|
{
|
||||||
// setViewMode(IconMode);
|
|
||||||
// setMovement(Snap);
|
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
// setWordWrap(true);
|
|
||||||
// setDragDropMode(QListView::InternalMove);
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
m_spacing = 5;
|
setAutoScroll(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupView::~GroupView()
|
GroupView::~GroupView()
|
||||||
@ -72,7 +67,7 @@ void GroupView::updateGeometries()
|
|||||||
geometryCache.clear();
|
geometryCache.clear();
|
||||||
int previousScroll = verticalScrollBar()->value();
|
int previousScroll = verticalScrollBar()->value();
|
||||||
|
|
||||||
QMap<QString, Group *> cats;
|
QMap<QString, VisualGroup *> cats;
|
||||||
|
|
||||||
for (int i = 0; i < model()->rowCount(); ++i)
|
for (int i = 0; i < model()->rowCount(); ++i)
|
||||||
{
|
{
|
||||||
@ -80,14 +75,14 @@ void GroupView::updateGeometries()
|
|||||||
model()->index(i, 0).data(GroupViewRoles::GroupRole).toString();
|
model()->index(i, 0).data(GroupViewRoles::GroupRole).toString();
|
||||||
if (!cats.contains(groupName))
|
if (!cats.contains(groupName))
|
||||||
{
|
{
|
||||||
Group *old = this->category(groupName);
|
VisualGroup *old = this->category(groupName);
|
||||||
if (old)
|
if (old)
|
||||||
{
|
{
|
||||||
cats.insert(groupName, new Group(old));
|
cats.insert(groupName, new VisualGroup(old));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cats.insert(groupName, new Group(groupName, this));
|
cats.insert(groupName, new VisualGroup(groupName, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +144,7 @@ void GroupView::modelReset()
|
|||||||
|
|
||||||
bool GroupView::isIndexHidden(const QModelIndex &index) const
|
bool GroupView::isIndexHidden(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
Group *cat = category(index);
|
VisualGroup *cat = category(index);
|
||||||
if (cat)
|
if (cat)
|
||||||
{
|
{
|
||||||
return cat->collapsed;
|
return cat->collapsed;
|
||||||
@ -160,12 +155,12 @@ bool GroupView::isIndexHidden(const QModelIndex &index) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Group *GroupView::category(const QModelIndex &index) const
|
VisualGroup *GroupView::category(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
return category(index.data(GroupViewRoles::GroupRole).toString());
|
return category(index.data(GroupViewRoles::GroupRole).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Group *GroupView::category(const QString &cat) const
|
VisualGroup *GroupView::category(const QString &cat) const
|
||||||
{
|
{
|
||||||
for (auto group : m_groups)
|
for (auto group : m_groups)
|
||||||
{
|
{
|
||||||
@ -177,11 +172,11 @@ Group *GroupView::category(const QString &cat) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group *GroupView::categoryAt(const QPoint &pos) const
|
VisualGroup *GroupView::categoryAt(const QPoint &pos) const
|
||||||
{
|
{
|
||||||
for (auto group : m_groups)
|
for (auto group : m_groups)
|
||||||
{
|
{
|
||||||
if(group->hitScan(pos) & Group::CheckboxHit)
|
if(group->hitScan(pos) & VisualGroup::CheckboxHit)
|
||||||
{
|
{
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
@ -189,7 +184,7 @@ Group *GroupView::categoryAt(const QPoint &pos) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GroupView::itemsPerRow() const
|
int GroupView::calculateItemsPerRow() const
|
||||||
{
|
{
|
||||||
return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
|
return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
|
||||||
}
|
}
|
||||||
@ -201,77 +196,7 @@ int GroupView::contentWidth() const
|
|||||||
|
|
||||||
int GroupView::itemWidth() const
|
int GroupView::itemWidth() const
|
||||||
{
|
{
|
||||||
return itemDelegate()
|
return m_itemWidth;
|
||||||
->sizeHint(viewOptions(), model()->index(model()->rowCount() - 1, 0))
|
|
||||||
.width();
|
|
||||||
}
|
|
||||||
|
|
||||||
int GroupView::categoryRowHeight(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
QModelIndexList indices;
|
|
||||||
int internalRow = categoryInternalPosition(index).second;
|
|
||||||
for (auto &i : category(index)->items())
|
|
||||||
{
|
|
||||||
if (categoryInternalPosition(i).second == internalRow)
|
|
||||||
{
|
|
||||||
indices.append(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int largestHeight = 0;
|
|
||||||
for (auto &i : indices)
|
|
||||||
{
|
|
||||||
largestHeight =
|
|
||||||
qMax(largestHeight, itemDelegate()->sizeHint(viewOptions(), i).height());
|
|
||||||
}
|
|
||||||
return largestHeight + m_spacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPair<int, int> GroupView::categoryInternalPosition(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
QList<QModelIndex> indices = category(index)->items();
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
const int perRow = itemsPerRow();
|
|
||||||
for (int i = 0; i < indices.size(); ++i)
|
|
||||||
{
|
|
||||||
if (indices.at(i) == index)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++x;
|
|
||||||
if (x == perRow)
|
|
||||||
{
|
|
||||||
x = 0;
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return qMakePair(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GroupView::categoryInternalRowTop(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
Group *cat = category(index);
|
|
||||||
int categoryInternalRow = categoryInternalPosition(index).second;
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < categoryInternalRow; ++i)
|
|
||||||
{
|
|
||||||
result += cat->rowHeights.at(i);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GroupView::itemHeightForCategoryRow(const Group *category, const int internalRow) const
|
|
||||||
{
|
|
||||||
for (auto &i : category->items())
|
|
||||||
{
|
|
||||||
QPair<int, int> pos = categoryInternalPosition(i);
|
|
||||||
if (pos.second == internalRow)
|
|
||||||
{
|
|
||||||
return categoryRowHeight(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupView::mousePressEvent(QMouseEvent *event)
|
void GroupView::mousePressEvent(QMouseEvent *event)
|
||||||
@ -297,13 +222,19 @@ void GroupView::mousePressEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
if (index.isValid() && (index.flags() & Qt::ItemIsEnabled))
|
if (index.isValid() && (index.flags() & Qt::ItemIsEnabled))
|
||||||
{
|
{
|
||||||
|
if(index != currentIndex())
|
||||||
|
{
|
||||||
|
// FIXME: better!
|
||||||
|
m_currentCursorColumn = -1;
|
||||||
|
}
|
||||||
// we disable scrollTo for mouse press so the item doesn't change position
|
// we disable scrollTo for mouse press so the item doesn't change position
|
||||||
// when the user is interacting with it (ie. clicking on it)
|
// when the user is interacting with it (ie. clicking on it)
|
||||||
bool autoScroll = hasAutoScroll();
|
bool autoScroll = hasAutoScroll();
|
||||||
setAutoScroll(false);
|
setAutoScroll(false);
|
||||||
selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
|
selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
|
||||||
|
|
||||||
setAutoScroll(autoScroll);
|
setAutoScroll(autoScroll);
|
||||||
QRect rect(geometryPos, geometryPos);
|
QRect rect(visualPos, visualPos);
|
||||||
setSelection(rect, QItemSelectionModel::ClearAndSelect);
|
setSelection(rect, QItemSelectionModel::ClearAndSelect);
|
||||||
|
|
||||||
// signal handlers may change the model
|
// signal handlers may change the model
|
||||||
@ -360,7 +291,7 @@ void GroupView::mouseMoveEvent(QMouseEvent *event)
|
|||||||
{
|
{
|
||||||
setState(DragSelectingState);
|
setState(DragSelectingState);
|
||||||
|
|
||||||
setSelection(QRect(geometryPos, geometryPos), QItemSelectionModel::ClearAndSelect);
|
setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect);
|
||||||
QModelIndex index = indexAt(visualPos);
|
QModelIndex index = indexAt(visualPos);
|
||||||
|
|
||||||
// set at the end because it might scroll the view
|
// set at the end because it might scroll the view
|
||||||
@ -453,7 +384,7 @@ void GroupView::paintEvent(QPaintEvent *event)
|
|||||||
option.rect.setWidth(wpWidth);
|
option.rect.setWidth(wpWidth);
|
||||||
for (int i = 0; i < m_groups.size(); ++i)
|
for (int i = 0; i < m_groups.size(); ++i)
|
||||||
{
|
{
|
||||||
Group *category = m_groups.at(i);
|
VisualGroup *category = m_groups.at(i);
|
||||||
int y = category->verticalPosition();
|
int y = category->verticalPosition();
|
||||||
y -= verticalOffset();
|
y -= verticalOffset();
|
||||||
QRect backup = option.rect;
|
QRect backup = option.rect;
|
||||||
@ -529,16 +460,12 @@ void GroupView::paintEvent(QPaintEvent *event)
|
|||||||
|
|
||||||
void GroupView::resizeEvent(QResizeEvent *event)
|
void GroupView::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
// QListView::resizeEvent(event);
|
int newItemsPerRow = calculateItemsPerRow();
|
||||||
|
if(newItemsPerRow != m_currentItemsPerRow)
|
||||||
// if (m_categoryEditor)
|
{
|
||||||
// {
|
m_currentItemsPerRow = newItemsPerRow;
|
||||||
// m_categoryEditor->resize(qMax(contentWidth() / 2,
|
updateGeometries();
|
||||||
// m_editedCategory->textRect.width()),
|
}
|
||||||
// m_categoryEditor->height());
|
|
||||||
// }
|
|
||||||
|
|
||||||
updateGeometries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupView::dragEnterEvent(QDragEnterEvent *event)
|
void GroupView::dragEnterEvent(QDragEnterEvent *event)
|
||||||
@ -581,8 +508,8 @@ void GroupView::dropEvent(QDropEvent *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<Group *, int> dropPos = rowDropPos(event->pos() + offset());
|
QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset());
|
||||||
const Group *category = dropPos.first;
|
const VisualGroup *category = dropPos.first;
|
||||||
const int row = dropPos.second;
|
const int row = dropPos.second;
|
||||||
|
|
||||||
if (row == -1)
|
if (row == -1)
|
||||||
@ -606,44 +533,44 @@ void GroupView::dropEvent(QDropEvent *event)
|
|||||||
void GroupView::startDrag(Qt::DropActions supportedActions)
|
void GroupView::startDrag(Qt::DropActions supportedActions)
|
||||||
{
|
{
|
||||||
QModelIndexList indexes = selectionModel()->selectedIndexes();
|
QModelIndexList indexes = selectionModel()->selectedIndexes();
|
||||||
if (indexes.count() > 0)
|
if(indexes.count() == 0)
|
||||||
{
|
return;
|
||||||
QMimeData *data = model()->mimeData(indexes);
|
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QRect rect;
|
|
||||||
QPixmap pixmap = renderToPixmap(indexes, &rect);
|
|
||||||
//rect.translate(offset());
|
|
||||||
// rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
|
|
||||||
QDrag *drag = new QDrag(this);
|
|
||||||
drag->setPixmap(pixmap);
|
|
||||||
drag->setMimeData(data);
|
|
||||||
Qt::DropAction defaultDropAction = Qt::IgnoreAction;
|
|
||||||
if (this->defaultDropAction() != Qt::IgnoreAction &&
|
|
||||||
(supportedActions & this->defaultDropAction()))
|
|
||||||
{
|
|
||||||
defaultDropAction = this->defaultDropAction();
|
|
||||||
}
|
|
||||||
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
|
|
||||||
{
|
|
||||||
const QItemSelection selection = selectionModel()->selection();
|
|
||||||
|
|
||||||
for (auto it = selection.constBegin(); it != selection.constEnd(); ++it)
|
QMimeData *data = model()->mimeData(indexes);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QRect rect;
|
||||||
|
QPixmap pixmap = renderToPixmap(indexes, &rect);
|
||||||
|
//rect.translate(offset());
|
||||||
|
// rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
|
||||||
|
QDrag *drag = new QDrag(this);
|
||||||
|
drag->setPixmap(pixmap);
|
||||||
|
drag->setMimeData(data);
|
||||||
|
Qt::DropAction defaultDropAction = Qt::IgnoreAction;
|
||||||
|
if (this->defaultDropAction() != Qt::IgnoreAction &&
|
||||||
|
(supportedActions & this->defaultDropAction()))
|
||||||
|
{
|
||||||
|
defaultDropAction = this->defaultDropAction();
|
||||||
|
}
|
||||||
|
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
|
||||||
|
{
|
||||||
|
const QItemSelection selection = selectionModel()->selection();
|
||||||
|
|
||||||
|
for (auto it = selection.constBegin(); it != selection.constEnd(); ++it)
|
||||||
|
{
|
||||||
|
QModelIndex parent = (*it).parent();
|
||||||
|
if ((*it).left() != 0)
|
||||||
{
|
{
|
||||||
QModelIndex parent = (*it).parent();
|
continue;
|
||||||
if ((*it).left() != 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((*it).right() != (model()->columnCount(parent) - 1))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int count = (*it).bottom() - (*it).top() + 1;
|
|
||||||
model()->removeRows((*it).top(), count, parent);
|
|
||||||
}
|
}
|
||||||
|
if ((*it).right() != (model()->columnCount(parent) - 1))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int count = (*it).bottom() - (*it).top() + 1;
|
||||||
|
model()->removeRows((*it).top(), count, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -665,61 +592,20 @@ QRect GroupView::geometryRect(const QModelIndex &index) const
|
|||||||
{
|
{
|
||||||
return *geometryCache[row];
|
return *geometryCache[row];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
const Group *cat = category(index);
|
|
||||||
QPair<int, int> pos = categoryInternalPosition(index);
|
|
||||||
int x = pos.first;
|
|
||||||
// int y = pos.second;
|
|
||||||
|
|
||||||
QRect out;
|
const VisualGroup *cat = category(index);
|
||||||
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + categoryInternalRowTop(index));
|
QPair<int, int> pos = cat->positionOf(index);
|
||||||
out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
|
int x = pos.first;
|
||||||
out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
|
// int y = pos.second;
|
||||||
const_cast<QCache<int, QRect>&>(geometryCache).insert(row, new QRect(out));
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
QRect out;
|
||||||
void CategorizedView::startCategoryEditor(Category *category)
|
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
|
||||||
{
|
out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
|
||||||
if (m_categoryEditor != 0)
|
out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
|
||||||
{
|
geometryCache.insert(row, new QRect(out));
|
||||||
return;
|
return out;
|
||||||
}
|
|
||||||
m_editedCategory = category;
|
|
||||||
m_categoryEditor = new QLineEdit(m_editedCategory->text, this);
|
|
||||||
QRect rect = m_editedCategory->textRect;
|
|
||||||
rect.setWidth(qMax(contentWidth() / 2, rect.width()));
|
|
||||||
m_categoryEditor->setGeometry(rect);
|
|
||||||
m_categoryEditor->show();
|
|
||||||
m_categoryEditor->setFocus();
|
|
||||||
connect(m_categoryEditor, &QLineEdit::returnPressed, this,
|
|
||||||
&CategorizedView::endCategoryEditor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CategorizedView::endCategoryEditor()
|
|
||||||
{
|
|
||||||
if (m_categoryEditor == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_editedCategory->text = m_categoryEditor->text();
|
|
||||||
m_updatesDisabled = true;
|
|
||||||
foreach (const QModelIndex &index, itemsForCategory(m_editedCategory))
|
|
||||||
{
|
|
||||||
const_cast<QAbstractItemModel *>(index.model())->setData(index,
|
|
||||||
m_categoryEditor->text(), CategoryRole);
|
|
||||||
}
|
|
||||||
m_updatesDisabled = false;
|
|
||||||
delete m_categoryEditor;
|
|
||||||
m_categoryEditor = 0;
|
|
||||||
m_editedCategory = 0;
|
|
||||||
updateGeometries();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
QModelIndex GroupView::indexAt(const QPoint &point) const
|
QModelIndex GroupView::indexAt(const QPoint &point) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < model()->rowCount(); ++i)
|
for (int i = 0; i < model()->rowCount(); ++i)
|
||||||
@ -733,21 +619,19 @@ QModelIndex GroupView::indexAt(const QPoint &point) const
|
|||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: is rect supposed to be geometry or visual coords?
|
|
||||||
void GroupView::setSelection(const QRect &rect,
|
void GroupView::setSelection(const QRect &rect,
|
||||||
const QItemSelectionModel::SelectionFlags commands)
|
const QItemSelectionModel::SelectionFlags commands)
|
||||||
{
|
{
|
||||||
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);
|
||||||
QRect itemRect = geometryRect(index);
|
QRect itemRect = visualRect(index);
|
||||||
if (itemRect.intersects(rect))
|
if (itemRect.intersects(rect))
|
||||||
{
|
{
|
||||||
selectionModel()->select(index, commands);
|
selectionModel()->select(index, commands);
|
||||||
update(itemRect.translated(-offset()));
|
update(itemRect.translated(-offset()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) const
|
QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) const
|
||||||
@ -790,33 +674,23 @@ QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelInde
|
|||||||
|
|
||||||
bool GroupView::isDragEventAccepted(QDropEvent *event)
|
bool GroupView::isDragEventAccepted(QDropEvent *event)
|
||||||
{
|
{
|
||||||
if (event->source() != this)
|
return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!listsIntersect(event->mimeData()->formats(), model()->mimeTypes()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!model()->canDropMimeData(event->mimeData(), event->dropAction(),
|
|
||||||
rowDropPos(event->pos()).second, 0, QModelIndex()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
QPair<VisualGroup *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||||
{
|
{
|
||||||
|
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||||
|
// FIXME: PIXIE DUST.
|
||||||
|
/*
|
||||||
// check that we aren't on a category header and calculate which category we're in
|
// check that we aren't on a category header and calculate which category we're in
|
||||||
Group *category = 0;
|
VisualGroup *category = 0;
|
||||||
{
|
{
|
||||||
int y = 0;
|
int y = 0;
|
||||||
for (auto cat : m_groups)
|
for (auto cat : m_groups)
|
||||||
{
|
{
|
||||||
if (pos.y() > y && pos.y() < (y + cat->headerHeight()))
|
if (pos.y() > y && pos.y() < (y + cat->headerHeight()))
|
||||||
{
|
{
|
||||||
return qMakePair<Group*, int>(nullptr, -1);
|
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||||
}
|
}
|
||||||
y += cat->totalHeight() + m_categoryMargin;
|
y += cat->totalHeight() + m_categoryMargin;
|
||||||
if (pos.y() < y)
|
if (pos.y() < y)
|
||||||
@ -827,7 +701,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
|||||||
}
|
}
|
||||||
if (category == 0)
|
if (category == 0)
|
||||||
{
|
{
|
||||||
return qMakePair<Group*, int>(nullptr, -1);
|
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,7 +717,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0, c = 0; i < contentWidth(); i += itemWidth + 10 /*spacing()*/, ++c)
|
for (int i = 0, c = 0; i < contentWidth(); i += itemWidth + 10 , ++c)
|
||||||
{
|
{
|
||||||
if (pos.x() > (i - itemWidth / 2) && pos.x() <= (i + itemWidth / 2))
|
if (pos.x() > (i - itemWidth / 2) && pos.x() <= (i + itemWidth / 2))
|
||||||
{
|
{
|
||||||
@ -854,7 +728,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
|||||||
}
|
}
|
||||||
if (internalColumn == -1)
|
if (internalColumn == -1)
|
||||||
{
|
{
|
||||||
return qMakePair<Group*, int>(nullptr, -1);
|
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,13 +748,13 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
|||||||
}
|
}
|
||||||
if (internalRow == -1)
|
if (internalRow == -1)
|
||||||
{
|
{
|
||||||
return qMakePair<Group*, int>(nullptr, -1);
|
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||||
}
|
}
|
||||||
// this happens if we're in the margin between a one category and another
|
// this happens if we're in the margin between a one category and another
|
||||||
// categories header
|
// categories header
|
||||||
if (internalRow > (indices.size() / itemsPerRow()))
|
if (internalRow > (indices.size() / itemsPerRow()))
|
||||||
{
|
{
|
||||||
return qMakePair<Group*, int>(nullptr, -1);
|
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,6 +768,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return qMakePair(category, indices.at(categoryRow).row());
|
return qMakePair(category, indices.at(categoryRow).row());
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint GroupView::offset() const
|
QPoint GroupView::offset() const
|
||||||
@ -921,34 +796,162 @@ QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) con
|
|||||||
}
|
}
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction,
|
QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction,
|
||||||
Qt::KeyboardModifiers modifiers)
|
Qt::KeyboardModifiers modifiers)
|
||||||
{
|
{
|
||||||
auto current = currentIndex();
|
auto current = currentIndex();
|
||||||
if(!current.isValid())
|
if(!current.isValid())
|
||||||
{
|
{
|
||||||
QLOG_DEBUG() << "model row: invalid";
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
QLOG_DEBUG() << "model row: " << current.row();
|
|
||||||
auto cat = category(current);
|
auto cat = category(current);
|
||||||
int i = m_groups.indexOf(cat);
|
int group_index = m_groups.indexOf(cat);
|
||||||
if(i >= 0)
|
if(group_index < 0)
|
||||||
|
return current;
|
||||||
|
|
||||||
|
auto real_group = m_groups[group_index];
|
||||||
|
int beginning_row = 0;
|
||||||
|
for(auto group: m_groups)
|
||||||
{
|
{
|
||||||
// this is a pile of something foul
|
if(group == real_group)
|
||||||
auto real_group = m_groups[i];
|
break;
|
||||||
int beginning_row = 0;
|
beginning_row += group->numRows();
|
||||||
for(auto group: m_groups)
|
}
|
||||||
|
|
||||||
|
QPair<int, int> pos = cat->positionOf(current);
|
||||||
|
int column = pos.first;
|
||||||
|
int row = pos.second;
|
||||||
|
if(m_currentCursorColumn < 0)
|
||||||
|
{
|
||||||
|
m_currentCursorColumn = column;
|
||||||
|
}
|
||||||
|
switch(cursorAction)
|
||||||
|
{
|
||||||
|
case MoveUp:
|
||||||
{
|
{
|
||||||
if(group == real_group)
|
if(row == 0)
|
||||||
break;
|
{
|
||||||
beginning_row += group->numRows();
|
if(group_index == 0)
|
||||||
|
return current;
|
||||||
|
auto prevgroup = m_groups[group_index-1];
|
||||||
|
int newRow = prevgroup->numRows() - 1;
|
||||||
|
int newRowSize = prevgroup->rows[newRow].size();
|
||||||
|
int newColumn = m_currentCursorColumn;
|
||||||
|
if (m_currentCursorColumn >= newRowSize)
|
||||||
|
{
|
||||||
|
newColumn = newRowSize - 1;
|
||||||
|
}
|
||||||
|
return prevgroup->rows[newRow][newColumn];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int newRow = row - 1;
|
||||||
|
int newRowSize = cat->rows[newRow].size();
|
||||||
|
int newColumn = m_currentCursorColumn;
|
||||||
|
if (m_currentCursorColumn >= newRowSize)
|
||||||
|
{
|
||||||
|
newColumn = newRowSize - 1;
|
||||||
|
}
|
||||||
|
return cat->rows[newRow][newColumn];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QLOG_DEBUG() << "category: " << real_group->text;
|
case MoveDown:
|
||||||
QPair<int, int> pos = categoryInternalPosition(current);
|
{
|
||||||
int row = beginning_row + pos.second;
|
if(row == cat->rows.size() - 1)
|
||||||
QLOG_DEBUG() << "row: " << row;
|
{
|
||||||
QLOG_DEBUG() << "column: " << pos.first;
|
if(group_index == m_groups.size() - 1)
|
||||||
|
return current;
|
||||||
|
auto nextgroup = m_groups[group_index+1];
|
||||||
|
int newRowSize = nextgroup->rows[0].size();
|
||||||
|
int newColumn = m_currentCursorColumn;
|
||||||
|
if (m_currentCursorColumn >= newRowSize)
|
||||||
|
{
|
||||||
|
newColumn = newRowSize - 1;
|
||||||
|
}
|
||||||
|
return nextgroup->rows[0][newColumn];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int newRow = row + 1;
|
||||||
|
int newRowSize = cat->rows[newRow].size();
|
||||||
|
int newColumn = m_currentCursorColumn;
|
||||||
|
if (m_currentCursorColumn >= newRowSize)
|
||||||
|
{
|
||||||
|
newColumn = newRowSize - 1;
|
||||||
|
}
|
||||||
|
return cat->rows[newRow][newColumn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case MoveLeft:
|
||||||
|
{
|
||||||
|
if(column > 0)
|
||||||
|
{
|
||||||
|
m_currentCursorColumn = column - 1;
|
||||||
|
return cat->rows[row][column - 1];
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
case MoveRight:
|
||||||
|
{
|
||||||
|
if(column < cat->rows[row].size() - 1)
|
||||||
|
{
|
||||||
|
m_currentCursorColumn = column + 1;
|
||||||
|
return cat->rows[row][column + 1];
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GroupView::horizontalOffset() const
|
||||||
|
{
|
||||||
|
return horizontalScrollBar()->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GroupView::verticalOffset() const
|
||||||
|
{
|
||||||
|
return verticalScrollBar()->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupView::scrollContentsBy(int dx, int dy)
|
||||||
|
{
|
||||||
|
scrollDirtyRegion(dx, dy);
|
||||||
|
viewport()->scroll(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint)
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QRect rect = visualRect(index);
|
||||||
|
if (hint == EnsureVisible && viewport()->rect().contains(rect))
|
||||||
|
{
|
||||||
|
viewport()->update(rect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
int GroupView::verticalScrollToValue(const QModelIndex &index, const QRect &rect,
|
||||||
|
QListView::ScrollHint hint) const
|
||||||
|
{
|
||||||
|
const QRect area = viewport()->rect();
|
||||||
|
const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());
|
||||||
|
const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
|
||||||
|
|
||||||
|
int verticalValue = verticalScrollBar()->value();
|
||||||
|
QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
|
||||||
|
if (hint == QListView::PositionAtTop || above)
|
||||||
|
verticalValue += adjusted.top();
|
||||||
|
else if (hint == QListView::PositionAtBottom || below)
|
||||||
|
verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
|
||||||
|
else if (hint == QListView::PositionAtCenter)
|
||||||
|
verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
|
||||||
|
return verticalValue;
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ struct GroupViewRoles
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Group;
|
struct VisualGroup;
|
||||||
|
|
||||||
class GroupView : public QAbstractItemView
|
class GroupView : public QAbstractItemView
|
||||||
{
|
{
|
||||||
@ -36,35 +36,20 @@ public:
|
|||||||
void setSelection(const QRect &rect,
|
void setSelection(const QRect &rect,
|
||||||
const QItemSelectionModel::SelectionFlags commands) override;
|
const QItemSelectionModel::SelectionFlags commands) override;
|
||||||
|
|
||||||
virtual int horizontalOffset() const override
|
virtual int horizontalOffset() const override;
|
||||||
{
|
virtual int verticalOffset() const override;
|
||||||
return horizontalScrollBar()->value();
|
virtual void scrollContentsBy(int dx, int dy) override;
|
||||||
}
|
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
|
||||||
|
|
||||||
virtual int verticalOffset() const override
|
|
||||||
{
|
|
||||||
return verticalScrollBar()->value();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void scrollContentsBy(int dx, int dy) override
|
|
||||||
{
|
|
||||||
scrollDirtyRegion(dx, dy);
|
|
||||||
viewport()->scroll(dx, dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO!
|
|
||||||
*/
|
|
||||||
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual QModelIndex moveCursor(CursorAction cursorAction,
|
virtual QModelIndex moveCursor(CursorAction cursorAction,
|
||||||
Qt::KeyboardModifiers modifiers) override;
|
Qt::KeyboardModifiers modifiers) override;
|
||||||
|
|
||||||
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
|
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
|
||||||
|
|
||||||
|
int spacing() const
|
||||||
|
{
|
||||||
|
return m_spacing;
|
||||||
|
};
|
||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
|
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
|
||||||
@ -91,58 +76,50 @@ protected:
|
|||||||
void startDrag(Qt::DropActions supportedActions) override;
|
void startDrag(Qt::DropActions supportedActions) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct Group;
|
friend struct VisualGroup;
|
||||||
|
QList<VisualGroup *> m_groups;
|
||||||
|
|
||||||
QList<Group *> m_groups;
|
// geometry
|
||||||
|
int m_leftMargin = 5;
|
||||||
|
int m_rightMargin = 5;
|
||||||
|
int m_bottomMargin = 5;
|
||||||
|
int m_categoryMargin = 5;
|
||||||
|
int m_spacing = 5;
|
||||||
|
int m_itemWidth = 100;
|
||||||
|
int m_currentItemsPerRow = -1;
|
||||||
|
int m_currentCursorColumn= -1;
|
||||||
|
mutable QCache<int, QRect> geometryCache;
|
||||||
|
|
||||||
int m_leftMargin;
|
// point where the currently active mouse action started in geometry coordinates
|
||||||
int m_rightMargin;
|
|
||||||
int m_bottomMargin;
|
|
||||||
int m_categoryMargin;
|
|
||||||
|
|
||||||
// bool m_updatesDisabled;
|
|
||||||
|
|
||||||
Group *category(const QModelIndex &index) const;
|
|
||||||
Group *category(const QString &cat) const;
|
|
||||||
Group *categoryAt(const QPoint &pos) const;
|
|
||||||
|
|
||||||
int itemsPerRow() const;
|
|
||||||
int contentWidth() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int itemWidth() const;
|
|
||||||
int categoryRowHeight(const QModelIndex &index) const;
|
|
||||||
|
|
||||||
/*QLineEdit *m_categoryEditor;
|
|
||||||
Category *m_editedCategory;
|
|
||||||
void startCategoryEditor(Category *category);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void endCategoryEditor();*/
|
|
||||||
|
|
||||||
private: /* variables */
|
|
||||||
/// point where the currently active mouse action started in geometry coordinates
|
|
||||||
QPoint m_pressedPosition;
|
QPoint m_pressedPosition;
|
||||||
QPersistentModelIndex m_pressedIndex;
|
QPersistentModelIndex m_pressedIndex;
|
||||||
bool m_pressedAlreadySelected;
|
bool m_pressedAlreadySelected;
|
||||||
Group *m_pressedCategory;
|
VisualGroup *m_pressedCategory;
|
||||||
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
|
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
|
||||||
QPoint m_lastDragPosition;
|
QPoint m_lastDragPosition;
|
||||||
int m_spacing = 5;
|
|
||||||
QCache<int, QRect> geometryCache;
|
VisualGroup *category(const QModelIndex &index) const;
|
||||||
|
VisualGroup *category(const QString &cat) const;
|
||||||
|
VisualGroup *categoryAt(const QPoint &pos) const;
|
||||||
|
|
||||||
|
int itemsPerRow() const
|
||||||
|
{
|
||||||
|
return m_currentItemsPerRow;
|
||||||
|
};
|
||||||
|
int contentWidth() const;
|
||||||
|
|
||||||
private: /* methods */
|
private: /* methods */
|
||||||
QPair<int, int> categoryInternalPosition(const QModelIndex &index) const;
|
int itemWidth() const;
|
||||||
int categoryInternalRowTop(const QModelIndex &index) const;
|
int calculateItemsPerRow() const;
|
||||||
int itemHeightForCategoryRow(const Group *category, const int internalRow) const;
|
int verticalScrollToValue(const QModelIndex &index, const QRect &rect,
|
||||||
|
QListView::ScrollHint hint) const;
|
||||||
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
|
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
|
||||||
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices,
|
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices,
|
||||||
QRect *r) const;
|
QRect *r) const;
|
||||||
|
|
||||||
bool isDragEventAccepted(QDropEvent *event);
|
bool isDragEventAccepted(QDropEvent *event);
|
||||||
|
|
||||||
QPair<Group *, int> rowDropPos(const QPoint &pos);
|
QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
|
||||||
|
|
||||||
QPoint offset() const;
|
QPoint offset() const;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "Group.h"
|
#include "VisualGroup.h"
|
||||||
|
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
@ -7,30 +7,83 @@
|
|||||||
|
|
||||||
#include "GroupView.h"
|
#include "GroupView.h"
|
||||||
|
|
||||||
Group::Group(const QString &text, GroupView *view) : view(view), text(text), collapsed(false)
|
VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), text(text), collapsed(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Group::Group(const Group *other)
|
VisualGroup::VisualGroup(const VisualGroup *other)
|
||||||
: view(other->view), text(other->text), collapsed(other->collapsed)
|
: view(other->view), text(other->text), collapsed(other->collapsed)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::update()
|
void VisualGroup::update()
|
||||||
{
|
{
|
||||||
firstItemIndex = firstItem().row();
|
auto temp_items = items();
|
||||||
|
auto itemsPerRow = view->itemsPerRow();
|
||||||
|
|
||||||
rowHeights = QVector<int>(numRows());
|
int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow));
|
||||||
for (int i = 0; i < numRows(); ++i)
|
rows = QVector<VisualRow>(numRows);
|
||||||
|
|
||||||
|
int maxRowHeight = 0;
|
||||||
|
int positionInRow = 0;
|
||||||
|
int currentRow = 0;
|
||||||
|
int offsetFromTop = 0;
|
||||||
|
for (auto item: temp_items)
|
||||||
{
|
{
|
||||||
rowHeights[i] = view->categoryRowHeight(
|
if(positionInRow == itemsPerRow)
|
||||||
view->model()->index(i * view->itemsPerRow() + firstItemIndex, 0));
|
{
|
||||||
|
rows[currentRow].height = maxRowHeight;
|
||||||
|
rows[currentRow].top = offsetFromTop;
|
||||||
|
currentRow ++;
|
||||||
|
offsetFromTop += maxRowHeight + 5;
|
||||||
|
positionInRow = 0;
|
||||||
|
maxRowHeight = 0;
|
||||||
|
}
|
||||||
|
auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
|
||||||
|
if(itemHeight > maxRowHeight)
|
||||||
|
{
|
||||||
|
maxRowHeight = itemHeight;
|
||||||
|
}
|
||||||
|
rows[currentRow].items.append(item);
|
||||||
|
positionInRow++;
|
||||||
}
|
}
|
||||||
|
rows[currentRow].height = maxRowHeight;
|
||||||
|
rows[currentRow].top = offsetFromTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group::HitResults Group::hitScan(const QPoint &pos) const
|
QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
Group::HitResults results = Group::NoHit;
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
for (auto & row: rows)
|
||||||
|
{
|
||||||
|
for(auto x = 0; x < row.items.size(); x++)
|
||||||
|
{
|
||||||
|
if(row.items[x] == index)
|
||||||
|
{
|
||||||
|
return qMakePair(x,y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
return qMakePair(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisualGroup::rowTopOf(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
auto position = positionOf(index);
|
||||||
|
return rows[position.second].top;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisualGroup::rowHeightOf(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
auto position = positionOf(index);
|
||||||
|
return rows[position.second].height;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const
|
||||||
|
{
|
||||||
|
VisualGroup::HitResults results = VisualGroup::NoHit;
|
||||||
int y_start = verticalPosition();
|
int y_start = verticalPosition();
|
||||||
int body_start = y_start + headerHeight();
|
int body_start = y_start + headerHeight();
|
||||||
int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
|
int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
|
||||||
@ -38,28 +91,28 @@ Group::HitResults Group::hitScan(const QPoint &pos) const
|
|||||||
// int x = pos.x();
|
// int x = pos.x();
|
||||||
if (y < y_start)
|
if (y < y_start)
|
||||||
{
|
{
|
||||||
results = Group::NoHit;
|
results = VisualGroup::NoHit;
|
||||||
}
|
}
|
||||||
else if (y < body_start)
|
else if (y < body_start)
|
||||||
{
|
{
|
||||||
results = Group::HeaderHit;
|
results = VisualGroup::HeaderHit;
|
||||||
int collapseSize = headerHeight() - 4;
|
int collapseSize = headerHeight() - 4;
|
||||||
|
|
||||||
// the icon
|
// the icon
|
||||||
QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize);
|
QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize);
|
||||||
if (iconRect.contains(pos))
|
if (iconRect.contains(pos))
|
||||||
{
|
{
|
||||||
results |= Group::CheckboxHit;
|
results |= VisualGroup::CheckboxHit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (y < body_end)
|
else if (y < body_end)
|
||||||
{
|
{
|
||||||
results |= Group::BodyHit;
|
results |= VisualGroup::BodyHit;
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
|
void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
|
||||||
{
|
{
|
||||||
painter->setRenderHint(QPainter::Antialiasing);
|
painter->setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
@ -190,12 +243,12 @@ void Group::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
|
|||||||
//END: text
|
//END: text
|
||||||
}
|
}
|
||||||
|
|
||||||
int Group::totalHeight() const
|
int VisualGroup::totalHeight() const
|
||||||
{
|
{
|
||||||
return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
|
return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
|
||||||
}
|
}
|
||||||
|
|
||||||
int Group::headerHeight() const
|
int VisualGroup::headerHeight() const
|
||||||
{
|
{
|
||||||
QFont font(QApplication::font());
|
QFont font(QApplication::font());
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
@ -213,31 +266,27 @@ int Group::headerHeight() const
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int Group::contentHeight() const
|
int VisualGroup::contentHeight() const
|
||||||
{
|
{
|
||||||
if (collapsed)
|
if (collapsed)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int result = 0;
|
auto last = rows[numRows() - 1];
|
||||||
for (int i = 0; i < rowHeights.size(); ++i)
|
return last.top + last.height;
|
||||||
{
|
|
||||||
result += rowHeights[i];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Group::numRows() const
|
int VisualGroup::numRows() const
|
||||||
{
|
{
|
||||||
return qMax(1, qCeil((qreal)numItems() / (qreal)view->itemsPerRow()));
|
return rows.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Group::verticalPosition() const
|
int VisualGroup::verticalPosition() const
|
||||||
{
|
{
|
||||||
return m_verticalPosition;
|
return m_verticalPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QModelIndex> Group::items() const
|
QList<QModelIndex> VisualGroup::items() const
|
||||||
{
|
{
|
||||||
QList<QModelIndex> indices;
|
QList<QModelIndex> indices;
|
||||||
for (int i = 0; i < view->model()->rowCount(); ++i)
|
for (int i = 0; i < view->model()->rowCount(); ++i)
|
||||||
@ -250,20 +299,3 @@ QList<QModelIndex> Group::items() const
|
|||||||
}
|
}
|
||||||
return indices;
|
return indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Group::numItems() const
|
|
||||||
{
|
|
||||||
return items().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex Group::firstItem() const
|
|
||||||
{
|
|
||||||
QList<QModelIndex> indices = items();
|
|
||||||
return indices.isEmpty() ? QModelIndex() : indices.first();
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex Group::lastItem() const
|
|
||||||
{
|
|
||||||
QList<QModelIndex> indices = items();
|
|
||||||
return indices.isEmpty() ? QModelIndex() : indices.last();
|
|
||||||
}
|
|
@ -9,22 +9,37 @@ class GroupView;
|
|||||||
class QPainter;
|
class QPainter;
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
|
|
||||||
struct Group
|
struct VisualRow
|
||||||
|
{
|
||||||
|
QList<QModelIndex> items;
|
||||||
|
int height = 0;
|
||||||
|
int top = 0;
|
||||||
|
inline int size() const
|
||||||
|
{
|
||||||
|
return items.size();
|
||||||
|
}
|
||||||
|
inline QModelIndex &operator[](int i)
|
||||||
|
{
|
||||||
|
return items[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VisualGroup
|
||||||
{
|
{
|
||||||
/* constructors */
|
/* constructors */
|
||||||
Group(const QString &text, GroupView *view);
|
VisualGroup(const QString &text, GroupView *view);
|
||||||
Group(const Group *other);
|
VisualGroup(const VisualGroup *other);
|
||||||
|
|
||||||
/* data */
|
/* data */
|
||||||
GroupView *view = nullptr;
|
GroupView *view = nullptr;
|
||||||
QString text;
|
QString text;
|
||||||
bool collapsed = false;
|
bool collapsed = false;
|
||||||
QVector<int> rowHeights;
|
QVector<VisualRow> rows;
|
||||||
int firstItemIndex = 0;
|
int firstItemIndex = 0;
|
||||||
int m_verticalPosition = 0;
|
int m_verticalPosition = 0;
|
||||||
|
|
||||||
/* logic */
|
/* logic */
|
||||||
/// do stuff. and things. TODO: redo.
|
/// update the internal list of items and flow them into the rows.
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
/// draw the header at y-position.
|
/// draw the header at y-position.
|
||||||
@ -42,9 +57,21 @@ struct Group
|
|||||||
/// the number of visual rows this group has
|
/// the number of visual rows this group has
|
||||||
int numRows() const;
|
int numRows() const;
|
||||||
|
|
||||||
|
/// actually calculate the above value
|
||||||
|
int calculateNumRows() const;
|
||||||
|
|
||||||
/// the height at which this group starts, in pixels
|
/// the height at which this group starts, in pixels
|
||||||
int verticalPosition() const;
|
int verticalPosition() const;
|
||||||
|
|
||||||
|
/// relative geometry - top of the row of the given item
|
||||||
|
int rowTopOf(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
/// height of the row of the given item
|
||||||
|
int rowHeightOf(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
/// x/y position of the given item inside the group (in items!)
|
||||||
|
QPair<int, int> positionOf(const QModelIndex &index) const;
|
||||||
|
|
||||||
enum HitResult
|
enum HitResult
|
||||||
{
|
{
|
||||||
NoHit = 0x0,
|
NoHit = 0x0,
|
||||||
@ -58,12 +85,7 @@ struct Group
|
|||||||
/// shoot! BANG! what did we hit?
|
/// shoot! BANG! what did we hit?
|
||||||
HitResults hitScan (const QPoint &pos) const;
|
HitResults hitScan (const QPoint &pos) const;
|
||||||
|
|
||||||
/// super derpy thing.
|
|
||||||
QList<QModelIndex> items() const;
|
QList<QModelIndex> items() const;
|
||||||
/// I don't even
|
|
||||||
int numItems() const;
|
|
||||||
QModelIndex firstItem() const;
|
|
||||||
QModelIndex lastItem() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Group::HitResults)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults)
|
Loading…
Reference in New Issue
Block a user