Merge pull request #767 from GriffinRichards/map-list-sorting

Add sorting options to the Locations and Layouts list
This commit is contained in:
GriffinR 2025-08-27 22:45:34 -04:00 committed by GitHub
commit 4ab3322d97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 65 additions and 24 deletions

View File

@ -98,6 +98,8 @@ public:
int mapListTab;
bool mapListEditGroupsEnabled;
QMap<int, bool> mapListHideEmptyEnabled;
bool mapListLayoutsSorted;
bool mapListLocationsSorted;
bool prettyCursors;
bool mirrorConnectingMaps;
bool showDiveEmergeMaps;

View File

@ -393,10 +393,10 @@ private:
void openDuplicateMapOrLayoutDialog();
void openNewMapGroupDialog();
void openNewLocationDialog();
void scrollMapList(MapTree *list, const QString &itemName);
void scrollMapList(MapTree *list, const QString &itemName, bool expandItem = true);
void scrollMapListToCurrentMap(MapTree *list);
void scrollMapListToCurrentLayout(MapTree *list);
void scrollCurrentMapListToItem(const QString &itemName);
void scrollCurrentMapListToItem(const QString &itemName, bool expandItem = true);
void showFileWatcherWarning();
bool openProject(QString dir, bool initial = false);
bool closeProject();
@ -410,6 +410,7 @@ private:
void rebuildMapList_Locations();
void rebuildMapList_Layouts();
void setMapListSorted(MapTree *list, bool sort);
void updateMapList();
void openMapListItem(const QModelIndex &index);
void onMapListTabChanged(int index);

View File

@ -52,8 +52,6 @@ public:
QStringList bgEventFacingDirections;
QStringList trainerTypes;
QStringList globalScriptLabels;
QStringList mapSectionIdNamesSaveOrder;
QStringList mapSectionIdNames;
QMap<uint32_t, QString> encounterTypeToName;
QMap<uint32_t, QString> terrainTypeToName;
QMap<QString, QMap<QString, uint16_t>> metatileLabelsMap;
@ -83,6 +81,7 @@ public:
Map* loadMap(const QString &mapName);
const QStringList& layoutIds() const { return this->alphabeticalLayoutIds; }
const QStringList& layoutIdsOrdered() const { return this->orderedLayoutIds; }
bool isKnownLayout(const QString &layoutId) const { return this->mapLayouts.contains(layoutId); }
bool isLoadedLayout(const QString &layoutId) const { return this->loadedLayoutIds.contains(layoutId); }
bool isUnsavedLayout(const QString &layoutId) const;
@ -93,6 +92,12 @@ public:
Layout* getLayout(const QString &layoutId) const { return this->mapLayouts.value(layoutId); }
Layout* loadLayout(const QString &layoutId);
const QStringList& locationNames() const { return this->mapSectionIdNames; }
const QStringList& locationNamesOrdered() const { return this->mapSectionIdNamesSaveOrder; }
QString getLocationName(int locationValue) const { return this->mapSectionIdNamesSaveOrder.value(locationValue, getEmptyMapsecName()); }
int getLocationValue(const QString &locationName) const { return this->mapSectionIdNamesSaveOrder.indexOf(locationName); }
void clearMaps();
void clearTilesetCache();
void clearMapLayouts();
@ -284,6 +289,8 @@ private:
QStringList orderedLayoutIdsMaster;
QHash<QString, Layout*> mapLayouts;
QHash<QString, Layout*> mapLayoutsMaster;
QStringList mapSectionIdNamesSaveOrder;
QStringList mapSectionIdNames;
// Fields for preserving top-level JSON data that Porymap isn't expecting.
QJsonObject customLayoutsData;

View File

