From 7d50367ba44518ab55aa40c98b351910611388c0 Mon Sep 17 00:00:00 2001 From: Tobias Hunger <tobias.hunger@nokia.com> Date: Mon, 30 Nov 2009 15:16:05 +0100 Subject: [PATCH] Improve visual appearance of DetailsWidget * Make toolswidget appear on hover. * Use a cached gradient in the background. * Remove layout fixup as that does not help on Linux and Windows anymore. Reevaluate after testing on Mac. Reviewed-by: dt --- src/libs/utils/detailswidget.cpp | 212 +++++++++++++++++-------------- src/libs/utils/detailswidget.h | 32 +++-- 2 files changed, 135 insertions(+), 109 deletions(-) diff --git a/src/libs/utils/detailswidget.cpp b/src/libs/utils/detailswidget.cpp index b0b9db7724c..982fbb2f822 100644 --- a/src/libs/utils/detailswidget.cpp +++ b/src/libs/utils/detailswidget.cpp @@ -9,31 +9,41 @@ using namespace Utils; -DetailsWidget::DetailsWidget(QWidget *parent) - : QWidget(parent), - m_summaryLabel(new QLabel(this)), - m_detailsButton(new DetailsButton(this)), - m_widget(0), - m_toolWidget(0), - m_grid(new QGridLayout(this)) +namespace { +const int MARGIN=8; +} +// This widget is using a grid layout and places the items +// in the following way: +// +// +------------+-------------------------+---------------+ +// + toolWidget | summaryLabel | detailsButton | +// +------------+-------------------------+---------------+ +// | | widget | +// +------------+-------------------------+---------------+ + +DetailsWidget::DetailsWidget(QWidget *parent) : + QWidget(parent), + m_detailsButton(new DetailsButton(this)), + m_grid(new QGridLayout(this)), + m_summaryLabel(new QLabel(this)), + m_toolWidget(0), + m_widget(0), + m_hovered(false) { - m_grid->setContentsMargins(4, 3, 4, 3); - m_summaryLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); m_summaryLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_summaryLabel->setContentsMargins(MARGIN, MARGIN, MARGIN, MARGIN); - m_grid->addWidget(m_summaryLabel, 0, 0); - m_grid->addWidget(m_detailsButton, 0, 2, 1, 1, Qt::AlignBottom); + m_grid->setContentsMargins(0, 0, 0, 0); + m_grid->setSpacing(0); + m_grid->addWidget(m_summaryLabel, 0, 1); + m_grid->addWidget(m_detailsButton, 0, 2, 1, 1, Qt::AlignCenter); - m_dummyWidget = new QWidget(this); - m_dummyWidget->setMaximumHeight(4); - m_dummyWidget->setMaximumHeight(4); - m_dummyWidget->setVisible(false); - m_grid->addWidget(m_dummyWidget, 2, 0, 1, 1); + m_detailsButton->setEnabled(false); - connect(m_detailsButton, SIGNAL(clicked()), - this, SLOT(detailsButtonClicked())); + connect(m_detailsButton, SIGNAL(toggled(bool)), + this, SLOT(setExpanded(bool))); } DetailsWidget::~DetailsWidget() @@ -43,53 +53,36 @@ DetailsWidget::~DetailsWidget() void DetailsWidget::paintEvent(QPaintEvent *paintEvent) { - //TL--> ___________ <-- TR - // | | - //ML-> ______________| <--MM | <--MR - // | | - //BL-> |_________________________| <-- BR - - QWidget::paintEvent(paintEvent); - if (!m_detailsButton->isToggled()) - return; - - const QRect detailsGeometry = m_detailsButton->geometry(); - const QRect widgetGeometry = m_widget ? m_widget->geometry() : QRect(x(), y() + height(), width(), 0); - - QPoint tl(detailsGeometry.topLeft()); - tl += QPoint(-3, -3); - - QPoint tr(detailsGeometry.topRight()); - tr += QPoint(3, -3); - - QPoint mm(detailsGeometry.left() - 3, widgetGeometry.top() - 3); - - QPoint ml(1, mm.y()); - - QPoint mr(tr.x(), mm.y()); - - int bottom = geometry().height() - 3; - QPoint bl(1, bottom); - QPoint br(tr.x(), bottom); - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - p.setPen(Qt::NoPen); - p.setBrush(palette().dark()); - p.drawRoundedRect(QRect(tl, br), 5, 5); - p.drawRoundedRect(QRect(ml, br), 5, 5); + const QRect paintArea(m_summaryLabel->geometry().topLeft(), + contentsRect().bottomRight()); + + if (!isExpanded()) { + if (m_collapsedPixmap.isNull() || + m_collapsedPixmap.size() != size()) + m_collapsedPixmap = cacheBackground(paintArea.size(), false); + p.drawPixmap(paintArea, m_collapsedPixmap); + } else { + if (m_expandedPixmap.isNull() || + m_expandedPixmap.size() != size()) + m_expandedPixmap = cacheBackground(paintArea.size(), true); + p.drawPixmap(paintArea, m_expandedPixmap); + } } -void DetailsWidget::detailsButtonClicked() +void DetailsWidget::enterEvent(QEvent * event) { - bool visible = m_detailsButton->isToggled(); - if (m_widget) - m_widget->setVisible(visible); - m_dummyWidget->setVisible(visible); - fixUpLayout(); + QWidget::enterEvent(event); + changeHoverState(true); +} + +void DetailsWidget::leaveEvent(QEvent * event) +{ + QWidget::leaveEvent(event); + changeHoverState(false); } void DetailsWidget::setSummaryText(const QString &text) @@ -102,15 +95,21 @@ QString DetailsWidget::summaryText() const return m_summaryLabel->text(); } -bool DetailsWidget::expanded() const +bool DetailsWidget::isExpanded() const { - return m_detailsButton->isToggled(); + if (!m_widget) + return false; + return m_widget->isVisible(); } -void DetailsWidget::setExpanded(bool v) +void DetailsWidget::setExpanded(bool visible) { - if (expanded() != v) - m_detailsButton->animateClick(); + if (!m_widget) + return; + + m_summaryLabel->setEnabled(!visible); + m_widget->setVisible(visible); + m_detailsButton->setChecked(visible); } QWidget *DetailsWidget::widget() const @@ -122,31 +121,40 @@ void DetailsWidget::setWidget(QWidget *widget) { if (m_widget == widget) return; - if (m_widget) { + + const bool wasExpanded(isExpanded()); + + if (m_widget) m_grid->removeWidget(m_widget); - m_widget = 0; - } + m_widget = widget; + if (widget) { - m_grid->addWidget(widget, 1, 0, 1, 3); - m_widget = widget; - bool visible = m_detailsButton->isToggled(); - m_widget->setVisible(visible); - m_dummyWidget->setVisible(visible); + m_widget->setContentsMargins(MARGIN, MARGIN, MARGIN, MARGIN); + m_grid->addWidget(widget, 1, 1, 1, 2); + setExpanded(wasExpanded); + } else { + m_detailsButton->setEnabled(false); } + m_detailsButton->setEnabled(0 != m_widget); } void DetailsWidget::setToolWidget(QWidget *widget) { if (m_toolWidget == widget) return; - if (m_toolWidget) { - m_grid->removeWidget(m_toolWidget); - m_toolWidget = 0; - } - if (widget) { - m_grid->addWidget(widget, 0, 1, 1, 1, Qt::AlignBottom); - m_toolWidget = widget; - } + + m_toolWidget = widget; + + if (!m_toolWidget) + return; + + m_toolWidget->adjustSize(); + m_grid->addWidget(m_toolWidget, 0, 0, 1, 1, Qt::AlignCenter); + + m_grid->setColumnMinimumWidth(0, m_toolWidget->width()); + m_grid->setRowMinimumHeight(0, m_toolWidget->height()); + + changeHoverState(m_hovered); } QWidget *DetailsWidget::toolWidget() const @@ -154,25 +162,35 @@ QWidget *DetailsWidget::toolWidget() const return m_toolWidget; } -// This function works around a qt limitation. -// In a deeply nested widget structure, nested layouts -// tell their parents per a delayed invocation that they -// need to repaint. Thus hiding a widget triggers -// one relayout (and repaint) for each level of widget -// nesting. We circumvent that, by forcing a update() -// activate() on the widget after hiding. -void DetailsWidget::fixUpLayout() +QPixmap DetailsWidget::cacheBackground(const QSize &size, bool expanded) { - if (!m_widget) - return; - QWidget *parent = m_widget; - QStack<QWidget *> widgets; - while((parent = parent->parentWidget()) && parent && parent->layout()) { - widgets.push(parent); - parent->layout()->update(); - } + QLinearGradient lg; + lg.setCoordinateMode(QGradient::ObjectBoundingMode); + lg.setFinalStop(0, 1); + + lg.setColorAt(0, palette().color(QPalette::Midlight)); + lg.setColorAt(1, palette().color(QPalette::Button)); + + QPixmap pixmap(size); + QPainter p(&pixmap); + p.setBrush(lg); + p.setPen(QPen(palette().color(QPalette::Mid))); + + p.drawRect(0, 0, size.width() - 1, size.height() - 1); - while(!widgets.isEmpty()) { - widgets.pop()->layout()->activate(); + if (expanded) { + p.drawLine(0, m_summaryLabel->height(), + size.width(), m_summaryLabel->height()); } + + return pixmap; +} + +void DetailsWidget::changeHoverState(bool hovered) +{ + m_hovered = hovered; + if (!m_toolWidget) + return; + + m_toolWidget->setVisible(m_hovered); } diff --git a/src/libs/utils/detailswidget.h b/src/libs/utils/detailswidget.h index 781fc4026ed..6304dc3c3c6 100644 --- a/src/libs/utils/detailswidget.h +++ b/src/libs/utils/detailswidget.h @@ -3,6 +3,7 @@ #include "utils_global.h" +#include <QtGui/QPixmap> #include <QtGui/QWidget> QT_BEGIN_NAMESPACE @@ -17,7 +18,8 @@ class QTCREATOR_UTILS_EXPORT DetailsWidget : public QWidget { Q_OBJECT Q_PROPERTY(QString summaryText READ summaryText WRITE setSummaryText DESIGNABLE true) - Q_PROPERTY(bool expanded READ expanded WRITE setExpanded DESIGNABLE true) + Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded DESIGNABLE true) + public: DetailsWidget(QWidget *parent = 0); ~DetailsWidget(); @@ -25,8 +27,7 @@ public: void setSummaryText(const QString &text); QString summaryText() const; - bool expanded() const; - void setExpanded(bool); + bool isExpanded() const; void setWidget(QWidget *widget); QWidget *widget() const; @@ -34,21 +35,28 @@ public: void setToolWidget(QWidget *widget); QWidget *toolWidget() const; +public slots: + void setExpanded(bool); + protected: void paintEvent(QPaintEvent *paintEvent); - -private slots: - void detailsButtonClicked(); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); private: - void fixUpLayout(); - QLabel *m_summaryLabel; - DetailsButton *m_detailsButton; + QPixmap cacheBackground(const QSize &size, bool expanded); + void changeHoverState(bool hovered); - QWidget *m_widget; - QWidget *m_toolWidget; - QWidget *m_dummyWidget; + DetailsButton *m_detailsButton; QGridLayout *m_grid; + QLabel *m_summaryLabel; + QWidget *m_toolWidget; + QWidget *m_widget; + + QPixmap m_collapsedPixmap; + QPixmap m_expandedPixmap; + + bool m_hovered; }; } -- GitLab