Source code for BaseMod.Explorer

from abc import abstractmethod
import os

from PySide6.QtCore import Signal, Qt, QSize, QTimer
from PySide6.QtGui import QColor
from PySide6.QtWidgets import QTreeWidgetItem, QListWidgetItem, QListWidget
from PySide6.QtWidgets import QDialog, QMessageBox, QDialogButtonBox
from BaseMod.ui.createcategory_ui import Ui_CreateCategory
from BaseMod.ui.itemaction_ui import Ui_ItemAction

from BaseMod.ui.explorer_ui import Ui_Explorer
from RWS.Configurable import BoolConfigurable
from RWS.Widgets import ViewDockWidget
from RWS.Utils import paint_svg_qicon


[docs] class Explorer(ViewDockWidget): itemselected = Signal(list)
[docs] def __init__(self, mod, parent=None): super().__init__(parent) parent.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self) self.manager = mod.manager self.mod = mod self.category_colors = BoolConfigurable(self.mod, "TileExplorer.category_colors", False, "Color of categories") self.ui = Ui_Explorer() self.ui.setupUi(self) self.preview = self.ui.Preview self.preview.add_manager(self.manager) self.view_categories = self.ui.Categories self.view_items = self.ui.Items self.view_categories.setAlternatingRowColors(True) self.view_categories.setEditTriggers(QListWidget.EditTrigger.DoubleClicked) self.view_categories.itemSelectionChanged.connect(self.change_items) self.view_categories.setDragDropMode(QListWidget.DragDropMode.NoDragDrop) self.view_items.itemSelectionChanged.connect(self.change_item) self.view_items.setDragDropMode(QListWidget.DragDropMode.NoDragDrop) # todo change in future self.view_items.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection) self.view_items.setIconSize(QSize(20, 20)) #self.ui.Favourite.clicked.connect() self.simplemode = False self.load_categories() self.items_grid() self.change_items() self.selected = [] self.ui.TilesListView.clicked.connect(self.items_list) self.ui.TilesGridViewBig.clicked.connect(self.items_grid) self.ui.TilesGridViewSmall.clicked.connect(self.items_grid_small) self.ui.TilesIconView.clicked.connect(self.items_grid_ununiform) self.view_items.setResizeMode(QListWidget.ResizeMode.Adjust) self.category = 0 self.item = 0 self.ui.CatNext.clicked.connect(self.cat_next) self.ui.CatPrev.clicked.connect(self.cat_prev) self.ui.TileNext.clicked.connect(self.item_next) self.ui.TilePrev.clicked.connect(self.item_prev) self.setFloating(True) self.mod.bmconfig.icon_color.valueChanged.connect(self.changecolor) self.changecolor(self.mod.bmconfig.icon_color.value) self.ui.splitter.splitterMoved.connect(self.splitter_moved) self.ui.SearchBar.textChanged.connect(self.search) self.ui.OnetoOne.clicked.connect(self.preview.ratio1) self.ui.CatsAddCC.clicked.connect(self.add_category) self.ui.CatsRemoveCC.clicked.connect(self.remove_category) self.ui.Favourite.clicked.connect(self.item_action)
[docs] def resizeEvent(self, event): if hasattr(self, 'ui') and self.ui: width, height = self.width(), self.height() aspect_ratio = width / height if height else 1 self.ui.splitter_3.setOrientation(Qt.Orientation.Horizontal if aspect_ratio > 1.6 else Qt.Orientation.Vertical) self.ui.splitter_2.setOrientation(Qt.Orientation.Vertical if 1.6 < aspect_ratio < 2 else Qt.Orientation.Horizontal) super().resizeEvent(event)
[docs] def splitter_moved(self, pos, index): if self.ui.splitter.sizes()[1] == 0 and not self.simplemode: self.simplemode = True self.load_categories() self.view_items.clear() elif self.ui.splitter.sizes()[1] != 0 and self.simplemode: self.simplemode = False self.load_categories() self.change_items()
[docs] def changecolor(self, color: QColor): self.ui.TilesListView.setIcon(paint_svg_qicon(u":/grids/grid/list.svg", color)) self.ui.TilesGridViewBig.setIcon(paint_svg_qicon(u":/grids/grid/mediumgrid.svg", color)) self.ui.TilesGridViewSmall.setIcon(paint_svg_qicon(u":/grids/grid/smallgrid.svg", color)) self.ui.TilesIconView.setIcon(paint_svg_qicon(u":/grids/grid/smallgrid2.svg", color)) self.ui.Pin.setIcon(paint_svg_qicon(u":/special/special/pin.svg", color)) self.ui.CatsAddCC.setIcon(paint_svg_qicon(u":/special/special/add_category.svg", color)) self.ui.CatsRemoveCC.setIcon(paint_svg_qicon(u":/special/special/remove_category.svg", color)) self.ui.Favourite.setIcon(paint_svg_qicon(u":/special/special/add.svg", color)) self.ui.CatPrev.setIcon(paint_svg_qicon(u":/misc/misc/arrow_left.svg", color)) self.ui.CatNext.setIcon(paint_svg_qicon(u":/misc/misc/arrow_right.svg", color)) self.ui.TilePrev.setIcon(paint_svg_qicon(u":/misc/misc/arrow_up.svg", color)) self.ui.TileNext.setIcon(paint_svg_qicon(u":/misc/misc/arrow_down.svg", color))
[docs] def cat_next(self): if self.simplemode: self.view_categories.topLevelItem(self.category).setExpanded(False) self.category = (self.categoryindex + 1) % self.view_categories.topLevelItemCount() self.view_categories.setCurrentItem(self.view_categories.topLevelItem(self.category)) if self.simplemode: cat = self.view_categories.topLevelItem(self.category) self.item = self.itemindex % cat.childCount() self.view_categories.setCurrentItem(cat.child(self.item)) cat.setExpanded(True) return if self.view_items.count() == 0: return self.item = self.itemindex % self.view_items.count() self.view_items.setCurrentRow(self.item)
[docs] def cat_prev(self): if self.simplemode: self.view_categories.topLevelItem(self.category).setExpanded(False) self.category = (self.categoryindex - 1) % self.view_categories.topLevelItemCount() self.view_categories.setCurrentItem(self.view_categories.topLevelItem(self.category)) if self.simplemode: cat = self.view_categories.topLevelItem(self.category) self.item = self.itemindex % cat.childCount() self.view_categories.setCurrentItem(cat.child(self.item)) cat.setExpanded(True) return self.item = self.itemindex % self.view_items.count() self.view_items.setCurrentRow(self.item)
[docs] def item_next(self): if self.simplemode: if self.view_categories.topLevelItem(self.category).childCount() == 0: return self.item = (self.itemindex + 1) % self.view_categories.topLevelItem(self.category).childCount() self.view_categories.setCurrentItem(self.view_categories.topLevelItem(self.category).child(self.item)) return if self.view_items.count() == 0: return self.item = (self.itemindex + 1) % self.view_items.count() self.view_items.setCurrentRow(self.item)
[docs] def item_prev(self): if self.simplemode: if self.view_categories.topLevelItem(self.category).childCount() == 0: return self.item = (self.itemindex - 1) % self.view_categories.topLevelItem(self.category).childCount() self.view_categories.setCurrentItem(self.view_categories.topLevelItem(self.category).child(self.item)) return if self.view_items.count() == 0: return self.item = (self.itemindex - 1) % self.view_items.count() self.view_items.setCurrentRow(self.item)
[docs] def items_grid(self): self.view_items.setViewMode(QListWidget.ViewMode.IconMode) self.view_items.setIconSize(QSize(40, 40)) self.view_items.setSpacing(20) self.view_items.setUniformItemSizes(True) self.view_items.setAlternatingRowColors(False)
[docs] def items_grid_ununiform(self): self.view_items.setViewMode(QListWidget.ViewMode.IconMode) self.view_items.setIconSize(QSize(40, 40)) self.view_items.setSpacing(10) self.view_items.setUniformItemSizes(False) self.view_items.setAlternatingRowColors(False)
[docs] def items_grid_small(self): self.view_items.setViewMode(QListWidget.ViewMode.IconMode) self.view_items.setIconSize(QSize(20, 20)) self.view_items.setSpacing(5) self.view_items.setUniformItemSizes(True) self.view_items.setAlternatingRowColors(False)
[docs] def items_list(self): self.view_items.setViewMode(QListWidget.ViewMode.ListMode) self.view_items.setIconSize(QSize(20, 20)) self.view_items.setSpacing(0) self.view_items.setUniformItemSizes(True) self.view_items.setAlternatingRowColors(True)
[docs] def load_categories(self): filter = self.ui.SearchBar.text() self.view_categories.clear() self.view_categories.collapseAll() for category in self.get_categories(): item = self.cat_from_data(category) if item is None: continue if not self.simplemode: self.view_categories.addTopLevelItem(item) continue for i in self.category_items(category): tileitem = self.treeitem_from_data(i) if item is None: continue item.addChild(tileitem) if filter == "" or item.childCount() > 0: self.view_categories.addTopLevelItem(item) if filter != "": self.view_categories.expandAll()
[docs] def change_items(self): if self.simplemode: self.change_item() return filter = self.ui.SearchBar.text() if len(self.view_categories.selectedItems()) == 0 and filter == "": return self.view_items.clear() if filter != "": for i in self.get_all_items(): if filter.lower() not in i.name.lower(): continue item = self.item_from_data(i) self.view_items.addItem(item) return categories = [] for i in self.view_categories.selectedItems(): categories.append(i.data(0, Qt.ItemDataRole.UserRole)) for category in categories: for i in self.category_items(category): item = self.item_from_data(i) self.view_items.addItem(item)
[docs] def change_item(self): if self.simplemode: selection = list(filter(lambda x: isinstance(x, self.itemtype()), list( map(lambda x: x.data(0, Qt.ItemDataRole.UserRole), self.view_categories.selectedItems())))) if len(selection) == 0: return self.selected = selection else: selection = list(map(lambda x: x.data(Qt.ItemDataRole.UserRole), self.view_items.selectedItems())) if len(selection) == 0: return self.selected = selection self.itemselected.emit(self.selected) self.preview_item(None) if len(self.selected) == 1: self.preview_item(self.selected[0])
# self.preview.preview_tile(self.selected_tiles[0], self.synced_draw_option, self.layer.value, self.colortable)
[docs] def search(self, text: str): self.load_categories() self.change_items()
[docs] def add_category(self): while True: d = QDialog() ui = Ui_CreateCategory() ui.setupUi(d) ui.CategoryName.setText("Custom Category") ui.CategoryColor.set_color(QColor(160, 20, 20)) value = d.exec() print(value, QDialogButtonBox.StandardButton.Cancel) if value == 0: return filepath = os.path.join(self.custom_categories_path, ui.CategoryName.text()) color = ui.CategoryColor.color if os.path.exists(filepath): message = QMessageBox(QMessageBox.Icon.Warning, "Category Exists", "This category already exists!\nWould you like to override it?") message.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel) message.setDefaultButton(QMessageBox.StandardButton.Cancel) value2 = message.exec() if value2 == QMessageBox.StandardButton.No: return if value2 == QMessageBox.StandardButton.Cancel: continue break with open(filepath, "w") as f: f.write(f"{color.red()} {color.green()} {color.blue()}") self.categories_modified()
[docs] def remove_category(self): if not self.category_is_custom(self.category_at_index(self.categoryindex)): QMessageBox(QMessageBox.Icon.Critical, "Error", "Not a Custom Category Selected!").exec() return message = QMessageBox(QMessageBox.Icon.Warning, "Delete Custom Category", "Are you sure?") message.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel) message.setDefaultButton(QMessageBox.StandardButton.Cancel) value = message.exec() if value == QMessageBox.StandardButton.Cancel: return filepath = os.path.join(self.custom_categories_path, self.category_name(self.category_at_index(self.categoryindex))) if os.path.exists(filepath): os.remove(filepath) self.categories_modified()
[docs] def item_action(self): d = QDialog() ui = Ui_ItemAction() ui.setupUi(d) ui.Action.clear() ui.Action.addItem("Nothing", userData=lambda : None) if len(self.selected) < 1: QMessageBox(QMessageBox.Icon.Critical, "Error", "No Tiles Selected!").exec() return selectedtiles = self.selected selectedtilenames = [self.item_name(i) for i in self.selected] for i in self.get_categories(): items = self.category_items(i) if not self.category_is_custom(i): continue hascurrentitems = False for i1 in selectedtiles: if i1 in items: # if one or more tiles inside of custom category hascurrentitems = True filepath = os.path.join(self.custom_categories_path, self.category_name(i)) if hascurrentitems: ui.Action.addItem(f"Remove Item{'s' if len(selectedtiles) > 1 else ''} from \"{self.category_name(i)}\"", userData=lambda : self.remove_items_from_file(filepath, selectedtilenames)) ui.Action.addItem(f"Add Item{'s' if len(selectedtiles) > 1 else ''} to \"{self.category_name(i)}\"", userData=lambda : self.add_items_to_file(filepath, selectedtilenames)) ui.ItemName.setText(", ".join(selectedtilenames)) value = d.exec() if value == 0: return ui.Action.currentData(Qt.ItemDataRole.UserRole)() self.categories_modified() self.change_items()
[docs] def add_items_to_file(self, file, names: list[str]): with open(file, "r+") as f: lines = [i.replace("\n", "") for i in f.readlines()] color = lines[0] lines = list(set([*lines[1:], *names])) f.seek(0) f.write(color + "\n") f.write("\n".join(lines)) f.truncate()
[docs] def remove_items_from_file(self, file, names): with open(file, "r+") as f: lines = [i.replace("\n", "") for i in f.readlines()] color = lines[0] lines = [x for x in lines[1:] if x not in names] f.seek(0) f.write(color + "\n") f.write("\n".join(lines)) f.truncate()
[docs] def focussearch(self): self.raise_() self.activateWindow() QTimer.singleShot(0, self.ui.SearchBar.setFocus)
@property def categoryindex(self): if len(self.view_categories.selectedItems()) == 0: return self.category item = self.view_categories.selectedItems()[0] if self.view_categories.indexOfTopLevelItem(item) == -1: return self.view_categories.indexFromItem(item.parent()).row() return self.view_categories.indexFromItem(item).row() @property def itemindex(self): if len(self.view_categories.selectedItems()) == 0 or len(self.view_items.selectedItems()) == 0: return self.item if self.simplemode: if self.view_categories.indexFromItem(self.view_categories.selectedItems()[0]).column() == 1: return self.view_categories.indexFromItem(self.view_categories.selectedItems()[0]).row() return 0 return self.view_items.row(self.view_items.selectedItems()[0])
[docs] @abstractmethod def get_categories(self) -> list: pass
[docs] @abstractmethod def get_all_items(self) -> list: pass
[docs] @abstractmethod def item_from_data(self, data) -> QListWidgetItem | None: pass
[docs] @abstractmethod def treeitem_from_data(self, data) -> QTreeWidgetItem | None: pass
[docs] @abstractmethod def cat_from_data(self, cat) -> QTreeWidgetItem | None: pass
[docs] @abstractmethod def itemtype(self) -> type: pass
[docs] @abstractmethod def preview_item(self, item): pass
[docs] @abstractmethod def category_items(self, cat) -> list: pass
[docs] @abstractmethod def categories_modified(self) -> None: pass
@property @abstractmethod def custom_categories_path(self) -> str: return ""
[docs] @abstractmethod def category_is_custom(self, cat) -> bool: return False
[docs] @abstractmethod def category_at_index(self, index): return None
[docs] @abstractmethod def category_name(self, cat) -> str: return ""
[docs] @abstractmethod def item_name(self, item) -> str: return ""