From 7da23759988be15c8abec5aa6d34a758ca1adb83 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 18 Oct 2024 14:22:34 -0400 Subject: [PATCH] Refactor map list buttons --- forms/mainwindow.ui | 663 ++++++-------------------- forms/maplisttoolbar.ui | 172 +++++++ include/mainwindow.h | 58 +-- include/ui/filterchildrenproxymodel.h | 2 +- include/ui/maplistmodels.h | 22 +- include/ui/maplisttoolbar.h | 49 ++ porymap.pro | 3 + resources/icons/collapse_all.ico | Bin 318 -> 1871 bytes resources/icons/expand_all.ico | Bin 318 -> 2142 bytes resources/icons/folder_add.ico | Bin 0 -> 1572 bytes resources/icons/folder_closed_map.ico | Bin 1150 -> 5558 bytes resources/images.qrc | 1 + src/core/map.cpp | 2 +- src/mainwindow.cpp | 566 +++++++++------------- src/ui/maplistmodels.cpp | 12 +- src/ui/maplisttoolbar.cpp | 121 +++++ 16 files changed, 772 insertions(+), 899 deletions(-) create mode 100644 forms/maplisttoolbar.ui create mode 100644 include/ui/maplisttoolbar.h create mode 100755 resources/icons/folder_add.ico create mode 100644 src/ui/maplisttoolbar.cpp diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index bc03f823..44d69d30 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 1287 - 936 + 1298 + 963 @@ -30,7 +30,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -45,7 +45,7 @@ 0 - + Groups @@ -66,140 +66,7 @@ 0 - - - 0 - - - 3 - - - 3 - - - 3 - - - - - <html><head/><body><p>Toggle hide all empty map folders</p></body></html> - - - - - - - :/icons/folder_eye_open.ico - :/icons/folder_eye_closed.ico:/icons/folder_eye_open.ico - - - true - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Expand all map folders</p></body></html> - - - - - - - :/icons/expand_all.ico:/icons/expand_all.ico - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Collapse all map list folders</p></body></html> - - - - - - - :/icons/collapse_all.ico:/icons/collapse_all.ico - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Toggle editability of group folders</p></body></html> - - - - - - - :/icons/lock_edit.ico - :/icons/unlock_edit.ico:/icons/lock_edit.ico - - - true - - - QToolButton::InstantPopup - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 12 - 20 - - - - - - - - true - - - - - - Filter... - - - true - - - - + @@ -216,10 +83,10 @@ - QAbstractItemView::SingleSelection + QAbstractItemView::SelectionMode::SingleSelection - QAbstractItemView::SelectItems + QAbstractItemView::SelectionBehavior::SelectItems false @@ -228,7 +95,7 @@ - + Areas @@ -249,116 +116,7 @@ 0 - - - 0 - - - 3 - - - 3 - - - 3 - - - - - <html><head/><body><p>Toggle hide all empty mapsection folders</p></body></html> - - - - - - - :/icons/folder_eye_open.ico - :/icons/folder_eye_closed.ico:/icons/folder_eye_open.ico - - - true - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Expand all map folders</p></body></html> - - - - - - - :/icons/expand_all.ico:/icons/expand_all.ico - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Collapse all map list folders</p></body></html> - - - - - - - :/icons/collapse_all.ico:/icons/collapse_all.ico - - - QToolButton::InstantPopup - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 12 - 20 - - - - - - - - true - - - - - - Filter... - - - true - - - - + @@ -375,10 +133,10 @@ - QAbstractItemView::SingleSelection + QAbstractItemView::SelectionMode::SingleSelection - QAbstractItemView::SelectItems + QAbstractItemView::SelectionBehavior::SelectItems false @@ -387,7 +145,7 @@ - + Layouts @@ -408,116 +166,7 @@ 0 - - - 0 - - - 3 - - - 3 - - - 3 - - - - - <html><head/><body><p>Toggle hide all unused layouts</p></body></html> - - - - - - - :/icons/folder_eye_open.ico - :/icons/folder_eye_closed.ico:/icons/folder_eye_open.ico - - - true - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Expand all layout folders</p></body></html> - - - - - - - :/icons/expand_all.ico:/icons/expand_all.ico - - - QToolButton::InstantPopup - - - true - - - - - - - <html><head/><body><p>Collapse all layout folders</p></body></html> - - - - - - - :/icons/collapse_all.ico:/icons/collapse_all.ico - - - QToolButton::InstantPopup - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 12 - 20 - - - - - - - - true - - - - - - Filter... - - - true - - - - + @@ -534,10 +183,10 @@ - QAbstractItemView::SingleSelection + QAbstractItemView::SelectionMode::SingleSelection - QAbstractItemView::SelectItems + QAbstractItemView::SelectionBehavior::SelectItems false @@ -581,7 +230,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -633,7 +282,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -643,10 +292,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised 1 @@ -670,10 +319,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -722,10 +371,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -746,10 +395,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -930,7 +579,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -953,10 +602,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -1004,7 +653,7 @@ - QLayout::SetNoConstraint + QLayout::SizeConstraint::SetNoConstraint 3 @@ -1033,17 +682,17 @@ 30 - Qt::Horizontal + Qt::Orientation::Horizontal - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Plain + QFrame::Shadow::Plain @@ -1067,7 +716,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1104,10 +753,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Plain + QFrame::Shadow::Plain true @@ -1117,8 +766,8 @@ 0 0 - 420 - 77 + 424 + 79 @@ -1140,7 +789,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1162,17 +811,17 @@ <html><head/><body><p>The border is a 2x2 metatile which is repeated outside of the map layout's boundary. Draw on this border area to modify it.</p></body></html> - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1223,10 +872,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Plain + QFrame::Shadow::Plain true @@ -1236,8 +885,8 @@ 0 0 - 420 - 78 + 424 + 79 @@ -1259,7 +908,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1284,17 +933,17 @@ - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1318,19 +967,19 @@ - Qt::ScrollBarAlwaysOn + Qt::ScrollBarPolicy::ScrollBarAlwaysOn - Qt::ScrollBarAsNeeded + Qt::ScrollBarPolicy::ScrollBarAsNeeded - QAbstractScrollArea::AdjustIgnored + QAbstractScrollArea::SizeAdjustPolicy::AdjustIgnored true - Qt::AlignHCenter|Qt::AlignTop + Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop @@ -1338,10 +987,10 @@ - 0 + 8 0 - 409 - 440 + 412 + 446 @@ -1369,7 +1018,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1391,20 +1040,20 @@ - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - QAbstractScrollArea::AdjustIgnored + QAbstractScrollArea::SizeAdjustPolicy::AdjustIgnored - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1417,7 +1066,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1444,10 +1093,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -1460,7 +1109,7 @@ - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus <html><head/><body><p>Primary Tileset</p><p>Defines the first 0x200 metatiles available for the map.</p></body></html> @@ -1480,7 +1129,7 @@ - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus <html><head/><body><p>Secondary Tileset</p><p>Defines the second 0x200 metatiles available for the map.</p></body></html> @@ -1493,10 +1142,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised @@ -1538,7 +1187,7 @@ - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint 3 @@ -1569,8 +1218,8 @@ 0 0 - 424 - 627 + 428 + 633 @@ -1592,7 +1241,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1617,17 +1266,17 @@ - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1640,7 +1289,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1666,7 +1315,7 @@ 30 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1682,17 +1331,17 @@ 50 - Qt::Horizontal + Qt::Orientation::Horizontal - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -1718,7 +1367,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1779,7 +1428,7 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true @@ -1789,8 +1438,8 @@ 0 0 - 379 - 732 + 383 + 744 @@ -1812,10 +1461,10 @@ <html><head/><body><p>No prefabs have been created for the currently-used tilesets. Create some by using the button above!</p><p>Prefabs are &quot;prefabricated&quot; metatile selections that are used for easy selecting of complicated map structures. For example, a useful prefab could be a building or tree formation, which would otherwise be annoying to paint with the regular metatile picker.</p></body></html> - Qt::RichText + Qt::TextFormat::RichText - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop true @@ -1888,10 +1537,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised 0 @@ -1928,7 +1577,7 @@ :/icons/add.ico:/icons/add.ico - Qt::ToolButtonTextBesideIcon + Qt::ToolButtonStyle::ToolButtonTextBesideIcon @@ -1951,7 +1600,7 @@ :/icons/delete.ico:/icons/delete.ico - Qt::ToolButtonTextBesideIcon + Qt::ToolButtonStyle::ToolButtonTextBesideIcon false @@ -1961,7 +1610,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1996,7 +1645,7 @@ There are no events on the current map. - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -2062,7 +1711,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -2077,13 +1726,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -2091,7 +1740,7 @@ 0 0 100 - 30 + 16 @@ -2156,7 +1805,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -2171,13 +1820,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -2185,7 +1834,7 @@ 0 0 100 - 30 + 16 @@ -2250,7 +1899,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -2265,13 +1914,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -2279,7 +1928,7 @@ 0 0 100 - 30 + 16 @@ -2350,7 +1999,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -2365,13 +2014,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -2379,7 +2028,7 @@ 0 0 100 - 30 + 16 @@ -2444,7 +2093,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -2459,13 +2108,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -2473,7 +2122,7 @@ 0 0 100 - 30 + 16 @@ -2513,13 +2162,13 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop @@ -2582,14 +2231,14 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised - QFormLayout::FieldsStayAtSizeHint + QFormLayout::FieldGrowthPolicy::FieldsStayAtSizeHint 12 @@ -2793,10 +2442,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -2809,10 +2458,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Plain + QFrame::Shadow::Plain @@ -2844,7 +2493,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -2925,10 +2574,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -2940,10 +2589,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -3008,7 +2657,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -3093,7 +2742,7 @@ 30 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -3109,7 +2758,7 @@ 30 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -3141,7 +2790,7 @@ 30 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -3172,7 +2821,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -3188,22 +2837,22 @@ false - Qt::ScrollBarAsNeeded + Qt::ScrollBarPolicy::ScrollBarAsNeeded - Qt::ScrollBarAsNeeded + Qt::ScrollBarPolicy::ScrollBarAsNeeded - QAbstractScrollArea::AdjustIgnored + QAbstractScrollArea::SizeAdjustPolicy::AdjustIgnored - QGraphicsView::NoDrag + QGraphicsView::DragMode::NoDrag - QGraphicsView::AnchorUnderMouse + QGraphicsView::ViewportAnchor::AnchorUnderMouse - QGraphicsView::AnchorUnderMouse + QGraphicsView::ViewportAnchor::AnchorUnderMouse @@ -3214,10 +2863,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -3234,10 +2883,10 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - Qt::ScrollBarAlwaysOff + Qt::ScrollBarPolicy::ScrollBarAlwaysOff true @@ -3247,8 +2896,8 @@ 0 0 - 365 - 651 + 204 + 16 @@ -3270,7 +2919,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -3298,19 +2947,19 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Raised + QFrame::Shadow::Raised - QFrame::NoFrame + QFrame::Shape::NoFrame - QFrame::Plain + QFrame::Shadow::Plain @@ -3323,7 +2972,7 @@ - QComboBox::AdjustToContents + QComboBox::SizeAdjustPolicy::AdjustToContents @@ -3364,7 +3013,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -3416,8 +3065,8 @@ 0 0 - 1287 - 22 + 1298 + 37 @@ -3788,7 +3437,7 @@ Check for Updates... - QAction::ApplicationSpecificRole + QAction::MenuRole::ApplicationSpecificRole @@ -3868,6 +3517,12 @@ QGraphicsView
mapview.h
+ + MapListToolBar + QFrame +
maplisttoolbar.h
+ 1 +
diff --git a/forms/maplisttoolbar.ui b/forms/maplisttoolbar.ui new file mode 100644 index 00000000..6f753ea8 --- /dev/null +++ b/forms/maplisttoolbar.ui @@ -0,0 +1,172 @@ + + + MapListToolBar + + + + 0 + 0 + 274 + 32 + + + + Form + + + + 0 + + + 3 + + + 3 + + + 0 + + + 3 + + + + + Add a folder to the list. + + + + :/icons/folder_add.ico:/icons/folder_add.ico + + + QToolButton::ToolButtonPopupMode::InstantPopup + + + true + + + + + + + Hide empty folders in the list. + + + + :/icons/folder_eye_open.ico + :/icons/folder_eye_closed.ico:/icons/folder_eye_open.ico + + + true + + + QToolButton::ToolButtonPopupMode::InstantPopup + + + true + + + + + + + Expand all folders in the list. + + + + + + + :/icons/expand_all.ico:/icons/expand_all.ico + + + QToolButton::ToolButtonPopupMode::InstantPopup + + + true + + + + + + + Collapse all folders in the list. + + + + + + + :/icons/collapse_all.ico:/icons/collapse_all.ico + + + QToolButton::ToolButtonPopupMode::InstantPopup + + + true + + + + + + + Toggle editability of folders in the list. + + + + + + + :/icons/lock_edit.ico + :/icons/unlock_edit.ico:/icons/lock_edit.ico + + + true + + + QToolButton::ToolButtonPopupMode::InstantPopup + + + true + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Preferred + + + + 12 + 19 + + + + + + + + true + + + + + + Filter... + + + true + + + + + + + + + + diff --git a/include/mainwindow.h b/include/mainwindow.h index 06b9bf78..e0bf7177 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -173,11 +173,6 @@ private slots: void on_action_Open_Project_triggered(); void on_action_Reload_Project_triggered(); void on_action_Close_Project_triggered(); - - void on_mapList_activated(const QModelIndex &index); - void on_areaList_activated(const QModelIndex &index); - void on_layoutList_activated(const QModelIndex &index); - void on_action_Save_Project_triggered(); void openWarpMap(QString map_name, int event_id, Event::Group event_group); @@ -275,10 +270,6 @@ private slots: void on_actionTileset_Editor_triggered(); - void on_lineEdit_filterBox_textChanged(const QString &arg1); - void on_lineEdit_filterBox_Areas_textChanged(const QString &arg1); - void on_lineEdit_filterBox_Layouts_textChanged(const QString &arg1); - void moveEvent(QMoveEvent *event); void closeEvent(QCloseEvent *); @@ -292,19 +283,9 @@ private slots: void on_slider_EmergeMapOpacity_valueChanged(int value); void on_horizontalSlider_CollisionTransparency_valueChanged(int value); - void do_HideShow(); - void do_ExpandAll(); - void do_CollapseAll(); - void on_toolButton_HideShow_Groups_clicked(); - void on_toolButton_ExpandAll_Groups_clicked(); - void on_toolButton_CollapseAll_Groups_clicked(); - void on_toolButton_EnableDisable_EditGroups_clicked(); - void on_toolButton_HideShow_Areas_clicked(); - void on_toolButton_ExpandAll_Areas_clicked(); - void on_toolButton_CollapseAll_Areas_clicked(); - void on_toolButton_HideShow_Layouts_clicked(); - void on_toolButton_ExpandAll_Layouts_clicked(); - void on_toolButton_CollapseAll_Layouts_clicked(); + void mapListShortcut_ToggleEmptyFolders(); + void mapListShortcut_ExpandAll(); + void mapListShortcut_CollapseAll(); void on_actionAbout_Porymap_triggered(); void on_actionOpen_Log_File_triggered(); @@ -347,14 +328,12 @@ private: QPointer gridSettingsDialog = nullptr; QPointer customScriptsEditor = nullptr; - FilterChildrenProxyModel *groupListProxyModel; - MapGroupModel *mapGroupModel; - - FilterChildrenProxyModel *areaListProxyModel; - MapAreaModel *mapAreaModel; - - FilterChildrenProxyModel *layoutListProxyModel; - LayoutTreeModel *layoutTreeModel; + QPointer groupListProxyModel = nullptr; + QPointer mapGroupModel = nullptr; + QPointer areaListProxyModel = nullptr; + QPointer mapAreaModel = nullptr; + QPointer layoutListProxyModel = nullptr; + QPointer layoutTreeModel = nullptr; QPointer updatePromoter = nullptr; QPointer networkAccessManager = nullptr; @@ -375,9 +354,10 @@ private: bool tilesetNeedsRedraw = false; bool setLayout(QString layoutId); - bool setMap(QString, bool scroll = false); + bool setMap(QString); void unsetMap(); - bool userSetMap(QString, bool scrollTreeView = false); + bool userSetLayout(QString layoutId); + bool userSetMap(QString); void redrawMapScene(); void redrawLayoutScene(); void refreshMapScene(); @@ -389,7 +369,10 @@ private: void clearProjectUI(); void openSubWindow(QWidget * window); - void scrollTreeView(QString itemName); + void scrollMapList(MapTree *list, QString itemName); + void scrollMapListToCurrentMap(MapTree *list); + void scrollMapListToCurrentLayout(MapTree *list); + void resetMapListFilters(); QString getExistingDirectory(QString); bool openProject(QString dir, bool initial = false); bool closeProject(); @@ -403,31 +386,29 @@ private: void refreshRecentProjectsMenu(); void updateMapList(); - void mapListAddItem(); - void mapListRemoveItem(); void mapListAddGroup(); void mapListAddLayout(); void mapListAddArea(); void mapListRemoveGroup(); void mapListRemoveArea(); void mapListRemoveLayout(); + void openMapListItem(const QModelIndex &index); void displayMapProperties(); void checkToolButtons(); void clickToolButtonFromEditAction(Editor::EditAction editAction); - void showWindowTitle(); + void updateWindowTitle(); void initWindow(); void initCustomUI(); void initExtraSignals(); void initEditor(); void initMiscHeapObjects(); - void initMapSortOrder(); + void initMapList(); void initShortcuts(); void initExtraShortcuts(); void loadUserSettings(); - void applyMapListFilter(QString filterText); void restoreWindowState(); void setTheme(QString); void updateTilesetEditor(); @@ -447,6 +428,7 @@ private: double getMetatilesZoomScale(); void redrawMetatileSelection(); void scrollMetatileSelectorToSelection(); + MapListToolBar* getCurrentMapListToolBar(); QObjectList shortcutableObjects() const; void addCustomHeaderValue(QString key, QJsonValue value, bool isNew = false); diff --git a/include/ui/filterchildrenproxymodel.h b/include/ui/filterchildrenproxymodel.h index 5853d625..d9eed7af 100644 --- a/include/ui/filterchildrenproxymodel.h +++ b/include/ui/filterchildrenproxymodel.h @@ -9,7 +9,7 @@ class FilterChildrenProxyModel : public QSortFilterProxyModel public: explicit FilterChildrenProxyModel(QObject *parent = nullptr); - void toggleHideEmpty() { this->hideEmpty = !this->hideEmpty; } + bool toggleHideEmpty() { return this->hideEmpty = !this->hideEmpty; } protected: bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const; private: diff --git a/include/ui/maplistmodels.h b/include/ui/maplistmodels.h index d99c8815..8d00c492 100644 --- a/include/ui/maplistmodels.h +++ b/include/ui/maplistmodels.h @@ -53,7 +53,17 @@ private: class QRegularExpressionValidator; -class MapGroupModel : public QStandardItemModel { +class MapListModel : public QStandardItemModel { + Q_OBJECT + +public: + MapListModel(QObject *parent = nullptr) : QStandardItemModel(parent) {}; + ~MapListModel() { } + + virtual QModelIndex indexOf(QString id) const = 0; +}; + +class MapGroupModel : public MapListModel { Q_OBJECT public: @@ -80,7 +90,7 @@ public: void removeGroup(int groupIndex); QStandardItem *getItem(const QModelIndex &index) const; - QModelIndex indexOfMap(QString mapName); + virtual QModelIndex indexOf(QString mapName) const override; void initialize(); @@ -103,7 +113,7 @@ signals: -class MapAreaModel : public QStandardItemModel { +class MapAreaModel : public MapListModel { Q_OBJECT public: @@ -123,7 +133,7 @@ public: void removeArea(int groupIndex); QStandardItem *getItem(const QModelIndex &index) const; - QModelIndex indexOfMap(QString mapName); + virtual QModelIndex indexOf(QString mapName) const override; void initialize(); @@ -143,7 +153,7 @@ signals: -class LayoutTreeModel : public QStandardItemModel { +class LayoutTreeModel : public MapListModel { Q_OBJECT public: @@ -162,7 +172,7 @@ public: QStandardItem *insertMapItem(QString mapName, QString layoutId); QStandardItem *getItem(const QModelIndex &index) const; - QModelIndex indexOfLayout(QString layoutName); + virtual QModelIndex indexOf(QString layoutName) const override; void initialize(); diff --git a/include/ui/maplisttoolbar.h b/include/ui/maplisttoolbar.h new file mode 100644 index 00000000..c66b0d80 --- /dev/null +++ b/include/ui/maplisttoolbar.h @@ -0,0 +1,49 @@ +#ifndef MAPLISTTOOLBAR_H +#define MAPLISTTOOLBAR_H + +#include "maplistmodels.h" +#include "filterchildrenproxymodel.h" + +#include +#include + +namespace Ui { +class MapListToolBar; +} + +class MapListToolBar : public QFrame +{ + Q_OBJECT + +public: + explicit MapListToolBar(QWidget *parent = nullptr); + ~MapListToolBar(); + + MapTree* list() const { return m_list; } + void setList(MapTree *list); + + void setEditsAllowedButtonHidden(bool hidden); + + void toggleEmptyFolders(); + void expandList(); + void collapseList(); + void toggleEditsAllowed(); + + void applyFilter(const QString &filterText); + void clearFilter(); + void setFilterLocked(bool locked) { m_filterLocked = locked; } + bool isFilterLocked() const { return m_filterLocked; } + +signals: + void filterCleared(MapTree*); + void addFolderClicked(); + +private: + Ui::MapListToolBar *ui; + QPointer m_list; + bool m_filterLocked = false; + + void setEditsAllowed(bool allowed); +}; + +#endif // MAPLISTTOOLBAR_H diff --git a/porymap.pro b/porymap.pro index d65bdf07..1b1c693e 100644 --- a/porymap.pro +++ b/porymap.pro @@ -75,6 +75,7 @@ SOURCES += src/core/block.cpp \ src/ui/eventfilters.cpp \ src/ui/filterchildrenproxymodel.cpp \ src/ui/maplistmodels.cpp \ + src/ui/maplisttoolbar.cpp \ src/ui/graphicsview.cpp \ src/ui/imageproviders.cpp \ src/ui/layoutpixmapitem.cpp \ @@ -174,6 +175,7 @@ HEADERS += include/core/block.h \ include/ui/eventfilters.h \ include/ui/filterchildrenproxymodel.h \ include/ui/maplistmodels.h \ + include/ui/maplisttoolbar.h \ include/ui/graphicsview.h \ include/ui/imageproviders.h \ include/ui/layoutpixmapitem.h \ @@ -229,6 +231,7 @@ FORMS += forms/mainwindow.ui \ forms/colorinputwidget.ui \ forms/connectionslistitem.ui \ forms/gridsettingsdialog.ui \ + forms/maplisttoolbar.ui \ forms/newmapconnectiondialog.ui \ forms/prefabcreationdialog.ui \ forms/prefabframe.ui \ diff --git a/resources/icons/collapse_all.ico b/resources/icons/collapse_all.ico index f6c7f315826bdea6dc03fe387720105362368e68..806f2435f3d3cd6ecec97362dc3eaba5627bd310 100644 GIT binary patch literal 1871 zcmZ`)3p|r+7=O2^u_el-a=NT_a*JIkmo>{}h1xQdE#_p_uwv6T4HZKU(d{G^DnjWV zDXExsq1Gu;x~NdUh7hG9iFUrxDZkU{{eIu~KHu~I|DWf1pZER!-mQ$~?z$)w6aYZi z(}U^*%^1zAJs$dsV`D!;lUAq;-35S>o#-LXI1R}4@Sy_`YYKpD3jl+VOZFOoC;|YT zK>(2U1284>z-4bT1Tc6k&k#BtSVFcofWsyO1Z2UW2c+|| zl}d3^Tbxi7iYGccI^qd7cpDpQh+!>`5lA@E)&lXI(IEfEq4LCB5kFGG7YZ<%xSU{N zl*9>()g<~pM(gB7^M7O#h`%ihS|DD7;E6Z_{{LhWe#kFm8e~*9vaZo|WKA#WYac_hnEz>hk|2wA@pjsgBFbQ6XPMZS?7E{{U|mTQb_3|mt*$xFoN zK@HWkO+)|5_l-}+YkE4S$D=$NPB)VtzG9`} z*PfimSr(ZXocYy4RxrE4!^mS`>%!|xxpn2Qmz;J%B$d}2S+OU_u>m@}#`EEmsSRPN z^+xC@F2f+mD%CjIE)2UzLVIfJaPZTi7HLaGZC4j5 zW2d0kva)LmUxNguztI3?QIZLTNZ5hMxNW>q9J)|R2uM19WbVEqQelPktv&iYq>^?v(?Mdn!j{B#iwZ_w%^K32bg=8yERQ;4+itQ zru$RkdZo1Ha;1^!y3_2|<$?Lg>1Ig#QdcXnu^(9>j8zn}+kzG#4Rxvmj0kZr?K}I5 zdFqs*)yk(<@MOi}mrak`IOjnj7-~QIVE(C27|eX%=550S6bTks+2w8Gw4~|1vlvVe zSJ&fF&XDF8)UyxeZ_G?v9Mj1u>I}L$0lTk@l6l=s`@*}VT>Q-$xF17EvuPkT6PC4Lb8}8l#b-N zhE|s%D$N`FfPTW-CI=}@wnw~WcNSL%b<#QgO`;Sni&dUFYkV(+i3YY>4DIPhNc=`u zeg9dpvNBTo7TMi{cK%R%jD+=_aLF)8_r(&j=JFiR| zv=qx&4ioU(s*xFB{Qr-VC!{>L9}a124*NiHiNl z(Mi|manEHR>dYr?x@iBk0yC=y8&Gt5P`m;N{mg}{& zKOVkrin~$VUeYnm_U=QPs=&d$^n>4fccO)ey?P=z-L~^gO;$Y2+#uj|dl4%_bKiI_ LUQRvZ8kG1CNBinz literal 318 zcmah@$qm3D40C7)2%o+yUW~!$9jO~oheYLtFmfys=KzFHRT)oI0WJWQRPrV*zd~yb yz4ujln=i#JAt>BG5Gqq8XWqzTL)|v(i+?txuq8GV`mcN0^#sR&U9dsM!}$R)WC;%d diff --git a/resources/icons/expand_all.ico b/resources/icons/expand_all.ico index 0707936c59da83addeb3911acd285a97cf4119dd..ca913a1322074b24f0642be85334412725e89c4b 100644 GIT binary patch literal 2142 zcmZ`)3p|s1AODZ#vdAUg$|Y;nQrI&KWo=3p>dZAK>*VA*&SIOkITp&w%4I}}crzTS zQ=Q1<_L5vma$Jf|F_)AghQq;oToUg_Z~46EJ^$zPJpbSG`+mQ_+yD7|o>*r`J5_`Z z0sx?T(4OQf-I20eNkRH#hlNc^H+X=xgEau6#MSfOt7M?By{iKNVQ2t&d;sR8F5Vyj zAy@z;UI5_J09Y5CQSL&J0?t&*L4OAautRDq0Xdi^ke6C8=>?)`0KQ}cAdMtl^4YMj zXtvxJ6qzmm)s_(-9wUzeAcv*7Q8*L_GTxU-$9VfOeW(~NJy=En1TJ1`(y1J8B$pn< zVB@(&)DiH=9)0ro0o(9Hx7x)_GQt6IW#5% zDU0jv!wlgNQ7BoWFKf9@Dwp;(6NCM^Eop<041r8BSm^)BI5hvik;#x{*-~H2=?Jo5 zcxM`y8g!IIqf;4dX=zqFafGETe*wPMxk5H0CW3|+Rpph*z1Ju_$CA zhLLBhc-%l7&L)-yh_(Sekuv#1UTRIQ7D8~*Z*Y&-45_o@-~F|c&JYa!nmFB%^5@2k zh5ehfkM=i$YOS^H%DliM%6^`QHsgA79sL{vqVREgku;-Nv8bq5e3J$^-dh_$)O$F# zs}#|cY-);2{Z=GSMH8ZWidx5AUTiiWmZZ9^w`!)mWKGz0c48Dhl|s>HAJkw);8hd~87$UTSTrzu8^kU{1XWxA>+SA6Q73Xs*}N5Cv2eFpE>T$* z?^+X8u-o)TIZ61cXH?*OeEhZhMbWTg>pXROR|F~_+#<-b30mJ^<9^u~CCu0-8PL!k zw}=_K{PdFBX;x`AgIG~-c;1rQ_sVMwYmQU9iBlPDK_V0xIU}(lk1a@LxDD)tfsu#7 z(G8(_>oDj~d*8L~_^0T zwbY3@v~TY(BU@GOPtIzr$*55yzP0Ig77Lzihru2*;G%*Dm+k5XXzAn^5PEiNO5yn1 zd?czB?v$4vpflBaX-(c>`k(Z!SHbJ&P=?NG zF>(j)_PmEcS4XF${T1feA9Ja;9tL{l!uS?V$Rtups6VO%SJ*PMrc<%3Rx=4YtKLGD zG`Yk1zZFGH4m2A;CZ6SUFB4Q_wq^M5ikH(PMy$7~`RRpFC>(2ZJeSBypKM5b)~^NI zWPHTTf+0TY;X2X%&9JA-h5CzU1om54cPcAS7tl1iSW)n{m} zq4z#(FYBfFNC*n=KcET?$fuGsJ<@FGzwc|YZ+iyeG?5}rp6Yw<=FAnOtYIG+H|GFW CWC>FM diff --git a/resources/icons/folder_add.ico b/resources/icons/folder_add.ico new file mode 100755 index 0000000000000000000000000000000000000000..d881adf8e9202901244af1bafbc1c39dc939a9a7 GIT binary patch literal 1572 zcmV+<2HW|GP)4k@LZHNm0kuIuj3$~G9|=D&_$DD3O;BSn$`7eQK@(63(eMuu8kGhRsSlvl zMZ?1a-FE51w%gY(ZMVDk;mkSPeUxptC5_%>a_^mc?wy%$zL_&uv27dw=b@13jXRbd z&|s{zEsJjLjLQ^Ng$eyo)r-g0lERoQ2XvAgHa>s-9{MbO*H%VxQ-f#c^N;X)lJI0Y z;1-dS@#y)j6u%a?n0lCSl|KVxD1xTi#UVveCI+*rF?xpyy+=o)rzfmg25i+ycMg&i z1Dp}tgf$dI)rPNc_ARS*`he~r^qyUr2|Yb&h#XVtR?*WD5SJ=q!Q(*Z(Ft0&>2(v% z%8iixf_roa5T(FX#w$Y#Sg)l(lJG1GAhtx@3JtGRGI2oatr*$SMsXlhUa2w^MV!Y* zfWB!Bq^C7A0){9x5p5O+*r=+h@HRE0yY(6qXmkMB38jIus}X^h1fyZ^WW2TUA`lzGf|vFR0%NR(ri}2)L8RQZPLML00y`%1tgvXBL@YzvI0Emf z3&dFyW%DZ#y|@jdH?Wb11ud@}D6BzmIC`2CPCd2ORYE}39PpkwhhR%Pna=c46@_Ib zD8FY8EXx+C3EE_Hz?PM!PMM3~<P}q$N-GMfpk(1r-VyV z$;cAPkvLZp3v8wc1>-7(88y*;wYlSuOMOAE{UidaA>a%Jf|z;la`LU6?w#@aSH@yh z;?O7;oW?{s50{>8$wrqq3td+{IPdMTjpS2KM_=eE58)Rjb^g#j3bb3 zOQmY(R1km81)A~IU-dXb<*6pY$BOb|tgC(<1^zZ1_jK1W{ONr_HPL%DfP#uUgfj|v zFICUp6Zln*Sa;#$-@d_jEoZT2!BePxU@>x>xnj*=bO0XjFL=3bGnOc&`10tre@H!q zM0hf3=xOt#a84y|A3D;cM2NY<(XaYTiQe^t|Wp+lVEIH-3S@jcb17&n_1o&1Qax2(>Xq zp{jwyg*~3{@z|oLarXKb=pOJvSJPWRU$d@@p8e_Hjhd<_;V#5hdgPD@5P`b9tpxu( zy6Y#~1g#^xfW_%T{S_a|O7hVjJ`aORZirYHP1zp!nsxll7e0s5>3O{CS0`FAr=Zu{ zhKh%&Jr5E2^t|zoI^;x-h^`}YMzDR`gEx1?ovV_%&GiZbgQth7EnBf^D`CyynCkg# z7qwSw+~WqZ0C}pLs}KEA34PXgXw8jiTcWk`xqxKuhSl?`BT;igGrCEWS}1J9I@VtO zyk;rYJ3~!-T8z#S>O0#XlAn9^2L*0jCfwzaeE7KmsM~}RT_hdwesb_~=eWAg&0EaW z>g8zc>PFR!=`upoO5Y-KsZw(t@)>P6=pakf>6`d{c7S|F4@uvxI?&}oZA&rs&MKCz z!{D}`vWTN*zOr$iQ7^Xu?Ty&Z{G8~Fo9WctCX7%@sg%#;hLy9)=H zrN7b?(BZ|w;~(M`()hJWaDZ8Bc^lAFbSKI>L%2PM!q1;Zu+t3ecFLC55dfMzG+4Ld z@K4+DCaJD-m!1p+WI>Qkl3A52u(WIu);p)+?$iM~8p7GO-?6Lt2u_lwJ)UxNvK$z8 zf*VL7NfF7ExK55+RDC2o19ZoUZ)P9sZ|!H-5&r{nB5fq09}hVL#Kt*5{x`?J0t^7^ WWe&kFMnG%;0000e6r<%oD&DDM{_ScOGMf<*{M zN4qF$WsW7KX5p<81a@IrWMM%r3R;?(DSJEr{?A@)S4a>>RkFlDC^t;{YoE z0=AC<=~sOxeBTPTf5iDh*$p76!VC(J(oZy+VEhyK@G4O90Hn{h-yYCU+BMka1QMvF zrC)j-C>jC`m(>SSe8tyS`iEj*UE#1cpNvqyTwA~Rcc9>ssuFA&^hAUL&Qr+w43~ZD z{EYhXVe}2Omwr%H3GxR#k%9Vp*$?%L2OQXQTU$SgXHr0$=Jk72f)D!K5h0KBy8*X7v0G1^I&uD2)??dz5irm3vvg6jXiFaV1wNi zF*f$Nu&GyY;v2q~@#QV|JpU=w-_);SZMREZ*X_dEE@wnp*UkCJ(Qx_|Em+^HVwKIM zuC}?bs?#}UR6njxh1(rC`rsag9&Yy-!fMGMwyFw6~9FR%IPzWj46zaQ@kbbr7qAe~<&e*N#Se*l&E@Oc0L delta 230 zcmdm{{f|SKfq@YS1q48}0z(E11B2LPZ$ar0VQvNn5Qc&O|Nk>kf`R53Os*4Do;+7j ylErb_#gCJB30i;|o4*O}VPbQhacP6|jLAPl?3^gE2BLSOqZtR|e+Hm~85jT*rh9q- diff --git a/resources/images.qrc b/resources/images.qrc index 15650a65..a89535a9 100644 --- a/resources/images.qrc +++ b/resources/images.qrc @@ -10,6 +10,7 @@ icons/file_put.ico icons/fill_color_cursor.ico icons/fill_color.ico + icons/folder_add.ico icons/folder_closed_map.ico icons/folder_closed.ico icons/folder_eye_closed.ico diff --git a/src/core/map.cpp b/src/core/map.cpp index 01ab95b0..8067b9a7 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -257,7 +257,7 @@ void Map::clean() { } bool Map::hasUnsavedChanges() { - return !editHistory.isClean() || !this->layout->editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile; + return !editHistory.isClean() || this->layout->hasUnsavedChanges() || hasUnsavedDataChanges || !isPersistedToFile; } void Map::pruneEditHistory() { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 08cdaf8c..14a255c2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -119,7 +119,7 @@ void MainWindow::initWindow() { this->initExtraSignals(); this->initEditor(); this->initMiscHeapObjects(); - this->initMapSortOrder(); + this->initMapList(); this->initShortcuts(); this->restoreWindowState(); @@ -166,15 +166,15 @@ void MainWindow::initExtraShortcuts() { shortcutToggle_Smart_Paths->setObjectName("shortcutToggle_Smart_Paths"); shortcutToggle_Smart_Paths->setWhatsThis("Toggle Smart Paths"); - auto *shortcutHide_Show = new Shortcut(QKeySequence(), this, SLOT(do_HideShow())); + auto *shortcutHide_Show = new Shortcut(QKeySequence(), this, SLOT(mapListShortcut_ToggleEmptyFolders())); shortcutHide_Show->setObjectName("shortcutHide_Show"); shortcutHide_Show->setWhatsThis("Map List: Hide/Show Empty Folders"); - auto *shortcutExpand_All = new Shortcut(QKeySequence(), this, SLOT(do_ExpandAll())); + auto *shortcutExpand_All = new Shortcut(QKeySequence(), this, SLOT(mapListShortcut_ExpandAll())); shortcutExpand_All->setObjectName("shortcutExpand_All"); shortcutExpand_All->setWhatsThis("Map List: Expand all folders"); - auto *shortcutCollapse_All = new Shortcut(QKeySequence(), this, SLOT(do_CollapseAll())); + auto *shortcutCollapse_All = new Shortcut(QKeySequence(), this, SLOT(mapListShortcut_CollapseAll())); shortcutCollapse_All->setObjectName("shortcutCollapse_All"); shortcutCollapse_All->setWhatsThis("Map List: Collapse all folders"); @@ -240,44 +240,9 @@ void MainWindow::initCustomUI() { ui->mainTabBar->addTab(mainTabNames.value(i)); ui->mainTabBar->setTabIcon(i, mainTabIcons.value(i)); } - - WheelFilter *wheelFilter = new WheelFilter(this); - ui->mainTabBar->installEventFilter(wheelFilter); - this->ui->mapListContainer->tabBar()->installEventFilter(wheelFilter); - - // Create buttons for adding and removing items from the mapList - QFrame *frame = new QFrame(this->ui->mapListContainer); - frame->setFrameShape(QFrame::NoFrame); - QHBoxLayout *layout = new QHBoxLayout(frame); - - QPushButton *buttonAdd = new QPushButton(QIcon(":/icons/add.ico"), ""); - connect(buttonAdd, &QPushButton::clicked, [this]() { this->mapListAddItem(); }); - QPushButton *buttonRemove = new QPushButton(QIcon(":/icons/delete.ico"), ""); - connect(buttonRemove, &QPushButton::clicked, [this]() { this->mapListRemoveItem(); }); - - layout->addWidget(buttonAdd); - layout->addWidget(buttonRemove); - - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - - this->ui->mapListContainer->setCornerWidget(frame, Qt::TopRightCorner); } void MainWindow::initExtraSignals() { - // Right-clicking on items in the map list tree view brings up a context menu. - ui->mapList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->mapList, &QTreeView::customContextMenuRequested, - this, &MainWindow::onOpenMapListContextMenu); - - ui->areaList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->areaList, &QTreeView::customContextMenuRequested, - this, &MainWindow::onOpenMapListContextMenu); - - ui->layoutList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->layoutList, &QTreeView::customContextMenuRequested, - this, &MainWindow::onOpenMapListContextMenu); - // other signals connect(ui->newEventToolButton, &NewEventToolButton::newEventAdded, this, &MainWindow::addNewEvent); connect(ui->tabWidget_EventType, &QTabWidget::currentChanged, this, &MainWindow::eventTabChanged); @@ -381,7 +346,7 @@ void MainWindow::initEditor() { ui->menuEdit->addAction(showHistory); // Toggle an asterisk in the window title when the undo state is changed - connect(&editor->editGroup, &QUndoGroup::indexChanged, this, &MainWindow::showWindowTitle); + connect(&editor->editGroup, &QUndoGroup::indexChanged, this, &MainWindow::updateWindowTitle); // selecting objects from the spinners connect(this->ui->spinner_ObjectID, QOverload::of(&QSpinBox::valueChanged), [this](int value) { @@ -405,37 +370,104 @@ void MainWindow::initMiscHeapObjects() { ui->tabWidget_EventType->clear(); } -void MainWindow::initMapSortOrder() { - this->ui->mapListContainer->setCurrentIndex(static_cast(porymapConfig.mapSortOrder)); +void MainWindow::initMapList() { + ui->mapListContainer->setCurrentIndex(static_cast(porymapConfig.mapSortOrder)); + + WheelFilter *wheelFilter = new WheelFilter(this); + ui->mainTabBar->installEventFilter(wheelFilter); + ui->mapListContainer->tabBar()->installEventFilter(wheelFilter); + + // Create buttons for adding and removing items from the mapList + QFrame *buttonFrame = new QFrame(this->ui->mapListContainer); + buttonFrame->setFrameShape(QFrame::NoFrame); + + QHBoxLayout *layout = new QHBoxLayout(buttonFrame); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + + // Create add map/layout button + QPushButton *buttonAdd = new QPushButton(QIcon(":/icons/add.ico"), ""); + connect(buttonAdd, &QPushButton::clicked, this, &MainWindow::on_action_NewMap_triggered); + layout->addWidget(buttonAdd); + + /* TODO: Remove button disabled, no current support for deleting maps/layouts + // Create remove map/layout button + QPushButton *buttonRemove = new QPushButton(QIcon(":/icons/delete.ico"), ""); + connect(buttonRemove, &QPushButton::clicked, this, &MainWindow::deleteCurrentMapOrLayout); + layout->addWidget(buttonRemove); + */ + + ui->mapListContainer->setCornerWidget(buttonFrame, Qt::TopRightCorner); + + // Connect tool bars to lists + ui->mapListToolBar_Groups->setList(ui->mapList); + ui->mapListToolBar_Areas->setList(ui->areaList); + ui->mapListToolBar_Layouts->setList(ui->layoutList); + + // Left-clicking on items in the map list opens the corresponding map/layout. + connect(ui->mapList, &QAbstractItemView::activated, this, &MainWindow::openMapListItem); + connect(ui->areaList, &QAbstractItemView::activated, this, &MainWindow::openMapListItem); + connect(ui->layoutList, &QAbstractItemView::activated, this, &MainWindow::openMapListItem); + + // Right-clicking on items in the map list brings up a context menu. + ui->mapList->setContextMenuPolicy(Qt::CustomContextMenu); + ui->areaList->setContextMenuPolicy(Qt::CustomContextMenu); + ui->layoutList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->mapList, &QTreeView::customContextMenuRequested, this, &MainWindow::onOpenMapListContextMenu); + connect(ui->areaList, &QTreeView::customContextMenuRequested, this, &MainWindow::onOpenMapListContextMenu); + connect(ui->layoutList, &QTreeView::customContextMenuRequested, this, &MainWindow::onOpenMapListContextMenu); + + // Only the groups list allows reorganizing folder contents, editing folder names, etc. + ui->mapListToolBar_Areas->setEditsAllowedButtonHidden(true); + ui->mapListToolBar_Layouts->setEditsAllowedButtonHidden(true); + + // When map list search filter is cleared we want the current map/layout in the editor to be visible in the list. + connect(ui->mapListToolBar_Groups, &MapListToolBar::filterCleared, this, &MainWindow::scrollMapListToCurrentMap); + connect(ui->mapListToolBar_Areas, &MapListToolBar::filterCleared, this, &MainWindow::scrollMapListToCurrentMap); + connect(ui->mapListToolBar_Layouts, &MapListToolBar::filterCleared, this, &MainWindow::scrollMapListToCurrentLayout); + + // Connect the "add folder" button in each of the map lists + connect(ui->mapListToolBar_Groups, &MapListToolBar::addFolderClicked, this, &MainWindow::mapListAddGroup); + connect(ui->mapListToolBar_Areas, &MapListToolBar::addFolderClicked, this, &MainWindow::mapListAddArea); + connect(ui->mapListToolBar_Layouts, &MapListToolBar::addFolderClicked, this, &MainWindow::mapListAddLayout); } -void MainWindow::showWindowTitle() { +void MainWindow::updateWindowTitle() { + if (!editor || !editor->project) { + setWindowTitle(QCoreApplication::applicationName()); + return; + } + + const QString projectName = editor->project->getProjectTitle(); + if (!editor->layout) { + setWindowTitle(projectName); + return; + } + if (editor->map) { setWindowTitle(QString("%1%2 - %3") .arg(editor->map->hasUnsavedChanges() ? "* " : "") .arg(editor->map->name) - .arg(editor->project->getProjectTitle()) + .arg(projectName) ); - } - else if (editor->layout) { + } else { setWindowTitle(QString("%1%2 - %3") .arg(editor->layout->hasUnsavedChanges() ? "* " : "") .arg(editor->layout->name) - .arg(editor->project->getProjectTitle()) + .arg(projectName) ); } - if (editor && editor->layout) { - // For some reason (perhaps on Qt < 6?) we had to clear the icon first here or mainTabBar wouldn't display correctly. - ui->mainTabBar->setTabIcon(MainTab::Map, QIcon()); - QPixmap pixmap = editor->layout->pixmap; - if (!pixmap.isNull()) { - ui->mainTabBar->setTabIcon(MainTab::Map, QIcon(pixmap)); - } else { - ui->mainTabBar->setTabIcon(MainTab::Map, QIcon(QStringLiteral(":/icons/map.ico"))); - } + // For some reason (perhaps on Qt < 6?) we had to clear the icon first here or mainTabBar wouldn't display correctly. + ui->mainTabBar->setTabIcon(MainTab::Map, QIcon()); + + QPixmap pixmap = editor->layout->pixmap; + if (!pixmap.isNull()) { + ui->mainTabBar->setTabIcon(MainTab::Map, QIcon(pixmap)); + } else { + ui->mainTabBar->setTabIcon(MainTab::Map, QIcon(QStringLiteral(":/icons/map.ico"))); } - updateMapList(); + updateMapList(); // TODO: Why is this function responsible for this } void MainWindow::markMapEdited() { @@ -448,52 +480,7 @@ void MainWindow::markSpecificMapEdited(Map* map) { map->hasUnsavedDataChanges = true; if (editor && editor->map == map) - showWindowTitle(); -} - -void MainWindow::on_lineEdit_filterBox_textChanged(const QString &text) { - this->applyMapListFilter(text); -} - -void MainWindow::on_lineEdit_filterBox_Areas_textChanged(const QString &text) { - this->applyMapListFilter(text); -} - -void MainWindow::on_lineEdit_filterBox_Layouts_textChanged(const QString &text) { - this->applyMapListFilter(text); -} - -void MainWindow::applyMapListFilter(QString filterText) { - FilterChildrenProxyModel *proxy; - QTreeView *list; - QModelIndex sourceIndex; - switch (porymapConfig.mapSortOrder) { - case MapSortOrder::SortByGroup: - proxy = this->groupListProxyModel; - list = this->ui->mapList; - sourceIndex = mapGroupModel->indexOfMap(editor->map->name); - break; - case MapSortOrder::SortByArea: - proxy = this->areaListProxyModel; - list = this->ui->areaList; - sourceIndex = mapAreaModel->indexOfMap(editor->map->name); - break; - case MapSortOrder::SortByLayout: - proxy = this->layoutListProxyModel; - list = this->ui->layoutList; - sourceIndex = layoutTreeModel->indexOfLayout(editor->layout->id); - break; - } - - proxy->setFilterRegularExpression(QRegularExpression(filterText, QRegularExpression::CaseInsensitiveOption)); - if (filterText.isEmpty()) { - list->collapseAll(); - } else { - list->expandToDepth(0); - } - - list->setExpanded(proxy->mapFromSource(sourceIndex), true); - list->scrollTo(proxy->mapFromSource(sourceIndex), QAbstractItemView::PositionAtCenter); + updateWindowTitle(); } void MainWindow::loadUserSettings() { @@ -640,7 +627,7 @@ bool MainWindow::openProject(QString dir, bool initial) { // Only create the config files once the project has opened successfully in case the user selected an invalid directory this->editor->project->saveConfig(); - showWindowTitle(); + updateWindowTitle(); this->statusBar()->showMessage(QString("Opened %1").arg(projectString)); porymapConfig.projectManuallyClosed = false; @@ -702,7 +689,7 @@ bool MainWindow::setInitialMap() { const QString recent = userConfig.recentMapOrLayout; if (editor->project->mapNames.contains(recent)) { // User recently had a map open that still exists. - if (setMap(recent, true)) + if (setMap(recent)) return true; } else if (editor->project->mapLayoutsTable.contains(recent)) { // User recently had a layout open that still exists. @@ -712,7 +699,7 @@ bool MainWindow::setInitialMap() { // Failed to open recent map/layout, or no recent map/layout. Try opening maps then layouts sequentially. for (const auto &name : editor->project->mapNames) { - if (name != recent && setMap(name, true)) + if (name != recent && setMap(name)) return true; } for (const auto &id : editor->project->mapLayoutsTable) { @@ -808,7 +795,7 @@ void MainWindow::unsetMap() { // setMap, but with a visible error message in case of failure. // Use when the user is specifically requesting a map to open. -bool MainWindow::userSetMap(QString map_name, bool scrollTreeView) { +bool MainWindow::userSetMap(QString map_name) { if (editor->map && editor->map->name == map_name) return true; // Already set @@ -819,7 +806,7 @@ bool MainWindow::userSetMap(QString map_name, bool scrollTreeView) { return false; } - if (!setMap(map_name, scrollTreeView)) { + if (!setMap(map_name)) { QMessageBox msgBox(this); QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3") .arg(map_name) @@ -831,7 +818,7 @@ bool MainWindow::userSetMap(QString map_name, bool scrollTreeView) { return true; } -bool MainWindow::setMap(QString map_name, bool scroll) { +bool MainWindow::setMap(QString map_name) { // if map name is empty, clear & disable map ui if (map_name.isEmpty()) { unsetMap(); @@ -851,7 +838,7 @@ bool MainWindow::setMap(QString map_name, bool scroll) { } if (editor->map && !editor->map->name.isNull()) { - ui->mapList->setExpanded(groupListProxyModel->mapFromSource(mapGroupModel->indexOfMap(map_name)), false); + ui->mapList->setExpanded(groupListProxyModel->mapFromSource(mapGroupModel->indexOf(map_name)), false); } setLayoutOnlyMode(false); @@ -859,12 +846,8 @@ bool MainWindow::setMap(QString map_name, bool scroll) { refreshMapScene(); displayMapProperties(); - - if (scroll) { - scrollTreeView(map_name); - } - - showWindowTitle(); + updateWindowTitle(); + resetMapListFilters(); connect(editor->map, &Map::mapNeedsRedrawing, this, &MainWindow::onMapNeedsRedrawing, Qt::UniqueConnection); connect(editor->map, &Map::modified, this, &MainWindow::markMapEdited, Qt::UniqueConnection); @@ -892,12 +875,28 @@ void MainWindow::setLayoutOnlyMode(bool layoutOnly) { this->ui->comboBox_LayoutSelector->setEnabled(mapEditingEnabled); } +// setLayout, but with a visible error message in case of failure. +// Use when the user is specifically requesting a layout to open. +bool MainWindow::userSetLayout(QString layoutId) { + if (!setLayout(layoutId)) { + QMessageBox msgBox(this); + QString errorMsg = QString("There was an error opening layout %1. Please see %2 for full error details.\n\n%3") + .arg(layoutId) + .arg(getLogPath()) + .arg(getMostRecentError()); + msgBox.critical(nullptr, "Error Opening Layout", errorMsg); + return false; + } + return true; +} + bool MainWindow::setLayout(QString layoutId) { if (this->editor->map) logInfo("Switching to a layout-only editing mode. Disabling map-related edits."); - setMap(QString()); + unsetMap(); + // TODO: Using the 'id' instead of the layout name here is inconsistent with how we treat maps. logInfo(QString("Setting layout to '%1'").arg(layoutId)); if (!this->editor->setLayout(layoutId)) { @@ -907,8 +906,8 @@ bool MainWindow::setLayout(QString layoutId) { layoutTreeModel->setLayout(layoutId); refreshMapScene(); - showWindowTitle(); - updateMapList(); + updateWindowTitle(); + resetMapListFilters(); connect(editor->layout, &Layout::needsRedrawing, this, &MainWindow::onLayoutNeedsRedrawing, Qt::UniqueConnection); @@ -969,7 +968,7 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_ } // Open the destination map. - if (!userSetMap(map_name, true)) + if (!userSetMap(map_name)) return; // Select the target event. @@ -1229,7 +1228,7 @@ bool MainWindow::setProjectUI() { this->layoutListProxyModel->setSourceModel(this->layoutTreeModel); ui->layoutList->setModel(layoutListProxyModel); - on_toolButton_EnableDisable_EditGroups_clicked(); + //on_toolButton_EnableDisable_EditGroups_clicked();//TODO return true; } @@ -1245,8 +1244,7 @@ void MainWindow::clearProjectUI() { const QSignalBlocker blocker7(ui->comboBox_Type); const QSignalBlocker blocker8(ui->comboBox_DiveMap); const QSignalBlocker blocker9(ui->comboBox_EmergeMap); - const QSignalBlocker blockerA(ui->lineEdit_filterBox); - const QSignalBlocker blockerB(ui->comboBox_LayoutSelector); + const QSignalBlocker blockerA(ui->comboBox_LayoutSelector); ui->comboBox_Song->clear(); ui->comboBox_Location->clear(); @@ -1257,49 +1255,51 @@ void MainWindow::clearProjectUI() { ui->comboBox_Type->clear(); ui->comboBox_DiveMap->clear(); ui->comboBox_EmergeMap->clear(); - ui->lineEdit_filterBox->clear(); ui->comboBox_LayoutSelector->clear(); // Clear map models - if (this->mapGroupModel) { - delete this->mapGroupModel; - this->mapGroupModel = nullptr; - delete this->groupListProxyModel; - this->groupListProxyModel = nullptr; - } - if (this->mapAreaModel) { - delete this->mapAreaModel; - this->mapAreaModel = nullptr; - delete this->areaListProxyModel; - this->areaListProxyModel = nullptr; - } - if (this->layoutTreeModel) { - delete this->layoutTreeModel; - this->layoutTreeModel = nullptr; - delete this->layoutListProxyModel; - this->layoutListProxyModel = nullptr; - } + delete this->mapGroupModel; + delete this->groupListProxyModel; + delete this->mapAreaModel; + delete this->areaListProxyModel; + delete this->layoutTreeModel; + delete this->layoutListProxyModel; + resetMapListFilters(); Event::clearIcons(); } -void MainWindow::scrollTreeView(QString itemName) { - switch (ui->mapListContainer->currentIndex()) { - case MapListTab::Groups: - groupListProxyModel->setFilterRegularExpression(QString()); - ui->mapList->setCurrentIndex(groupListProxyModel->mapFromSource(mapGroupModel->indexOfMap(itemName))); - ui->mapList->scrollTo(ui->mapList->currentIndex(), QAbstractItemView::PositionAtCenter); - break; - case MapListTab::Areas: - areaListProxyModel->setFilterRegularExpression(QString()); - ui->areaList->setCurrentIndex(areaListProxyModel->mapFromSource(mapAreaModel->indexOfMap(itemName))); - ui->areaList->scrollTo(ui->areaList->currentIndex(), QAbstractItemView::PositionAtCenter); - break; - case MapListTab::Layouts: - layoutListProxyModel->setFilterRegularExpression(QString()); - ui->layoutList->setCurrentIndex(layoutListProxyModel->mapFromSource(layoutTreeModel->indexOfLayout(itemName))); - ui->layoutList->scrollTo(ui->layoutList->currentIndex(), QAbstractItemView::PositionAtCenter); - break; +void MainWindow::scrollMapList(MapTree *list, QString itemName) { + if (!list || itemName.isEmpty()) + return; + auto model = static_cast(list->model()); + if (!model) + return; + auto sourceModel = static_cast(model->sourceModel()); + if (!sourceModel) + return; + QModelIndex sourceIndex = sourceModel->indexOf(itemName); + if (!sourceIndex.isValid()) + return; + QModelIndex index = model->mapFromSource(sourceIndex); + if (!index.isValid()) + return; + + list->setCurrentIndex(index); + list->setExpanded(index, true); + list->scrollTo(index, QAbstractItemView::PositionAtCenter); +} + +void MainWindow::scrollMapListToCurrentMap(MapTree *list) { + if (this->editor->map) { + scrollMapList(list, this->editor->map->name); + } +} + +// TODO: Initial scrolling doesn't center the layout on launch if it's not the current tab. +void MainWindow::scrollMapListToCurrentLayout(MapTree *list) { + if (this->editor->layout) { + scrollMapList(list, this->editor->layout->id); } } @@ -1346,6 +1346,7 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { QStandardItem *selectedItem = model->itemFromIndex(index); if (selectedItem->parent()) { + // TODO: Right-click delete on maps? return; } @@ -1376,6 +1377,7 @@ void MainWindow::mapListAddGroup() { connect(&newItemButtonBox, &QDialogButtonBox::accepted, [&](){ if (!this->editor->project->groupNames.contains(newNameEdit->text())) dialog.accept(); + // TODO: Else display error? }); QFormLayout form(&dialog); @@ -1390,6 +1392,8 @@ void MainWindow::mapListAddGroup() { } } +// TODO: Pull this all out into a custom window. Connect that to an action in the main menu as well. +// (or, re-use the new map dialog with some tweaks) void MainWindow::mapListAddLayout() { if (!editor || !editor->project) return; @@ -1421,6 +1425,7 @@ void MainWindow::mapListAddLayout() { errorMessageLabel->setStyleSheet("QLabel { background-color: rgba(255, 0, 0, 25%) }"); QString errorMessage; + // TODO: Select default tilesets QComboBox *primaryCombo = new QComboBox(&dialog); primaryCombo->addItems(this->editor->project->primaryTilesetLabels); QComboBox *secondaryCombo = new QComboBox(&dialog); @@ -1529,14 +1534,19 @@ void MainWindow::mapListAddArea() { newNameEdit->setValidator(new QRegularExpressionValidator(re_validChars, newNameEdit)); connect(&newItemButtonBox, &QDialogButtonBox::accepted, [&](){ - if (!this->editor->project->mapSectionNameToValue.contains(newNameEdit->text())) + if (!this->editor->project->mapSectionNameToValue.contains(newNameDisplay->text())) dialog.accept(); + // TODO: Else display error? }); + QLabel *newNameEditLabel = new QLabel("New Map Section Name", &dialog); + QLabel *newNameDisplayLabel = new QLabel("Constant Name", &dialog); + newNameDisplayLabel->setEnabled(false); + QFormLayout form(&dialog); - form.addRow("New Map Section Name", newNameEdit); - form.addRow("Constant Name", newNameDisplay); + form.addRow(newNameEditLabel, newNameEdit); + form.addRow(newNameDisplayLabel, newNameDisplay); form.addRow(&newItemButtonBox); if (dialog.exec() == QDialog::Accepted) { @@ -1545,22 +1555,7 @@ void MainWindow::mapListAddArea() { } } -void MainWindow::mapListAddItem() { - if (!this->editor || !this->editor->project) return; - - switch (this->ui->mapListContainer->currentIndex()) { - case MapListTab::Groups: - this->mapListAddGroup(); - break; - case MapListTab::Areas: - this->mapListAddArea(); - break; - case MapListTab::Layouts: - this->mapListAddLayout(); - break; - } -} - +// TODO: Connect to right-click on map group folder in list void MainWindow::mapListRemoveGroup() { QItemSelectionModel *selectionModel = this->ui->mapList->selectionModel(); if (selectionModel->hasSelection()) { @@ -1579,6 +1574,7 @@ void MainWindow::mapListRemoveGroup() { } } +// TODO: Decide what to do about this. Currently unused. void MainWindow::mapListRemoveArea() { QItemSelectionModel *selectionModel = this->ui->areaList->selectionModel(); if (selectionModel->hasSelection()) { @@ -1597,27 +1593,11 @@ void MainWindow::mapListRemoveArea() { } } +// TODO: Connect to right-click on layout void MainWindow::mapListRemoveLayout() { // TODO: consider this in the future } -void MainWindow::mapListRemoveItem() { - if (!this->editor || !this->editor->project) return; - - switch (this->ui->mapListContainer->currentIndex()) { - case MapListTab::Groups: - this->mapListRemoveGroup(); - break; - case MapListTab::Areas: - // Disabled - // this->mapListRemoveArea(); - break; - case MapListTab::Layouts: - // Disabled - // this->mapListRemoveLayout(); - break; - } -} void MainWindow::onAddNewMapToGroupClick(QAction* triggeredAction) { if (!triggeredAction) return; @@ -1661,7 +1641,7 @@ void MainWindow::onNewMapCreated() { this->mapAreaModel->insertMapItem(newMapName, newMap->location, newMapGroup); this->layoutTreeModel->insertMapItem(newMapName, newMap->layout->id); - setMap(newMapName, true); + setMap(newMapName); // Refresh any combo box that displays map names and persists between maps // (other combo boxes like for warp destinations are repopulated when the map changes). @@ -1877,51 +1857,42 @@ void MainWindow::currentMetatilesSelectionChanged() { scrollMetatileSelectorToSelection(); } +// TODO: Redundant. Remove void MainWindow::on_mapListContainer_currentChanged(int index) { switch (index) { case MapListTab::Groups: porymapConfig.mapSortOrder = MapSortOrder::SortByGroup; - if (this->editor && this->editor->map) scrollTreeView(this->editor->map->name); break; case MapListTab::Areas: porymapConfig.mapSortOrder = MapSortOrder::SortByArea; - if (this->editor && this->editor->map) scrollTreeView(this->editor->map->name); break; case MapListTab::Layouts: porymapConfig.mapSortOrder = MapSortOrder::SortByLayout; - if (this->editor && this->editor->layout) scrollTreeView(this->editor->layout->id); break; } } -void MainWindow::on_mapList_activated(const QModelIndex &index) { - QVariant data = index.data(Qt::UserRole); - if (index.data(MapListUserRoles::TypeRole) == "map_name" && !data.isNull()) { - QString mapName = data.toString(); - userSetMap(mapName); - } -} - -void MainWindow::on_areaList_activated(const QModelIndex &index) { - on_mapList_activated(index); -} - -void MainWindow::on_layoutList_activated(const QModelIndex &index) { - if (!index.isValid()) return; +void MainWindow::openMapListItem(const QModelIndex &index) { + if (!index.isValid()) + return; QVariant data = index.data(Qt::UserRole); - if (index.data(MapListUserRoles::TypeRole) == "map_layout" && !data.isNull()) { - QString layoutId = data.toString(); + if (data.isNull()) + return; - if (!setLayout(layoutId)) { - QMessageBox msgBox(this); - QString errorMsg = QString("There was an error opening layout %1. Please see %2 for full error details.\n\n%3") - .arg(layoutId) - .arg(getLogPath()) - .arg(getMostRecentError()); - msgBox.critical(nullptr, "Error Opening Layout", errorMsg); - } + // Normally when a new map/layout is opened the search filters are cleared and the lists will scroll to display that map/layout in the list. + // We don't want to do this when the user interacts with a list directly, so we temporarily prevent changes to the search filter. + auto toolbar = getCurrentMapListToolBar(); + if (toolbar) toolbar->setFilterLocked(true); + + QString type = index.data(MapListUserRoles::TypeRole).toString(); + if (type == "map_name") { + userSetMap(data.toString()); + } else if (type == "map_layout") { + userSetLayout(data.toString()); } + + if (toolbar) toolbar->setFilterLocked(false); } void MainWindow::updateMapList() { @@ -1930,8 +1901,7 @@ void MainWindow::updateMapList() { this->groupListProxyModel->layoutChanged(); this->mapAreaModel->setMap(this->editor->map->name); this->areaListProxyModel->layoutChanged(); - } - else { + } else { this->mapGroupModel->setMap(QString()); this->groupListProxyModel->layoutChanged(); this->ui->mapList->clearSelection(); @@ -1943,8 +1913,7 @@ void MainWindow::updateMapList() { if (this->editor->layout) { this->layoutTreeModel->setLayout(this->editor->layout->id); this->layoutListProxyModel->layoutChanged(); - } - else { + } else { this->layoutTreeModel->setLayout(QString()); this->layoutListProxyModel->layoutChanged(); this->ui->layoutList->clearSelection(); @@ -1953,14 +1922,12 @@ void MainWindow::updateMapList() { void MainWindow::on_action_Save_Project_triggered() { editor->saveProject(); - updateMapList(); - showWindowTitle(); + updateWindowTitle(); } void MainWindow::on_action_Save_triggered() { editor->save(); - updateMapList(); - showWindowTitle(); + updateWindowTitle(); } void MainWindow::duplicate() { @@ -2884,7 +2851,7 @@ void MainWindow::clickToolButtonFromEditAction(Editor::EditAction editAction) { void MainWindow::onOpenConnectedMap(MapConnection *connection) { if (!connection) return; - if (userSetMap(connection->targetMapName(), true)) + if (userSetMap(connection->targetMapName())) editor->setSelectedConnection(connection->findMirror()); } @@ -2904,6 +2871,7 @@ void MainWindow::onMapLoaded(Map *map) { connect(map, &Map::modified, [this, map] { this->markSpecificMapEdited(map); }); } +// TODO: editor->layout below? and redrawLayoutScene? void MainWindow::onTilesetsSaved(QString primaryTilesetLabel, QString secondaryTilesetLabel) { // If saved tilesets are currently in-use, update them and redraw // Otherwise overwrite the cache for the saved tileset @@ -3042,13 +3010,13 @@ void MainWindow::on_pushButton_ConfigureEncountersJSON_clicked() { void MainWindow::on_button_OpenDiveMap_clicked() { const QString mapName = ui->comboBox_DiveMap->currentText(); if (editor->project->mapNames.contains(mapName)) - userSetMap(mapName, true); + userSetMap(mapName); } void MainWindow::on_button_OpenEmergeMap_clicked() { const QString mapName = ui->comboBox_EmergeMap->currentText(); if (editor->project->mapNames.contains(mapName)) - userSetMap(mapName, true); + userSetMap(mapName); } void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName) { @@ -3211,124 +3179,36 @@ void MainWindow::initTilesetEditor() { connect(this->tilesetEditor, &TilesetEditor::tilesetsSaved, this, &MainWindow::onTilesetsSaved); } -void MainWindow::do_ExpandAll() { +MapListToolBar* MainWindow::getCurrentMapListToolBar() { switch (ui->mapListContainer->currentIndex()) { - case MapListTab::Groups: - this->on_toolButton_ExpandAll_Groups_clicked(); - break; - case MapListTab::Areas: - this->on_toolButton_ExpandAll_Areas_clicked(); - break; - case MapListTab::Layouts: - this->on_toolButton_ExpandAll_Layouts_clicked(); - break; + case MapListTab::Groups: return ui->mapListToolBar_Groups; + case MapListTab::Areas: return ui->mapListToolBar_Areas; + case MapListTab::Layouts: return ui->mapListToolBar_Layouts; + default: return nullptr; } } -void MainWindow::do_CollapseAll() { - switch (ui->mapListContainer->currentIndex()) { - case MapListTab::Groups: - this->on_toolButton_CollapseAll_Groups_clicked(); - break; - case MapListTab::Areas: - this->on_toolButton_CollapseAll_Areas_clicked(); - break; - case MapListTab::Layouts: - this->on_toolButton_CollapseAll_Layouts_clicked(); - break; - } +// Clear the search filters on all the map lists. +// When the search filter is cleared the map lists will (if possible) display the currently-selected map/layout. +void MainWindow::resetMapListFilters() { + ui->mapListToolBar_Groups->clearFilter(); + ui->mapListToolBar_Areas->clearFilter(); + ui->mapListToolBar_Layouts->clearFilter(); } -// TODO: Save this state in porymapConfig -void MainWindow::do_HideShow() { - switch (ui->mapListContainer->currentIndex()) { - case MapListTab::Groups: - this->on_toolButton_HideShow_Groups_clicked(); - break; - case MapListTab::Areas: - this->on_toolButton_HideShow_Areas_clicked(); - break; - case MapListTab::Layouts: - this->on_toolButton_HideShow_Layouts_clicked(); - break; - } +void MainWindow::mapListShortcut_ExpandAll() { + auto toolbar = getCurrentMapListToolBar(); + if (toolbar) toolbar->expandList(); } -void MainWindow::on_toolButton_HideShow_Groups_clicked() { - if (ui->mapList) { - this->groupListProxyModel->toggleHideEmpty(); - this->groupListProxyModel->setFilterRegularExpression(this->ui->lineEdit_filterBox->text()); - } +void MainWindow::mapListShortcut_CollapseAll() { + auto toolbar = getCurrentMapListToolBar(); + if (toolbar) toolbar->collapseList(); } -void MainWindow::on_toolButton_ExpandAll_Groups_clicked() { - if (ui->mapList) { - ui->mapList->expandToDepth(0); - } -} - -void MainWindow::on_toolButton_CollapseAll_Groups_clicked() { - if (ui->mapList) { - ui->mapList->collapseAll(); - } -} - -// TODO: Save this state in porymapConfig -void MainWindow::on_toolButton_EnableDisable_EditGroups_clicked() { - this->ui->mapList->clearSelection(); - if (this->ui->toolButton_EnableDisable_EditGroups->isChecked()) { - ui->mapList->setSelectionMode(QAbstractItemView::ExtendedSelection); - ui->mapList->setDragEnabled(true); - ui->mapList->setAcceptDrops(true); - ui->mapList->setDropIndicatorShown(true); - ui->mapList->setDragDropMode(QAbstractItemView::InternalMove); - ui->mapList->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); - } else { - ui->mapList->setSelectionMode(QAbstractItemView::NoSelection); - ui->mapList->setDragEnabled(false); - ui->mapList->setAcceptDrops(false); - ui->mapList->setDropIndicatorShown(false); - ui->mapList->setDragDropMode(QAbstractItemView::NoDragDrop); - ui->mapList->setEditTriggers(QAbstractItemView::NoEditTriggers); - } -} - -void MainWindow::on_toolButton_HideShow_Areas_clicked() { - if (ui->areaList) { - this->areaListProxyModel->toggleHideEmpty(); - this->areaListProxyModel->setFilterRegularExpression(this->ui->lineEdit_filterBox->text()); - } -} - -void MainWindow::on_toolButton_ExpandAll_Areas_clicked() { - if (ui->areaList) { - ui->areaList->expandToDepth(0); - } -} - -void MainWindow::on_toolButton_CollapseAll_Areas_clicked() { - if (ui->areaList) { - ui->areaList->collapseAll(); - } -} - -void MainWindow::on_toolButton_HideShow_Layouts_clicked() { - if (ui->layoutList) { - this->layoutListProxyModel->toggleHideEmpty(); - this->layoutListProxyModel->setFilterRegularExpression(this->ui->lineEdit_filterBox->text()); - } -} - -void MainWindow::on_toolButton_ExpandAll_Layouts_clicked() { - if (ui->layoutList) { - ui->layoutList->expandToDepth(0); - } -} - -void MainWindow::on_toolButton_CollapseAll_Layouts_clicked() { - if (ui->layoutList) { - ui->layoutList->collapseAll(); - } +void MainWindow::mapListShortcut_ToggleEmptyFolders() { + auto toolbar = getCurrentMapListToolBar(); + if (toolbar) toolbar->toggleEmptyFolders(); } void MainWindow::on_actionAbout_Porymap_triggered() @@ -3646,7 +3526,7 @@ bool MainWindow::closeProject() { editor->closeProject(); clearProjectUI(); setWindowDisabled(true); - setWindowTitle(QCoreApplication::applicationName()); + updateWindowTitle(); return true; } diff --git a/src/ui/maplistmodels.cpp b/src/ui/maplistmodels.cpp index 7e0d7e62..e9fbaa1f 100644 --- a/src/ui/maplistmodels.cpp +++ b/src/ui/maplistmodels.cpp @@ -44,7 +44,7 @@ void GroupNameDelegate::updateEditorGeometry(QWidget *editor, const QStyleOption -MapGroupModel::MapGroupModel(Project *project, QObject *parent) : QStandardItemModel(parent) { +MapGroupModel::MapGroupModel(Project *project, QObject *parent) : MapListModel(parent) { this->project = project; this->root = this->invisibleRootItem(); @@ -283,7 +283,7 @@ QStandardItem *MapGroupModel::getItem(const QModelIndex &index) const { return this->root; } -QModelIndex MapGroupModel::indexOfMap(QString mapName) { +QModelIndex MapGroupModel::indexOf(QString mapName) const { if (this->mapItems.contains(mapName)) { return this->mapItems[mapName]->index(); } @@ -366,7 +366,7 @@ bool MapGroupModel::setData(const QModelIndex &index, const QVariant &value, int -MapAreaModel::MapAreaModel(Project *project, QObject *parent) : QStandardItemModel(parent) { +MapAreaModel::MapAreaModel(Project *project, QObject *parent) : MapListModel(parent) { this->project = project; this->root = this->invisibleRootItem(); @@ -461,7 +461,7 @@ QStandardItem *MapAreaModel::getItem(const QModelIndex &index) const { return this->root; } -QModelIndex MapAreaModel::indexOfMap(QString mapName) { +QModelIndex MapAreaModel::indexOf(QString mapName) const { if (this->mapItems.contains(mapName)) { return this->mapItems[mapName]->index(); } @@ -531,7 +531,7 @@ QVariant MapAreaModel::data(const QModelIndex &index, int role) const { -LayoutTreeModel::LayoutTreeModel(Project *project, QObject *parent) : QStandardItemModel(parent) { +LayoutTreeModel::LayoutTreeModel(Project *project, QObject *parent) : MapListModel(parent) { this->project = project; this->root = this->invisibleRootItem(); @@ -609,7 +609,7 @@ QStandardItem *LayoutTreeModel::getItem(const QModelIndex &index) const { return this->root; } -QModelIndex LayoutTreeModel::indexOfLayout(QString layoutName) { +QModelIndex LayoutTreeModel::indexOf(QString layoutName) const { if (this->layoutItems.contains(layoutName)) { return this->layoutItems[layoutName]->index(); } diff --git a/src/ui/maplisttoolbar.cpp b/src/ui/maplisttoolbar.cpp new file mode 100644 index 00000000..4dd26ecd --- /dev/null +++ b/src/ui/maplisttoolbar.cpp @@ -0,0 +1,121 @@ +#include "maplisttoolbar.h" +#include "ui_maplisttoolbar.h" +#include "editor.h" + +#include + +MapListToolBar::MapListToolBar(QWidget *parent) + : QFrame(parent) + , ui(new Ui::MapListToolBar) +{ + ui->setupUi(this); + + connect(ui->button_ToggleEmptyFolders, &QAbstractButton::clicked, this, &MapListToolBar::toggleEmptyFolders); + connect(ui->button_AddFolder, &QAbstractButton::clicked, this, &MapListToolBar::addFolderClicked); // TODO: Tool tip + connect(ui->button_ExpandAll, &QAbstractButton::clicked, this, &MapListToolBar::expandList); + connect(ui->button_CollapseAll, &QAbstractButton::clicked, this, &MapListToolBar::collapseList); + connect(ui->button_ToggleEdit, &QAbstractButton::clicked, this, &MapListToolBar::toggleEditsAllowed); + connect(ui->lineEdit_filterBox, &QLineEdit::textChanged, this, &MapListToolBar::applyFilter); +} + +MapListToolBar::~MapListToolBar() +{ + delete ui; +} + +void MapListToolBar::setList(MapTree *list) { + m_list = list; + + // Sync list with current button states + setEditsAllowed(ui->button_ToggleEdit->isChecked()); + // TODO: Empty folders +} + +void MapListToolBar::setEditsAllowedButtonHidden(bool hidden) { + ui->button_ToggleEdit->setVisible(!hidden); +} + +void MapListToolBar::setEditsAllowed(bool allowed) { + if (!m_list) + return; + + if (allowed) { + m_list->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_list->setDragEnabled(true); + m_list->setAcceptDrops(true); + m_list->setDropIndicatorShown(true); + m_list->setDragDropMode(QAbstractItemView::InternalMove); + m_list->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); + } else { + m_list->setSelectionMode(QAbstractItemView::NoSelection); + m_list->setDragEnabled(false); + m_list->setAcceptDrops(false); + m_list->setDropIndicatorShown(false); + m_list->setDragDropMode(QAbstractItemView::NoDragDrop); + m_list->setEditTriggers(QAbstractItemView::NoEditTriggers); + } +} + +// TODO: Sync the UI in each of these + +void MapListToolBar::toggleEmptyFolders() { + if (!m_list) + return; + + auto model = static_cast(m_list->model()); + if (!model) + return; + + bool hidden = model->toggleHideEmpty(); + model->setFilterRegularExpression(ui->lineEdit_filterBox->text()); + + // Update tool tip to reflect what will happen if the button is pressed. + const QString toolTip = QString("%1 empty folders in the list.").arg(hidden ? "Show" : "Hide"); + ui->button_ToggleEmptyFolders->setToolTip(toolTip); + + // Display message to let user know what just happened (if there are no empty folders visible it's not obvious). + const QString message = QString("%1 empty folders!").arg(hidden ? "Hiding" : "Showing"); + QToolTip::showText(ui->button_ToggleEmptyFolders->mapToGlobal(QPoint(0, 0)), message); +} + +void MapListToolBar::expandList() { + if (m_list) + m_list->expandToDepth(0); +} + +void MapListToolBar::collapseList() { + if (m_list) { + m_list->collapseAll(); + } +} + +// TODO: Save this state in porymapConfig? +// TODO: This isn't actually toggling anything, it's just updating based on the button +void MapListToolBar::toggleEditsAllowed() { + if (m_list) { + m_list->clearSelection(); + } + setEditsAllowed(ui->button_ToggleEdit->isChecked()); +} + +void MapListToolBar::applyFilter(const QString &filterText) { + if (!m_list || m_filterLocked) + return; + + const QSignalBlocker b(ui->lineEdit_filterBox); + ui->lineEdit_filterBox->setText(filterText); + + auto model = static_cast(m_list->model()); + if (model) model->setFilterRegularExpression(QRegularExpression(filterText, QRegularExpression::CaseInsensitiveOption)); + + if (filterText.isEmpty()) { + m_list->collapseAll(); + emit filterCleared(m_list); + } else { + m_list->expandToDepth(0); + } +} + +void MapListToolBar::clearFilter() { + applyFilter(""); +}