From 6835237465df94278ab291ad7a2e76d5df9407f1 Mon Sep 17 00:00:00 2001 From: AJ0070 Date: Sun, 14 Jun 2026 11:19:58 +0530 Subject: [PATCH 1/6] Fix note list row alignment on Windows display scaling --- src/notelistdelegate.cpp | 23 ++++++ src/notelistdelegate.h | 2 + src/notelistdelegateeditor.cpp | 131 ++++++++++++--------------------- src/notelistdelegateeditor.h | 3 + 4 files changed, 76 insertions(+), 83 deletions(-) diff --git a/src/notelistdelegate.cpp b/src/notelistdelegate.cpp index b96c151f..e7108135 100644 --- a/src/notelistdelegate.cpp +++ b/src/notelistdelegate.cpp @@ -89,6 +89,25 @@ NoteListDelegate::NoteListDelegate(NoteListView *view, TagPool *tagPool, QObject }); } +int NoteListDelegate::minimumContentHeight() const +{ + const int titleHeight = qMax(QFontMetrics(m_titleFont).height(), QFontMetrics(m_titleSelectedFont).height()); + const int dateHeight = QFontMetrics(m_dateFont).height(); + const int contentHeight = titleHeight; + + return note_list_constants::TOP_OFFSET_Y + titleHeight + dateHeight + contentHeight + note_list_constants::DATE_DESC_SPACE; +} + +int NoteListDelegate::minimumRowHeight(bool isInAllNotes) const +{ + int result = minimumContentHeight() + note_list_constants::LAST_EL_SEP_SPACE; + if (isInAllNotes) { + const int folderLineHeight = qMax(QFontMetrics(m_titleFont).height(), 16) + note_list_constants::DESC_FOLDER_SPACE; + result += folderLineHeight; + } + return result; +} + void NoteListDelegate::setState(NoteListState NewState, QModelIndexList indexes) { if (animationState() != QTimeLine::NotRunning) { @@ -224,11 +243,13 @@ QSize NoteListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMode } int yOffsets = secondYOffset + thirdYOffset + fourthYOffset + fifthYOffset; + const int minimumHeight = minimumRowHeight(m_isInAllNotes) + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { result.setHeight(result.height() - 10 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } + result.setHeight(qMax(result.height(), minimumHeight)); return result; } @@ -278,11 +299,13 @@ QSize NoteListDelegate::bufferSizeHint(const QStyleOptionViewItem &option, const } int yOffsets = secondYOffset + thirdYOffset + fourthYOffset; + const int minimumHeight = minimumRowHeight(m_isInAllNotes) + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { result.setHeight(result.height() - 10 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } + result.setHeight(qMax(result.height(), minimumHeight)); return result; } diff --git a/src/notelistdelegate.h b/src/notelistdelegate.h index c7767a39..8397eeff 100644 --- a/src/notelistdelegate.h +++ b/src/notelistdelegate.h @@ -53,6 +53,8 @@ public slots: void animationFinished(NoteListState animationState); private: + int minimumContentHeight() const; + int minimumRowHeight(bool isInAllNotes) const; void paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintLabels(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintSeparator(QPainter *painter, QRect rect, const QModelIndex &index) const; diff --git a/src/notelistdelegateeditor.cpp b/src/notelistdelegateeditor.cpp index a34245f2..af84fe68 100644 --- a/src/notelistdelegateeditor.cpp +++ b/src/notelistdelegateeditor.cpp @@ -71,49 +71,7 @@ NoteListDelegateEditor::NoteListDelegateEditor(const NoteListDelegate *delegate, m_tagListView->setItemDelegate(m_tagListDelegate); m_tagListModel->setTagPool(tagPool); m_tagListModel->setModelData(index.data(NoteListModel::NoteTagsList).value>()); - if (m_delegate->isInAllNotes()) { - int y = 90; - auto const *noteListModel = static_cast(m_view->model()); - if (noteListModel != nullptr) { - auto idx = noteListModel->getNoteIndex(m_id); - if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { - y += 25; - } - } - int fourthYOffset = 0; - if ((noteListModel != nullptr) && noteListModel->isFirstUnpinnedNote(index)) { - fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; - } - int fifthYOffset = 0; - if ((noteListModel != nullptr) && noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } - int yOffsets = fourthYOffset + fifthYOffset; - - y += yOffsets; - m_tagListView->setGeometry(10, y - 5, rect().width() - 15, m_tagListView->height()); - } else { - int y = 70; - auto const *noteListModel = static_cast(m_view->model()); - if (noteListModel != nullptr) { - auto idx = noteListModel->getNoteIndex(m_id); - if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { - y += 25; - } - } - int fourthYOffset = 0; - if ((noteListModel != nullptr) && noteListModel->isFirstUnpinnedNote(index)) { - fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; - } - int fifthYOffset = 0; - if ((noteListModel != nullptr) && noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } - int yOffsets = fourthYOffset + fifthYOffset; - - y += yOffsets; - m_tagListView->setGeometry(10, y - 5, rect().width() - 15, m_tagListView->height()); - } + m_tagListView->setGeometry(10, tagListTop(index) - 5, rect().width() - 15, m_tagListView->height()); connect(m_tagListView->verticalScrollBar(), &QScrollBar::valueChanged, this, [this] { auto idx = static_cast(m_view->model())->getNoteIndex(m_id); static_cast(m_view->model())->setData(idx, getScrollBarPos(), NoteListModel::NoteTagListScrollbarPos); @@ -127,6 +85,49 @@ NoteListDelegateEditor::NoteListDelegateEditor(const NoteListDelegate *delegate, setAcceptDrops(true); } +int NoteListDelegateEditor::minimumContentHeight() const +{ + const int titleHeight = qMax(QFontMetrics(m_titleFont).height(), QFontMetrics(m_titleSelectedFont).height()); + const int dateHeight = QFontMetrics(m_dateFont).height(); + const int contentHeight = titleHeight; + + return note_list_constants::TOP_OFFSET_Y + titleHeight + dateHeight + contentHeight + note_list_constants::DATE_DESC_SPACE; +} + +int NoteListDelegateEditor::minimumRowHeight() const +{ + int result = minimumContentHeight() + note_list_constants::LAST_EL_SEP_SPACE; + if (m_delegate->isInAllNotes()) { + const int folderLineHeight = qMax(QFontMetrics(m_titleFont).height(), 16) + note_list_constants::DESC_FOLDER_SPACE; + result += folderLineHeight; + } + return result; +} + +int NoteListDelegateEditor::tagListTop(const QModelIndex &index) const +{ + int top = minimumContentHeight(); + if (m_delegate->isInAllNotes()) { + top += qMax(QFontMetrics(m_titleFont).height(), 16) + note_list_constants::DESC_FOLDER_SPACE; + } + + auto const *noteListModel = static_cast(m_view->model()); + if (noteListModel != nullptr) { + auto idx = noteListModel->getNoteIndex(m_id); + if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { + top += 25; + } + if (noteListModel->isFirstUnpinnedNote(index)) { + top += note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; + } + if (noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { + top += note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; + } + } + + return top; +} + NoteListDelegateEditor::~NoteListDelegateEditor() { m_view->unsetEditorWidget(m_id, nullptr); @@ -402,46 +403,9 @@ void NoteListDelegateEditor::paintEvent(QPaintEvent *event) void NoteListDelegateEditor::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); - if (m_delegate->isInAllNotes()) { - int y = 90; - auto const *noteListModel = static_cast(m_view->model()); - auto const idx = noteListModel->getNoteIndex(m_id); - if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { - y += 25; - } - int fourthYOffset = 0; - if (noteListModel->isFirstUnpinnedNote(idx)) { - fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; - } - int fifthYOffset = 0; - if (noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(idx)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } - int yOffsets = fourthYOffset + fifthYOffset; - y += yOffsets; - - m_tagListView->setGeometry(note_list_constants::LEFT_OFFSET_X - 5, y + 5, rect().width() - 15, m_tagListView->height()); - } else { - int y = 70; - auto const *noteListModel = static_cast(m_view->model()); - auto const idx = noteListModel->getNoteIndex(m_id); - if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { - y += 25; - } - int fourthYOffset = 0; - if (noteListModel->isFirstUnpinnedNote(idx)) { - fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; - } - int fifthYOffset = 0; - if (noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(idx)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } - int yOffsets = fourthYOffset + fifthYOffset; - - y += yOffsets; - - m_tagListView->setGeometry(note_list_constants::LEFT_OFFSET_X - 5, y, rect().width() - 15, m_tagListView->height()); - } + auto const *noteListModel = static_cast(m_view->model()); + auto const idx = noteListModel->getNoteIndex(m_id); + m_tagListView->setGeometry(note_list_constants::LEFT_OFFSET_X - 5, tagListTop(idx), rect().width() - 15, m_tagListView->height()); recalculateSize(); } @@ -536,6 +500,7 @@ void NoteListDelegateEditor::recalculateSize() } else { result.setHeight(result.height() - 10 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } + result.setHeight(qMax(result.height(), minimumRowHeight() + m_tagListView->height() + 2 + yOffsets)); emit updateSizeHint(m_id, result, idx); } diff --git a/src/notelistdelegateeditor.h b/src/notelistdelegateeditor.h index e0b6ac9d..279fdd6b 100644 --- a/src/notelistdelegateeditor.h +++ b/src/notelistdelegateeditor.h @@ -47,6 +47,9 @@ public slots: void nearDestroyed(int id, const QModelIndex &index); private: + int minimumContentHeight() const; + int minimumRowHeight() const; + int tagListTop(const QModelIndex &index) const; void paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintLabels(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintSeparator(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; From 287928b2281f04cdcf8c4cc13673f6dee6ee6a15 Mon Sep 17 00:00:00 2001 From: AJ0070 Date: Sun, 14 Jun 2026 14:22:42 +0530 Subject: [PATCH 2/6] fixed formatting on touched files --- src/notelistdelegate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notelistdelegate.h b/src/notelistdelegate.h index 8397eeff..15766f54 100644 --- a/src/notelistdelegate.h +++ b/src/notelistdelegate.h @@ -53,7 +53,7 @@ public slots: void animationFinished(NoteListState animationState); private: - int minimumContentHeight() const; + int minimumContentHeight() const; int minimumRowHeight(bool isInAllNotes) const; void paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintLabels(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; From 2c62c539d6f8a7aa7dbeeb9952cfe3f8c7d821b1 Mon Sep 17 00:00:00 2001 From: AJ0070 Date: Sun, 14 Jun 2026 14:36:30 +0530 Subject: [PATCH 3/6] removed isAllNotes parameter and used m_isInAllNotes --- src/notelistdelegate.cpp | 8 ++++---- src/notelistdelegate.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/notelistdelegate.cpp b/src/notelistdelegate.cpp index e7108135..9fbda22a 100644 --- a/src/notelistdelegate.cpp +++ b/src/notelistdelegate.cpp @@ -98,10 +98,10 @@ int NoteListDelegate::minimumContentHeight() const return note_list_constants::TOP_OFFSET_Y + titleHeight + dateHeight + contentHeight + note_list_constants::DATE_DESC_SPACE; } -int NoteListDelegate::minimumRowHeight(bool isInAllNotes) const +int NoteListDelegate::minimumRowHeight() const { int result = minimumContentHeight() + note_list_constants::LAST_EL_SEP_SPACE; - if (isInAllNotes) { + if (m_isInAllNotes) { const int folderLineHeight = qMax(QFontMetrics(m_titleFont).height(), 16) + note_list_constants::DESC_FOLDER_SPACE; result += folderLineHeight; } @@ -243,7 +243,7 @@ QSize NoteListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMode } int yOffsets = secondYOffset + thirdYOffset + fourthYOffset + fifthYOffset; - const int minimumHeight = minimumRowHeight(m_isInAllNotes) + yOffsets; + const int minimumHeight = minimumRowHeight() + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { @@ -299,7 +299,7 @@ QSize NoteListDelegate::bufferSizeHint(const QStyleOptionViewItem &option, const } int yOffsets = secondYOffset + thirdYOffset + fourthYOffset; - const int minimumHeight = minimumRowHeight(m_isInAllNotes) + yOffsets; + const int minimumHeight = minimumRowHeight() + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { diff --git a/src/notelistdelegate.h b/src/notelistdelegate.h index 15766f54..3840d352 100644 --- a/src/notelistdelegate.h +++ b/src/notelistdelegate.h @@ -54,7 +54,7 @@ public slots: private: int minimumContentHeight() const; - int minimumRowHeight(bool isInAllNotes) const; + int minimumRowHeight() const; void paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintLabels(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintSeparator(QPainter *painter, QRect rect, const QModelIndex &index) const; From f90b26fc052ff3e5129079d6cbc03ddfce6b1046 Mon Sep 17 00:00:00 2001 From: AJ0070 Date: Fri, 19 Jun 2026 16:45:11 +0530 Subject: [PATCH 4/6] addressed review --- src/notelistdelegate.cpp | 63 +++++++++++++++++++++------------- src/notelistdelegate.h | 1 + src/notelistdelegateeditor.cpp | 24 ++++++------- src/notelistdelegateeditor.h | 1 + 4 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/notelistdelegate.cpp b/src/notelistdelegate.cpp index 9fbda22a..0bc3dbb4 100644 --- a/src/notelistdelegate.cpp +++ b/src/notelistdelegate.cpp @@ -108,6 +108,15 @@ int NoteListDelegate::minimumRowHeight() const return result; } +int NoteListDelegate::sectionHeaderHeight(const QModelIndex &index, const NoteListModel &model) +{ + if (model.hasPinnedNote() && (model.isFirstPinnedNote(index) || model.isFirstUnpinnedNote(index))) { + return note_list_constants::SECTION_HEADER_HEIGHT; + } + + return 0; +} + void NoteListDelegate::setState(NoteListState NewState, QModelIndexList indexes) { if (animationState() != QTimeLine::NotRunning) { @@ -197,9 +206,8 @@ QSize NoteListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMode if (m_state == NoteListState::MoveIn) { result.setHeight(rowHeight); } else { - double rate = m_timeLine->currentFrame() / (m_maxFrame * 1.0); - double height = rowHeight * rate; - result.setHeight(int(height)); + const double rate = m_timeLine->currentFrame() / (m_maxFrame * 1.0); + result.setHeight(int(rowHeight * rate)); } } else { result.setHeight(rowHeight); @@ -211,18 +219,18 @@ QSize NoteListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMode auto isPinned = note.isPinnedNote(); if (isPinned) { if (noteListModel->isFirstPinnedNote(index)) { - result.setHeight(25); + result.setHeight(note_list_constants::SECTION_HEADER_HEIGHT); return result; } result.setHeight(0); return result; } if (noteListModel->hasPinnedNote() && noteListModel->isFirstUnpinnedNote(index)) { - result.setHeight(result.height() + 25); + result.setHeight(result.height() + note_list_constants::SECTION_HEADER_HEIGHT); } } else { if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(index) || noteListModel->isFirstUnpinnedNote(index))) { - result.setHeight(result.height() + 25); + result.setHeight(result.height() + note_list_constants::SECTION_HEADER_HEIGHT); } } int secondYOffset = 0; @@ -243,13 +251,15 @@ QSize NoteListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMode } int yOffsets = secondYOffset + thirdYOffset + fourthYOffset + fifthYOffset; - const int minimumHeight = minimumRowHeight() + yOffsets; + const int minimumHeight = minimumRowHeight() + sectionHeaderHeight(index, *noteListModel) + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { result.setHeight(result.height() - 10 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } - result.setHeight(qMax(result.height(), minimumHeight)); + if (!m_animatedIndexes.contains(index)) { + result.setHeight(qMax(result.height(), minimumHeight)); + } return result; } @@ -278,7 +288,7 @@ QSize NoteListDelegate::bufferSizeHint(const QStyleOptionViewItem &option, const auto isPinned = index.data(NoteListModel::NoteIsPinned).value(); if (isPinned) { if (noteListModel->isFirstPinnedNote(index)) { - result.setHeight(25); + result.setHeight(note_list_constants::SECTION_HEADER_HEIGHT); return result; } result.setHeight(0); @@ -299,7 +309,7 @@ QSize NoteListDelegate::bufferSizeHint(const QStyleOptionViewItem &option, const } int yOffsets = secondYOffset + thirdYOffset + fourthYOffset; - const int minimumHeight = minimumRowHeight() + yOffsets; + const int minimumHeight = minimumRowHeight() + sectionHeaderHeight(index, *noteListModel) + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { @@ -419,16 +429,18 @@ void NoteListDelegate::paintBackground(QPainter *painter, const QStyleOptionView if (m_animatedIndexes.contains(index)) { if (m_state == NoteListState::MoveIn) { if (model->hasPinnedNote() && (model->isFirstPinnedNote(index) || model->isFirstUnpinnedNote(index))) { - painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + bufferSize.height() - rowHeight + 25, option.rect.width(), rowHeight }, buffer, - QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); + painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + bufferSize.height() - rowHeight + note_list_constants::SECTION_HEADER_HEIGHT, + option.rect.width(), rowHeight }, + buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } else { painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + bufferSize.height() - rowHeight, option.rect.width(), rowHeight }, buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } } else { if (model->hasPinnedNote() && (model->isFirstPinnedNote(index) || model->isFirstUnpinnedNote(index))) { - painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + 25, option.rect.width(), option.rect.height() }, buffer, - QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); + painter->drawPixmap( + QRect{ option.rect.x(), option.rect.y() + note_list_constants::SECTION_HEADER_HEIGHT, option.rect.width(), option.rect.height() }, + buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } else { painter->drawPixmap(option.rect, buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } @@ -552,16 +564,17 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem if (m_state == NoteListState::MoveIn) { if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(index) || noteListModel->isFirstUnpinnedNote(index))) { - painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + bufferSize.height() - rowHeight + 25, option.rect.width(), rowHeight }, buffer, - QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); + painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + bufferSize.height() - rowHeight + note_list_constants::SECTION_HEADER_HEIGHT, + option.rect.width(), rowHeight }, + buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } else { painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + bufferSize.height() - rowHeight, option.rect.width(), rowHeight }, buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } } else { if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(index) || noteListModel->isFirstUnpinnedNote(index))) { - painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + 25, option.rect.width(), rowHeight }, buffer, - QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); + painter->drawPixmap(QRect{ option.rect.x(), option.rect.y() + note_list_constants::SECTION_HEADER_HEIGHT, option.rect.width(), rowHeight }, + buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } else { painter->drawPixmap(option.rect, buffer, QRect{ 0, bufferSize.height() - rowHeight, option.rect.width(), rowHeight }); } @@ -569,7 +582,7 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem if (noteListModel->hasPinnedNote()) { if (noteListModel->isFirstPinnedNote(index)) { QRect headerRect(option.rect.x() + (note_list_constants::LEFT_OFFSET_X / 2), option.rect.y(), - option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), 25); + option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), note_list_constants::SECTION_HEADER_HEIGHT); #ifdef __APPLE__ int iconPointSizeOffset = 0; #else @@ -589,7 +602,7 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem painter->drawText(headerRect, Qt::AlignLeft | Qt::AlignVCenter, "Pinned"); } else if (noteListModel->isFirstUnpinnedNote(index)) { QRect headerRect(option.rect.x() + (note_list_constants::LEFT_OFFSET_X / 2), option.rect.y() + fifthYOffset, - option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), 25); + option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), note_list_constants::SECTION_HEADER_HEIGHT); painter->setPen(m_contentColor); painter->setFont(m_headerFont); painter->drawText(headerRect, Qt::AlignLeft | Qt::AlignVCenter, "Notes"); @@ -623,7 +636,8 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem } if (noteListModel->isFirstPinnedNote(index)) { - QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), 25); + QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), + note_list_constants::SECTION_HEADER_HEIGHT); #ifdef __APPLE__ int iconPointSizeOffset = 0; #else @@ -641,14 +655,15 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem painter->setPen(m_contentColor); painter->setFont(m_headerFont); painter->drawText(headerRect, Qt::AlignLeft | Qt::AlignVCenter, "Pinned"); - rowPosY += 25; + rowPosY += note_list_constants::SECTION_HEADER_HEIGHT; } else if (noteListModel->hasPinnedNote() && noteListModel->isFirstUnpinnedNote(index)) { rowPosY += fifthYOffset; - QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), 25); + QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), + note_list_constants::SECTION_HEADER_HEIGHT); painter->setPen(m_contentColor); painter->setFont(m_headerFont); painter->drawText(headerRect, Qt::AlignLeft | Qt::AlignVCenter, "Notes"); - rowPosY += 25; + rowPosY += note_list_constants::SECTION_HEADER_HEIGHT; } if (m_view->isPinnedNotesCollapsed()) { auto isPinned = index.data(NoteListModel::NoteIsPinned).value(); diff --git a/src/notelistdelegate.h b/src/notelistdelegate.h index 3840d352..d04a4f80 100644 --- a/src/notelistdelegate.h +++ b/src/notelistdelegate.h @@ -36,6 +36,7 @@ class NoteListDelegate : public QStyledItemDelegate Theme::Value theme() const; void setIsInAllNotes(bool newIsInAllNotes); bool isInAllNotes() const; + static int sectionHeaderHeight(const QModelIndex &index, const NoteListModel &model); void clearSizeMap(); public slots: diff --git a/src/notelistdelegateeditor.cpp b/src/notelistdelegateeditor.cpp index af84fe68..112d2941 100644 --- a/src/notelistdelegateeditor.cpp +++ b/src/notelistdelegateeditor.cpp @@ -113,10 +113,7 @@ int NoteListDelegateEditor::tagListTop(const QModelIndex &index) const auto const *noteListModel = static_cast(m_view->model()); if (noteListModel != nullptr) { - auto idx = noteListModel->getNoteIndex(m_id); - if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { - top += 25; - } + top += NoteListDelegate::sectionHeaderHeight(index, *noteListModel); if (noteListModel->isFirstUnpinnedNote(index)) { top += note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; } @@ -147,7 +144,7 @@ void NoteListDelegateEditor::paintBackground(QPainter *painter, const QStyleOpti if (!m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; } - bufferRect.setY(bufferRect.y() + 25 + fifthYOffset); + bufferRect.setY(bufferRect.y() + note_list_constants::SECTION_HEADER_HEIGHT + fifthYOffset); } auto isPinned = index.data(NoteListModel::NoteIsPinned).toBool(); if (m_view->selectionModel()->isSelected(index)) { @@ -261,7 +258,8 @@ void NoteListDelegateEditor::paintLabels(QPainter *painter, const QStyleOptionVi } if (noteListModel->hasPinnedNote()) { if (noteListModel->isFirstPinnedNote(index)) { - QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, rowWidth - (note_list_constants::LEFT_OFFSET_X / 2), 25); + QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, rowWidth - (note_list_constants::LEFT_OFFSET_X / 2), + note_list_constants::SECTION_HEADER_HEIGHT); #ifdef __APPLE__ int iconPointSizeOffset = 0; #else @@ -279,14 +277,15 @@ void NoteListDelegateEditor::paintLabels(QPainter *painter, const QStyleOptionVi painter->setPen(m_contentColor); painter->setFont(m_headerFont); painter->drawText(headerRect, Qt::AlignLeft | Qt::AlignVCenter, "Pinned"); - rowPosY += 25; + rowPosY += note_list_constants::SECTION_HEADER_HEIGHT; } else if (noteListModel->isFirstUnpinnedNote(index)) { rowPosY += fifthYOffset; - QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, rowWidth - (note_list_constants::LEFT_OFFSET_X / 2), 25); + QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, rowWidth - (note_list_constants::LEFT_OFFSET_X / 2), + note_list_constants::SECTION_HEADER_HEIGHT); painter->setPen(m_contentColor); painter->setFont(m_headerFont); painter->drawText(headerRect, Qt::AlignLeft | Qt::AlignVCenter, "Notes"); - rowPosY += 25; + rowPosY += note_list_constants::SECTION_HEADER_HEIGHT; } } if (m_view->isPinnedNotesCollapsed()) { @@ -462,13 +461,13 @@ void NoteListDelegateEditor::recalculateSize() auto const *noteListModel = static_cast(m_view->model()); auto idx = noteListModel->getNoteIndex(m_id); if (noteListModel->hasPinnedNote() && (noteListModel->isFirstPinnedNote(idx) || noteListModel->isFirstUnpinnedNote(idx))) { - result.setHeight(result.height() + 25); + result.setHeight(result.height() + note_list_constants::SECTION_HEADER_HEIGHT); } if (noteListModel->hasPinnedNote() && m_view->isPinnedNotesCollapsed()) { auto isPinned = idx.data(NoteListModel::NoteIsPinned).value(); if (isPinned) { if (noteListModel->isFirstPinnedNote(idx)) { - result.setHeight(25); + result.setHeight(note_list_constants::SECTION_HEADER_HEIGHT); } else { result.setHeight(0); } @@ -500,7 +499,8 @@ void NoteListDelegateEditor::recalculateSize() } else { result.setHeight(result.height() - 10 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } - result.setHeight(qMax(result.height(), minimumRowHeight() + m_tagListView->height() + 2 + yOffsets)); + const int minimumHeight = minimumRowHeight() + NoteListDelegate::sectionHeaderHeight(idx, *noteListModel) + m_tagListView->height() + 2 + yOffsets; + result.setHeight(qMax(result.height(), minimumHeight)); emit updateSizeHint(m_id, result, idx); } diff --git a/src/notelistdelegateeditor.h b/src/notelistdelegateeditor.h index 279fdd6b..b458df63 100644 --- a/src/notelistdelegateeditor.h +++ b/src/notelistdelegateeditor.h @@ -18,6 +18,7 @@ auto constexpr TITLE_DATE_SPACE = 2; // space between title and date auto constexpr DATE_DESC_SPACE = 5; // space between date and description auto constexpr DESC_FOLDER_SPACE = 14; // space between description and folder name auto constexpr LAST_EL_SEP_SPACE = 12; // space between the last element and the separator +auto constexpr SECTION_HEADER_HEIGHT = 25; auto constexpr NEXT_NOTE_OFFSET = 0; // space between the separator and the next note underneath it auto constexpr PINNED_HEADER_TO_NOTE_SPACE = 0; // space between Pinned label to the pinned list auto constexpr UNPINNED_HEADER_TO_NOTE_SPACE = 0; // space between Notes label and the normal notes list From 6919e4622dc4e18e35d8fd96d2f367170933cc60 Mon Sep 17 00:00:00 2001 From: AJ0070 Date: Fri, 19 Jun 2026 17:15:07 +0530 Subject: [PATCH 5/6] fixed follow-up visual regression --- src/notelistdelegate.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/notelistdelegate.cpp b/src/notelistdelegate.cpp index 0bc3dbb4..9c1b6777 100644 --- a/src/notelistdelegate.cpp +++ b/src/notelistdelegate.cpp @@ -334,7 +334,16 @@ void NoteListDelegate::paintBackground(QPainter *painter, const QStyleOptionView QRect bufferRect = buffer.rect(); auto isPinned = index.data(NoteListModel::NoteIsPinned).toBool(); auto const *model = static_cast(m_view->model()); - if (model->hasPinnedNote() && model->isFirstPinnedNote(index) && static_cast(m_view)->isPinnedNotesCollapsed()) { + const bool isCollapsedPinnedHeader = m_view->isPinnedNotesCollapsed() && model->isFirstPinnedNote(index); + const int headerOffset = sectionHeaderHeight(index, *model); + if (headerOffset > 0 && !isCollapsedPinnedHeader) { + int fifthYOffset = 0; + if (!m_view->isPinnedNotesCollapsed() && model->isFirstUnpinnedNote(index)) { + fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; + } + bufferRect.setY(bufferRect.y() + headerOffset + fifthYOffset); + } + if (model->hasPinnedNote() && isCollapsedPinnedHeader) { bufferPainter.fillRect(bufferRect, QBrush(m_defaultColor)); } else if ((option.state & QStyle::State_Selected) == QStyle::State_Selected) { if (qApp->applicationState() == Qt::ApplicationActive) { From f5f7d000c15f870d338d2a0b9c3be09c788f617d Mon Sep 17 00:00:00 2001 From: Jash Date: Fri, 3 Jul 2026 17:09:31 +0530 Subject: [PATCH 6/6] addressed reviews --- src/notelistdelegate.cpp | 45 +++++++++++++++++++++------------------- src/notelistdelegate.h | 1 + 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/notelistdelegate.cpp b/src/notelistdelegate.cpp index 9c1b6777..3cdbcafe 100644 --- a/src/notelistdelegate.cpp +++ b/src/notelistdelegate.cpp @@ -117,6 +117,17 @@ int NoteListDelegate::sectionHeaderHeight(const QModelIndex &index, const NoteLi return 0; } +// Extra vertical gap inserted above the first unpinned note so it clears the +// pinned section. Used by sizeHint() (row height) and paintLabels() (header/body +// positions) so the row rect and the drawn content agree on where the body starts. +int NoteListDelegate::firstUnpinnedGap(const QModelIndex &index, const NoteListModel &model) const +{ + if (model.hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && model.isFirstUnpinnedNote(index)) { + return note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; + } + return 0; +} + void NoteListDelegate::setState(NoteListState NewState, QModelIndexList indexes) { if (animationState() != QTimeLine::NotRunning) { @@ -245,10 +256,7 @@ QSize NoteListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMode if (noteListModel->isFirstUnpinnedNote(index)) { fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; } - int fifthYOffset = 0; - if (noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } + int fifthYOffset = firstUnpinnedGap(index, *noteListModel); int yOffsets = secondYOffset + thirdYOffset + fourthYOffset + fifthYOffset; const int minimumHeight = minimumRowHeight() + sectionHeaderHeight(index, *noteListModel) + yOffsets; @@ -308,8 +316,11 @@ QSize NoteListDelegate::bufferSizeHint(const QStyleOptionViewItem &option, const fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; } + // The buffer is body-only: unlike sizeHint() it intentionally excludes the + // section header and the first-unpinned gap, because it is drawn bottom-aligned + // into the row. The floor is therefore the body minimum only (no header term). int yOffsets = secondYOffset + thirdYOffset + fourthYOffset; - const int minimumHeight = minimumRowHeight() + sectionHeaderHeight(index, *noteListModel) + yOffsets; + const int minimumHeight = minimumRowHeight() + yOffsets; if (m_isInAllNotes) { result.setHeight(result.height() - 2 + note_list_constants::LAST_EL_SEP_SPACE + yOffsets); } else { @@ -334,15 +345,13 @@ void NoteListDelegate::paintBackground(QPainter *painter, const QStyleOptionView QRect bufferRect = buffer.rect(); auto isPinned = index.data(NoteListModel::NoteIsPinned).toBool(); auto const *model = static_cast(m_view->model()); + // The buffer holds only the note body (bufferSizeHint() excludes the section + // header and the first-unpinned gap). It is drawn bottom-aligned into the row + // by the drawPixmap() calls below, so the header/gap space at the top of the + // row is reserved automatically. The buffer must NOT be shifted or grown here + // to make room for it, or the header offset is counted twice and the first + // unpinned row's background/body drifts down. const bool isCollapsedPinnedHeader = m_view->isPinnedNotesCollapsed() && model->isFirstPinnedNote(index); - const int headerOffset = sectionHeaderHeight(index, *model); - if (headerOffset > 0 && !isCollapsedPinnedHeader) { - int fifthYOffset = 0; - if (!m_view->isPinnedNotesCollapsed() && model->isFirstUnpinnedNote(index)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } - bufferRect.setY(bufferRect.y() + headerOffset + fifthYOffset); - } if (model->hasPinnedNote() && isCollapsedPinnedHeader) { bufferPainter.fillRect(bufferRect, QBrush(m_defaultColor)); } else if ((option.state & QStyle::State_Selected) == QStyle::State_Selected) { @@ -507,10 +516,7 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem fourthYOffset = note_list_constants::UNPINNED_HEADER_TO_NOTE_SPACE; } - int fifthYOffset = 0; - if (noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } + int fifthYOffset = firstUnpinnedGap(index, *noteListModel); int yOffsets = secondYOffset + thirdYOffset + fourthYOffset + fifthYOffset; double titleRectPosX = rowPosX + note_list_constants::LEFT_OFFSET_X; @@ -639,10 +645,7 @@ void NoteListDelegate::paintLabels(QPainter *painter, const QStyleOptionViewItem double rowPosX = option.rect.x(); double rowPosY = option.rect.y(); auto const *noteListModel = static_cast(m_view->model()); - int fifthYOffset = 0; - if (noteListModel->hasPinnedNote() && !m_view->isPinnedNotesCollapsed() && noteListModel->isFirstUnpinnedNote(index)) { - fifthYOffset = note_list_constants::LAST_PINNED_TO_UNPINNED_HEADER; - } + int fifthYOffset = firstUnpinnedGap(index, *noteListModel); if (noteListModel->isFirstPinnedNote(index)) { QRect headerRect(rowPosX + (note_list_constants::LEFT_OFFSET_X / 2), rowPosY, option.rect.width() - (note_list_constants::LEFT_OFFSET_X / 2), diff --git a/src/notelistdelegate.h b/src/notelistdelegate.h index d04a4f80..5d803d13 100644 --- a/src/notelistdelegate.h +++ b/src/notelistdelegate.h @@ -56,6 +56,7 @@ public slots: private: int minimumContentHeight() const; int minimumRowHeight() const; + int firstUnpinnedGap(const QModelIndex &index, const NoteListModel &model) const; void paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintLabels(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintSeparator(QPainter *painter, QRect rect, const QModelIndex &index) const;