@ -327,6 +327,8 @@ void PorymapConfig::reset() {
this->mapListTab = 0;
this->mapListEditGroupsEnabled = false;
this->mapListHideEmptyEnabled.clear();
this->mapListLayoutsSorted = true;
this->mapListLocationsSorted = true;
this->prettyCursors = true;
this->mirrorConnectingMaps = true;
this->showDiveEmergeMaps = false;
@ -407,6 +409,10 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
return;
}
this->mapListHideEmptyEnabled.insert(tab, getConfigBool(key, value));
} else if (key == "map_list_layouts_sorted") {
this->mapListLayoutsSorted = getConfigBool(key, value);
} else if (key == "map_list_locations_sorted") {
this->mapListLocationsSorted = getConfigBool(key, value);
} else if (key == "main_window_geometry") {
this->mainWindowGeometry = bytesFromString(value);
} else if (key == "main_window_state") {
@ -591,6 +597,8 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
for (auto i = this->mapListHideEmptyEnabled.constBegin(); i != this->mapListHideEmptyEnabled.constEnd(); i++) {
map.insert(QStringLiteral("map_list_hide_empty_enabled/") + QString::number(i.key()), i.value() ? "1" : "0");
}
map.insert("map_list_layouts_sorted", this->mapListLayoutsSorted ? "1" : "0");
map.insert("map_list_locations_sorted", this->mapListLocationsSorted ? "1" : "0");
map.insert("main_window_geometry", stringFromByteArray(this->mainWindowGeometry));
map.insert("main_window_state", stringFromByteArray(this->mainWindowState));
map.insert("map_splitter_state", stringFromByteArray(this->mapSplitterState));

View File

@ -156,7 +156,7 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
for (int x = 0; x < this->layout_width; x++) {
int bin_index = x + y * this->layout_width;
uint8_t square_section_id = mapBinData.at(bin_index);
QString square_section_name = project->mapSectionIdNames.value(square_section_id, this->default_map_section);
QString square_section_name = project->getLocationName(square_section_id);
LayoutSquare square;
square.map_section = square_section_name;
@ -397,11 +397,11 @@ void RegionMap::saveLayout() {
case LayoutFormat::Binary:
{
QByteArray data;
int defaultValue = this->project->mapSectionIdNames.indexOf(this->default_map_section);
int defaultValue = this->project->getLocationValue(this->default_map_section);
for (int m = 0; m < this->layout_height; m++) {
for (int n = 0; n < this->layout_width; n++) {
int i = n + this->layout_width * m;
int mapSectionValue = this->project->mapSectionIdNames.indexOf(this->layouts["main"][i].map_section);
int mapSectionValue = this->project->getLocationValue(this->layouts["main"][i].map_section);
if (mapSectionValue < 0){
mapSectionValue = defaultValue;
}

View File

@ -1440,16 +1440,15 @@ bool MainWindow::setProjectUI() {
this->locationListProxyModel = new FilterChildrenProxyModel();
this->locationListProxyModel->setSourceModel(this->mapLocationModel);
this->locationListProxyModel->setHideEmpty(porymapConfig.mapListHideEmptyEnabled[MapListTab::Locations]);
ui->locationList->setModel(locationListProxyModel);
ui->locationList->sortByColumn(0, Qt::SortOrder::AscendingOrder);
setMapListSorted(ui->locationList, porymapConfig.mapListLocationsSorted);
this->layoutTreeModel = new LayoutTreeModel(editor->project);
this->layoutListProxyModel = new FilterChildrenProxyModel();
this->layoutListProxyModel->setSourceModel(this->layoutTreeModel);
this->layoutListProxyModel->setHideEmpty(porymapConfig.mapListHideEmptyEnabled[MapListTab::Layouts]);
ui->layoutList->setModel(layoutListProxyModel);
ui->layoutList->sortByColumn(0, Qt::SortOrder::AscendingOrder);
setMapListSorted(ui->layoutList, porymapConfig.mapListLayoutsSorted);
ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->getTopLevelMapFields());
@ -1503,7 +1502,7 @@ void MainWindow::clearProjectUI() {
resetMapNavigation();
}
void MainWindow::scrollMapList(MapTree *list, const QString &itemName) {
void MainWindow::scrollMapList(MapTree *list, const QString &itemName, bool expandItem) {
if (!list || itemName.isEmpty())
return;
auto model = static_cast<FilterChildrenProxyModel*>(list->model());
@ -1516,7 +1515,7 @@ void MainWindow::scrollMapList(MapTree *list, const QString &itemName) {
return;
list->setCurrentIndex(index);
list->setExpanded(index, true);
if (expandItem) list->setExpanded(index, true);
list->scrollTo(index, QAbstractItemView::PositionAtCenter);
}
@ -1537,13 +1536,13 @@ void MainWindow::scrollMapListToCurrentLayout(MapTree *list) {
// - The map list was in the middle of a search
// - A map/layout is being opened by interacting with the list (in which case `lockMapListAutoScroll` is true)
// - The item is not in the list (e.g. a layout ID for the Groups list)
void MainWindow::scrollCurrentMapListToItem(const QString &itemName) {
void MainWindow::scrollCurrentMapListToItem(const QString &itemName, bool expandItem) {
if (this->lockMapListAutoScroll)
return;
auto toolbar = getCurrentMapListToolBar();
if (toolbar && toolbar->filterText().isEmpty()) {
scrollMapList(toolbar->list(), itemName);
scrollMapList(toolbar->list(), itemName, expandItem);
}
}
@ -1565,6 +1564,7 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
QAction* openItemAction = nullptr;
QAction* copyListNameAction = nullptr;
QAction* copyToolTipAction = nullptr;
QAction* sortFoldersAction = nullptr;
if (itemType == "map_name") {
// Right-clicking on a map.
@ -1596,6 +1596,8 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
deleteFolderAction = menu.addAction("Delete Location");
if (itemName == this->editor->project->getEmptyMapsecName())
deleteFolderAction->setEnabled(false); // Disallow deleting the default name
menu.addSeparator();
sortFoldersAction = menu.addAction(list->isSortingEnabled() ? "Sort List by Value" : "Sort List Alphabetically");
} else if (itemType == "map_layout") {
// Right-clicking on a map layout
openItemAction = menu.addAction("Open Layout");
@ -1612,6 +1614,8 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
addToFolderAction = menu.addAction("Add New Map with Layout");
//menu.addSeparator();
//deleteFolderAction = menu.addAction("Delete Layout"); // TODO: No support for deleting layouts
menu.addSeparator();
sortFoldersAction = menu.addAction(list->isSortingEnabled() ? "Sort List by Value" : "Sort List Alphabetically");
}
if (addToFolderAction) {
@ -1646,6 +1650,12 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) {
setClipboardData(selectedItem->toolTip());
});
}
if (sortFoldersAction) {
connect(sortFoldersAction, &QAction::triggered, [this, list, itemName] {
setMapListSorted(list, !list->isSortingEnabled());
scrollCurrentMapListToItem(itemName, false);
});
}
if (menu.actions().length() != 0)
menu.exec(QCursor::pos());
@ -1895,6 +1905,19 @@ void MainWindow::rebuildMapList_Layouts() {
ui->mapListToolBar_Layouts->refreshFilter();
}
void MainWindow::setMapListSorted(MapTree *list, bool sort) {
if (sort == list->isSortingEnabled())
return;
list->setSortingEnabled(sort);
list->sortByColumn(sort ? 0 : -1, Qt::SortOrder::AscendingOrder);
if (list == ui->locationList) {
porymapConfig.mapListLocationsSorted = sort;
} else if (list == ui->layoutList) {
porymapConfig.mapListLayoutsSorted = sort;
}
}
QString MainWindow::getActiveItemName() {
if (this->editor->map) return this->editor->map->name();
if (this->editor->layout) return this->editor->layout->id;

View File

@ -288,7 +288,7 @@ QList<QString> ScriptUtility::getSongNames() {
QList<QString> ScriptUtility::getLocationNames() {
if (!window || !window->editor || !window->editor->project)
return QList<QString>();
return window->editor->project->mapSectionIdNames;
return window->editor->project->locationNames();
}
QList<QString> ScriptUtility::getWeatherNames() {

View File

@ -67,7 +67,7 @@ void MapHeaderForm::setProject(Project * project, bool allowChanges) {
const QSignalBlocker b_Locations(ui->comboBox_Location);
ui->comboBox_Location->clear();
ui->comboBox_Location->addItems(m_project->mapSectionIdNames);
ui->comboBox_Location->addItems(m_project->locationNames());
// Hide config-specific settings

View File

@ -442,7 +442,7 @@ bool MapGroupModel::setData(const QModelIndex &index, const QVariant &value, int
MapLocationModel::MapLocationModel(Project *project, QObject *parent) : MapListModel(project, parent) {
this->folderTypeName = "map_section";
for (const auto &idName : this->project->mapSectionIdNames) {
for (const auto &idName : this->project->locationNamesOrdered()) {
insertMapFolderItem(idName);
}
for (const auto &mapName : this->project->mapNames()) {
@ -466,7 +466,7 @@ QStandardItem *MapLocationModel::createMapFolderItem(const QString &folderName,
LayoutTreeModel::LayoutTreeModel(Project *project, QObject *parent) : MapListModel(project, parent) {
this->folderTypeName = "map_layout";
for (const auto &layoutId : this->project->layoutIds()) {
for (const auto &layoutId : this->project->layoutIdsOrdered()) {
insertMapFolderItem(layoutId);
}
for (const auto &mapName : this->project->mapNames()) {

View File

@ -648,7 +648,7 @@ void RegionMapEditor::displayRegionMapLayoutOptions() {
const QSignalBlocker b(ui->comboBox_RM_ConnectedMap);
this->ui->comboBox_RM_ConnectedMap->clear();
this->ui->comboBox_RM_ConnectedMap->addItems(this->project->mapSectionIdNames);
this->ui->comboBox_RM_ConnectedMap->addItems(this->project->locationNames());
this->ui->frame_RM_Options->setEnabled(true);
@ -711,7 +711,7 @@ void RegionMapEditor::displayRegionMapEntryOptions() {
if (!this->region_map->layoutEnabled()) return;
this->ui->comboBox_RM_Entry_MapSection->clear();
this->ui->comboBox_RM_Entry_MapSection->addItems(this->project->mapSectionIdNames);
this->ui->comboBox_RM_Entry_MapSection->addItems(this->project->locationNames());
this->ui->spinBox_RM_Entry_x->setMaximum(128);
this->ui->spinBox_RM_Entry_y->setMaximum(128);
this->ui->spinBox_RM_Entry_width->setMinimum(1);
@ -1103,10 +1103,10 @@ void RegionMapEditor::on_action_Swap_triggered() {
QFormLayout form(&popup);
QComboBox *oldSecBox = new QComboBox();
oldSecBox->addItems(this->project->mapSectionIdNames);
oldSecBox->addItems(this->project->locationNames());
form.addRow(new QLabel("Map Section 1:"), oldSecBox);
QComboBox *newSecBox = new QComboBox();
newSecBox->addItems(this->project->mapSectionIdNames);
newSecBox->addItems(this->project->locationNames());
form.addRow(new QLabel("Map Section 2:"), newSecBox);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);
@ -1142,10 +1142,10 @@ void RegionMapEditor::on_action_Replace_triggered() {
QFormLayout form(&popup);
QComboBox *oldSecBox = new QComboBox();
oldSecBox->addItems(this->project->mapSectionIdNames);
oldSecBox->addItems(this->project->locationNames());
form.addRow(new QLabel("Old Map Section:"), oldSecBox);
QComboBox *newSecBox = new QComboBox();
newSecBox->addItems(this->project->mapSectionIdNames);
newSecBox->addItems(this->project->locationNames());
form.addRow(new QLabel("New Map Section:"), newSecBox);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);