/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** No Commercial Usage ** ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "crumblepath.h" #include "stylehelper.h" #include #include #include #include #include #include #include #include #include namespace Utils { static const int ArrowBorderSize = 12; class CrumblePathButton : public QPushButton { public: enum SegmentType { LastSegment = 1, MiddleSegment = 2, FirstSegment = 4 }; explicit CrumblePathButton(const QString &title, QWidget *parent = 0); void setSegmentType(int type); void select(bool s); void setData(QVariant data); QVariant data() const; protected: void paintEvent(QPaintEvent *); void mouseMoveEvent(QMouseEvent *e); void leaveEvent(QEvent *); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); private: void tintImages(); private: bool m_isHovering; bool m_isPressed; bool m_isSelected; bool m_isEnd; QColor m_baseColor; QImage m_segment; QImage m_segmentEnd; QImage m_segmentSelected; QImage m_segmentSelectedEnd; QImage m_segmentHover; QImage m_segmentHoverEnd; QImage m_triangleIcon; QPoint m_textPos; QVariant m_data; }; CrumblePathButton::CrumblePathButton(const QString &title, QWidget *parent) : QPushButton(title, parent), m_isHovering(false), m_isPressed(false), m_isSelected(false), m_isEnd(true) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); setToolTip(title); setMinimumHeight(24); setMaximumHeight(24); setMouseTracking(true); m_textPos.setX(18); m_textPos.setY(height()); m_baseColor = StyleHelper::baseColor(); m_segment = QImage(":/utils/images/crumblepath-segment.png"); m_segmentSelected = QImage(":/utils/images/crumblepath-segment-selected.png"); m_segmentHover = QImage(":/utils/images/crumblepath-segment-hover.png"); m_segmentEnd = QImage(":/utils/images/crumblepath-segment-end.png"); m_segmentSelectedEnd = QImage(":/utils/images/crumblepath-segment-selected-end.png"); m_segmentHoverEnd = QImage(":/utils/images/crumblepath-segment-hover-end.png"); m_triangleIcon = QImage(":/utils/images/triangle_vert.png"); tintImages(); } void CrumblePathButton::paintEvent(QPaintEvent *) { QPainter p(this); QRect geom(0, 0, geometry().width(), geometry().height()); if (StyleHelper::baseColor() != m_baseColor) { m_baseColor = StyleHelper::baseColor(); tintImages(); } if (m_isEnd) { if (m_isPressed || m_isSelected) { Utils::StyleHelper::drawCornerImage(m_segmentSelectedEnd, &p, geom, 2, 0, 2, 0); } else if (m_isHovering) { Utils::StyleHelper::drawCornerImage(m_segmentHoverEnd, &p, geom, 2, 0, 2, 0); } else { Utils::StyleHelper::drawCornerImage(m_segmentEnd, &p, geom, 2, 0, 2, 0); } } else { if (m_isPressed || m_isSelected) { Utils::StyleHelper::drawCornerImage(m_segmentSelected, &p, geom, 2, 0, 12, 0); } else if (m_isHovering) { Utils::StyleHelper::drawCornerImage(m_segmentHover, &p, geom, 2, 0, 12, 0); } else { Utils::StyleHelper::drawCornerImage(m_segment, &p, geom, 2, 0, 12, 0); } } p.setPen(StyleHelper::panelTextColor()); QFontMetrics fm(p.font()); QString textToDraw = fm.elidedText(text(), Qt::ElideRight, geom.width() - m_textPos.x()); p.drawText(QRectF(m_textPos.x(), 4, geom.width(), geom.height()), textToDraw); if (menu()) { p.drawImage(geom.width() - m_triangleIcon.width() - 6, geom.center().y() - m_triangleIcon.height()/2, m_triangleIcon); } } void CrumblePathButton::tintImages() { StyleHelper::tintImage(m_segmentEnd, m_baseColor); StyleHelper::tintImage(m_segmentSelectedEnd, m_baseColor); StyleHelper::tintImage(m_segmentHoverEnd, m_baseColor); StyleHelper::tintImage(m_segmentSelected, m_baseColor); StyleHelper::tintImage(m_segmentHover, m_baseColor); StyleHelper::tintImage(m_segment, m_baseColor); } void CrumblePathButton::leaveEvent(QEvent *e) { QPushButton::leaveEvent(e); m_isHovering = false; update(); } void CrumblePathButton::mouseMoveEvent(QMouseEvent *e) { QPushButton::mouseMoveEvent(e); m_isHovering = true; update(); } void CrumblePathButton::mousePressEvent(QMouseEvent *e) { QPushButton::mousePressEvent(e); m_isPressed = true; update(); } void CrumblePathButton::mouseReleaseEvent(QMouseEvent *e) { QPushButton::mouseReleaseEvent(e); m_isPressed = false; update(); } void CrumblePathButton::select(bool s) { m_isSelected = s; update(); } void CrumblePathButton::setSegmentType(int type) { bool useLeftPadding = !(type & FirstSegment); m_isEnd = (type & LastSegment); m_textPos.setX(useLeftPadding ? 18 : 4); } void CrumblePathButton::setData(QVariant data) { m_data = data; } QVariant CrumblePathButton::data() const { return m_data; } /////////////////////////////////////////////////////////////////////////////// struct CrumblePathPrivate { explicit CrumblePathPrivate(CrumblePath *q); QColor m_baseColor; QList m_buttons; QWidget *m_background; }; CrumblePathPrivate::CrumblePathPrivate(CrumblePath *q) : m_baseColor(StyleHelper::baseColor()), m_background(new QWidget(q)) { } // // CrumblePath // CrumblePath::CrumblePath(QWidget *parent) : QWidget(parent), d(new CrumblePathPrivate(this)) { setMinimumHeight(25); setMaximumHeight(25); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); setBackgroundStyle(); d->m_background->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); } CrumblePath::~CrumblePath() { qDeleteAll(d->m_buttons); d->m_buttons.clear(); } void CrumblePath::selectIndex(int index) { if ((index > -1) && (index < d->m_buttons.length())) d->m_buttons[index]->select(true); } QVariant CrumblePath::dataForIndex(int index) const { if ((index > -1) && (index < d->m_buttons.length())) return d->m_buttons[index]->data(); return QVariant(); } void CrumblePath::setBackgroundStyle() { d->m_background->setStyleSheet("QWidget { background-color:" + d->m_baseColor.name() + ";}"); } void CrumblePath::pushElement(const QString &title, const QVariant data) { CrumblePathButton *newButton = new CrumblePathButton(title, this); newButton->hide(); connect(newButton, SIGNAL(clicked()), SLOT(mapClickToIndex())); int segType = CrumblePathButton::MiddleSegment; if (!d->m_buttons.isEmpty()) { if (d->m_buttons.length() == 1) segType = segType | CrumblePathButton::FirstSegment; d->m_buttons.last()->setSegmentType(segType); } else { segType = CrumblePathButton::FirstSegment | CrumblePathButton::LastSegment; newButton->setSegmentType(segType); } newButton->setData(data); d->m_buttons.append(newButton); resizeButtons(); } void CrumblePath::addChild(const QString &title, const QVariant data) { QTC_ASSERT(d->m_buttons.count()>0,return); QPushButton *lastButton = d->m_buttons.last(); QMenu *childList = lastButton->menu(); if (childList == 0) childList = new QMenu(lastButton); QAction *childAction = new QAction(title, lastButton); childAction->setData(data); connect(childAction, SIGNAL(triggered()), this, SLOT(mapClickToIndex())); childList->addAction(childAction); lastButton->setMenu(childList); } void CrumblePath::popElement() { QWidget *last = d->m_buttons.last(); d->m_buttons.removeLast(); last->setParent(0); last->deleteLater(); int segType = CrumblePathButton::MiddleSegment | CrumblePathButton::LastSegment; if (!d->m_buttons.isEmpty()) { if (d->m_buttons.length() == 1) segType = CrumblePathButton::FirstSegment | CrumblePathButton::LastSegment; d->m_buttons.last()->setSegmentType(segType); } resizeButtons(); } void CrumblePath::clear() { while (!d->m_buttons.isEmpty()) { popElement(); } } void CrumblePath::resizeEvent(QResizeEvent *) { resizeButtons(); } void CrumblePath::resizeButtons() { int totalWidthLeft = width(); if (d->m_buttons.length() >= 1) { QPoint nextElementPosition(0,0); d->m_buttons[0]->raise(); // rearrange all items so that the first item is on top (added last). // compute relative sizes QList sizes; int totalSize = 0; for(int i = 0; i < d->m_buttons.length() ; ++i) { CrumblePathButton *button = d->m_buttons[i]; QFontMetrics fm(button->font()); int originalSize = ArrowBorderSize + fm.width(button->text()) + ArrowBorderSize + 12; sizes << originalSize; totalSize += originalSize - ArrowBorderSize; } for (int i = 0; i < d->m_buttons.length() ; ++i) { CrumblePathButton *button = d->m_buttons[i]; int candidateSize = (sizes[i]*totalWidthLeft)/totalSize; if (candidateSize < ArrowBorderSize) candidateSize = ArrowBorderSize; if (candidateSize > sizes[i]*1.3) candidateSize = sizes[i]*1.3; button->setMinimumWidth(candidateSize); button->setMaximumWidth(candidateSize); button->move(nextElementPosition); nextElementPosition.rx() += button->width() - ArrowBorderSize; button->show(); if (i > 0) button->stackUnder(d->m_buttons[i - 1]); } } d->m_background->setGeometry(0,0, width(), height()); d->m_background->update(); } void CrumblePath::mapClickToIndex() { QObject *element = sender(); if (QString("QAction") == element->metaObject()->className()) { emit elementClicked(static_cast(element)->data().toInt()); } else if (QString("QPushButton") == element->metaObject()->className()) { emit elementClicked(static_cast(element)->data().toInt()); } } void CrumblePath::paintEvent(QPaintEvent *event) { if (StyleHelper::baseColor() != d->m_baseColor) { d->m_baseColor = StyleHelper::baseColor(); setBackgroundStyle(); } QWidget::paintEvent(event); } } // namespace Utils