probonopd / Filer

A clean rewrite of the Filer file manager for helloSystem, inspired by John Siracusa's descriptions of "Spatial Orientation"
BSD 2-Clause "Simplified" License
12 stars 1 forks source link

New approach for custom icon coordinates needed #20

Open probonopd opened 2 months ago

probonopd commented 2 months ago

Still looking for a straightforward way in Qt to freely position items at x, y coordinates rather than in a grid of items.

The Mac could do this from the beginning in 1984. Even Windows 3.1 could do it - you could freely move an icon anywhere and it would stay at that exact location, even if you quit and restarted Windows.

image

Somewhere along the way, we lost this capability. The QListView icon view can't seem to do it, at least not out of the box?

The following allows us to draw items at defined locations:

image

However,

is totally messed up.

How can this be fixed?

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QListView, QStyledItemDelegate
from PyQt6.QtGui import QIcon, QStandardItemModel, QStandardItem
from PyQt6.QtCore import Qt, QSize

class CoordinateModel(QStandardItemModel):
    def __init__(self):
        super().__init__()

    def addItem(self, text, icon, x, y):
        item = QStandardItem(icon, text)
        # Store x coordinate in UserRole + 1
        item.setData(x, Qt.ItemDataRole.UserRole + 1)
        # Store y coordinate in UserRole + 2
        item.setData(y, Qt.ItemDataRole.UserRole + 2)

        self.appendRow(item)

class CoordinateDelegate(QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        x = index.data(Qt.ItemDataRole.UserRole + 1) # Retrieve x coordinate
        y = index.data(Qt.ItemDataRole.UserRole + 2) # Retrieve y coordinate
        option.rect.moveTo(x, y)  # Set item position based on stored coordinates

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.model = CoordinateModel()
        self.model.addItem("Item 1", QIcon.fromTheme('applications-internet'), 0, 0)
        self.model.addItem("Item 2", QIcon.fromTheme('applications-internet'), 70, 70)
        self.model.addItem("Item 3", QIcon.fromTheme('applications-internet'), 140, 140)

        self.listView = QListView()
        self.listView.setModel(self.model)
        self.listView.setViewMode(QListView.ViewMode.IconMode)  # Specify ViewMode explicitly
        self.listView.setIconSize(QSize(48, 48))  # Set icon size
        self.listView.setItemDelegate(CoordinateDelegate())  # Use custom delegate

        # Selections blue
        self.listView.setStyleSheet("QListView::item:selected { background-color: blue; }")

        self.setCentralWidget(self.listView)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())
probonopd commented 2 months ago

Key question:

Can this be achieved properly by using a QListView with a QStyledItemDelegate and a custom model, or would we need to subclass or replace QListView?

We don't want the rigid grid-based layout of QListView, but our custom way of aligning the icons; not always in a grid that has rows and columns at all.