add drag-drop reordering for maps in groups

This commit is contained in:
garak 2023-02-13 17:44:56 -05:00
parent a14e70ef53
commit 0ec8f4fee5
9 changed files with 242 additions and 39 deletions

View file

@ -154,7 +154,7 @@
</layout>
</item>
<item>
<widget class="QTreeView" name="mapList">
<widget class="MapTree" name="mapList">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -289,7 +289,7 @@
</layout>
</item>
<item>
<widget class="QTreeView" name="areaList">
<widget class="MapTree" name="areaList">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -424,7 +424,7 @@
</layout>
</item>
<item>
<widget class="QTreeView" name="layoutList">
<widget class="MapTree" name="layoutList">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -3607,6 +3607,11 @@
<extends>QWidget</extends>
<header>mapview.h</header>
</customwidget>
<customwidget>
<class>MapTree</class>
<extends>QTreeView</extends>
<header>maplistmodels.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../resources/images.qrc"/>

12
include/ui/eventfilters.h Normal file
View file

@ -0,0 +1,12 @@
#include <QObject>
#include <QEvent>
class WheelFilter : public QObject {
Q_OBJECT
public:
WheelFilter(QObject *parent) : QObject(parent) {}
virtual ~WheelFilter() {}
bool eventFilter(QObject *obj, QEvent *event) override;
};

View file

