Add in delegate for spinbox

This commit is contained in:
Keith Edmunds 2024-12-12 18:02:58 +00:00
parent 0b30a02dde
commit e29c7ed0ff

View File

@ -53,7 +53,7 @@ if TYPE_CHECKING:
from musicmuster import Window
class TextDelegate(QStyledItemDelegate):
class PlaylistDelegate(QStyledItemDelegate):
"""
- closes the edit on control-return
- checks with user before abandoning edit on Escape
@ -92,11 +92,13 @@ class TextDelegate(QStyledItemDelegate):
parent: Optional[QWidget],
option: QStyleOptionViewItem,
index: QModelIndex,
) -> Optional[QTextEdit]:
) -> Optional[QDoubleSpinBox | QTextEdit]:
"""
Intercept createEditor call and make row just a little bit taller
"""
editor: QDoubleSpinBox | QTextEdit
class Editor(QTextEdit):
def resizeEvent(self, event):
super().resizeEvent(event)
@ -108,12 +110,17 @@ class TextDelegate(QStyledItemDelegate):
if self.current_editor:
editor = self.current_editor
else:
editor = Editor(parent)
editor.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
editor.setFrameShape(QFrame.Shape.NoFrame)
self.current_editor = editor
TextDelegate.EditorDocument(editor)
if index.column() == Col.INTRO.value:
editor = QDoubleSpinBox(parent)
editor.setDecimals(1)
editor.setSingleStep(0.1)
return editor
elif isinstance(index.data(), str):
editor = Editor(parent)
editor.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
editor.setFrameShape(QFrame.Shape.NoFrame)
self.current_editor = editor
PlaylistDelegate.EditorDocument(editor)
return editor
def destroyEditor(self, editor: Optional[QWidget], index: QModelIndex) -> None:
@ -174,9 +181,12 @@ class TextDelegate(QStyledItemDelegate):
elif key == Qt.Key.Key_Escape:
# Close editor if no changes have been made
if hasattr(editor, "toPlainText"):
data_modified = False
if isinstance(editor, QTextEdit):
data_modified = self.original_model_data.value() != editor.toPlainText()
elif isinstance(editor, QDoubleSpinBox):
data_modified = (
self.original_model_data.value() != editor.toPlainText()
self.original_model_data.value() != int(editor.value()) * 1000
)
if not data_modified:
self.closeEditor.emit(editor)
@ -211,7 +221,8 @@ class TextDelegate(QStyledItemDelegate):
edit_index, Qt.ItemDataRole.EditRole
)
if index.column() == Col.INTRO.value:
editor.setValue(self.original_model_data.value() / 1000)
if self.original_model_data.value():
editor.setValue(self.original_model_data.value() / 1000)
else:
editor.setPlainText(self.original_model_data.value())
@ -229,229 +240,6 @@ class TextDelegate(QStyledItemDelegate):
editor.setGeometry(option.rect)
# Will be int delegate
# class EscapeDelegate(QStyledItemDelegate):
# """
# - increases the height of a row when editing to make editing easier
# - closes the edit on control-return
# - checks with user before abandoning edit on Escape
# - positions cursor where double-click occurs
# Parts inspired by https://stackoverflow.com/questions/69113867/
# make-row-of-qtableview-expand-as-editor-grows-in-height
# """
# class EditorDocument(QTextDocument):
# def __init__(self, parent):
# super().__init__(parent)
# self.setDocumentMargin(0)
# self.contentsChange.connect(self.contents_change)
# self.height = None
# parent.setDocument(self)
# def contents_change(self, position, chars_removed, chars_added):
# def resize_func():
# if self.size().height() != self.height:
# doc_size = self.size()
# self.parent().resize(int(doc_size.width()), int(doc_size.height()))
# QTimer.singleShot(0, resize_func)
# def __init__(self, parent: QWidget, source_model: PlaylistModel) -> None:
# super().__init__(parent)
# self.source_model = source_model
# self.signals = MusicMusterSignals()
# self.click_position = None # Store the mouse click position
# self.current_editor = None
# def createEditor(
# self,
# parent: Optional[QWidget],
# option: QStyleOptionViewItem,
# index: QModelIndex,
# ) -> Optional[QDoubleSpinBox | QTextEdit]:
# """
# Intercept createEditor call and make row just a little bit taller
# """
# # editor: QDoubleSpinBox | QTextEdit
# class Editor(QTextEdit):
# def resizeEvent(self, event):
# super().resizeEvent(event)
# parent.parent().resizeRowToContents(index.row())
# def keyPressEvent(self, event):
# if event.modifiers() == Qt.KeyboardModifier.ControlModifier:
# if event.key() == Qt.Key.Key_Return:
# print("control-return")
# import pdb; pdb.set_trace()
# self.commit.emit(self)
# # self.closeEditor.emit(editor)
# return
# elif event.key() == Qt.Key.Key_Escape:
# # Close editor if no changes have been made
# print("escape")
# data_modified = False
# if isinstance(editor, QPlainTextEdit):
# data_modified = self.original_model_data != editor.toPlainText()
# elif isinstance(editor, QDoubleSpinBox):
# data_modified = (
# self.original_model_data != int(editor.value()) * 1000
# )
# if not data_modified:
# self.closeEditor.emit(editor)
# return True
# discard_edits = QMessageBox.question(
# cast(QWidget, self.parent()), "Abandon edit", "Discard changes?"
# )
# if discard_edits == QMessageBox.StandardButton.Yes:
# self.closeEditor.emit(editor)
# return True
# super().keyPressEvent(event)
# self.signals = MusicMusterSignals()
# self.signals.enable_escape_signal.emit(False)
# # if isinstance(self.parent(), PlaylistTab):
# # p = cast(PlaylistTab, self.parent())
# # if index.column() == Col.INTRO.value:
# # editor = QDoubleSpinBox(parent)
# # editor.setDecimals(1)
# # editor.setSingleStep(0.1)
# # return editor
# # elif isinstance(index.data(), str):
# if self.current_editor:
# editor = self.current_editor
# else:
# editor = Editor(parent)
# editor.setVerticalScrollBarPolicy(
# Qt.ScrollBarPolicy.ScrollBarAlwaysOff
# )
# editor.setFrameShape(QFrame.Shape.NoFrame)
# self.current_editor = editor
# # # editor.setGeometry(option.rect) # Match the cell geometry
# # row = index.row()
# # row_height = p.rowHeight(row)
# # p.setRowHeight(row, row_height + Config.MINIMUM_ROW_HEIGHT)
# EscapeDelegate.EditorDocument(editor)
# return editor
# # return super().createEditor(parent, option, index)
# def destroyEditor(self, editor: Optional[QWidget], index: QModelIndex) -> None:
# """
# Intercept editor destroyment
# """
# super().destroyEditor(editor, index)
# self.current_editor = None
# self.parent().resizeRowToContents(index.row())
# self.signals.enable_escape_signal.emit(True)
# def editorEvent(
# self, event: QEvent, model: QAbstractItemModel, option, index: QModelIndex
# ) -> bool:
# """Capture mouse click position."""
# if event.type() == QEvent.Type.MouseButtonPress:
# self.click_position = event.pos()
# return super().editorEvent(event, model, option, index)
# def eventFilter(self, editor: Optional[QObject], event: Optional[QEvent]) -> bool:
# """By default, QPlainTextEdit doesn't handle enter or return"""
# if editor is None or event is None:
# return False
# if event.type() == QEvent.Type.Show:
# if self.click_position and isinstance(editor, QTextEdit):
# # Map click position to editor's local space
# local_click_position = editor.mapFromParent(self.click_position)
# # Move cursor to the calculated position
# cursor = editor.cursorForPosition(local_click_position)
# editor.setTextCursor(cursor)
# # Reset click position
# self.click_position = None
# return False
# elif event.type() == QEvent.Type.KeyPress:
# key_event = cast(QKeyEvent, event)
# key = key_event.key()
# if key == Qt.Key.Key_Return:
# if key_event.modifiers() == (Qt.KeyboardModifier.ControlModifier):
# self.commitData.emit(editor)
# self.closeEditor.emit(editor)
# return True
# elif key == Qt.Key.Key_Escape:
# # Close editor if no changes have been made
# if hasattr(editor, "toPlainText"):
# data_modified = self.original_model_data.value() != editor.toPlainText()
# # if isinstance(editor, QPlainTextEdit):
# # data_modified = self.original_model_data.value() != editor.toPlainText()
# # elif isinstance(editor, QDoubleSpinBox):
# # data_modified = (
# # self.original_model_data != int(editor.value()) * 1000
# # )
# if not data_modified:
# self.closeEditor.emit(editor)
# return True
# discard_edits = QMessageBox.question(
# cast(QWidget, self.parent()), "Abandon edit", "Discard changes?"
# )
# if discard_edits == QMessageBox.StandardButton.Yes:
# self.closeEditor.emit(editor)
# return True
# return False
# def sizeHint(self, option, index):
# self.initStyleOption(option, index)
# if self.current_editor:
# doc = self.current_editor.document()
# else:
# doc = QTextDocument()
# doc.setTextWidth(option.rect.width())
# doc.setDefaultFont(option.font)
# doc.setDocumentMargin(0)
# doc.setHtml(option.text)
# return QSize(int(doc.idealWidth()), int(doc.size().height()))
# def setEditorData(self, editor, index):
# proxy_model = index.model()
# edit_index = proxy_model.mapToSource(index)
# self.original_model_data = self.source_model.data(
# edit_index, Qt.ItemDataRole.EditRole
# )
# if index.column() == Col.INTRO.value:
# editor.setValue(self.original_model_data.value() / 1000)
# else:
# editor.setPlainText(self.original_model_data.value())
# def setModelData(self, editor, model, index):
# proxy_model = index.model()
# edit_index = proxy_model.mapToSource(index)
# if isinstance(editor, QTextEdit):
# value = editor.toPlainText().strip()
# elif isinstance(editor, QDoubleSpinBox):
# value = editor.value()
# self.source_model.setData(edit_index, value, Qt.ItemDataRole.EditRole)
# def updateEditorGeometry(self, editor, option, index):
# editor.setGeometry(option.rect)
class PlaylistStyle(QProxyStyle):
def drawPrimitive(self, element, option, painter, widget=None):
"""
@ -490,7 +278,7 @@ class PlaylistTab(QTableView):
# Set up widget
self.source_model = PlaylistModel(playlist_id)
self.proxy_model = PlaylistProxyModel(self.source_model)
self.setItemDelegate(TextDelegate(self, self.source_model))
self.setItemDelegate(PlaylistDelegate(self, self.source_model))
self.setAlternatingRowColors(True)
self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)