From 8079fa79d2d92865776cbcf78d6afc74ab78773c Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 18 Jul 2023 09:54:20 +0200 Subject: [PATCH 01/17] Library: add multi-line editor delegate for comment column --- CMakeLists.txt | 1 + src/library/basetracktablemodel.cpp | 3 + src/library/multilineeditdelegate.cpp | 115 ++++++++++++++++++++++++++ src/library/multilineeditdelegate.h | 49 +++++++++++ src/library/tableitemdelegate.h | 2 - 5 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 src/library/multilineeditdelegate.cpp create mode 100644 src/library/multilineeditdelegate.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 559e3313587..b58f75cf112 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -818,6 +818,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/library/locationdelegate.cpp src/library/missingtablemodel.cpp src/library/mixxxlibraryfeature.cpp + src/library/multilineeditdelegate.cpp src/library/parser.cpp src/library/parsercsv.cpp src/library/parserm3u.cpp diff --git a/src/library/basetracktablemodel.cpp b/src/library/basetracktablemodel.cpp index e3414e29338..9ef7aca66ca 100644 --- a/src/library/basetracktablemodel.cpp +++ b/src/library/basetracktablemodel.cpp @@ -9,6 +9,7 @@ #include "library/coverartdelegate.h" #include "library/dao/trackschema.h" #include "library/locationdelegate.h" +#include "library/multilineeditdelegate.h" #include "library/previewbuttondelegate.h" #include "library/stardelegate.h" #include "library/starrating.h" @@ -394,6 +395,8 @@ QAbstractItemDelegate* BaseTrackTableModel::delegateForColumn( } else if (PlayerManager::numPreviewDecks() > 0 && index == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW)) { return new PreviewButtonDelegate(pTableView, index); + } else if (index == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COMMENT)) { + return new MultiLineEditDelegate(pTableView); } else if (index == fieldIndex(ColumnCache::COLUMN_TRACKLOCATIONSTABLE_LOCATION)) { return new LocationDelegate(pTableView); } else if (index == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COLOR)) { diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp new file mode 100644 index 00000000000..7d33a03e2bd --- /dev/null +++ b/src/library/multilineeditdelegate.cpp @@ -0,0 +1,115 @@ +#include "library/multilineeditdelegate.h" + +#include +#include + +#include "moc_multilineeditdelegate.cpp" + +MultiLineEditor::MultiLineEditor(QWidget* pParent) + : QPlainTextEdit(pParent) { + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + // Disable line wrap for a predictable view (like QLineEdit). + // Horizontal scrollbars show up automatically. + setLineWrapMode(QPlainTextEdit::NoWrap); + // Remove ugly content offset, most notable with one-liners + setContentsMargins(0, 0, 0, 0); + document()->setDocumentMargin(0); +}; + +void MultiLineEditor::keyPressEvent(QKeyEvent* pEvent) { + if ((pEvent->key() == Qt::Key_Return || pEvent->key() == Qt::Key_Enter) && + !pEvent->modifiers().testFlag(Qt::ShiftModifier)) { + // Finish editing like in QLineEdit + emit editingFinished(); + pEvent->ignore(); + } else { + QPlainTextEdit::keyPressEvent(pEvent); + } +}; + +MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView) + : TableItemDelegate(pTableView), + m_lineCount(0) { +} + +QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { + Q_UNUSED(index); + auto* pEditor = new MultiLineEditor(pParent); + auto* pDocLayout = pEditor->document()->documentLayout(); + // Adjust height to fit content and maybe shift vertically to fit into the + // library view. documentSizeChanged() is emitted when text changed, incl. + // initial fill. + connect(pDocLayout, + &QAbstractTextDocumentLayout::documentSizeChanged, + this, + [this, pEditor](const QSizeF size) { + adjustEditor(pEditor, size); + }); + // Also emitted when pressing Return key, see MultiLineEditor::keyPressEvent() + connect(pEditor, + &MultiLineEditor::editingFinished, + this, + &MultiLineEditDelegate::commitAndCloseEditor); + // Store the initial rectangle so we can read the x/y origin and in adjustEditor() + m_editRect = option.rect; + return pEditor; +} + +void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const { + // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks) + int newLineCount = static_cast(round(size.height())); + // Only act if line count changed + if (newLineCount == m_lineCount) { + return; + } else { + m_lineCount = newLineCount; + } + + // Remove the scrollbars if content is just one line to emulate QLineEdit + // appearace, else enable auto mode. + Qt::ScrollBarPolicy pol(m_lineCount > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); + pEditor->setVerticalScrollBarPolicy(pol); + pEditor->setHorizontalScrollBarPolicy(pol); + + // Calculate the content height + int lines = m_lineCount; + // Add extra margin so the horizontal scrollbar doesn't obstruct the last + // line (which also avoids the vertical scrollbar as long as possible) + lines += lines > 1 ? 1 : 0; + + QFontMetrics fm(pEditor->document()->defaultFont()); + int newH = fm.lineSpacing() * lines; + + // Limit editor to visible table height + int tableH = m_pTableView->viewport()->rect().height(); + newH = std::min(newH, tableH); + // If the editor overflows the table view, move it up so it's not clipped. + // No need to care about y < 0 or y > (table height - line height) since the + // table already ensures visibility when the index is selected. + int newY = m_editRect.y(); + if ((newY + newH) > tableH) { + newY = tableH - newH; + } + // Also limit width so scrollbars are visible and table is not scrolled if + // cursor is moved horizontally. + int newW = std::min(pEditor->width(), m_pTableView->viewport()->rect().width()); + + pEditor->setGeometry(QRect(m_editRect.x(), newY, newW, newH)); +} + +void MultiLineEditDelegate::commitAndCloseEditor() { + MultiLineEditor* pEditor = qobject_cast(sender()); + emit commitData(pEditor); + emit closeEditor(pEditor); +} + +void MultiLineEditDelegate::paintItem( + QPainter* pPainter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { + // Paint the item the default way, i.e. ellipsis after horizontal overflow + // and first linebreak + QStyledItemDelegate::paint(pPainter, option, index); +} diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h new file mode 100644 index 00000000000..a2ac5b520e5 --- /dev/null +++ b/src/library/multilineeditdelegate.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include "library/tableitemdelegate.h" + +/// A QPlainTextEdit to show all content lines in a scrollable view. +/// * finish editing with Return key, like QLineEdit used for other text columns +/// * add new line with Shift+Return +/// Horizontal scrollbar is hidden as long as content is just one line. +/// Note: QTextEdit is no option here since it seems to transform content with +/// line breaks to html doc when committing data. +class MultiLineEditor : public QPlainTextEdit { + Q_OBJECT + public: + MultiLineEditor(QWidget* pParent); + + void keyPressEvent(QKeyEvent* pEvent); + + signals: + void editingFinished(); +}; + +/// A delegate for text value columns that allows editing content +/// content in a multi-line editor instead of default QLineEdit +class MultiLineEditDelegate : public TableItemDelegate { + Q_OBJECT + public: + explicit MultiLineEditDelegate(QTableView* pTrackTable); + ~MultiLineEditDelegate() override = default; + + // called when the user starts editing an item + QWidget* createEditor(QWidget* parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const override; + + void paintItem( + QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const override; + + private slots: + void commitAndCloseEditor(); + + private: + void adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const; + mutable QRect m_editRect; + mutable int m_lineCount; +}; diff --git a/src/library/tableitemdelegate.h b/src/library/tableitemdelegate.h index a9cb54d7969..0d8a8b6a776 100644 --- a/src/library/tableitemdelegate.h +++ b/src/library/tableitemdelegate.h @@ -29,7 +29,5 @@ class TableItemDelegate : public QStyledItemDelegate { int columnWidth(const QModelIndex &index) const; QColor m_pFocusBorderColor; - - private: QTableView* m_pTableView; }; From e03b98e6c6d625dc7c442b73eb888accdae3c8eb Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 18 Jul 2023 13:31:14 +0200 Subject: [PATCH 02/17] MultiLineEditDelegate: fix right-click events / context menu --- src/library/multilineeditdelegate.cpp | 30 +++++++++++++++++++-------- src/library/multilineeditdelegate.h | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 7d33a03e2bd..a7b6db2e0fa 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -14,18 +14,30 @@ MultiLineEditor::MultiLineEditor(QWidget* pParent) // Remove ugly content offset, most notable with one-liners setContentsMargins(0, 0, 0, 0); document()->setDocumentMargin(0); + // Add event filter to catch right-clicks and key presses, see eventFilter() + installEventFilter(this); }; -void MultiLineEditor::keyPressEvent(QKeyEvent* pEvent) { - if ((pEvent->key() == Qt::Key_Return || pEvent->key() == Qt::Key_Enter) && - !pEvent->modifiers().testFlag(Qt::ShiftModifier)) { - // Finish editing like in QLineEdit - emit editingFinished(); - pEvent->ignore(); - } else { - QPlainTextEdit::keyPressEvent(pEvent); +bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) { + if (event->type() == QEvent::MouseButtonPress) { + // Work around a strange quirk: right-clicks outside the rectangle of + // the underlying table index are not triggering the context menu. + // Simply returning true fixes it. + QMouseEvent* me = static_cast(event); + if (me->button() == Qt::RightButton && rect().contains(me->pos(), false)) { + return true; + } + } else if (event->type() == QEvent::KeyPress) { + // Finish editing with Return key like in QLineEdit + QKeyEvent* ke = static_cast(event); + if ((ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) && + ke->modifiers().testFlag(Qt::NoModifier)) { + emit editingFinished(); + return false; + } } -}; + return QPlainTextEdit::eventFilter(obj, event); +} MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView) : TableItemDelegate(pTableView), diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h index a2ac5b520e5..d08db97e606 100644 --- a/src/library/multilineeditdelegate.h +++ b/src/library/multilineeditdelegate.h @@ -15,7 +15,7 @@ class MultiLineEditor : public QPlainTextEdit { public: MultiLineEditor(QWidget* pParent); - void keyPressEvent(QKeyEvent* pEvent); + bool eventFilter(QObject* obj, QEvent* event) override; signals: void editingFinished(); From 5020342be812b80e1950e481b54c6050ccec688c Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 18 Jul 2023 10:04:10 +0200 Subject: [PATCH 03/17] skins: set styles for multi-line table editor --- res/skins/Deere/style.qss | 20 +++++++++++++------- res/skins/LateNight/style_classic.qss | 10 +++++++++- res/skins/LateNight/style_palemoon.qss | 11 ++++++++++- res/skins/Shade/style.qss | 12 ++++++++++-- res/skins/Shade/style_dark.qss | 13 ++++++++----- res/skins/Shade/style_summer_sunset.qss | 6 +++++- res/skins/Tango/style.qss | 12 ++++++++++-- 7 files changed, 65 insertions(+), 19 deletions(-) diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss index f2d06b87589..f421d2f2668 100644 --- a/res/skins/Deere/style.qss +++ b/res/skins/Deere/style.qss @@ -263,15 +263,13 @@ WLibraryTextBrowser { /* Table cell in edit mode */ WLibrary QLineEdit, +WLibrary QPlainTextEdit, WBeatSpinBox, -#LibraryBPMSpinBox { - selection-color: #000; - selection-background-color: #ccc; -} -WLibrary QLineEdit, #LibraryBPMSpinBox { color: #ddd; background-color: #0f0f0f; + selection-color: #000; + selection-background-color: #ccc; border: 1px solid #006596; } @@ -847,6 +845,7 @@ WTrackTableViewHeader::section, WLibraryTextBrowser, WLibraryTextBrowser QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCueMenuPopup QLabel, WCueMenuPopup QLineEdit, @@ -1961,6 +1960,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WCoverArtMenu, WCoverArtMenu::item, WCueMenuPopup, @@ -1983,6 +1984,7 @@ WLibraryTextBrowser QMenu, WTrackMenu, WTrackMenu QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCoverArtMenu, WEffectSelector QAbstractScrollArea, @@ -2012,6 +2014,7 @@ WSearchLineEdit QAbstractScrollArea, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, + QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectSelector::indicator:unchecked:selected, @@ -2196,7 +2199,8 @@ WTrackTableViewHeader QMenu::separator, WTrackMenu::separator, WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, -QLineEdit QMenu::separator { +QLineEdit QMenu::separator, +QPlainTextEdit QMenu::separator { border-top: 1px solid #999; } @@ -2211,6 +2215,7 @@ WTrackMenu QMenu QCheckBox::indicator { } QLineEdit QMenu::icon:selected, +QPlainTextEdit QMenu::icon:selected, WLibrarySidebar QMenu::indicator:selected, WTrackTableViewHeader QMenu::indicator:selected, WTrackMenu QMenu QCheckBox::indicator:selected { @@ -2223,7 +2228,8 @@ WLibrarySidebar QMenu::item:disabled, WTrackMenu::item:disabled, WTrackMenu QMenu::item:disabled, WTrackMenu QMenu QCheckBox:disabled, -QLineEdit QMenu::item:disabled { +QLineEdit QMenu::item:disabled, +QPlainTextEdit QMenu::item:disabled { color: #555; } WTrackMenu QMenu QCheckBox::indicator:disabled { diff --git a/res/skins/LateNight/style_classic.qss b/res/skins/LateNight/style_classic.qss index 1123047665d..639c6172185 100644 --- a/res/skins/LateNight/style_classic.qss +++ b/res/skins/LateNight/style_classic.qss @@ -1115,6 +1115,7 @@ WTrackMenu, WTrackMenu QMenu, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, +QPlainTextEdit QMenu, WEffectChainPresetButton QMenu, WEffectChainPresetButton QMenu QCheckBox, WCoverArtMenu, @@ -2101,6 +2102,7 @@ WLibrarySidebar { /* Table cell in edit mode */ WLibrary QLineEdit, +WLibrary QPlainTextEdit, #LibraryBPMSpinBox { color: #ddd; background-color: #0f0f0f; @@ -2415,6 +2417,7 @@ WLibraryTextBrowser QMenu, WTrackMenu, WTrackMenu QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCoverArtMenu, WEffectSelector QAbstractScrollArea, @@ -2447,6 +2450,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WCoverArtMenu, WCoverArtMenu::item, WCueMenuPopup, @@ -2484,6 +2489,7 @@ WTrackMenu QMenu QCheckBox:selected, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, +QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectChainPresetSelector:item:selected, @@ -2525,7 +2531,8 @@ WLibrarySidebar QMenu::item:disabled, WTrackMenu::item:disabled, WTrackMenu QMenu::item:disabled, WTrackMenu QMenu QCheckBox:disabled, -QLineEdit QMenu::item:disabled { +QLineEdit QMenu::item:disabled, +QPlainTextEdit QMenu::item:disabled { color: #494949; } @@ -2601,6 +2608,7 @@ QLineEdit QMenu::item:disabled { WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, QLineEdit QMenu::separator, + QPlainTextEdit QMenu::separator, WEffectChainPresetButton QMenu::separator, #SkinSettingsSeparator { border-top: 1px solid #000; diff --git a/res/skins/LateNight/style_palemoon.qss b/res/skins/LateNight/style_palemoon.qss index b3cb97691c2..429e64127e3 100644 --- a/res/skins/LateNight/style_palemoon.qss +++ b/res/skins/LateNight/style_palemoon.qss @@ -1209,6 +1209,7 @@ WTrackMenu QMenu QCheckBox, WEffectChainPresetButton QMenu, WEffectChainPresetButton QMenu QCheckBox, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCueMenuPopup QLabel, #CueLabelEdit, @@ -2527,6 +2528,7 @@ WLibrarySidebar, #SkinSettings, WSearchLineEdit, WLibrary QLineEdit, +WLibrary QPlainTextEdit, #spinBoxTransition, #LibraryBPMSpinBox { background-color: #0f0f0f; @@ -2589,6 +2591,7 @@ WTrackTableView { /* Table cell in edit mode */ WLibrary QLineEdit, +WLibrary QPlainTextEdit, #LibraryBPMSpinBox { color: #ddd; selection-color: #000; @@ -2909,6 +2912,7 @@ WLibraryTextBrowser QMenu, WTrackMenu, WTrackMenu QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCoverArtMenu, WEffectSelector QAbstractScrollArea, @@ -2939,6 +2943,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WCoverArtMenu, WCoverArtMenu::item, WCueMenuPopup, @@ -2972,6 +2978,7 @@ WTrackMenu QMenu QCheckBox:selected, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, +QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectChainPresetSelector::item:selected, @@ -3018,7 +3025,8 @@ WLibrarySidebar QMenu::item:disabled, WTrackMenu::item:disabled, WTrackMenu QMenu::item:disabled, WTrackMenu QMenu QCheckBox:disabled, -QLineEdit QMenu::item:disabled { +QLineEdit QMenu::item:disabled, +QPlainTextEdit QMenu::item:disabled { color: #494949; } @@ -3029,6 +3037,7 @@ QLineEdit QMenu::item:disabled { WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, QLineEdit QMenu::separator, + QPlainTextEdit QMenu::separator, WEffectChainPresetButton QMenu::separator, #SkinSettingsSeparator { border-top: 1px solid #000; diff --git a/res/skins/Shade/style.qss b/res/skins/Shade/style.qss index 0f6f4c3c636..6d05e7c41ae 100644 --- a/res/skins/Shade/style.qss +++ b/res/skins/Shade/style.qss @@ -36,6 +36,7 @@ WLibrarySidebar QMenu, WLibraryTextBrowser, WLibraryTextBrowser QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCueMenuPopup QMenu, WCueMenuPopup QLabel, @@ -109,6 +110,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WBeatSpinBox::up-button, WBeatSpinBox::down-button, WCueMenuPopup, @@ -159,6 +162,7 @@ WTrackMenu QMenu QCheckBox:selected, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, +QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectSelector::indicator:unchecked:selected, @@ -239,6 +243,7 @@ WLibraryTextBrowser QMenu, WTrackMenu, WTrackMenu QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCoverArtMenu, WEffectSelector QAbstractScrollArea, @@ -354,7 +359,8 @@ WEffectSelector QAbstractScrollArea, WTrackMenu::item:disabled, WTrackMenu QMenu::item:disabled, WTrackMenu QMenu QCheckBox:disabled, - QLineEdit QMenu::item:disabled { + QLineEdit QMenu::item:disabled, + QPlainTextEdit QMenu::item:disabled { color: #666; } WTrackMenu QMenu QCheckBox::indicator:disabled { @@ -367,7 +373,8 @@ WEffectSelector QAbstractScrollArea, WTrackMenu::separator, WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, - QLineEdit QMenu::separator { + QLineEdit QMenu::separator, + QPlainTextEdit QMenu::separator { border-top: 1px solid #71777a; } @@ -498,6 +505,7 @@ WTrackTableView { /* Table cell in edit mode */ WLibrary QLineEdit, + WLibrary QPlainTextEdit, #LibraryBPMSpinBox { color: #ddd; background-color: #0f0f0f; diff --git a/res/skins/Shade/style_dark.qss b/res/skins/Shade/style_dark.qss index e607f6c9023..edb6d1ac61a 100644 --- a/res/skins/Shade/style_dark.qss +++ b/res/skins/Shade/style_dark.qss @@ -16,6 +16,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WBeatSpinBox::up-button, WBeatSpinBox::down-button, WCueMenuPopup, @@ -61,6 +63,7 @@ WTrackMenu QMenu QCheckBox:selected, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, +QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectSelector::indicator:unchecked:selected, @@ -84,7 +87,8 @@ WEffectSelector::indicator:unchecked:selected, WTrackMenu::separator, WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, - QLineEdit QMenu::separator { + QLineEdit QMenu::separator, + QPlainTextEdit QMenu::separator { border-top: 1px solid #3F3041; } /* checked checkbox */ @@ -108,7 +112,8 @@ WEffectSelector::indicator:unchecked:selected, WTrackMenu::item:disabled, WTrackMenu QMenu::item:disabled, WTrackMenu QMenu QCheckBox:disabled, - QLineEdit QMenu::item:disabled { + QLineEdit QMenu::item:disabled, + QPlainTextEdit QMenu::item:disabled { border-color: #444; color: #444; } @@ -188,14 +193,12 @@ WTrackTableView { /* Table cell in edit mode */ WLibrary QLineEdit, + WLibrary QPlainTextEdit, #LibraryBPMSpinBox { color: #ddd; background-color: #0f0f0f; selection-color: #000; selection-background-color: #aaa; - } - WLibrary QLineEdit, - #LibraryBPMSpinBox { border: 1px solid #666; } #LibraryBPMSpinBox::up-button, diff --git a/res/skins/Shade/style_summer_sunset.qss b/res/skins/Shade/style_summer_sunset.qss index 3a4d19d121d..b6d449a02d8 100644 --- a/res/skins/Shade/style_summer_sunset.qss +++ b/res/skins/Shade/style_summer_sunset.qss @@ -16,6 +16,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WBeatSpinBox::up-button, WBeatSpinBox::down-button, WCueMenuPopup, @@ -50,7 +52,8 @@ WBeatSpinBox, WTrackMenu::separator, WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, - QLineEdit QMenu::separator { + QLineEdit QMenu::separator, + QPlainTextEdit QMenu::separator { border-top: 1px solid #222; } #MainMenu::item:selected, @@ -70,6 +73,7 @@ WTrackMenu QMenu QCheckBox:selected, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, +QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectSelector::indicator:unchecked:selected, diff --git a/res/skins/Tango/style.qss b/res/skins/Tango/style.qss index 2570e895eb5..0f7ac4a8626 100644 --- a/res/skins/Tango/style.qss +++ b/res/skins/Tango/style.qss @@ -49,6 +49,7 @@ WTrackMenu, WTrackMenu QMenu, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, +QPlainTextEdit QMenu, WCoverArtMenu, WLibrarySidebar QMenu, WLibraryTextBrowser QMenu, @@ -2296,6 +2297,8 @@ WTrackMenu QMenu::item, WTrackMenu QMenu QCheckBox, QLineEdit QMenu, QLineEdit QMenu::item, +QPlainTextEdit QMenu, +QPlainTextEdit QMenu::item, WCoverArtMenu, WCoverArtMenu::item, WCueMenuPopup, @@ -2326,6 +2329,7 @@ WLibraryTextBrowser QMenu, WTrackMenu, WTrackMenu QMenu, QLineEdit QMenu, +QPlainTextEdit QMenu, WCueMenuPopup, WCoverArtMenu, WEffectSelector QAbstractScrollArea, @@ -2359,6 +2363,7 @@ WTrackMenu QMenu QCheckBox:selected, WTrackMenu QMenu QCheckBox:focus, WTrackMenu QMenu QCheckBox:hover, QLineEdit QMenu::item:selected, +QPlainTextEdit QMenu::item:selected, WCoverArtMenu::item:selected, WEffectSelector::item:selected, WEffectChainPresetSelector::item:selected, @@ -2381,7 +2386,8 @@ WLibrarySidebar QMenu::item:disabled, WTrackMenu::item:disabled, WTrackMenu QMenu::item:disabled, WTrackMenu QMenu QCheckBox:disabled, -QLineEdit QMenu::item:disabled { +QLineEdit QMenu::item:disabled, +QPlainTextEdit QMenu::item:disabled { color: #555; } @@ -2392,7 +2398,8 @@ QLineEdit QMenu::item:disabled { WTrackMenu::separator, WTrackMenu QMenu::separator, WLibraryTextBrowser QMenu::separator, - QLineEdit QMenu::separator { + QLineEdit QMenu::separator, + QPlainTextEdit QMenu::separator { border-top: 1px solid #0a0a0a; } @@ -2578,6 +2585,7 @@ WTrackTableView { /* Table cell in edit mode */ WLibrary QLineEdit, + WLibrary QPlainTextEdit, #LibraryBPMSpinBox { color: #ddd; background-color: #0f0f0f; From 303cab976df15e093d43180aaf18a6f5db1f124d Mon Sep 17 00:00:00 2001 From: ronso0 Date: Wed, 19 Jul 2023 00:11:22 +0200 Subject: [PATCH 04/17] TableItemDelegate: add default paintItem() implementation so MultiLineEditDelegate doesn't have to implement it just for calling the base class implementation QStyledItemDelegate::paint() (which raised a clazy error) --- src/library/bpmdelegate.h | 5 +++-- src/library/multilineeditdelegate.cpp | 9 --------- src/library/multilineeditdelegate.h | 5 ----- src/library/tableitemdelegate.cpp | 7 +++++++ src/library/tableitemdelegate.h | 2 +- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/library/bpmdelegate.h b/src/library/bpmdelegate.h index 02db4ad09b5..9d543a22c0b 100644 --- a/src/library/bpmdelegate.h +++ b/src/library/bpmdelegate.h @@ -13,8 +13,9 @@ class BPMDelegate : public TableItemDelegate { explicit BPMDelegate(QTableView* pTableView); virtual ~BPMDelegate(); - void paintItem(QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const; + void paintItem(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const override; private: QTableView* m_pTableView; diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index a7b6db2e0fa..27df3bc1f15 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -116,12 +116,3 @@ void MultiLineEditDelegate::commitAndCloseEditor() { emit commitData(pEditor); emit closeEditor(pEditor); } - -void MultiLineEditDelegate::paintItem( - QPainter* pPainter, - const QStyleOptionViewItem& option, - const QModelIndex& index) const { - // Paint the item the default way, i.e. ellipsis after horizontal overflow - // and first linebreak - QStyledItemDelegate::paint(pPainter, option, index); -} diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h index d08db97e606..c039fdfc647 100644 --- a/src/library/multilineeditdelegate.h +++ b/src/library/multilineeditdelegate.h @@ -34,11 +34,6 @@ class MultiLineEditDelegate : public TableItemDelegate { const QStyleOptionViewItem& option, const QModelIndex& index) const override; - void paintItem( - QPainter* painter, - const QStyleOptionViewItem& option, - const QModelIndex& index) const override; - private slots: void commitAndCloseEditor(); diff --git a/src/library/tableitemdelegate.cpp b/src/library/tableitemdelegate.cpp index 48f8d70f258..83b2ccdfed1 100644 --- a/src/library/tableitemdelegate.cpp +++ b/src/library/tableitemdelegate.cpp @@ -73,3 +73,10 @@ void TableItemDelegate::paintItemBackground( const auto bgBrush = qvariant_cast(bgValue); painter->fillRect(option.rect, bgBrush); } + +void TableItemDelegate::paintItem( + QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { + QStyledItemDelegate::paint(painter, option, index); +} diff --git a/src/library/tableitemdelegate.h b/src/library/tableitemdelegate.h index 0d8a8b6a776..058df3f9875 100644 --- a/src/library/tableitemdelegate.h +++ b/src/library/tableitemdelegate.h @@ -18,7 +18,7 @@ class TableItemDelegate : public QStyledItemDelegate { virtual void paintItem( QPainter* painter, const QStyleOptionViewItem& option, - const QModelIndex& index) const = 0; + const QModelIndex& index) const; protected: static void paintItemBackground( From d4fd3eba53d06cb987f9a0970a8b95a709d7fce0 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 23 Jul 2023 21:21:06 +0200 Subject: [PATCH 05/17] MultiLineEditDelegate: don't let editor overlap macOS scrollbars --- src/library/multilineeditdelegate.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 27df3bc1f15..4b1e6496fe9 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -1,6 +1,7 @@ #include "library/multilineeditdelegate.h" #include +#include #include #include "moc_multilineeditdelegate.cpp" @@ -106,7 +107,25 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF } // Also limit width so scrollbars are visible and table is not scrolled if // cursor is moved horizontally. - int newW = std::min(pEditor->width(), m_pTableView->viewport()->rect().width()); + int tableW = m_pTableView->viewport()->rect().width(); + int newW = std::min(pEditor->width(), tableW); +#ifdef __APPLE__ + // Don't let table view scrollbars overlap the editor + int scrollW = m_pTableView->verticalScrollBar()->width(); + if (scrollW > 0 && (m_editRect.x() + newW > tableW - scrollW)) { + newW -= scrollW; + } + int scrollH = m_pTableView->horizontalScrollBar()->height(); + if (scrollH > 0 && (newH > tableH - scrollH)) { + if (newY >= scrollH) { + // shift it up + newY += scrollH; + } else { + // reduce height + newH -= scrollH; + } + } +#endif pEditor->setGeometry(QRect(m_editRect.x(), newY, newW, newH)); } From 550f4dff2cfac52a2aef570cfce166c97c96b28a Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 23 Jul 2023 21:50:05 +0200 Subject: [PATCH 06/17] MultiLineEditDelegate: don't let the editor shrink smaller than the original height when returning to single-line mode after removing a line break --- src/library/multilineeditdelegate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 4b1e6496fe9..3ad3143e1db 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -93,7 +93,8 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF lines += lines > 1 ? 1 : 0; QFontMetrics fm(pEditor->document()->defaultFont()); - int newH = fm.lineSpacing() * lines; + // Don't let the editor shrink smaller than the original height + int newH = std::max(fm.lineSpacing() * lines, m_editRect.height()); // Limit editor to visible table height int tableH = m_pTableView->viewport()->rect().height(); From 2f55431116d04fb08cc340362dccb9ecfcc2abef Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 25 Jul 2023 18:02:45 +0200 Subject: [PATCH 07/17] MultiLineEditDelegate: (fix macOS) cover underlying index text --- src/library/multilineeditdelegate.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 3ad3143e1db..50ff3c44f9a 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -15,6 +15,9 @@ MultiLineEditor::MultiLineEditor(QWidget* pParent) // Remove ugly content offset, most notable with one-liners setContentsMargins(0, 0, 0, 0); document()->setDocumentMargin(0); + // Paint the entire rectangle, i.e. expand document background in order to + // cover all underlying index text. Seems to be required for one-liners on macOS. + setBackgroundVisible(true); // Add event filter to catch right-clicks and key presses, see eventFilter() installEventFilter(this); }; @@ -94,6 +97,8 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF QFontMetrics fm(pEditor->document()->defaultFont()); // Don't let the editor shrink smaller than the original height + // Note: also setBackgroundVisible(true) on the editor to paint the entire + // rectangle, not just the document. int newH = std::max(fm.lineSpacing() * lines, m_editRect.height()); // Limit editor to visible table height From 3f6dc73e87b40645866db7929d1ece9bdcdd3284 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 25 Jul 2023 18:04:28 +0200 Subject: [PATCH 08/17] MultiLineEditDelegate: always remove scrollbars for one-liners setting seems to be reset if document size changed while line count didn't --- src/library/multilineeditdelegate.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 50ff3c44f9a..281bd1bda30 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -76,19 +76,19 @@ QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const { // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks) int newLineCount = static_cast(round(size.height())); - // Only act if line count changed + // Remove the scrollbars if content is just one line to emulate QLineEdit + // appearace, else enable auto mode. + Qt::ScrollBarPolicy pol(newLineCount > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); + pEditor->setVerticalScrollBarPolicy(pol); + pEditor->setHorizontalScrollBarPolicy(pol); + + // Only resize if line count changed if (newLineCount == m_lineCount) { return; } else { m_lineCount = newLineCount; } - // Remove the scrollbars if content is just one line to emulate QLineEdit - // appearace, else enable auto mode. - Qt::ScrollBarPolicy pol(m_lineCount > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); - pEditor->setVerticalScrollBarPolicy(pol); - pEditor->setHorizontalScrollBarPolicy(pol); - // Calculate the content height int lines = m_lineCount; // Add extra margin so the horizontal scrollbar doesn't obstruct the last From 87d2dfd035b0f5599d76c08b7d5e634398d1ee31 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 27 Jul 2023 18:55:07 +0200 Subject: [PATCH 09/17] MultiLineEditDelegate: allow editor to expand horizontally like QLineEdit --- src/library/multilineeditdelegate.cpp | 27 +++++++++++++++------------ src/library/multilineeditdelegate.h | 1 - 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 281bd1bda30..70dafb2e41e 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -44,8 +44,7 @@ bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) { } MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView) - : TableItemDelegate(pTableView), - m_lineCount(0) { + : TableItemDelegate(pTableView) { } QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, @@ -75,22 +74,15 @@ QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const { // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks) - int newLineCount = static_cast(round(size.height())); + int lines = static_cast(round(size.height())); // Remove the scrollbars if content is just one line to emulate QLineEdit // appearace, else enable auto mode. - Qt::ScrollBarPolicy pol(newLineCount > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); + Qt::ScrollBarPolicy pol(lines > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); pEditor->setVerticalScrollBarPolicy(pol); pEditor->setHorizontalScrollBarPolicy(pol); - // Only resize if line count changed - if (newLineCount == m_lineCount) { - return; - } else { - m_lineCount = newLineCount; - } // Calculate the content height - int lines = m_lineCount; // Add extra margin so the horizontal scrollbar doesn't obstruct the last // line (which also avoids the vertical scrollbar as long as possible) lines += lines > 1 ? 1 : 0; @@ -111,10 +103,21 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF if ((newY + newH) > tableH) { newY = tableH - newH; } + + // Calculate the content width + // Initial size.width() is the factor for tabStopDistance. + // After first resize the width is in pixels + // Let the editor expand horizontally like QLineEdit, limit to table width + int newW = std::max(static_cast(size.width()) + pEditor->frameWidth() * 2, + m_editRect.width()); + // Also limit width so scrollbars are visible and table is not scrolled if // cursor is moved horizontally. int tableW = m_pTableView->viewport()->rect().width(); - int newW = std::min(pEditor->width(), tableW); + if (m_editRect.x() + newW > tableW) { + newW = tableW - m_editRect.x(); + } + #ifdef __APPLE__ // Don't let table view scrollbars overlap the editor int scrollW = m_pTableView->verticalScrollBar()->width(); diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h index c039fdfc647..7c5a84a724d 100644 --- a/src/library/multilineeditdelegate.h +++ b/src/library/multilineeditdelegate.h @@ -40,5 +40,4 @@ class MultiLineEditDelegate : public TableItemDelegate { private: void adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const; mutable QRect m_editRect; - mutable int m_lineCount; }; From 857b7cb4c7d4515039d74de0cd35a53927d20423 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 27 Jul 2023 20:00:36 +0200 Subject: [PATCH 10/17] MultiLineEditDelegate: ensure correct editor position after scroll & edit --- src/library/multilineeditdelegate.cpp | 35 +++++++++++++++------------ src/library/multilineeditdelegate.h | 3 +-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 70dafb2e41e..bc609393689 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -59,20 +59,23 @@ QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, connect(pDocLayout, &QAbstractTextDocumentLayout::documentSizeChanged, this, - [this, pEditor](const QSizeF size) { - adjustEditor(pEditor, size); + [this, pEditor, index](const QSizeF size) { + // Pass the current geometry of the index so the editor is + // positioned correctly when the text is edited after the + // table was scrolled. + adjustEditor(pEditor, size, m_pTableView->visualRect(index)); }); // Also emitted when pressing Return key, see MultiLineEditor::keyPressEvent() connect(pEditor, &MultiLineEditor::editingFinished, this, &MultiLineEditDelegate::commitAndCloseEditor); - // Store the initial rectangle so we can read the x/y origin and in adjustEditor() - m_editRect = option.rect; return pEditor; } -void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const { +void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, + const QSizeF size, + QRect iRect) const { // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks) int lines = static_cast(round(size.height())); // Remove the scrollbars if content is just one line to emulate QLineEdit @@ -81,7 +84,6 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF pEditor->setVerticalScrollBarPolicy(pol); pEditor->setHorizontalScrollBarPolicy(pol); - // Calculate the content height // Add extra margin so the horizontal scrollbar doesn't obstruct the last // line (which also avoids the vertical scrollbar as long as possible) @@ -91,15 +93,16 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF // Don't let the editor shrink smaller than the original height // Note: also setBackgroundVisible(true) on the editor to paint the entire // rectangle, not just the document. - int newH = std::max(fm.lineSpacing() * lines, m_editRect.height()); - + int txtH = fm.lineSpacing() * lines; + int newH = std::max(txtH, iRect.height()); // Limit editor to visible table height - int tableH = m_pTableView->viewport()->rect().height(); + QRect tableRect = m_pTableView->viewport()->rect(); + int tableH = tableRect.height(); newH = std::min(newH, tableH); // If the editor overflows the table view, move it up so it's not clipped. // No need to care about y < 0 or y > (table height - line height) since the // table already ensures visibility when the index is selected. - int newY = m_editRect.y(); + int newY = iRect.y(); if ((newY + newH) > tableH) { newY = tableH - newH; } @@ -109,19 +112,19 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF // After first resize the width is in pixels // Let the editor expand horizontally like QLineEdit, limit to table width int newW = std::max(static_cast(size.width()) + pEditor->frameWidth() * 2, - m_editRect.width()); + iRect.width()); // Also limit width so scrollbars are visible and table is not scrolled if // cursor is moved horizontally. - int tableW = m_pTableView->viewport()->rect().width(); - if (m_editRect.x() + newW > tableW) { - newW = tableW - m_editRect.x(); + int tableW = tableRect.width(); + if (iRect.x() + newW > tableW) { + newW = tableW - iRect.x(); } #ifdef __APPLE__ // Don't let table view scrollbars overlap the editor int scrollW = m_pTableView->verticalScrollBar()->width(); - if (scrollW > 0 && (m_editRect.x() + newW > tableW - scrollW)) { + if (scrollW > 0 && (iRect.x() + newW > tableW - scrollW)) { newW -= scrollW; } int scrollH = m_pTableView->horizontalScrollBar()->height(); @@ -136,7 +139,7 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF } #endif - pEditor->setGeometry(QRect(m_editRect.x(), newY, newW, newH)); + pEditor->setGeometry(QRect(iRect.x(), newY, newW, newH)); } void MultiLineEditDelegate::commitAndCloseEditor() { diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h index 7c5a84a724d..c0b98d496a0 100644 --- a/src/library/multilineeditdelegate.h +++ b/src/library/multilineeditdelegate.h @@ -38,6 +38,5 @@ class MultiLineEditDelegate : public TableItemDelegate { void commitAndCloseEditor(); private: - void adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const; - mutable QRect m_editRect; + void adjustEditor(MultiLineEditor* pEditor, const QSizeF size, const QRect iRect) const; }; From f28ea7b6aea86419ed0fe3b3548881ae1891ad93 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 28 Jul 2023 03:01:04 +0200 Subject: [PATCH 11/17] MultiLineEditDelegate: center one-line text vertically in editor --- src/library/multilineeditdelegate.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index bc609393689..c65326c29b2 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -94,6 +94,16 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, // Note: also setBackgroundVisible(true) on the editor to paint the entire // rectangle, not just the document. int txtH = fm.lineSpacing() * lines; + // If it's just one line center the text vertically like QLineEdist do. + // Note that the offset is applied in all directions which, hence with very + // tall library row spacing the left offset may be disturbing. + int diffH = (iRect.height() - txtH - pEditor->frameWidth() * 2) / 2; + if (lines == 1 && diffH > 1) { + pEditor->document()->setDocumentMargin(diffH); + } else { // Reset if lines were added + pEditor->document()->setDocumentMargin(0); + } + int newH = std::max(txtH, iRect.height()); // Limit editor to visible table height QRect tableRect = m_pTableView->viewport()->rect(); From 53cee164334e16f4cd3db89f292ca6e145ad5538 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 10 Aug 2023 02:31:52 +0200 Subject: [PATCH 12/17] MultiLineEditor: iRect -> indexRect --- src/library/multilineeditdelegate.cpp | 18 +++++++++--------- src/library/multilineeditdelegate.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index c65326c29b2..d6fa001e75c 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -75,7 +75,7 @@ QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size, - QRect iRect) const { + QRect indexRect) const { // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks) int lines = static_cast(round(size.height())); // Remove the scrollbars if content is just one line to emulate QLineEdit @@ -97,14 +97,14 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, // If it's just one line center the text vertically like QLineEdist do. // Note that the offset is applied in all directions which, hence with very // tall library row spacing the left offset may be disturbing. - int diffH = (iRect.height() - txtH - pEditor->frameWidth() * 2) / 2; + int diffH = (indexRect.height() - txtH - pEditor->frameWidth() * 2) / 2; if (lines == 1 && diffH > 1) { pEditor->document()->setDocumentMargin(diffH); } else { // Reset if lines were added pEditor->document()->setDocumentMargin(0); } - int newH = std::max(txtH, iRect.height()); + int newH = std::max(txtH, indexRect.height()); // Limit editor to visible table height QRect tableRect = m_pTableView->viewport()->rect(); int tableH = tableRect.height(); @@ -112,7 +112,7 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, // If the editor overflows the table view, move it up so it's not clipped. // No need to care about y < 0 or y > (table height - line height) since the // table already ensures visibility when the index is selected. - int newY = iRect.y(); + int newY = indexRect.y(); if ((newY + newH) > tableH) { newY = tableH - newH; } @@ -122,19 +122,19 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, // After first resize the width is in pixels // Let the editor expand horizontally like QLineEdit, limit to table width int newW = std::max(static_cast(size.width()) + pEditor->frameWidth() * 2, - iRect.width()); + indexRect.width()); // Also limit width so scrollbars are visible and table is not scrolled if // cursor is moved horizontally. int tableW = tableRect.width(); - if (iRect.x() + newW > tableW) { - newW = tableW - iRect.x(); + if (indexRect.x() + newW > tableW) { + newW = tableW - indexRect.x(); } #ifdef __APPLE__ // Don't let table view scrollbars overlap the editor int scrollW = m_pTableView->verticalScrollBar()->width(); - if (scrollW > 0 && (iRect.x() + newW > tableW - scrollW)) { + if (scrollW > 0 && (indexRect.x() + newW > tableW - scrollW)) { newW -= scrollW; } int scrollH = m_pTableView->horizontalScrollBar()->height(); @@ -149,7 +149,7 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, } #endif - pEditor->setGeometry(QRect(iRect.x(), newY, newW, newH)); + pEditor->setGeometry(QRect(indexRect.x(), newY, newW, newH)); } void MultiLineEditDelegate::commitAndCloseEditor() { diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h index c0b98d496a0..799d865d080 100644 --- a/src/library/multilineeditdelegate.h +++ b/src/library/multilineeditdelegate.h @@ -38,5 +38,5 @@ class MultiLineEditDelegate : public TableItemDelegate { void commitAndCloseEditor(); private: - void adjustEditor(MultiLineEditor* pEditor, const QSizeF size, const QRect iRect) const; + void adjustEditor(MultiLineEditor* pEditor, const QSizeF size, const QRect indexRect) const; }; From cfe15f03f9513d79f37aa482daad50b7c7d06dfa Mon Sep 17 00:00:00 2001 From: ronso0 Date: Thu, 10 Aug 2023 02:37:58 +0200 Subject: [PATCH 13/17] MultiLineEditor: move size adjust to MultiLineEditor class in order to access protected function and hopefully fix invisble cursor at line end if editor is clamped to fit into the table view --- src/library/multilineeditdelegate.cpp | 142 ++++++++++++-------------- src/library/multilineeditdelegate.h | 13 ++- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index d6fa001e75c..7e92468c697 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -1,31 +1,44 @@ #include "library/multilineeditdelegate.h" #include +#include #include #include #include "moc_multilineeditdelegate.cpp" -MultiLineEditor::MultiLineEditor(QWidget* pParent) - : QPlainTextEdit(pParent) { +MultiLineEditor::MultiLineEditor(QWidget* pParent, + QTableView* pTableView, + const QModelIndex& index) + : QPlainTextEdit(pParent), + m_pTableView(pTableView), + m_index(index) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - // Disable line wrap for a predictable view (like QLineEdit). - // Horizontal scrollbars show up automatically. + // Disable line wrap for a predictable view (like QLineEdit). Horizontal + // scrollbars will show up automatically. setLineWrapMode(QPlainTextEdit::NoWrap); - // Remove ugly content offset, most notable with one-liners - setContentsMargins(0, 0, 0, 0); + // Remove content offset, most notable with one-liners document()->setDocumentMargin(0); // Paint the entire rectangle, i.e. expand document background in order to // cover all underlying index text. Seems to be required for one-liners on macOS. setBackgroundVisible(true); // Add event filter to catch right-clicks and key presses, see eventFilter() installEventFilter(this); + + // Adjust height to fit content and maybe shift vertically to fit into the + // library view. documentSizeChanged() is emitted when the text waschanged, + // incl. initial fill. + auto* pDocLayout = document()->documentLayout(); + connect(pDocLayout, + &QAbstractTextDocumentLayout::documentSizeChanged, + this, + &MultiLineEditor::adjustSize); }; bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::MouseButtonPress) { - // Work around a strange quirk: right-clicks outside the rectangle of - // the underlying table index are not triggering the context menu. + // Work around a strange quirk: right-clicks outside the rectangle of the + // underlying table index are not triggering the document context menu. // Simply returning true fixes it. QMouseEvent* me = static_cast(event); if (me->button() == Qt::RightButton && rect().contains(me->pos(), false)) { @@ -43,87 +56,51 @@ bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) { return QPlainTextEdit::eventFilter(obj, event); } -MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView) - : TableItemDelegate(pTableView) { -} - -QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, - const QStyleOptionViewItem& option, - const QModelIndex& index) const { - Q_UNUSED(index); - auto* pEditor = new MultiLineEditor(pParent); - auto* pDocLayout = pEditor->document()->documentLayout(); - // Adjust height to fit content and maybe shift vertically to fit into the - // library view. documentSizeChanged() is emitted when text changed, incl. - // initial fill. - connect(pDocLayout, - &QAbstractTextDocumentLayout::documentSizeChanged, - this, - [this, pEditor, index](const QSizeF size) { - // Pass the current geometry of the index so the editor is - // positioned correctly when the text is edited after the - // table was scrolled. - adjustEditor(pEditor, size, m_pTableView->visualRect(index)); - }); - // Also emitted when pressing Return key, see MultiLineEditor::keyPressEvent() - connect(pEditor, - &MultiLineEditor::editingFinished, - this, - &MultiLineEditDelegate::commitAndCloseEditor); - return pEditor; -} - -void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, - const QSizeF size, - QRect indexRect) const { - // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks) - int lines = static_cast(round(size.height())); +void MultiLineEditor::adjustSize(const QSizeF size) { + // Compared to QTextEdit, size.height() is the paragraph/line count (Qt speak: blocks) + int lines = static_cast(size.height()); // Remove the scrollbars if content is just one line to emulate QLineEdit - // appearace, else enable auto mode. + // appearance, else enable auto mode. Qt::ScrollBarPolicy pol(lines > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); - pEditor->setVerticalScrollBarPolicy(pol); - pEditor->setHorizontalScrollBarPolicy(pol); + setVerticalScrollBarPolicy(pol); + setHorizontalScrollBarPolicy(pol); - // Calculate the content height - // Add extra margin so the horizontal scrollbar doesn't obstruct the last - // line (which also avoids the vertical scrollbar as long as possible) + // If we have more than one line, add extra bottom margin so the horizontal + // scrollbar that may pop up will not obstruct the last line (which also avoids the + // vertical scrollbar as long as possible) lines += lines > 1 ? 1 : 0; - QFontMetrics fm(pEditor->document()->defaultFont()); - // Don't let the editor shrink smaller than the original height - // Note: also setBackgroundVisible(true) on the editor to paint the entire - // rectangle, not just the document. + // Calculate the editor height ///////////////////////////////////////////// + QFontMetrics fm(document()->defaultFont()); + // Don't let the editor shrink smaller than the height of the table index. + QRect indexRect = m_pTableView->visualRect(m_index); int txtH = fm.lineSpacing() * lines; - // If it's just one line center the text vertically like QLineEdist do. - // Note that the offset is applied in all directions which, hence with very - // tall library row spacing the left offset may be disturbing. - int diffH = (indexRect.height() - txtH - pEditor->frameWidth() * 2) / 2; - if (lines == 1 && diffH > 1) { - pEditor->document()->setDocumentMargin(diffH); + int newH = std::max(txtH, indexRect.height()); + // If it's just one line center the text vertically like in QLineEdit. + int diffH = (indexRect.height() - txtH - frameWidth() * 2) / 2; + if (lines == 1 && diffH > 0) { + document()->setDocumentMargin(diffH); } else { // Reset if lines were added - pEditor->document()->setDocumentMargin(0); + document()->setDocumentMargin(0); } - - int newH = std::max(txtH, indexRect.height()); // Limit editor to visible table height QRect tableRect = m_pTableView->viewport()->rect(); int tableH = tableRect.height(); newH = std::min(newH, tableH); - // If the editor overflows the table view, move it up so it's not clipped. - // No need to care about y < 0 or y > (table height - line height) since the - // table already ensures visibility when the index is selected. + // If the editor overflows the table view at the bottom, move it up so it's + // not clipped. No need to care about y < 0 or y > (table height - line height) + // since the table already ensures visibility when the index is selected + // and manual scrolling should simply move the editor with the table. int newY = indexRect.y(); if ((newY + newH) > tableH) { newY = tableH - newH; } - // Calculate the content width - // Initial size.width() is the factor for tabStopDistance. - // After first resize the width is in pixels - // Let the editor expand horizontally like QLineEdit, limit to table width - int newW = std::max(static_cast(size.width()) + pEditor->frameWidth() * 2, - indexRect.width()); - + // Calculate the editor width ////////////////////////////////////////////// + // Let the editor expand horizontally like QLineEdit, limit to table width. + auto cm = contentsMargins(); + int newW = std::max(indexRect.width(), + static_cast(std::ceil(size.width())) + frameWidth() * 2 + cm.left() + cm.right()); // Also limit width so scrollbars are visible and table is not scrolled if // cursor is moved horizontally. int tableW = tableRect.width(); @@ -132,7 +109,7 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, } #ifdef __APPLE__ - // Don't let table view scrollbars overlap the editor + // Don't let table view scrollbars overlap the editor, shrink or shift as required int scrollW = m_pTableView->verticalScrollBar()->width(); if (scrollW > 0 && (indexRect.x() + newW > tableW - scrollW)) { newW -= scrollW; @@ -149,7 +126,24 @@ void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, } #endif - pEditor->setGeometry(QRect(indexRect.x(), newY, newW, newH)); + setGeometry(QRect(indexRect.x(), newY, newW, newH)); +} + +MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView) + : TableItemDelegate(pTableView) { +} + +QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const { + Q_UNUSED(index); + auto* pEditor = new MultiLineEditor(pParent, m_pTableView, index); + // Also emitted when pressing Return key, see MultiLineEditor::keyPressEvent() + connect(pEditor, + &MultiLineEditor::editingFinished, + this, + &MultiLineEditDelegate::commitAndCloseEditor); + return pEditor; } void MultiLineEditDelegate::commitAndCloseEditor() { diff --git a/src/library/multilineeditdelegate.h b/src/library/multilineeditdelegate.h index 799d865d080..47fa22704f9 100644 --- a/src/library/multilineeditdelegate.h +++ b/src/library/multilineeditdelegate.h @@ -13,12 +13,20 @@ class MultiLineEditor : public QPlainTextEdit { Q_OBJECT public: - MultiLineEditor(QWidget* pParent); + MultiLineEditor(QWidget* pParent, + QTableView* pTableView, + const QModelIndex& index); bool eventFilter(QObject* obj, QEvent* event) override; + void adjustSize(const QSizeF size); + signals: void editingFinished(); + + private: + QTableView* m_pTableView; + const QModelIndex m_index; }; /// A delegate for text value columns that allows editing content @@ -36,7 +44,4 @@ class MultiLineEditDelegate : public TableItemDelegate { private slots: void commitAndCloseEditor(); - - private: - void adjustEditor(MultiLineEditor* pEditor, const QSizeF size, const QRect indexRect) const; }; From 9ec5ed6fe9c43c5ee8a902b93d5e2acda6fc5fec Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 11 Aug 2023 01:37:18 +0200 Subject: [PATCH 14/17] MultiLineEditor: setContentsMargins() to apply v-center offset only vertically --- src/library/multilineeditdelegate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 7e92468c697..289fe6d7039 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -79,9 +79,9 @@ void MultiLineEditor::adjustSize(const QSizeF size) { // If it's just one line center the text vertically like in QLineEdit. int diffH = (indexRect.height() - txtH - frameWidth() * 2) / 2; if (lines == 1 && diffH > 0) { - document()->setDocumentMargin(diffH); + setContentsMargins(0, diffH, 0, diffH); // left/right > 0 are not applied } else { // Reset if lines were added - document()->setDocumentMargin(0); + setContentsMargins(0, 0, 0, 0); } // Limit editor to visible table height QRect tableRect = m_pTableView->viewport()->rect(); From ce3e4d3525ef985e34b5646708a45eaf260d3691 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 11 Aug 2023 23:28:28 +0200 Subject: [PATCH 15/17] MultiLineEditor: calculate correct height with QFontMetrics height() should avoid unneeded v-scrollbars with many lines --- src/library/multilineeditdelegate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 289fe6d7039..2a51bafdc89 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -73,8 +73,8 @@ void MultiLineEditor::adjustSize(const QSizeF size) { // Calculate the editor height ///////////////////////////////////////////// QFontMetrics fm(document()->defaultFont()); // Don't let the editor shrink smaller than the height of the table index. - QRect indexRect = m_pTableView->visualRect(m_index); - int txtH = fm.lineSpacing() * lines; + const QRect indexRect = m_pTableView->visualRect(m_index); + int txtH = lines * fm.height(); int newH = std::max(txtH, indexRect.height()); // If it's just one line center the text vertically like in QLineEdit. int diffH = (indexRect.height() - txtH - frameWidth() * 2) / 2; From 3917548fed7758a2f1eb0b1aa60af49991ff379e Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sat, 12 Aug 2023 22:42:43 +0200 Subject: [PATCH 16/17] MultiLineEditor: overhaul adjustSize(), compact h/w calc, scroll fixes, always stick to index rect --- src/library/multilineeditdelegate.cpp | 117 +++++++++++++++++--------- 1 file changed, 78 insertions(+), 39 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index 2a51bafdc89..b8d3d477339 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -19,20 +19,37 @@ MultiLineEditor::MultiLineEditor(QWidget* pParent, setLineWrapMode(QPlainTextEdit::NoWrap); // Remove content offset, most notable with one-liners document()->setDocumentMargin(0); + setContentsMargins(0, 0, 0, 0); + setCenterOnScroll(false); // Paint the entire rectangle, i.e. expand document background in order to // cover all underlying index text. Seems to be required for one-liners on macOS. setBackgroundVisible(true); // Add event filter to catch right-clicks and key presses, see eventFilter() installEventFilter(this); - // Adjust height to fit content and maybe shift vertically to fit into the - // library view. documentSizeChanged() is emitted when the text waschanged, - // incl. initial fill. + // Adjust size to fit content and maybe shift vertically to fit into the + // library view. documentSizeChanged() is emitted when the layout has been + // adjusted according to text changes, incl. initial fill. auto* pDocLayout = document()->documentLayout(); connect(pDocLayout, &QAbstractTextDocumentLayout::documentSizeChanged, this, &MultiLineEditor::adjustSize); + + // Also adjust size if the table is scrolled: maybe we can now expand horizontally + // to show all content, or need to shift the editor vertically. + connect(m_pTableView->horizontalScrollBar(), + &QScrollBar::valueChanged, + this, + [this]() { + adjustSize(document()->size()); + }); + connect(m_pTableView->verticalScrollBar(), + &QScrollBar::valueChanged, + this, + [this]() { + adjustSize(document()->size()); + }); }; bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) { @@ -56,9 +73,21 @@ bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) { return QPlainTextEdit::eventFilter(obj, event); } +// The editor can grow vertically and to the right to show all content and avoid +// scrollbars as long as possible. It may be shifted up/down if it would exceed +// the table view. Size and position are adjusted if the table view is scrolled. +// The only constraints are: +// * minimum rectangle is the index rectangle +// * it's Left edge is always the left edge of the index +// * the editor must always include the index rectangle, hence it may be scrolled +// out of view along with the table content (it remains open) void MultiLineEditor::adjustSize(const QSizeF size) { // Compared to QTextEdit, size.height() is the paragraph/line count (Qt speak: blocks) int lines = static_cast(size.height()); + int docW = static_cast(std::ceil(size.width())); + const QRect indexRect = m_pTableView->visualRect(m_index); + const QRect tableRect = m_pTableView->viewport()->rect(); + // Remove the scrollbars if content is just one line to emulate QLineEdit // appearance, else enable auto mode. Qt::ScrollBarPolicy pol(lines > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); @@ -70,58 +99,68 @@ void MultiLineEditor::adjustSize(const QSizeF size) { // vertical scrollbar as long as possible) lines += lines > 1 ? 1 : 0; - // Calculate the editor height ///////////////////////////////////////////// - QFontMetrics fm(document()->defaultFont()); + // Height // Don't let the editor shrink smaller than the height of the table index. - const QRect indexRect = m_pTableView->visualRect(m_index); - int txtH = lines * fm.height(); - int newH = std::max(txtH, indexRect.height()); + int optH = lines * QFontMetrics(document()->defaultFont()).height() + frameWidth() * 2; + int newH = std::max(optH, indexRect.height()); // If it's just one line center the text vertically like in QLineEdit. - int diffH = (indexRect.height() - txtH - frameWidth() * 2) / 2; - if (lines == 1 && diffH > 0) { - setContentsMargins(0, diffH, 0, diffH); // left/right > 0 are not applied - } else { // Reset if lines were added + int vMargin = (indexRect.height() - optH) / 2; + if (lines == 1 && vMargin > 0) { + setContentsMargins(0, vMargin, 0, vMargin); // left/right > 0 are not applied + } else { // Reset if lines were added setContentsMargins(0, 0, 0, 0); } - // Limit editor to visible table height - QRect tableRect = m_pTableView->viewport()->rect(); - int tableH = tableRect.height(); - newH = std::min(newH, tableH); - // If the editor overflows the table view at the bottom, move it up so it's - // not clipped. No need to care about y < 0 or y > (table height - line height) - // since the table already ensures visibility when the index is selected - // and manual scrolling should simply move the editor with the table. + // Avoid clipping if the editor overflows the table view at the bottom int newY = indexRect.y(); - if ((newY + newH) > tableH) { - newY = tableH - newH; + bool vScrollbarVisible = false; + int tableH = tableRect.height(); + if (newY + newH > tableH) { + // First, try to shift the editor up + if (newY >= 0) { + newY = std::max(0, tableH - newH); // Keep top edge inside table view + } + } + if (newY + newH > tableH) { + // If that doesn't suffice reduce height + newH = tableH - newY; + vScrollbarVisible = true; + } + // The editor must always include the index rectangle + if (newY + newH < indexRect.bottom()) { + newY = indexRect.bottom() - newH; } - // Calculate the editor width ////////////////////////////////////////////// - // Let the editor expand horizontally like QLineEdit, limit to table width. - auto cm = contentsMargins(); - int newW = std::max(indexRect.width(), - static_cast(std::ceil(size.width())) + frameWidth() * 2 + cm.left() + cm.right()); - // Also limit width so scrollbars are visible and table is not scrolled if - // cursor is moved horizontally. + // Width + // Let the editor expand horizontally like QLineEdit (max. to right table edge, + // to not scroll the table horizontally if the cursor is moved), but don't + // shrink smaller than the index width. + int vScrollW = vScrollbarVisible ? verticalScrollBar()->width() : 0; + // TODO For some reason the width isn't enough for all content, h-scrollbars show up + // BUT after v- or h-scroll, the document is suddenly 8px wider, no idea where those + // are coming from + int optW = docW + frameWidth() * 2 + vScrollW; + int newW = std::max(indexRect.width(), optW); int tableW = tableRect.width(); if (indexRect.x() + newW > tableW) { - newW = tableW - indexRect.x(); + newW = std::max(indexRect.width(), tableW - indexRect.x()); } #ifdef __APPLE__ - // Don't let table view scrollbars overlap the editor, shrink or shift as required - int scrollW = m_pTableView->verticalScrollBar()->width(); - if (scrollW > 0 && (indexRect.x() + newW > tableW - scrollW)) { - newW -= scrollW; + // macOS' transient (table view) scrollbars are drawn inside the table, hence + // the cover content. Don't let them cover the editor, instead shrink or shift + // it as required. + int tableVScrollW = m_pTableView->verticalScrollBar()->width(); + if (tableVScrollW > 0 && (indexRect.x() + newW > tableW - tableVScrollW)) { + newW -= tableVScrollW; } - int scrollH = m_pTableView->horizontalScrollBar()->height(); - if (scrollH > 0 && (newH > tableH - scrollH)) { - if (newY >= scrollH) { + int tableHscrollW = m_pTableView->horizontalScrollBar()->height(); + if (tableHscrollW > 0 && newY + newH > tableH - tableHscrollW) { + if (newY >= tableHscrollW) { // shift it up - newY += scrollH; + newY -= tableHscrollW; } else { // reduce height - newH -= scrollH; + newH -= tableHscrollW; } } #endif From 0fe376b0951242bb42f2e754bca4749a6c21b361 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 15 Aug 2023 01:29:49 +0200 Subject: [PATCH 17/17] MultiLineEditor: work around unneeded h-scrolbars with texts wider than the table index --- src/library/multilineeditdelegate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library/multilineeditdelegate.cpp b/src/library/multilineeditdelegate.cpp index b8d3d477339..f6f9611cef3 100644 --- a/src/library/multilineeditdelegate.cpp +++ b/src/library/multilineeditdelegate.cpp @@ -137,8 +137,8 @@ void MultiLineEditor::adjustSize(const QSizeF size) { int vScrollW = vScrollbarVisible ? verticalScrollBar()->width() : 0; // TODO For some reason the width isn't enough for all content, h-scrollbars show up // BUT after v- or h-scroll, the document is suddenly 8px wider, no idea where those - // are coming from - int optW = docW + frameWidth() * 2 + vScrollW; + // are coming from. Adding these magic 8px fixes it. + int optW = docW + frameWidth() * 2 + 8 + vScrollW; int newW = std::max(indexRect.width(), optW); int tableW = tableRect.width(); if (indexRect.x() + newW > tableW) {