@ -2,6 +2,8 @@
#ifndef MAPLISTMODELS_H
#define MAPLISTMODELS_H
#include <QTreeView>
#include <QFontDatabase>
#include <QStandardItemModel>
#include <QMap>
@ -17,6 +19,20 @@ enum MapListRoles {
class MapTree : public QTreeView {
Q_OBJECT
public:
MapTree(QWidget *parent) : QTreeView(parent) {
this->setDropIndicatorShown(true);
this->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
}
public slots:
void removeSelected();
};
class MapGroupModel : public QStandardItemModel {
Q_OBJECT
@ -26,11 +42,16 @@ public:
QVariant data(const QModelIndex &index, int role) const override;
Qt::DropActions supportedDropActions() const override;
QStringList mimeTypes() const override;
virtual QMimeData *mimeData(const QModelIndexList &indexes) const override;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
public:
void setMap(QString mapName) { this->openMap = mapName; }
QStandardItem *createGroupItem(QString groupName, int groupIndex);
QStandardItem *createMapItem(QString mapName, int groupIndex, int mapIndex);
QStandardItem *createMapItem(QString mapName, QStandardItem *fromItem = nullptr);
QStandardItem *insertMapItem(QString mapName, QString groupName);
@ -39,6 +60,9 @@ public:
void initialize();
private:
void updateProject();
private:
Project *project;
QStandardItem *root = nullptr;
@ -50,7 +74,7 @@ private:
QString openMap;
signals:
void edited();
void dragMoveCompleted();
};

View file

@ -32,8 +32,6 @@ public slots:
void deactivateTab(int tabIndex);
private:
bool eventFilter(QObject *object, QEvent *event);
void actionCopyTab(int index);
void actionAddDeleteTab(int index);

View file

@ -57,6 +57,7 @@ SOURCES += src/core/block.cpp \
src/ui/cursortilerect.cpp \
src/ui/customattributestable.cpp \
src/ui/eventframes.cpp \
src/ui/eventfilters.cpp \
src/ui/filterchildrenproxymodel.cpp \
src/ui/maplistmodels.cpp \
src/ui/graphicsview.cpp \
@ -147,6 +148,7 @@ HEADERS += include/core/block.h \
include/ui/cursortilerect.h \
include/ui/customattributestable.h \
include/ui/eventframes.h \
include/ui/eventfilters.h \
include/ui/filterchildrenproxymodel.h \
include/ui/maplistmodels.h \
include/ui/graphicsview.h \

View file

@ -20,6 +20,7 @@
#include "montabwidget.h"
#include "imageexport.h"
#include "maplistmodels.h"
#include "eventfilters.h"
#include <QFileDialog>
#include <QClipboard>
@ -212,6 +213,10 @@ void MainWindow::initCustomUI() {
ui->mainTabBar->setTabIcon(3, QIcon(QStringLiteral(":/icons/connections.ico")));
ui->mainTabBar->addTab("Wild Pokemon");
ui->mainTabBar->setTabIcon(4, QIcon(QStringLiteral(":/icons/tall_grass.ico")));
WheelFilter *wheelFilter = new WheelFilter(this);
ui->mainTabBar->installEventFilter(wheelFilter);
this->ui->mapListContainer->tabBar()->installEventFilter(wheelFilter);
}
void MainWindow::initExtraSignals() {
@ -1110,6 +1115,16 @@ bool MainWindow::populateMapList() {
groupListProxyModel->setSourceModel(this->mapGroupModel);
ui->mapList->setModel(groupListProxyModel);
//
// connect(this->mapGroupModel, &QStandardItemModel::dataChanged, [=](const QModelIndex &, const QModelIndex &, const QList<int> &){
// qDebug() << "mapGroupModel dataChanged";
// });
// connect(this->mapGroupModel, &MapGroupModel::edited, [=, this](){
// qDebug() << "model edited with" << this->ui->mapList->selectionModel()->selection().size() << "items";
// }); removeSelected
connect(this->mapGroupModel, &MapGroupModel::dragMoveCompleted, this->ui->mapList, &MapTree::removeSelected);
this->mapAreaModel = new MapAreaModel(editor->project);
this->areaListProxyModel = new FilterChildrenProxyModel();
areaListProxyModel->setSourceModel(this->mapAreaModel);
@ -1121,10 +1136,11 @@ bool MainWindow::populateMapList() {
ui->layoutList->setModel(layoutListProxyModel);
/// !TODO
// ui->mapList->setSelectionMode(QAbstractItemView::ExtendedSelection);
// ui->mapList->setDragEnabled(true);
// ui->mapList->setAcceptDrops(true);
// ui->mapList->setDropIndicatorShown(true);
ui->mapList->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->mapList->setDragEnabled(true);
ui->mapList->setAcceptDrops(true);
ui->mapList->setDropIndicatorShown(true);
ui->mapList->setDragDropMode(QAbstractItemView::InternalMove);
return success;
}
@ -1244,19 +1260,11 @@ void MainWindow::onNewMapCreated() {
editor->project->saveMap(newMap);
editor->project->saveAllDataStructures();
// !TODO
// QStandardItem* groupItem = mapGroupItemsList->at(newMapGroup);
// int numMapsInGroup = groupItem->rowCount();
// Add new Map / Layout to the mapList models
this->mapGroupModel->insertMapItem(newMapName, editor->project->groupNames[newMapGroup]);
this->mapAreaModel->insertMapItem(newMapName, newMap->location, newMapGroup);
this->layoutTreeModel->insertMapItem(newMapName, newMap->layout->id);
// QStandardItem *newMapItem = createMapItem(newMapName, newMapGroup, numMapsInGroup);
// groupItem->appendRow(newMapItem);
// mapListIndexes.insert(newMapName, newMapItem->index());
// sortMapList();
setMap(newMapName, true);
if (newMap->needsHealLocation) {
@ -1512,11 +1520,18 @@ void MainWindow::updateMapList() {
mapAreaModel->setMap(this->editor->map->name);
areaListProxyModel->layoutChanged();
}
else {
// !TODO
qDebug() << "need to clear map list";
}
if (this->editor->layout) {
layoutTreeModel->setLayout(this->editor->layout->id);
layoutListProxyModel->layoutChanged();
}
else {
qDebug() << "need to clear layout list";
}
}
void MainWindow::on_action_Save_Project_triggered() {

10
src/ui/eventfilters.cpp Normal file
View file

@ -0,0 +1,10 @@
#include "eventfilters.h"
bool WheelFilter::eventFilter(QObject *, QEvent *event) {
if (event->type() == QEvent::Wheel) {
return true;
}
return false;
}

View file

@ -1,6 +1,18 @@
#include "maplistmodels.h"
#include <QMouseEvent>
#include "project.h"
#include "filterchildrenproxymodel.h"
void MapTree::removeSelected() {
while (!this->selectedIndexes().isEmpty()) {
QModelIndex i = this->selectedIndexes().takeLast();
this->model()->removeRow(i.row(), i.parent());
}
}
@ -11,6 +23,122 @@ MapGroupModel::MapGroupModel(Project *project, QObject *parent) : QStandardItemM
initialize();
}
Qt::DropActions MapGroupModel::supportedDropActions() const {
return Qt::MoveAction;
}
QStringList MapGroupModel::mimeTypes() const {
QStringList types;
types << "application/porymap.mapgroupmodel.map"
<< "application/porymap.mapgroupmodel.group";
return types;
}
QMimeData *MapGroupModel::mimeData(const QModelIndexList &indexes) const {
QMimeData *mimeData = QStandardItemModel::mimeData(indexes);
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const QModelIndex &index : indexes) {
if (index.isValid()) {
QString mapName = data(index, Qt::UserRole).toString();
stream << mapName;
}
}
mimeData->setData("application/porymap.mapgroupmodel.map", encodedData);
return mimeData;
}
bool MapGroupModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parentIndex) {
if (action == Qt::IgnoreAction)
return true;
if (!data->hasFormat("application/porymap.mapgroupmodel.map"))
return false;
if (!parentIndex.isValid())
return false;
int firstRow = 0;
if (row != -1) {
firstRow = row;
}
else if (parentIndex.isValid()) {
firstRow = rowCount(parentIndex);
}
QByteArray encodedData = data->data("application/porymap.mapgroupmodel.map");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList droppedMaps;
int rowCount = 0;
QList<QStandardItem *> newItems;
while (!stream.atEnd()) {
QString mapName;
stream >> mapName;
droppedMaps << mapName;
rowCount++;
}
this->insertRows(firstRow, rowCount, parentIndex);
int newItemIndex = 0;
for (QString mapName : droppedMaps) {
QModelIndex mapIndex = index(firstRow, 0, parentIndex);
QStandardItem *mapItem = this->itemFromIndex(mapIndex);
createMapItem(mapName, mapItem);
firstRow++;
}
// updateProject();
emit dragMoveCompleted();
return false;
}
/*
QStringList groupNames;
QMap<QString, int> mapGroups;
QList<QStringList> groupedMapNames;
QStringList mapNames;
*/
void MapGroupModel::updateProject() {
//
QStringList groups;
int numGroups = this->root->rowCount();
qDebug() << "group count:" << numGroups;
for (int g = 0; g < this->root->rowCount(); g++) {
QStandardItem *groupItem = this->item(g);
qDebug() << g << "group item" << groupItem->text(); //data(Qt::UserRole).toString();
for (int m = 0; m < groupItem->rowCount(); m++) {
//
QStandardItem *mapItem = groupItem->child(m);
qDebug() << " " << m << "map item" << mapItem->data(Qt::UserRole).toString();
}
}
QList<QStringList> maps;
for (auto mapName : this->mapItems.keys()) {
//
QStandardItem *mapItem = this->mapItems[mapName];
QStandardItem *groupItem = mapItem->parent();
if (!groupItem) {
qDebug() << "FAIL: no parent" << mapName;
continue;
}
auto mapIndex = this->indexFromItem(mapItem).row();
auto groupIndex = this->indexFromItem(groupItem).row();
// qDebug().nospace() << "map: " << mapName << "[" << parentIndex.row() << "." << mapIndex.row() << "]";
}
}
QStandardItem *MapGroupModel::createGroupItem(QString groupName, int groupIndex) {
QStandardItem *group = new QStandardItem;
group->setText(groupName);
@ -18,31 +146,30 @@ QStandardItem *MapGroupModel::createGroupItem(QString groupName, int groupIndex)
group->setData(groupName, Qt::UserRole);
group->setData("map_group", MapListRoles::TypeRole);
group->setData(groupIndex, MapListRoles::GroupRole);
// group->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
group->setFlags(Qt::ItemIsEditable | /* Qt::ItemIsSelectable | */ Qt::ItemIsEnabled | /* Qt::ItemIsDragEnabled | */ Qt::ItemIsDropEnabled);
this->groupItems.insert(groupName, group);
return group;
}
QStandardItem *MapGroupModel::createMapItem(QString mapName, int groupIndex, int mapIndex) {
QStandardItem *map = new QStandardItem;
map->setText(QString("[%1.%2] ").arg(groupIndex).arg(mapIndex, 2, 10, QLatin1Char('0')) + mapName);
QStandardItem *MapGroupModel::createMapItem(QString mapName, QStandardItem *map) {
if (!map) map = new QStandardItem;
map->setEditable(false);
map->setData(mapName, Qt::UserRole);
map->setData("map_name", MapListRoles::TypeRole);
map->setData(groupIndex, MapListRoles::GroupRole);
// map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
this->mapItems.insert(mapName, map);
// map->setData(groupIndex, MapListRoles::GroupRole);
map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
this->mapItems[mapName] = map;
return map;
}
QStandardItem *MapGroupModel::insertMapItem(QString mapName, QString groupName) {
int groupIndex = this->project->groupNames.indexOf(groupName);
//int groupIndex = this->project->groupNames.indexOf(groupName);
QStandardItem *group = this->groupItems[groupName];
if (!group) {
return nullptr;
}
int mapIndex = group->rowCount();
QStandardItem *map = createMapItem(mapName, groupIndex, mapIndex);
//int mapIndex = group->rowCount();
QStandardItem *map = createMapItem(mapName);
group->appendRow(map);
return map;
}
@ -54,10 +181,12 @@ void MapGroupModel::initialize() {
QString group_name = this->project->groupNames.value(i);
QStandardItem *group = createGroupItem(group_name, i);
root->appendRow(group);
//this->setItem(0, i, group);
QStringList names = this->project->groupedMapNames.value(i);
for (int j = 0; j < names.length(); j++) {
QString map_name = names.value(j);
QStandardItem *map = createMapItem(map_name, i, j);
QStandardItem *map = createMapItem(map_name);
//this->setItem(i, j, map);
group->appendRow(map);
}
}
@ -90,10 +219,13 @@ QVariant MapGroupModel::data(const QModelIndex &index, int role) const {
static QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico"));
static QIcon mapFolderIcon;
static QIcon folderIcon;
static bool loaded = false;
if (!loaded) {
mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off);
mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On);
folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off);
folderIcon.addFile(QStringLiteral(":/icons/folder.ico"), QSize(), QIcon::Normal, QIcon::On);
loaded = true;
}
@ -101,6 +233,9 @@ QVariant MapGroupModel::data(const QModelIndex &index, int role) const {
QString type = item->data(MapListRoles::TypeRole).toString();
if (type == "map_group") {
if (!item->hasChildren()) {
return folderIcon;
}
return mapFolderIcon;
} else if (type == "map_name") {
QString mapName = item->data(Qt::UserRole).toString();
@ -118,6 +253,14 @@ QVariant MapGroupModel::data(const QModelIndex &index, int role) const {
return mapGrayIcon;
}
}
else if (role == Qt::DisplayRole) {
//
QStandardItem *item = this->getItem(index)->child(row, col);
if (item->data(MapListRoles::TypeRole).toString() == "map_name") {
return QString("[%1.%2] ").arg(this->getItem(index)->row()).arg(row, 2, 10, QLatin1Char('0')) + item->data(Qt::UserRole).toString();
}
}
return QStandardItemModel::data(index, role);
}

View file

@ -3,6 +3,7 @@
#include "editor.h"
#include "encountertablemodel.h"
#include "encountertabledelegates.h"
#include "eventfilters.h"
@ -11,20 +12,13 @@ static WildMonInfo encounterClipboard;
MonTabWidget::MonTabWidget(Editor *editor, QWidget *parent) : QTabWidget(parent) {
this->editor = editor;
populate();
this->tabBar()->installEventFilter(this);
this->tabBar()->installEventFilter(new WheelFilter(this));
}
MonTabWidget::~MonTabWidget() {
}
bool MonTabWidget::eventFilter(QObject *, QEvent *event) {
if (event->type() == QEvent::Wheel) {
return true;
}
return false;
}
void MonTabWidget::populate() {
EncounterFields fields = editor->project->wildMonFields;
activeTabs.resize(fields.size());