mirror of
https://github.com/redstrate/Novus.git
synced 2025-05-14 20:47:46 +00:00
Create a proper ObjectListModel
Eventually we want to load multiple LGBs at once (and categorize objects further, of course) so we need an actual tree model.
This commit is contained in:
parent
fa47841440
commit
8ba4d0ba6f
5 changed files with 197 additions and 39 deletions
|
@ -10,6 +10,7 @@ target_sources(novus-mapeditor
|
||||||
include/objectpass.h
|
include/objectpass.h
|
||||||
include/objectlistwidget.h
|
include/objectlistwidget.h
|
||||||
include/appstate.h
|
include/appstate.h
|
||||||
|
include/objectlistmodel.h
|
||||||
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp
|
src/mainwindow.cpp
|
||||||
|
@ -17,7 +18,8 @@ target_sources(novus-mapeditor
|
||||||
src/mapview.cpp
|
src/mapview.cpp
|
||||||
src/objectpass.cpp
|
src/objectpass.cpp
|
||||||
src/objectlistwidget.cpp
|
src/objectlistwidget.cpp
|
||||||
src/appstate.cpp)
|
src/appstate.cpp
|
||||||
|
src/objectlistmodel.cpp)
|
||||||
target_include_directories(novus-mapeditor
|
target_include_directories(novus-mapeditor
|
||||||
PUBLIC
|
PUBLIC
|
||||||
include)
|
include)
|
||||||
|
|
49
apps/mapeditor/include/objectlistmodel.h
Normal file
49
apps/mapeditor/include/objectlistmodel.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
class AppState;
|
||||||
|
|
||||||
|
enum class TreeType {
|
||||||
|
/// Root of the tree
|
||||||
|
Root,
|
||||||
|
/// LGB file
|
||||||
|
File,
|
||||||
|
/// A single object
|
||||||
|
Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TreeInformation {
|
||||||
|
TreeType type;
|
||||||
|
TreeInformation *parent = nullptr;
|
||||||
|
int row = 0;
|
||||||
|
QString name;
|
||||||
|
|
||||||
|
std::vector<TreeInformation *> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectListModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ObjectListModel(AppState *appState, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||||
|
QModelIndex parent(const QModelIndex &child) const override;
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
AppState *m_appState = nullptr;
|
||||||
|
TreeInformation *m_rootItem = nullptr;
|
||||||
|
};
|
|
@ -3,10 +3,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QListView>
|
#include <QTreeView>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <physis.hpp>
|
#include <physis.hpp>
|
||||||
|
|
||||||
|
class ObjectListModel;
|
||||||
class QStringListModel;
|
class QStringListModel;
|
||||||
class AppState;
|
class AppState;
|
||||||
|
|
||||||
|
@ -18,9 +19,7 @@ public:
|
||||||
explicit ObjectListWidget(AppState *appState, QWidget *parent = nullptr);
|
explicit ObjectListWidget(AppState *appState, QWidget *parent = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refresh();
|
QTreeView *treeWidget = nullptr;
|
||||||
|
AppState *m_appState = nullptr;
|
||||||
QListView *listWidget = nullptr;
|
ObjectListModel *m_objectListModel = nullptr;
|
||||||
AppState *m_appState;
|
|
||||||
QStringListModel *m_originalModel;
|
|
||||||
};
|
};
|
||||||
|
|
132
apps/mapeditor/src/objectlistmodel.cpp
Normal file
132
apps/mapeditor/src/objectlistmodel.cpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "objectlistmodel.h"
|
||||||
|
#include "appstate.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
ObjectListModel::ObjectListModel(AppState *appState, QObject *parent)
|
||||||
|
: QAbstractItemModel(parent)
|
||||||
|
, m_appState(appState)
|
||||||
|
{
|
||||||
|
m_rootItem = new TreeInformation();
|
||||||
|
m_rootItem->type = TreeType::Root;
|
||||||
|
|
||||||
|
connect(m_appState, &AppState::mapLoaded, this, &ObjectListModel::refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObjectListModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
TreeInformation *parentItem;
|
||||||
|
if (parent.column() > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!parent.isValid())
|
||||||
|
parentItem = m_rootItem;
|
||||||
|
else
|
||||||
|
parentItem = static_cast<TreeInformation *>(parent.internalPointer());
|
||||||
|
|
||||||
|
return static_cast<int>(parentItem->children.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObjectListModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ObjectListModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!hasIndex(row, column, parent))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
TreeInformation *parentItem;
|
||||||
|
|
||||||
|
if (!parent.isValid())
|
||||||
|
parentItem = m_rootItem;
|
||||||
|
else
|
||||||
|
parentItem = static_cast<TreeInformation *>(parent.internalPointer());
|
||||||
|
|
||||||
|
TreeInformation *childItem = parentItem->children[row];
|
||||||
|
if (childItem)
|
||||||
|
return createIndex(row, column, childItem);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ObjectListModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto childItem = static_cast<TreeInformation *>(index.internalPointer());
|
||||||
|
TreeInformation *parentItem = childItem->parent;
|
||||||
|
|
||||||
|
if (parentItem == m_rootItem)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return createIndex(parentItem->row, 0, parentItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ObjectListModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto item = static_cast<TreeInformation *>(index.internalPointer());
|
||||||
|
|
||||||
|
if (item->type == TreeType::File) {
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
return item->name;
|
||||||
|
}
|
||||||
|
} else if (item->type == TreeType::Object) {
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
return item->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ObjectListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||||
|
if (section == 0) {
|
||||||
|
return i18nc("@title:column Object id", "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QAbstractItemModel::headerData(section, orientation, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectListModel::refresh()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
|
||||||
|
auto fileItem = new TreeInformation();
|
||||||
|
fileItem->type = TreeType::File;
|
||||||
|
fileItem->parent = m_rootItem;
|
||||||
|
fileItem->name = QStringLiteral("bg");
|
||||||
|
m_rootItem->children.push_back(fileItem);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_appState->bgGroup.num_chunks; i++) {
|
||||||
|
const auto chunk = m_appState->bgGroup.chunks[i];
|
||||||
|
for (int j = 0; j < chunk.num_layers; j++) {
|
||||||
|
const auto layer = chunk.layers[j];
|
||||||
|
for (int z = 0; z < layer.num_objects; z++) {
|
||||||
|
const auto object = layer.objects[z];
|
||||||
|
const QString name = QString::fromLatin1(object.name);
|
||||||
|
|
||||||
|
auto objectItem = new TreeInformation();
|
||||||
|
objectItem->type = TreeType::Object;
|
||||||
|
objectItem->parent = fileItem;
|
||||||
|
objectItem->name = i18n("Unknown (%1)", object.instance_id); // TODO: do display names if we have them
|
||||||
|
objectItem->row = z;
|
||||||
|
fileItem->children.push_back(objectItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_objectlistmodel.cpp"
|
|
@ -10,6 +10,7 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "appstate.h"
|
#include "appstate.h"
|
||||||
|
#include "objectlistmodel.h"
|
||||||
|
|
||||||
ObjectListWidget::ObjectListWidget(AppState *appState, QWidget *parent)
|
ObjectListWidget::ObjectListWidget(AppState *appState, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
@ -25,7 +26,7 @@ ObjectListWidget::ObjectListWidget(AppState *appState, QWidget *parent)
|
||||||
searchModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
searchModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||||
|
|
||||||
auto searchEdit = new QLineEdit();
|
auto searchEdit = new QLineEdit();
|
||||||
searchEdit->setWhatsThis(i18nc("@info:whatsthis", "Search box for Excel sheet names."));
|
searchEdit->setWhatsThis(i18nc("@info:whatsthis", "Search box for objects."));
|
||||||
searchEdit->setPlaceholderText(i18nc("@info:placeholder", "Search…"));
|
searchEdit->setPlaceholderText(i18nc("@info:placeholder", "Search…"));
|
||||||
searchEdit->setClearButtonEnabled(true);
|
searchEdit->setClearButtonEnabled(true);
|
||||||
searchEdit->setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags{Qt::BottomEdge}));
|
searchEdit->setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags{Qt::BottomEdge}));
|
||||||
|
@ -34,39 +35,14 @@ ObjectListWidget::ObjectListWidget(AppState *appState, QWidget *parent)
|
||||||
});
|
});
|
||||||
layout->addWidget(searchEdit);
|
layout->addWidget(searchEdit);
|
||||||
|
|
||||||
m_originalModel = new QStringListModel();
|
m_objectListModel = new ObjectListModel(appState, this);
|
||||||
searchModel->setSourceModel(m_originalModel);
|
searchModel->setSourceModel(m_objectListModel);
|
||||||
|
|
||||||
listWidget = new QListView();
|
treeWidget = new QTreeView();
|
||||||
listWidget->setWhatsThis(i18nc("@info:whatsthis", "A list of Excel sheet names. Select one to view it's contents."));
|
treeWidget->setWhatsThis(i18nc("@info:whatsthis", "A list of objects on this map."));
|
||||||
listWidget->setModel(searchModel);
|
treeWidget->setModel(searchModel);
|
||||||
|
|
||||||
layout->addWidget(listWidget);
|
layout->addWidget(treeWidget);
|
||||||
|
|
||||||
connect(m_appState, &AppState::mapLoaded, this, &ObjectListWidget::refresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectListWidget::refresh()
|
|
||||||
{
|
|
||||||
QStringList list;
|
|
||||||
|
|
||||||
for (int i = 0; i < m_appState->bgGroup.num_chunks; i++) {
|
|
||||||
const auto chunk = m_appState->bgGroup.chunks[i];
|
|
||||||
for (int j = 0; j < chunk.num_layers; j++) {
|
|
||||||
const auto layer = chunk.layers[j];
|
|
||||||
for (int z = 0; z < layer.num_objects; z++) {
|
|
||||||
const auto object = layer.objects[z];
|
|
||||||
const QString name = QString::fromLatin1(object.name);
|
|
||||||
if (true) { // TODO: do display names if we have them
|
|
||||||
list << i18n("Unknown (%1)", object.instance_id);
|
|
||||||
} else {
|
|
||||||
list << name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_originalModel->setStringList(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_objectlistwidget.cpp"
|
#include "moc_objectlistwidget.cpp"
|
||||||
|
|
Loading…
Add table
Reference in a new issue