Skip to content

Commit

Permalink
Lib sidebar: expand items to full width to maximize click-responsive …
Browse files Browse the repository at this point in the history
…area
  • Loading branch information
ronso0 committed Oct 26, 2024
1 parent 75a44d6 commit 8ebeda8
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/library/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ void Library::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) {
&WLibrarySidebar::deleteItem,
m_pSidebarModel,
&SidebarModel::deleteItem);
connect(m_pSidebarModel,
&SidebarModel::dataChanged,
pSidebarWidget,
&WLibrarySidebar::queueHeaderAdjustRequest);

connect(pSidebarWidget,
&WLibrarySidebar::setLibraryFocus,
Expand Down
69 changes: 68 additions & 1 deletion src/widget/wlibrarysidebar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
#include "moc_wlibrarysidebar.cpp"
#include "util/defs.h"
#include "util/dnd.h"
#include "util/duration.h"

constexpr int expand_time = 250;
// Delay for header adjust requests. 50 ms seems to be a good compromise between
// fast GUI update and long enough wait time for potential follow-up events.
constexpr int resize_header_delay = 50;

WLibrarySidebar::WLibrarySidebar(QWidget* parent)
: QTreeView(parent),
Expand All @@ -28,6 +32,15 @@ WLibrarySidebar::WLibrarySidebar(QWidget* parent)
header()->setStretchLastSection(false);
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
// Adjust header when an item's expand state has changed
connect(this,
&QTreeView::expanded,
this,
&WLibrarySidebar::queueHeaderAdjustRequest);
connect(this,
&QTreeView::collapsed,
this,
&WLibrarySidebar::queueHeaderAdjustRequest);
}

void WLibrarySidebar::contextMenuEvent(QContextMenuEvent *event) {
Expand Down Expand Up @@ -122,6 +135,8 @@ void WLibrarySidebar::dragMoveEvent(QDragMoveEvent * event) {
}
}

/// Timer events for delayed tree item expand/collapse on drag'n'drop and
/// header width adjustment when item layout changes
void WLibrarySidebar::timerEvent(QTimerEvent *event) {
if (event->timerId() == m_expandTimer.timerId()) {
QPoint pos = viewport()->mapFromGlobal(QCursor::pos());
Expand All @@ -133,6 +148,16 @@ void WLibrarySidebar::timerEvent(QTimerEvent *event) {
}
m_expandTimer.stop();
return;
} else if (event->timerId() == m_headerAdjustTimer.timerId()) {
// The header timer is a repeating QBasicTimer. Stop it when we can be
// sure that the last trigger event has been processed (add some margin
// since it's a Qt::CoarseTimer with an imprecision of +- 5%)
if (m_eventFrequencyTimer.elapsed().toIntegerMillis() > resize_header_delay * 1.9) {
m_headerAdjustTimer.stop();
return;
}
adjustHeaderStretch();
return;
}
QTreeView::timerEvent(event);
}
Expand Down Expand Up @@ -418,12 +443,54 @@ void WLibrarySidebar::focusSelectedIndex() {
}

bool WLibrarySidebar::event(QEvent* pEvent) {
if (pEvent->type() == QEvent::ToolTip) {
QVector<int> evIgnore = {
1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 23, 24, 25, 26, 31, 39,
43, 51, 68, 69, 71, 76, 78, 97, 100, 103, 104, 110, 207};
int iType = static_cast<int>(pEvent->type());
if (!evIgnore.contains(iType)) {
qWarning() << " XXX event" << iType << pEvent;
}

switch (pEvent->type()) {
case QEvent::ToolTip:
updateTooltip();
break;
case QEvent::Resize:
// Stretch the header when layout changes, e.g. viewport size changed due to
// scrollbar hide/show
case QEvent::LayoutRequest:
case QEvent::FontChange:
case QEvent::Polish:
case QEvent::PolishRequest:
queueHeaderAdjustRequest();
break;
default:
break;
}
return QTreeView::event(pEvent);
}

void WLibrarySidebar::queueHeaderAdjustRequest() {
m_eventFrequencyTimer.restart();
m_headerAdjustTimer.start(resize_header_delay, this);
}

/// Ensure tree items expand horizontally so we have the entire view width respond
/// to mouse clicks, i.e. no unresponsive space right next to short items.
void WLibrarySidebar::adjustHeaderStretch() {
// Disable stretching to trigger adjusting columns (ResizeToContents),
// i.e. full labels without elide
if (header()->stretchLastSection()) {
header()->setStretchLastSection(false);
}

// Enable stretching if there's space for the header to expand.
// Else, horizontal scrollbars are visible, nothing to do.
if (header()->sectionSize(0) < header()->width()) {
header()->setStretchLastSection(true);
}
}

void WLibrarySidebar::slotSetFont(const QFont& font) {
setFont(font);
// Resize the feature icons to be a bit taller than the label's capital
Expand Down
6 changes: 6 additions & 0 deletions src/widget/wlibrarysidebar.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QTreeView>

#include "library/library_decl.h"
#include "util/performancetimer.h"
#include "widget/wbasewidget.h"

class LibraryFeature;
Expand All @@ -31,6 +32,7 @@ class WLibrarySidebar : public QTreeView, public WBaseWidget {
public slots:
void selectIndex(const QModelIndex&);
void selectChildIndex(const QModelIndex&, bool selectItem = true);
void queueHeaderAdjustRequest();
void slotSetFont(const QFont& font);

signals:
Expand All @@ -45,7 +47,11 @@ class WLibrarySidebar : public QTreeView, public WBaseWidget {
private:
void focusSelectedIndex();
QModelIndex selectedIndex();
void adjustHeaderStretch();

QBasicTimer m_expandTimer;
QBasicTimer m_headerAdjustTimer;
PerformanceTimer m_eventFrequencyTimer;

QModelIndex m_hoverIndex;
};

0 comments on commit 8ebeda8

Please sign in to comment.