diff options
| author | Christian Kamm <christian.d.kamm@nokia.com> | 2010-02-26 09:40:50 +0100 |
|---|---|---|
| committer | Christian Kamm <christian.d.kamm@nokia.com> | 2010-02-26 09:40:50 +0100 |
| commit | 40c3f2af63cd3c584f355e49d1b2b19be579ce60 (patch) | |
| tree | 13a37759f849b9b9a30c8462e112cca4a75941cc | |
Initial version of the remote control widget.
31 files changed, 3749 insertions, 0 deletions
diff --git a/example/example.pro b/example/example.pro new file mode 100644 index 0000000..9b8f895 --- /dev/null +++ b/example/example.pro @@ -0,0 +1,16 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-02-25T15:28:57 +# +#------------------------------------------------- + +QT += core gui + +TARGET = example +TEMPLATE = app + +INCLUDEPATH += ../library +LIBS += -L../library -lremotecontrolwidget -Wl,-rpath=../library + +SOURCES += main.cpp + diff --git a/example/main.cpp b/example/main.cpp new file mode 100644 index 0000000..1274a5b --- /dev/null +++ b/example/main.cpp @@ -0,0 +1,13 @@ +#include <QtGui/QApplication> +#include "remotecontrolwidget.h" +#include "locationui.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + RemoteControlWidget w; + LocationUi l(&w); + + w.show(); + return a.exec(); +} diff --git a/library/locationui.cpp b/library/locationui.cpp new file mode 100644 index 0000000..4d1f6ff --- /dev/null +++ b/library/locationui.cpp @@ -0,0 +1,76 @@ +#include "locationui.h" + +#include "optionsitem.h" +#include "remotecontrolwidget.h" + +#include <QtGui/QLineEdit> +#include <QtGui/QDoubleValidator> +#include <QtGui/QPushButton> +#include <QtGui/QBoxLayout> +#include <QtGui/QDateTimeEdit> + +LocationUi::LocationUi(RemoteControlWidget *w) + : QObject(w) + , mLatitudeEdit(0) + , mLongitudeEdit(0) + , mAltitudeEdit(0) + , mTimeEdit(0) +{ + QStringList tags; + QList<OptionsItem *> optionsList; + + mLatitudeEdit = new QLineEdit("52.5056819"); + mLatitudeEdit->setValidator(new QDoubleValidator(-90, 90, 10, this)); + OptionsItem *item = new OptionsItem(tr("Latitude"), mLatitudeEdit); + //connect(mLatitudeEdit, SIGNAL(editingFinished()), SLOT(triggerLocationInfoChange())); + item->setTags(tags); + optionsList << item; + + mLongitudeEdit = new QLineEdit("13.3232027"); + mLatitudeEdit->setValidator(new QDoubleValidator(-180, 180, 10, this)); + item = new OptionsItem(tr("Longitude"), mLongitudeEdit); + //connect(mLongitudeEdit, SIGNAL(editingFinished()), SLOT(triggerLocationInfoChange())); + item->setTags(tags); + optionsList << item; + + mAltitudeEdit = new QLineEdit("13.3232027"); + mAltitudeEdit->setValidator(new QDoubleValidator(-15000, 15000, 10, this)); + item = new OptionsItem(tr("Altitude"), mAltitudeEdit); + //connect(mAltitudeEdit, SIGNAL(editingFinished()), SLOT(triggerLocationInfoChange())); + item->setTags(tags); + optionsList << item; + + mTimeEdit = new QDateTimeEdit(); + QPushButton *locationTimeButton = new QPushButton(tr("Now")); + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(0, 0, 0, 0); + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->addWidget(mTimeEdit); + vLayout->addWidget(locationTimeButton); + hLayout->addLayout(vLayout); + QWidget *tmp = new QWidget(); + tmp->setLayout(hLayout); + //connect(mTimeEdit, SIGNAL(dateTimeChanged(const QDateTime &)), SLOT(triggerLocationInfoChange())); + connect(locationTimeButton, SIGNAL(clicked()), this, SLOT(updateLocationTime())); + item = new OptionsItem(tr("Timestamp"), tmp); + item->setTags(tags); + optionsList << item; + + w->addToolBoxPage(tr("Location"), optionsList); +} + +void LocationUi::updateLocationTime() +{ + mTimeEdit->setDateTime(QDateTime::currentDateTime()); +} + +void LocationUi::setLocation() +{ + /* + mLatitudeEdit->setText(QString::number(mLocation->latitude(), 'f', 8)); + mLongitudeEdit->setText(QString::number(mLocation->longitude(), 'f', 8)); + mAltitudeEdit->setText(QString::number(mLocation->altitude(), 'f', 8)); + mTimeEdit->setDateTime(mLocation->dateTime()); + */ +} + diff --git a/library/locationui.h b/library/locationui.h new file mode 100644 index 0000000..53d0d14 --- /dev/null +++ b/library/locationui.h @@ -0,0 +1,34 @@ +#ifndef LOCATIONUI_H +#define LOCATIONUI_H + +#include "remotecontrolwidget_global.h" + +#include <QtCore/QObject> + +class RemoteControlWidget; +class QLineEdit; +class QDateTimeEdit; + +class REMOTECONTROLWIDGETSHARED_EXPORT LocationUi : public QObject +{ + Q_OBJECT +public: + LocationUi(RemoteControlWidget* w); + +public slots: + void setLocation(/* LocationData */); + +signals: + void locationChanged(/* LocationData */); + +private slots: + void updateLocationTime(); + +private: + QLineEdit *mLatitudeEdit; + QLineEdit *mLongitudeEdit; + QLineEdit *mAltitudeEdit; + QDateTimeEdit *mTimeEdit; +}; + +#endif // LOCATIONUI_H diff --git a/library/optionsitem.cpp b/library/optionsitem.cpp new file mode 100644 index 0000000..91d117d --- /dev/null +++ b/library/optionsitem.cpp @@ -0,0 +1,149 @@ +#include "optionsitem.h" + +#include <QtCore/QString> +#include <QtGui/QAbstractButton> +#include <QtGui/QBoxLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QLabel> + +OptionsItem::OptionsItem(const QString &name, QWidget *inputWidget, bool fullWidth, QObject *parent) + : QObject(parent) + , mLabel(0) + , mInputWidget(inputWidget) + , mAdvancedPage(0) + , mHidden(false) + , mAdvanced(false) +{ + if (fullWidth) + mType = FullWidthType; + else { + mType = DefaultType; + + mInputLayout = new QHBoxLayout(); + mInputLayout->addStretch(); + mInputLayout->addWidget(mInputWidget); + } + if (name != 0 && !name.isEmpty()) + mLabel = new QLabel(name); +} + +OptionsItem::~OptionsItem() +{} + +bool OptionsItem::addTag(const QString &tag) +{ + if (!mTags.contains(tag.toLower())) { + mTags.append(tag.toLower()); + return true; + } + return false; +} + +QLabel *OptionsItem::label() const +{ + return mLabel; +} + +QWidget *OptionsItem::inputWidget() const +{ + return mInputWidget; +} + +QHBoxLayout *OptionsItem::inputLayout() const +{ + return mInputLayout; +} + +bool OptionsItem::setAdvancedPage(OptionsItem *advancedPage) +{ + QAbstractButton *inputButton = qobject_cast<QAbstractButton *>(mInputWidget); + if (!inputButton) + return false; + mAdvancedPage = advancedPage; + mType = AdvancedType; + mAdvancedPage->setTags(mTags); + mAdvancedPage->setVisible(false, true); + disconnect(inputButton, SIGNAL(clicked()), this, SLOT(buttonClicked())); + connect(inputButton, SIGNAL(clicked()), SLOT(buttonClicked())); + return true; +} + +OptionsItem *OptionsItem::advancedPage() const +{ + return mAdvancedPage; +} + +void OptionsItem::setVisible(bool visible, bool explicitly) +{ + if (mLabel) + mLabel->setVisible(visible); + mInputWidget->setVisible(visible); + if (!visible && explicitly) + mHidden = true; + else + mHidden = false; +} + +bool OptionsItem::addTags(const QStringList &tags) +{ + bool ret = true; + foreach(const QString &tag, tags) + if (!addTag(tag)) + ret = false; + return ret; +} + +bool OptionsItem::removeTag(const QString &tag) +{ + return (mTags.removeAll(tag.toLower()) > 0); +} + +bool OptionsItem::removeTags(const QStringList &tags) +{ + bool ret = true; + foreach (const QString &tag, tags) + if (!removeTag(tag)) + ret = false; + return ret; +} + +bool OptionsItem::setTags(const QStringList &tags) +{ + mTags.clear(); + return addTags(tags); +} + +bool OptionsItem::matchTag(const QString &tag) const +{ + if (mLabel && mLabel->text().toLower().contains(tag.toLower())) + return true; + foreach (const QString &tagInList, mTags) + if (tagInList.contains(tag.toLower())) + return true; + return false; +} + +OptionsItem::OptionsType OptionsItem::type() const +{ + return mType; +} + +bool OptionsItem::isExplicitlyHidden() const +{ + return mHidden; +} + +void OptionsItem::setAdvanced(bool advanced) +{ + mAdvanced = advanced; +} + +bool OptionsItem::isAdvanced() const +{ + return mAdvanced; +} + +void OptionsItem::buttonClicked() +{ + emit toggleAdvanced(this); +} diff --git a/library/optionsitem.h b/library/optionsitem.h new file mode 100644 index 0000000..e6130ca --- /dev/null +++ b/library/optionsitem.h @@ -0,0 +1,63 @@ +#ifndef OPTIONSITEM_H +#define OPTIONSITEM_H + +#include "remotecontrolwidget_global.h" + +#include <QtCore/QObject> +#include <QtCore/QStringList> + +class QLayout; +class QLabel; +class QHBoxLayout; + +class REMOTECONTROLWIDGETSHARED_EXPORT OptionsItem: public QObject +{ + Q_OBJECT +public: + enum OptionsType { + DefaultType, + FullWidthType, + AdvancedType + }; + + OptionsItem(const QString &name, QWidget *inputWidget, bool fullWidth = false, QObject *parent = 0); + virtual ~OptionsItem(); + + QLabel *label() const; + QWidget *inputWidget() const; + QHBoxLayout *inputLayout() const; + + void setVisible(bool visible, bool explicitly = false); + bool setAdvancedPage(OptionsItem *advancedPage); + OptionsItem *advancedPage() const; + + bool addTag(const QString &tag); + bool addTags(const QStringList &tags); + bool removeTag(const QString &tag); + bool removeTags(const QStringList &tags); + bool setTags(const QStringList &tags); + bool matchTag(const QString &tag) const; + OptionsType type() const; + bool isExplicitlyHidden() const; + void setAdvanced(bool advanced = true); + bool isAdvanced() const; + +private: + friend class ToolBoxPage; + QLabel *mLabel; + QWidget *mInputWidget; + QHBoxLayout *mInputLayout; + OptionsItem *mAdvancedPage; + QStringList mTags; + OptionsType mType; + bool mHidden; + bool mAdvanced; + +private slots: + void buttonClicked(); + +signals: + void toggleAdvanced(OptionsItem *item); +}; + +#endif //OPTIONSITEM_H diff --git a/library/remotecontrolwidget.cpp b/library/remotecontrolwidget.cpp new file mode 100644 index 0000000..33adc40 --- /dev/null +++ b/library/remotecontrolwidget.cpp @@ -0,0 +1,182 @@ +#include "remotecontrolwidget.h" +#include "toolbox.h" +#include "optionsitem.h" +#include "style/filterlineedit.h" +#include "style/manhattanstyle.h" +#include "style/styledbar.h" + +#include <qmath.h> +#include <QtCore/QSettings> +#include <QtCore/QThread> +#include <QtCore/QDir> +#include <QtGui/QApplication> +#include <QtGui/QDesktopWidget> +#include <QtGui/QScrollBar> +#include <QtGui/QMessageBox> +#include <QtGui/QToolButton> +#include <QtGui/QCloseEvent> +#include <QtGui/QScrollArea> +#include <QtGui/QFrame> +#include <QtGui/QBoxLayout> +#include <QtGui/QLabel> + +RemoteControlWidget::RemoteControlWidget(QWidget *parent) + : QWidget(parent) +{ + QString baseName = style()->objectName(); +#ifdef Q_WS_X11 + if (baseName == QLatin1String("windows")) { + // Sometimes we get the standard windows 95 style as a fallback + // e.g. if we are running on a KDE4 desktop + QByteArray desktopEnvironment = qgetenv("DESKTOP_SESSION"); + if (desktopEnvironment == "kde") + baseName = QLatin1String("plastique"); + else + baseName = QLatin1String("cleanlooks"); + } +#endif + mManhattanStyle = new ManhattanStyle(baseName); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->setMargin(0); + mainLayout->setSpacing(0); + setLayout(mainLayout); + + StyledBar *menuBar = initializeMenuBar(); + mainLayout->addWidget(menuBar); + + QLabel *simulateLabel = new QLabel(tr("Simulate")); + QMargins labelMargins = simulateLabel->contentsMargins(); + QFont labelFont = simulateLabel->font(); + labelFont.setBold(true); + labelFont.setPointSize(11); + simulateLabel->setFont(labelFont); + simulateLabel->setStyle(mManhattanStyle); + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(9, 0, labelMargins.right(), 0); + hLayout->addWidget(simulateLabel); + StyledBar *simulateBar = new StyledBar(); + simulateBar->setStyle(mManhattanStyle); + simulateBar->setLayout(hLayout); + mainLayout->addWidget(simulateBar); + + QScrollArea *simulateArea = new QScrollArea; + simulateArea->setWidgetResizable(true); + + mToolBox = new ToolBox(false); + mToolBox->setStyle(mManhattanStyle); + simulateArea->setWidget(mToolBox); + mainLayout->addWidget(simulateArea); + + // Some styles have extra up/down buttons in the scrollbar. We only support + // the plain scrollbars and therefore force the style to be derived from cleanlooks for them. + QStyle *forceScrollbarStyle = new ManhattanStyle("cleanlooks"); + simulateArea->setStyle(forceScrollbarStyle); + simulateArea->verticalScrollBar()->setStyle(forceScrollbarStyle); + simulateArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + simulateArea->verticalScrollBar()->setProperty("styledScrollBar", true); + + mViewButton = new QToolButton(); + mViewButton->setFont(labelFont); + mViewButton->setText(tr("View")); + mViewButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + mViewButton->setArrowType(Qt::RightArrow); + mViewButton->setSizePolicy(QSizePolicy::Expanding, mViewButton->sizePolicy().verticalPolicy()); + mViewButton->setStyle(mManhattanStyle); + hLayout = new QHBoxLayout(); + hLayout->setMargin(0); + hLayout->addWidget(mViewButton); + StyledBar *viewBar = new StyledBar(); + viewBar->setStyle(mManhattanStyle); + viewBar->setLayout(hLayout); + mainLayout->addWidget(viewBar); + connect(mViewButton, SIGNAL(clicked()), SLOT(toggleViewPaneVisible())); + + mViewArea = new QFrame(); + initializeViewArea(mViewArea); + mainLayout->addWidget(mViewArea); +} + +RemoteControlWidget::~RemoteControlWidget() +{ + +} + +void RemoteControlWidget::filtersChanged() +{ + mToolBox->filtersChanged(mFilterLineEdit->typedText()); +} + +void RemoteControlWidget::addToolBoxPage(const QString &title, const QList<OptionsItem *> &options) +{ + mToolBox->addPage(title, options); +} + +void RemoteControlWidget::addMenuButton(QToolButton *button) +{ + mMenuLayout->addWidget(button); +} + +void RemoteControlWidget::writeSettings(const QString &vendor, const QString &name) const +{ + QSettings settings(vendor, name); + + settings.beginGroup("ConfigurationWidget"); + settings.setValue("size", size()); + settings.setValue("pos", pos()); + settings.endGroup(); +} + +void RemoteControlWidget::readSettings(const QString &vendor, const QString &name) +{ + QSettings settings(vendor, name); + + settings.beginGroup("ConfigurationWidget"); + if (settings.contains("size")) + resize(settings.value("size").toSize()); + if (settings.contains("pos")) + move(settings.value("pos").toPoint()); + settings.endGroup(); +} + +void RemoteControlWidget::toggleViewPaneVisible() +{ + if (mViewArea->isHidden()) { + mViewArea->show(); + mViewButton->setArrowType(Qt::RightArrow); + } else { + mViewArea->hide(); + mViewButton->setArrowType(Qt::DownArrow); + } +} + +StyledBar *RemoteControlWidget::initializeMenuBar() +{ + mMenuLayout = new QHBoxLayout; + mMenuLayout->setSpacing(0); + mMenuLayout->setMargin(0); + + QHBoxLayout *toplayout = new QHBoxLayout; + toplayout->setSpacing(0); + toplayout->setMargin(0); + toplayout->addLayout(mMenuLayout); + toplayout->addStretch(); + mFilterLineEdit = new FilterLineEdit(); + mFilterLineEdit->setStyle(mManhattanStyle); + connect(mFilterLineEdit, SIGNAL(filterChanged(const QString &)), SLOT(filtersChanged())); + toplayout->addWidget(mFilterLineEdit); + + StyledBar *bar = new StyledBar; + bar->setLayout(toplayout); + bar->setStyle(mManhattanStyle); + return bar; +} + +void RemoteControlWidget::initializeViewArea(QFrame *f) +{ + QVBoxLayout *layout = new QVBoxLayout; + QLabel *test = new QLabel(f); + test->setText("Test!"); + layout->addWidget(test); + f->setLayout(layout); +} diff --git a/library/remotecontrolwidget.h b/library/remotecontrolwidget.h new file mode 100644 index 0000000..891dcd2 --- /dev/null +++ b/library/remotecontrolwidget.h @@ -0,0 +1,50 @@ +#ifndef CONFIGURATIONWIDGET_H +#define CONFIGURATIONWIDGET_H + +#include "remotecontrolwidget_global.h" + +#include <QtGui/QWidget> + +class OptionsItem; +class FilterLineEdit; +class ToolBox; +class StyledBar; +class ManhattanStyle; +class QToolButton; +class QFrame; +class QLayout; + +class REMOTECONTROLWIDGETSHARED_EXPORT RemoteControlWidget: public QWidget +{ + Q_OBJECT +public: + explicit RemoteControlWidget(QWidget *parent = 0); + ~RemoteControlWidget(); + + virtual void writeSettings(const QString &vendor, const QString &name) const; + virtual void readSettings(const QString &vendor, const QString &name); + + void addToolBoxPage(const QString &title, const QList<OptionsItem *> &options); + void addMenuButton(QToolButton *button); + +protected: + virtual void initializeViewArea(QFrame *target); + +private slots: + void filtersChanged(); + void toggleViewPaneVisible(); + +private: + StyledBar *initializeMenuBar(); + +private: + ToolBox *mToolBox; + FilterLineEdit *mFilterLineEdit; + QLayout *mMenuLayout; + QToolButton *mViewButton; + QFrame *mViewArea; + + ManhattanStyle *mManhattanStyle; +}; + +#endif //CONFIGURATIONWIDGET_H diff --git a/library/remotecontrolwidget.pro b/library/remotecontrolwidget.pro new file mode 100644 index 0000000..f3cc3eb --- /dev/null +++ b/library/remotecontrolwidget.pro @@ -0,0 +1,41 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-02-25T14:32:24 +# +#------------------------------------------------- + +TARGET = remotecontrolwidget +TEMPLATE = lib + +CONFIG += hide_symbols + +DEFINES += REMOTECONTROLWIDGET_LIBRARY + +SOURCES += \ + remotecontrolwidget.cpp \ + toolbox.cpp \ + optionsitem.cpp \ + locationui.cpp \ + style/stylehelper.cpp \ + style/styledbar.cpp \ + style/styleanimator.cpp \ + style/manhattanstyle.cpp \ + style/filterlineedit.cpp \ + style/fancylineedit.cpp + +HEADERS += \ + remotecontrolwidget.h \ + remotecontrolwidget_global.h \ + toolbox.h \ + optionsitem.h \ + locationui.h \ + style/styledbar.h \ + style/styleanimator.h \ + style/qtcassert.h \ + style/manhattanstyle.h \ + style/filterlineedit.h \ + style/fancylineedit.h \ + style/stylehelper.h + +RESOURCES += \ + style/style.qrc diff --git a/library/remotecontrolwidget_global.h b/library/remotecontrolwidget_global.h new file mode 100644 index 0000000..a6223ce --- /dev/null +++ b/library/remotecontrolwidget_global.h @@ -0,0 +1,12 @@ +#ifndef REMOTECONTROLWIDGET_GLOBAL_H +#define REMOTECONTROLWIDGET_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(REMOTECONTROLWIDGET_LIBRARY) +# define REMOTECONTROLWIDGETSHARED_EXPORT Q_DECL_EXPORT +#else +# define REMOTECONTROLWIDGETSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // REMOTECONTROLWIDGET_GLOBAL_H diff --git a/library/style/fancylineedit.cpp b/library/style/fancylineedit.cpp new file mode 100644 index 0000000..f326770 --- /dev/null +++ b/library/style/fancylineedit.cpp @@ -0,0 +1,315 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "fancylineedit.h" + +#include <QtCore/QEvent> +#include <QtCore/QDebug> +#include <QtCore/QString> +#include <QtGui/QApplication> +#include <QtGui/QMenu> +#include <QtGui/QMouseEvent> +#include <QtGui/QLabel> + +enum { margin = 6 }; + +static inline QString sideToStyleSheetString(FancyLineEdit::Side side) +{ + return side == FancyLineEdit::Left ? QLatin1String("left") : QLatin1String("right"); +} + +// Format style sheet for the label containing the pixmap. It has a margin on +// the outer side of the whole FancyLineEdit. +static QString labelStyleSheet(FancyLineEdit::Side side) +{ + QString rc = QLatin1String("QLabel { margin-"); + rc += sideToStyleSheetString(side); + rc += QLatin1String(": "); + rc += QString::number(margin); + rc += QLatin1Char('}'); + return rc; +} + +// --------- FancyLineEditPrivate as QObject with label +// event filter + +class FancyLineEditPrivate : public QObject { +public: + explicit FancyLineEditPrivate(FancyLineEdit *parent); + + virtual bool eventFilter(QObject *obj, QEvent *event); + + const QString m_leftLabelStyleSheet; + const QString m_rightLabelStyleSheet; + + FancyLineEdit *m_lineEdit; + QPixmap m_pixmap; + QMenu *m_menu; + QLabel *m_menuLabel; + FancyLineEdit::Side m_side; + bool m_useLayoutDirection; + bool m_menuTabFocusTrigger; + QString m_hintText; + bool m_showingHintText; +}; + + +FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) : + QObject(parent), + m_leftLabelStyleSheet(labelStyleSheet(FancyLineEdit::Left)), + m_rightLabelStyleSheet(labelStyleSheet(FancyLineEdit::Right)), + m_lineEdit(parent), + m_menu(0), + m_menuLabel(0), + m_side(FancyLineEdit::Left), + m_useLayoutDirection(false), + m_menuTabFocusTrigger(false), + m_showingHintText(false) +{ +} + +bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event) +{ + if (obj != m_menuLabel) + return QObject::eventFilter(obj, event); + + switch (event->type()) { + case QEvent::MouseButtonPress: { + const QMouseEvent *me = static_cast<QMouseEvent *>(event); + if (m_menu) { + m_menu->exec(me->globalPos()); + } else { + emit m_lineEdit->buttonClicked(); + } + return true; + } + case QEvent::FocusIn: + if (m_menuTabFocusTrigger && m_menu) { + m_lineEdit->setFocus(); + m_menu->exec(m_menuLabel->mapToGlobal(m_menuLabel->rect().center())); + return true; + } + default: + break; + } + return QObject::eventFilter(obj, event); +} + +// --------- FancyLineEdit +FancyLineEdit::FancyLineEdit(QWidget *parent) : + QLineEdit(parent), + m_d(new FancyLineEditPrivate(this)) +{ + m_d->m_menuLabel = new QLabel(this); + m_d->m_menuLabel->installEventFilter(m_d); + updateMenuLabel(); + showHintText(); +} + +FancyLineEdit::~FancyLineEdit() +{ +} + +// Position the menu label left or right according to size. +// Called when switching side and from resizeEvent. +void FancyLineEdit::positionMenuLabel() +{ + switch (side()) { + case Left: + m_d->m_menuLabel->setGeometry(0, 0, m_d->m_pixmap.width()+margin, height()); + break; + case Right: + m_d->m_menuLabel->setGeometry(width() - m_d->m_pixmap.width() - margin, 0, + m_d->m_pixmap.width()+margin, height()); + break; + } +} + +void FancyLineEdit::updateStyleSheet(Side side) +{ + // Udate the LineEdit style sheet. Make room for the label on the + // respective side and set color according to whether we are showing the + // hint text + QString sheet = QLatin1String("QLineEdit{ padding-"); + sheet += sideToStyleSheetString(side); + sheet += QLatin1String(": "); + sheet += QString::number(m_d->m_pixmap.width() + margin); + sheet += QLatin1Char(';'); + if (m_d->m_showingHintText) + sheet += QLatin1String(" color: #BBBBBB;"); + // Fix the stylesheet's clearing the size hint. + sheet += QLatin1String(" height: "); + sheet += QString::number(sizeHint().height()); + sheet += QLatin1Char('}'); + setStyleSheet(sheet); +} + +void FancyLineEdit::updateMenuLabel() +{ + m_d->m_menuLabel->setPixmap(m_d->m_pixmap); + const Side s = side(); + switch (s) { + case Left: + m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); + m_d->m_menuLabel->setStyleSheet(m_d->m_leftLabelStyleSheet); + break; + case Right: + m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight); + m_d->m_menuLabel->setStyleSheet(m_d->m_rightLabelStyleSheet); + break; + } + updateStyleSheet(s); + positionMenuLabel(); +} + +void FancyLineEdit::setSide(Side side) +{ + m_d->m_side = side; + updateMenuLabel(); +} + +FancyLineEdit::Side FancyLineEdit::side() const +{ + if (m_d->m_useLayoutDirection) + return qApp->layoutDirection() == Qt::LeftToRight ? Left : Right; + return m_d->m_side; +} + +void FancyLineEdit::resizeEvent(QResizeEvent *) +{ + positionMenuLabel(); +} + +void FancyLineEdit::setPixmap(const QPixmap &pixmap) +{ + m_d->m_pixmap = pixmap; + updateMenuLabel(); +} + +QPixmap FancyLineEdit::pixmap() const +{ + return m_d->m_pixmap; +} + +void FancyLineEdit::setMenu(QMenu *menu) +{ + m_d->m_menu = menu; +} + +QMenu *FancyLineEdit::menu() const +{ + return m_d->m_menu; +} + +bool FancyLineEdit::useLayoutDirection() const +{ + return m_d->m_useLayoutDirection; +} + +void FancyLineEdit::setUseLayoutDirection(bool v) +{ + m_d->m_useLayoutDirection = v; +} + +bool FancyLineEdit::isSideStored() const +{ + return !m_d->m_useLayoutDirection; +} + +bool FancyLineEdit::hasMenuTabFocusTrigger() const +{ + return m_d->m_menuTabFocusTrigger; +} + +void FancyLineEdit::setMenuTabFocusTrigger(bool v) +{ + if (m_d->m_menuTabFocusTrigger == v) + return; + + m_d->m_menuTabFocusTrigger = v; + m_d->m_menuLabel->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus); +} + +QString FancyLineEdit::hintText() const +{ + return m_d->m_hintText; +} + +void FancyLineEdit::setHintText(const QString &ht) +{ + // Updating magic to make the property work in Designer. + if (ht == m_d->m_hintText) + return; + hideHintText(); + m_d->m_hintText = ht; + if (!hasFocus() && !ht.isEmpty()) + showHintText(); +} + +void FancyLineEdit::showHintText() +{ + if (!m_d->m_showingHintText && text().isEmpty() && !m_d->m_hintText.isEmpty()) { + m_d->m_showingHintText = true; + setText(m_d->m_hintText); + updateStyleSheet(side()); + } +} + +void FancyLineEdit::hideHintText() +{ + if (m_d->m_showingHintText && !m_d->m_hintText.isEmpty()) { + m_d->m_showingHintText = false; + setText(QString()); + updateStyleSheet(side()); + } +} + +void FancyLineEdit::focusInEvent(QFocusEvent *e) +{ + hideHintText(); + QLineEdit::focusInEvent(e); +} + +void FancyLineEdit::focusOutEvent(QFocusEvent *e) +{ + // Focus out: Switch to displaying the hint text unless + // there is user input + showHintText(); + QLineEdit::focusOutEvent(e); +} + +bool FancyLineEdit::isShowingHintText() const +{ + return m_d->m_showingHintText; +} + +QString FancyLineEdit::typedText() const +{ + return m_d->m_showingHintText ? QString() : text(); +} diff --git a/library/style/fancylineedit.h b/library/style/fancylineedit.h new file mode 100644 index 0000000..01978e0 --- /dev/null +++ b/library/style/fancylineedit.h @@ -0,0 +1,108 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FANCYLINEEDIT_H +#define FANCYLINEEDIT_H + +#include <QtGui/QLineEdit> + +class FancyLineEditPrivate; + +/* A line edit with an embedded pixmap on one side that is connected to + * a menu. Additionally, it can display a grayed hintText (like "Type Here to") + * when not focused and empty. When connecting to the changed signals and + * querying text, one has to be aware that the text is set to that hint + * text if isShowingHintText() returns true (that is, does not contain + * valid user input). + */ +class FancyLineEdit : public QLineEdit +{ + Q_DISABLE_COPY(FancyLineEdit) + Q_OBJECT + Q_ENUMS(Side) + Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE true) + Q_PROPERTY(Side side READ side WRITE setSide DESIGNABLE isSideStored STORED isSideStored) + Q_PROPERTY(bool useLayoutDirection READ useLayoutDirection WRITE setUseLayoutDirection DESIGNABLE true) + Q_PROPERTY(bool menuTabFocusTrigger READ hasMenuTabFocusTrigger WRITE setMenuTabFocusTrigger DESIGNABLE true) + Q_PROPERTY(QString hintText READ hintText WRITE setHintText DESIGNABLE true) + +public: + enum Side {Left, Right}; + + explicit FancyLineEdit(QWidget *parent = 0); + ~FancyLineEdit(); + + QPixmap pixmap() const; + + void setMenu(QMenu *menu); + QMenu *menu() const; + + void setSide(Side side); + Side side() const; + + bool useLayoutDirection() const; + void setUseLayoutDirection(bool v); + + // Set whether tabbing in will trigger the menu. + bool hasMenuTabFocusTrigger() const; + void setMenuTabFocusTrigger(bool v); + + // Hint text that is displayed when no focus is set. + QString hintText() const; + + bool isShowingHintText() const; + + // Convenience for accessing the text that returns "" in case of isShowingHintText(). + QString typedText() const; + +signals: + void buttonClicked(); + +public slots: + void setPixmap(const QPixmap &pixmap); + void setHintText(const QString &ht); + void showHintText(); + void hideHintText(); + +protected: + virtual void resizeEvent(QResizeEvent *e); + virtual void focusInEvent(QFocusEvent *e); + virtual void focusOutEvent(QFocusEvent *e); + +private: + friend class FancyLineEditPrivate; + bool isSideStored() const; + void updateMenuLabel(); + void positionMenuLabel(); + void updateStyleSheet(Side side); + + FancyLineEditPrivate *m_d; +}; + +#endif // FANCYLINEEDIT_H diff --git a/library/style/filterlineedit.cpp b/library/style/filterlineedit.cpp new file mode 100644 index 0000000..cc5e358 --- /dev/null +++ b/library/style/filterlineedit.cpp @@ -0,0 +1,51 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "filterlineedit.h" + +FilterLineEdit::FilterLineEdit(QWidget *parent) : + FancyLineEdit(parent), + m_lastFilterText(typedText()) +{ + setSide(FancyLineEdit::Right); + setPixmap(QPixmap(QLatin1String(":/style/images/reset.png"))); + setHintText(tr("Type to filter")); + + connect(this, SIGNAL(buttonClicked()), this, SLOT(clear())); + connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged())); +} + +void FilterLineEdit::slotTextChanged() +{ + const QString newlyTypedText = typedText(); + if (newlyTypedText != m_lastFilterText) { + m_lastFilterText = newlyTypedText; + emit filterChanged(m_lastFilterText); + } +} diff --git a/library/style/filterlineedit.h b/library/style/filterlineedit.h new file mode 100644 index 0000000..d0adb50 --- /dev/null +++ b/library/style/filterlineedit.h @@ -0,0 +1,53 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef FILTERLINEEDIT_H +#define FILTERLINEEDIT_H + +#include "fancylineedit.h" + +/* A fancy line edit customized for filtering purposes with a clear button. */ + +class FilterLineEdit : public FancyLineEdit +{ + Q_OBJECT +public: + explicit FilterLineEdit(QWidget *parent = 0); + +signals: + void filterChanged(const QString &); + +private slots: + void slotTextChanged(); + +private: + QString m_lastFilterText; +}; + +#endif // FILTERLINEEDIT_H diff --git a/library/style/images/advanced.png b/library/style/images/advanced.png Binary files differnew file mode 100644 index 0000000..2a894ec --- /dev/null +++ b/library/style/images/advanced.png diff --git a/library/style/images/closebutton.png b/library/style/images/closebutton.png Binary files differnew file mode 100644 index 0000000..6eea001 --- /dev/null +++ b/library/style/images/closebutton.png diff --git a/library/style/images/favoriteScripts.png b/library/style/images/favoriteScripts.png Binary files differnew file mode 100644 index 0000000..1348354 --- /dev/null +++ b/library/style/images/favoriteScripts.png diff --git a/library/style/images/reset.png b/library/style/images/reset.png Binary files differnew file mode 100644 index 0000000..cc0d6a2 --- /dev/null +++ b/library/style/images/reset.png diff --git a/library/style/manhattanstyle.cpp b/library/style/manhattanstyle.cpp new file mode 100644 index 0000000..3d43e7a --- /dev/null +++ b/library/style/manhattanstyle.cpp @@ -0,0 +1,1187 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "manhattanstyle.h" + +#include "styleanimator.h" + +#include <QtCore/QLibrary> + +#include "qtcassert.h" +#include "stylehelper.h" + +#include <QtGui/QApplication> +#include <QtGui/QComboBox> +#include <QtGui/QDialog> +#include <QtGui/QDialogButtonBox> +#include <QtGui/QDockWidget> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QMainWindow> +#include <QtGui/QMenuBar> +#include <QtGui/QPainter> +#include <QtGui/QPixmap> +#include <QtGui/QPixmapCache> +#include <QtGui/QPushButton> +#include <QtGui/QScrollArea> +#include <QtGui/QSplitter> +#include <QtGui/QStatusBar> +#include <QtGui/QStyleFactory> +#include <QtGui/QStyleOption> +#include <QtGui/QToolBar> +#include <QtGui/QToolButton> + +// We define a currently unused state for indicating animations +#define State_Animating 0x00000040 + +// Because designer needs to disable this for widget previews +// we have a custom property that is inherited +bool styleEnabled(const QWidget *widget) +{ + const QWidget *p = widget; + while (p) { + if (p->property("_q_custom_style_disabled").toBool()) + return false; + p = p->parentWidget(); + } + return true; +} + +// Consider making this a QStyle state +bool panelWidget(const QWidget *widget) +{ + if (!widget) + return false; + + // Don't style dialogs or explicitly ignored widgets + if (qobject_cast<const QDialog *>(widget->window())) + return false; + + const QWidget *p = widget; + while (p) { + if (qobject_cast<const QToolBar *>(p) || + qobject_cast<const QStatusBar *>(p) || + qobject_cast<const QMenuBar *>(p)) + return styleEnabled(widget); + if (p->property("panelwidget").toBool()) + return true; + p = p->parentWidget(); + } + return false; +} + +bool styledScrollBar(const QWidget *widget) +{ + if (!widget) + return false; + + // Don't style dialogs or explicitly ignored widgets + if (qobject_cast<const QDialog *>(widget->window())) + return false; + + const QWidget *p = widget; + while (p) { + if (qobject_cast<const QToolBar *>(p) || + qobject_cast<const QStatusBar *>(p) || + qobject_cast<const QMenuBar *>(p)) + return styleEnabled(widget); + if (p->property("styledScrollBar").toBool()) + return true; + p = p->parentWidget(); + } + return false; +} + +// Consider making this a QStyle state +bool lightColored(const QWidget *widget) +{ + if (!widget) + return false; + + // Don't style dialogs or explicitly ignored widgets + if (qobject_cast<const QDialog *>(widget->window())) + return false; + + const QWidget *p = widget; + while (p) { + if (p->property("lightColored").toBool()) + return true; + p = p->parentWidget(); + } + return false; +} + +class ManhattanStylePrivate +{ +public: + ManhattanStylePrivate(const QString &baseStyleName) + { + style = QStyleFactory::create(baseStyleName); + QTC_ASSERT(style, /**/); + + lineeditImage = QImage(":/core/images/inputfield.png"); + lineeditImage_disabled = QImage(":/core/images/inputfield_disabled.png"); + } + + ~ManhattanStylePrivate() + { + delete style; + style = 0; + } + + void init(); + +public: + QStyle *style; + QImage lineeditImage; + QImage lineeditImage_disabled; + + StyleAnimator animator; +}; + +ManhattanStyle::ManhattanStyle(const QString &baseStyleName) + : QWindowsStyle(), d(new ManhattanStylePrivate(baseStyleName)) +{ +} + +ManhattanStyle::~ManhattanStyle() +{ + delete d; + d = 0; +} + +QStyle *ManhattanStyle::systemStyle() const +{ + return d->style; +} + +// Draws a CSS-like border image where the defined borders are not stretched +void drawCornerImage(const QImage &img, QPainter *painter, QRect rect, + int left = 0, int top = 0, int right = 0, + int bottom = 0) +{ + QSize size = img.size(); + if (top > 0) { //top + painter->drawImage(QRect(rect.left() + left, rect.top(), rect.width() -right - left, top), img, + QRect(left, 0, size.width() -right - left, top)); + if (left > 0) //top-left + painter->drawImage(QRect(rect.left(), rect.top(), left, top), img, + QRect(0, 0, left, top)); + if (right > 0) //top-right + painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top(), right, top), img, + QRect(size.width() - right, 0, right, top)); + } + //left + if (left > 0) + painter->drawImage(QRect(rect.left(), rect.top()+top, left, rect.height() - top - bottom), img, + QRect(0, top, left, size.height() - bottom - top)); + //center + painter->drawImage(QRect(rect.left() + left, rect.top()+top, rect.width() -right - left, + rect.height() - bottom - top), img, + QRect(left, top, size.width() -right -left, + size.height() - bottom - top)); + if (right > 0) //right + painter->drawImage(QRect(rect.left() +rect.width() - right, rect.top()+top, right, rect.height() - top - bottom), img, + QRect(size.width() - right, top, right, size.height() - bottom - top)); + if (bottom > 0) { //bottom + painter->drawImage(QRect(rect.left() +left, rect.top() + rect.height() - bottom, + rect.width() - right - left, bottom), img, + QRect(left, size.height() - bottom, + size.width() - right - left, bottom)); + if (left > 0) //bottom-left + painter->drawImage(QRect(rect.left(), rect.top() + rect.height() - bottom, left, bottom), img, + QRect(0, size.height() - bottom, left, bottom)); + if (right > 0) //bottom-right + painter->drawImage(QRect(rect.left() + rect.width() - right, rect.top() + rect.height() - bottom, right, bottom), img, + QRect(size.width() - right, size.height() - bottom, right, bottom)); + } +} + +QPixmap ManhattanStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const +{ + QPixmap result; + result = d->style->generatedIconPixmap(iconMode, pixmap, opt); + return result; +} + +int ManhattanStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1, + QSizePolicy::ControlType control2, + Qt::Orientation orientation, + const QStyleOption * option , + const QWidget * widget ) const +{ + return d->style->layoutSpacing(control1, control2, orientation, option, widget); + +} + +QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const +{ + QSize newSize = d->style->sizeFromContents(type, option, size, widget); + + if (type == CT_Splitter && widget && widget->property("minisplitter").toBool()) + return QSize(1, 1); + else if (type == CT_ComboBox && panelWidget(widget)) + newSize += QSize(14, 0); + return newSize; +} + +QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + QRect rect; + rect = d->style->subElementRect(element, option, widget); + return rect; +} + +QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, + SubControl subControl, const QWidget *widget) const +{ + QRect rect; + rect = d->style->subControlRect(control, option, subControl, widget); + return rect; +} + +QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, + const QPoint &pos, const QWidget *widget) const +{ + SubControl result = QStyle::SC_None; + result = d->style->hitTestComplexControl(control, option, pos, widget); + return result; +} + +int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + int retval = 0; + retval = d->style->pixelMetric(metric, option, widget); + switch (metric) { + case PM_SplitterWidth: + if (widget && widget->property("minisplitter").toBool()) + retval = 1; + break; + case PM_ToolBarIconSize: + if (panelWidget(widget)) + retval = 16; + break; + case PM_MenuPanelWidth: + case PM_MenuBarHMargin: + case PM_MenuBarVMargin: + case PM_ToolBarFrameWidth: + if (panelWidget(widget)) + retval = 1; + break; + case PM_ButtonShiftVertical: + case PM_ButtonShiftHorizontal: + case PM_MenuBarPanelWidth: + case PM_ToolBarItemMargin: + case PM_ToolBarItemSpacing: + if (panelWidget(widget)) + retval = 0; + break; + case PM_DefaultFrameWidth: + if (qobject_cast<const QLineEdit*>(widget) && panelWidget(widget)) + return 1; + break; + default: + break; + } + return retval; +} + +QPalette ManhattanStyle::standardPalette() const +{ + QPalette result; + result = d->style->standardPalette(); + return result; +} + +void ManhattanStyle::polish(QApplication *app) +{ + d->style->polish(app); +} + +void ManhattanStyle::unpolish(QApplication *app) +{ + d->style->unpolish(app); +} + +QPalette panelPalette(const QPalette &oldPalette, bool lightColored = false) +{ + QColor color = StyleHelper::panelTextColor(lightColored); + QPalette pal = oldPalette; + pal.setBrush(QPalette::All, QPalette::WindowText, color); + pal.setBrush(QPalette::All, QPalette::ButtonText, color); + pal.setBrush(QPalette::All, QPalette::Foreground, color); + color.setAlpha(100); + pal.setBrush(QPalette::Disabled, QPalette::WindowText, color); + pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color); + pal.setBrush(QPalette::Disabled, QPalette::Foreground, color); + return pal; +} + +void ManhattanStyle::polish(QWidget *widget) +{ + d->style->polish(widget); + + // OxygenStyle forces a rounded widget mask on toolbars + if (d->style->inherits("OxygenStyle")) { + if (qobject_cast<QToolBar*>(widget)) + widget->removeEventFilter(d->style); + } + if (panelWidget(widget)) { + widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); + if (qobject_cast<QToolButton*>(widget)) { + widget->setAttribute(Qt::WA_Hover); + widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 1); + } + else if (qobject_cast<QLineEdit*>(widget)) { + widget->setAttribute(Qt::WA_Hover); + widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 1); + } + else if (qobject_cast<QLabel*>(widget)) + widget->setPalette(panelPalette(widget->palette())); + else if (qobject_cast<QToolBar*>(widget) || widget->property("panelwidget_singlerow").toBool()) + widget->setFixedHeight(StyleHelper::navigationWidgetHeight()); + else if (qobject_cast<QStatusBar*>(widget)) + widget->setFixedHeight(StyleHelper::navigationWidgetHeight() + 2); + else if (qobject_cast<QComboBox*>(widget)) { + widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 1); + widget->setAttribute(Qt::WA_Hover); + } + } +} + +void ManhattanStyle::unpolish(QWidget *widget) +{ + d->style->unpolish(widget); + if (panelWidget(widget)) { + widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); + if (qobject_cast<QTabBar*>(widget)) + widget->setAttribute(Qt::WA_Hover, false); + else if (qobject_cast<QToolBar*>(widget)) + widget->setAttribute(Qt::WA_Hover, false); + else if (qobject_cast<QComboBox*>(widget)) + widget->setAttribute(Qt::WA_Hover, false); + } +} + +void ManhattanStyle::polish(QPalette &pal) +{ + d->style->polish(pal); +} + +QIcon ManhattanStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, + const QWidget *widget) const +{ + QIcon icon; + switch (standardIcon) { + case QStyle::SP_TitleBarCloseButton: + case QStyle::SP_ToolBarHorizontalExtensionButton: + return QIcon(standardPixmap(standardIcon, option, widget)); + default: + icon = d->style->standardIcon(standardIcon, option, widget); + } + return icon; +} + +QPixmap ManhattanStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, + const QWidget *widget) const +{ + if (widget && !panelWidget(widget)) + return d->style->standardPixmap(standardPixmap, opt, widget); + + QPixmap pixmap; + switch (standardPixmap) { + case QStyle::SP_ToolBarHorizontalExtensionButton: { + static const QPixmap extButton(":/core/images/extension.png"); + pixmap = extButton; + } + break; + case QStyle::SP_TitleBarCloseButton: { + static const QPixmap closeButton(":/style/images/closebutton.png"); + pixmap = closeButton; + } + break; + default: + pixmap = d->style->standardPixmap(standardPixmap, opt, widget); + } + return pixmap; +} + + +int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, + QStyleHintReturn *returnData) const +{ + int ret = d->style->styleHint(hint, option, widget, returnData); + switch (hint) { + // Make project explorer alternate rows all the way + case QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea: + if (widget && widget->property("AlternateEmpty").toBool()) + ret = true; + break; + case QStyle::SH_EtchDisabledText: + if (panelWidget(widget)) + ret = false; + break; + default: + break; + } + return ret; +} + +void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + if (!panelWidget(widget)) + return d->style->drawPrimitive(element, option, painter, widget); + + bool animating = (option->state & State_Animating); + int state = option->state; + QRect rect = option->rect; + QRect oldRect; + QRect newRect; + if (widget && (element == PE_PanelButtonTool) && !animating) { + QWidget *w = const_cast<QWidget *> (widget); + int oldState = w->property("_q_stylestate").toInt(); + oldRect = w->property("_q_stylerect").toRect(); + newRect = w->rect(); + w->setProperty("_q_stylestate", (int)option->state); + w->setProperty("_q_stylerect", w->rect()); + + // Determine the animated transition + bool doTransition = ((state & State_On) != (oldState & State_On) || + (state & State_MouseOver) != (oldState & State_MouseOver)); + if (oldRect != newRect) + { + doTransition = false; + d->animator.stopAnimation(widget); + } + + if (doTransition) { + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + Animation *anim = d->animator.widgetAnimation(widget); + QStyleOption opt = *option; + opt.state = (QStyle::State)oldState; + opt.state |= (State)State_Animating; + startImage.fill(0); + Transition *t = new Transition; + t->setWidget(w); + QPainter startPainter(&startImage); + if (!anim) { + drawPrimitive(element, &opt, &startPainter, widget); + } else { + anim->paint(&startPainter, &opt); + d->animator.stopAnimation(widget); + } + QStyleOption endOpt = *option; + endOpt.state |= (State)State_Animating; + t->setStartImage(startImage); + d->animator.startAnimation(t); + endImage.fill(0); + QPainter endPainter(&endImage); + drawPrimitive(element, &endOpt, &endPainter, widget); + t->setEndImage(endImage); + if (oldState & State_MouseOver) + t->setDuration(150); + else + t->setDuration(75); + t->setStartTime(QTime::currentTime()); + } + } + + switch (element) { + case PE_PanelLineEdit: + { + painter->save(); + + // Fill the line edit background + QRect filledRect = option->rect.adjusted(1, 1, -1, -1); + painter->setBrushOrigin(filledRect.topLeft()); + painter->fillRect(filledRect, option->palette.base()); + + if (option->state & State_Enabled) + drawCornerImage(d->lineeditImage, painter, option->rect, 5, 5, 5, 5); + else + drawCornerImage(d->lineeditImage_disabled, painter, option->rect, 5, 5, 5, 5); + + if (option->state & State_HasFocus || option->state & State_MouseOver) { + QColor hover = StyleHelper::baseColor(); + if (state & State_HasFocus) + hover.setAlpha(100); + else + hover.setAlpha(50); + + painter->setPen(QPen(hover, 1)); + painter->drawRect(option->rect.adjusted(1, 1, -2 ,-2)); + } + painter->restore(); + } + break; + + case PE_FrameStatusBarItem: + break; + + case PE_PanelButtonTool: { + Animation *anim = d->animator.widgetAnimation(widget); + if (!animating && anim) { + anim->paint(painter, option); + } else { + bool pressed = option->state & State_Sunken || option->state & State_On; + QColor shadow(0, 0, 0, 30); + painter->setPen(shadow); + if (pressed) { + QColor shade(0, 0, 0, 40); + painter->fillRect(rect, shade); + painter->drawLine(rect.topLeft() + QPoint(1, 0), rect.topRight() - QPoint(1, 0)); + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + painter->drawLine(rect.topRight(), rect.bottomRight()); + // painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomRight() - QPoint(1, 0)); + QColor highlight(255, 255, 255, 30); + painter->setPen(highlight); + } + else if (option->state & State_Enabled && + option->state & State_MouseOver) { + QColor lighter(255, 255, 255, 37); + painter->fillRect(rect, lighter); + } + } + } + break; + + case PE_PanelStatusBar: + { + painter->save(); + QLinearGradient grad(option->rect.topLeft(), QPoint(rect.center().x(), rect.bottom())); + QColor startColor = StyleHelper::shadowColor().darker(164); + QColor endColor = StyleHelper::baseColor().darker(130); + grad.setColorAt(0, startColor); + grad.setColorAt(1, endColor); + painter->fillRect(option->rect, grad); + painter->setPen(QColor(255, 255, 255, 60)); + painter->drawLine(rect.topLeft() + QPoint(0,1), + rect.topRight()+ QPoint(0,1)); + painter->setPen(StyleHelper::borderColor().darker(110)); + painter->drawLine(rect.topLeft(), rect.topRight()); + painter->restore(); + } + break; + + case PE_IndicatorToolBarSeparator: + { + QColor separatorColor = StyleHelper::borderColor(); + separatorColor.setAlpha(100); + painter->setPen(separatorColor); + const int margin = 6; + if (option->state & State_Horizontal) { + const int offset = rect.width()/2; + painter->drawLine(rect.bottomLeft().x() + offset, + rect.bottomLeft().y() - margin, + rect.topLeft().x() + offset, + rect.topLeft().y() + margin); + } else { //Draw vertical separator + const int offset = rect.height()/2; + painter->setPen(QPen(option->palette.background().color().darker(110))); + painter->drawLine(rect.topLeft().x() + margin , + rect.topLeft().y() + offset, + rect.topRight().x() - margin, + rect.topRight().y() + offset); + } + } + break; + + case PE_IndicatorToolBarHandle: + { + bool horizontal = option->state & State_Horizontal; + painter->save(); + QPainterPath path; + int x = option->rect.x() + horizontal ? 2 : 6; + int y = option->rect.y() + horizontal ? 6 : 2; + static const int RectHeight = 2; + if (horizontal) { + while (y < option->rect.height() - RectHeight - 6) { + path.moveTo(x, y); + path.addRect(x, y, RectHeight, RectHeight); + y += 6; + } + } else { + while (x < option->rect.width() - RectHeight - 6) { + path.moveTo(x, y); + path.addRect(x, y, RectHeight, RectHeight); + x += 6; + } + } + + painter->setPen(Qt::NoPen); + QColor dark = StyleHelper::borderColor(); + dark.setAlphaF(0.4); + + QColor light = StyleHelper::baseColor(); + light.setAlphaF(0.4); + + painter->fillPath(path, light); + painter->save(); + painter->translate(1, 1); + painter->fillPath(path, dark); + painter->restore(); + painter->translate(3, 3); + painter->fillPath(path, light); + painter->translate(1, 1); + painter->fillPath(path, dark); + painter->restore(); + } + break; + case PE_IndicatorArrowUp: + case PE_IndicatorArrowDown: + case PE_IndicatorArrowRight: + case PE_IndicatorArrowLeft: + { + // From windowsstyle but modified to enable AA + if (option->rect.width() <= 1 || option->rect.height() <= 1) + break; + + QRect r = option->rect; + int size = qMin(r.height(), r.width()); + QPixmap pixmap; + QString pixmapName; + pixmapName.sprintf("%s-%s-%d-%d-%d-%lld", + "$qt_ia", metaObject()->className(), + uint(option->state), element, + size, option->palette.cacheKey()); + if (!QPixmapCache::find(pixmapName, pixmap)) { + int border = size/5; + int sqsize = 2*(size/2); + QImage image(sqsize, sqsize, QImage::Format_ARGB32); + image.fill(Qt::transparent); + QPainter imagePainter(&image); + imagePainter.setRenderHint(QPainter::Antialiasing, true); + imagePainter.translate(0.5, 0.5); + QPolygon a; + switch (element) { + case PE_IndicatorArrowUp: + a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize - border, sqsize/2); + break; + case PE_IndicatorArrowDown: + a.setPoints(3, border, sqsize/2, sqsize/2, sqsize - border, sqsize - border, sqsize/2); + break; + case PE_IndicatorArrowRight: + a.setPoints(3, sqsize - border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border); + break; + case PE_IndicatorArrowLeft: + a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border); + break; + default: + break; + } + + int bsx = 0; + int bsy = 0; + + if (option->state & State_Sunken) { + bsx = pixelMetric(PM_ButtonShiftHorizontal); + bsy = pixelMetric(PM_ButtonShiftVertical); + } + + QRect bounds = a.boundingRect(); + int sx = sqsize / 2 - bounds.center().x() - 1; + int sy = sqsize / 2 - bounds.center().y() - 1; + imagePainter.translate(sx + bsx, sy + bsy); + + if (!(option->state & State_Enabled)) { + QColor foreGround(150, 150, 150, 150); + imagePainter.setBrush(option->palette.mid().color()); + imagePainter.setPen(option->palette.mid().color()); + } else { + QColor shadow(0, 0, 0, 100); + imagePainter.translate(0, 1); + imagePainter.setPen(shadow); + imagePainter.setBrush(shadow); + QColor foreGround(255, 255, 255, 210); + imagePainter.drawPolygon(a); + imagePainter.translate(0, -1); + imagePainter.setPen(foreGround); + imagePainter.setBrush(foreGround); + } + imagePainter.drawPolygon(a); + imagePainter.end(); + pixmap = QPixmap::fromImage(image); + QPixmapCache::insert(pixmapName, pixmap); + } + int xOffset = r.x() + (r.width() - size)/2; + int yOffset = r.y() + (r.height() - size)/2; + painter->drawPixmap(xOffset, yOffset, pixmap); + } + break; + + default: + d->style->drawPrimitive(element, option, painter, widget); + break; + } +} + +void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + if (!panelWidget(widget) + && !styledScrollBar(widget)) + return d->style->drawControl(element, option, painter, widget); + + switch (element) { + case CE_MenuBarItem: + painter->save(); + if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + QColor highlightOutline = StyleHelper::borderColor().lighter(120); + bool act = mbi->state & State_Selected && mbi->state & State_Sunken; + bool dis = !(mbi->state & State_Enabled); + StyleHelper::menuGradient(painter, option->rect, option->rect); + QStyleOptionMenuItem item = *mbi; + item.rect = mbi->rect; + QPalette pal = mbi->palette; + pal.setBrush(QPalette::ButtonText, dis ? Qt::gray : Qt::black); + item.palette = pal; + QCommonStyle::drawControl(element, &item, painter, widget); + QRect r = option->rect; + + if (act) { + // Fill| + QColor baseColor = StyleHelper::baseColor(); + QLinearGradient grad(option->rect.topLeft(), option->rect.bottomLeft()); + grad.setColorAt(0, baseColor.lighter(120)); + grad.setColorAt(1, baseColor.lighter(130)); + painter->fillRect(option->rect.adjusted(1, 1, -1, 0), grad); + + // Outline + painter->setPen(QPen(highlightOutline, 0)); + painter->drawLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom())); + painter->drawLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom())); + painter->drawLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top())); + highlightOutline.setAlpha(60); + painter->setPen(QPen(highlightOutline, 0)); + painter->drawPoint(r.topLeft()); + painter->drawPoint(r.topRight()); + + QPalette pal = mbi->palette; + uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; + if (!styleHint(SH_UnderlineShortcut, mbi, widget)) + alignment |= Qt::TextHideMnemonic; + pal.setBrush(QPalette::Text, dis ? Qt::gray : QColor(0, 0, 0, 60)); + drawItemText(painter, item.rect.translated(0, 1), alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text); + pal.setBrush(QPalette::Text, dis ? Qt::gray : Qt::white); + drawItemText(painter, item.rect, alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text); + } + } + painter->restore(); + break; + + case CE_ComboBoxLabel: + if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + if (panelWidget(widget)) { + QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); + QPalette customPal = cb->palette; + + if (!cb->currentIcon.isNull()) { + QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal + : QIcon::Disabled; + QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode); + QRect iconRect(editRect); + iconRect.setWidth(cb->iconSize.width() + 4); + iconRect = alignedRect(cb->direction, + Qt::AlignLeft | Qt::AlignVCenter, + iconRect.size(), editRect); + if (cb->editable) + painter->fillRect(iconRect, customPal.brush(QPalette::Base)); + drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + if (cb->direction == Qt::RightToLeft) + editRect.translate(-4 - cb->iconSize.width(), 0); + else + editRect.translate(cb->iconSize.width() + 4, 0); + + // Reserve some space for the down-arrow + editRect.adjust(0, 0, -13, 0); + } + + customPal.setBrush(QPalette::All, QPalette::ButtonText, QColor(0, 0, 0, 70)); + + QString text = option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, editRect.width()); + drawItemText(painter, editRect.translated(0, 1), + visualAlignment(option->direction, Qt::AlignLeft | Qt::AlignVCenter), + customPal, cb->state & State_Enabled, text, QPalette::ButtonText); + customPal.setBrush(QPalette::All, QPalette::ButtonText, StyleHelper::panelTextColor()); + drawItemText(painter, editRect, + visualAlignment(option->direction, Qt::AlignLeft | Qt::AlignVCenter), + customPal, cb->state & State_Enabled, text, QPalette::ButtonText); + } else { + d->style->drawControl(element, option, painter, widget); + } + } + break; + + case CE_SizeGrip: { + painter->save(); + QColor dark = Qt::white; + dark.setAlphaF(0.1); + int x, y, w, h; + option->rect.getRect(&x, &y, &w, &h); + int sw = qMin(h, w); + if (h > w) + painter->translate(0, h - w); + else + painter->translate(w - h, 0); + int sx = x; + int sy = y; + int s = 4; + painter->setPen(dark); + if (option->direction == Qt::RightToLeft) { + sx = x + sw; + for (int i = 0; i < 4; ++i) { + painter->drawLine(x, sy, sx, sw); + sx -= s; + sy += s; + } + } else { + for (int i = 0; i < 4; ++i) { + painter->drawLine(sx, sw, sw, sy); + sx += s; + sy += s; + } + } + painter->restore(); + } + break; + + case CE_MenuBarEmptyArea: { + StyleHelper::menuGradient(painter, option->rect, option->rect); + painter->save(); + painter->setPen(StyleHelper::borderColor()); + painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); + painter->restore(); + } + break; + + case CE_ToolBar: + { + QString key; + QColor keyColor = StyleHelper::baseColor(lightColored(widget)); + key.sprintf("mh_toolbar %d %d %d", option->rect.width(), option->rect.height(), keyColor.rgb());; + + QPixmap pixmap; + QPainter *p = painter; + QRect rect = option->rect; + bool horizontal = option->state & State_Horizontal; + if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) { + pixmap = QPixmap(option->rect.size()); + p = new QPainter(&pixmap); + rect = QRect(0, 0, option->rect.width(), option->rect.height()); + } + + if (!StyleHelper::usePixmapCache() || !QPixmapCache::find(key, pixmap)) { + // Map offset for global window gradient + QPoint offset = widget->window()->mapToGlobal(option->rect.topLeft()) - + widget->mapToGlobal(option->rect.topLeft()); + QRect gradientSpan; + if (widget) { + gradientSpan = QRect(offset, widget->window()->size()); + } + bool drawLightColored = lightColored(widget); + if (horizontal) + StyleHelper::horizontalGradient(p, gradientSpan, rect, drawLightColored); + else + StyleHelper::verticalGradient(p, gradientSpan, rect, drawLightColored); + } + + if (StyleHelper::usePixmapCache() && !QPixmapCache::find(key, pixmap)) { + delete p; + QPixmapCache::insert(key, pixmap); + } + if (StyleHelper::usePixmapCache()) { + painter->drawPixmap(rect.topLeft(), pixmap); + } + + painter->setPen(StyleHelper::borderColor()); + + if (horizontal) { + // Note: This is a hack to determine if the + // toolbar should draw the top or bottom outline + // (needed for the find toolbar for instance) + QColor lighter(255, 255, 255, 40); + if (widget && widget->property("topBorder").toBool()) { + painter->drawLine(rect.topLeft(), rect.topRight()); + painter->setPen(lighter); + painter->drawLine(rect.topLeft() + QPoint(0, 1), rect.topRight() + QPoint(0, 1)); + } else { + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + painter->setPen(lighter); + painter->drawLine(rect.topLeft(), rect.topRight()); + } + } else { + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + painter->drawLine(rect.topRight(), rect.bottomRight()); + } + painter->end(); + } + break; + case CE_ScrollBarAddLine: + case CE_ScrollBarSubLine: { + PrimitiveElement arrow; + if (option->state & State_Horizontal) { + if (element == CE_ScrollBarAddLine) + arrow = option->direction == Qt::LeftToRight ? PE_IndicatorArrowRight : PE_IndicatorArrowLeft; + else + arrow = option->direction == Qt::LeftToRight ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; + } else { + if (element == CE_ScrollBarAddLine) + arrow = PE_IndicatorArrowDown; + else + arrow = PE_IndicatorArrowUp; + } + QStyleOption arrowOpt = *option; + arrowOpt.palette.setColor(QPalette::Active, QPalette::ButtonText, StyleHelper::baseColor()); + arrowOpt.palette.setColor(QPalette::Disabled, QPalette::ButtonText, StyleHelper::shadowColor()); + int squareSide = qMin(option->rect.width(), option->rect.height()); + arrowOpt.rect.setSize(QSize(squareSide, squareSide)); + arrowOpt.rect.adjust(5, 5, -1, -3); + + drawPrimitive(arrow, &arrowOpt, painter, widget); + break; } + case CE_ScrollBarSlider: { + QRect rect = option->rect.adjusted(5, 0, -3, 0); + if (option->state & State_Enabled) { + StyleHelper::drawSlider(painter, rect); + } + break; } + default: + d->style->drawControl(element, option, painter, widget); + break; + } +} + +void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, + QPainter *painter, const QWidget *widget) const +{ + if (!panelWidget(widget) && !styledScrollBar(widget)) + return d->style->drawComplexControl(control, option, painter, widget); + + QRect rect = option->rect; + switch (control) { + case CC_ToolButton: + if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { + QRect button, menuarea; + button = subControlRect(control, toolbutton, SC_ToolButton, widget); + menuarea = subControlRect(control, toolbutton, SC_ToolButtonMenu, widget); + + State bflags = toolbutton->state; + if (bflags & State_AutoRaise) { + if (!(bflags & State_MouseOver)) { + bflags &= ~State_Raised; + } + } + + State mflags = bflags; + if (toolbutton->state & State_Sunken) { + if (toolbutton->activeSubControls & SC_ToolButton) + bflags |= State_Sunken; + if (toolbutton->activeSubControls & SC_ToolButtonMenu) + mflags |= State_Sunken; + } + + QStyleOption tool(0); + tool.palette = toolbutton->palette; + if (toolbutton->subControls & SC_ToolButton) { + tool.rect = button; + tool.state = bflags; + drawPrimitive(PE_PanelButtonTool, &tool, painter, widget); + } + + if (toolbutton->state & State_HasFocus) { + QStyleOptionFocusRect fr; + fr.QStyleOption::operator=(*toolbutton); + fr.rect.adjust(3, 3, -3, -3); + if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup) + fr.rect.adjust(0, 0, -pixelMetric(QStyle::PM_MenuButtonIndicator, + toolbutton, widget), 0); + QPen oldPen = painter->pen(); + QColor focusColor = StyleHelper::panelTextColor(); + focusColor.setAlpha(120); + QPen outline(focusColor, 1); + outline.setStyle(Qt::DotLine); + painter->setPen(outline); + QRect r = option->rect.adjusted(2, 2, -2, -2); + painter->drawRect(r); + painter->setPen(oldPen); + } + + QStyleOptionToolButton label = *toolbutton; + + label.palette = panelPalette(option->palette, lightColored(widget)); + int fw = pixelMetric(PM_DefaultFrameWidth, option, widget); + label.rect = button.adjusted(fw, fw, -fw, -fw); + + drawControl(CE_ToolButtonLabel, &label, painter, widget); + + if (toolbutton->subControls & SC_ToolButtonMenu) { + tool.state = mflags; + tool.rect = menuarea.adjusted(1, 1, -1, -1); + if (mflags & (State_Sunken | State_On | State_Raised)) { + painter->setPen(Qt::gray); + painter->drawLine(tool.rect.topLeft(), tool.rect.bottomLeft()); + if (mflags & (State_Sunken)) { + QColor shade(0, 0, 0, 50); + painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade); + } +#ifndef Q_WS_MAC + else if (mflags & (State_MouseOver)) { + QColor shade(255, 255, 255, 50); + painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade); + } +#endif + } + tool.rect = tool.rect.adjusted(2, 2, -2, -2); + drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget); + } else if (toolbutton->features & QStyleOptionToolButton::HasMenu + && !widget->property("noArrow").toBool()) { + int arrowSize = 6; + QRect ir = toolbutton->rect.adjusted(1, 1, -1, -1); + QStyleOptionToolButton newBtn = *toolbutton; + newBtn.palette = panelPalette(option->palette); + newBtn.rect = QRect(ir.right() - arrowSize - 1, + ir.height() - arrowSize - 2, arrowSize, arrowSize); + drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget); + } + } + break; + + case CC_ComboBox: + if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + painter->save(); + bool isEmpty = cb->currentText.isEmpty() && cb->currentIcon.isNull(); + bool reverse = option->direction == Qt::RightToLeft; + + // Draw tool button + QLinearGradient grad(option->rect.topRight(), option->rect.bottomRight()); + grad.setColorAt(0, QColor(255, 255, 255, 20)); + grad.setColorAt(0.4, QColor(255, 255, 255, 60)); + grad.setColorAt(0.7, QColor(255, 255, 255, 50)); + grad.setColorAt(1, QColor(255, 255, 255, 40)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(rect.topRight(), rect.bottomRight()); + grad.setColorAt(0, QColor(0, 0, 0, 30)); + grad.setColorAt(0.4, QColor(0, 0, 0, 70)); + grad.setColorAt(0.7, QColor(0, 0, 0, 70)); + grad.setColorAt(1, QColor(0, 0, 0, 40)); + painter->setPen(QPen(grad, 0)); + if (!reverse) + painter->drawLine(rect.topRight() - QPoint(1,0), rect.bottomRight() - QPoint(1,0)); + else + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + QStyleOption toolbutton = *option; + if (isEmpty) + toolbutton.state &= ~(State_Enabled | State_Sunken); + painter->save(); + painter->setClipRect(toolbutton.rect.adjusted(0, 0, -2, 0)); + drawPrimitive(PE_PanelButtonTool, &toolbutton, painter, widget); + painter->restore(); + // Draw arrow + int menuButtonWidth = 12; + int left = !reverse ? rect.right() - menuButtonWidth : rect.left(); + int right = !reverse ? rect.right() : rect.left() + menuButtonWidth; + QRect arrowRect((left + right) / 2 + (reverse ? 6 : -6), rect.center().y() - 3, 9, 9); + if (option->state & State_On) + arrowRect.translate(d->style->pixelMetric(PM_ButtonShiftHorizontal, option, widget), + d->style->pixelMetric(PM_ButtonShiftVertical, option, widget)); + + QStyleOption arrowOpt = *option; + arrowOpt.rect = arrowRect; + if (isEmpty) + arrowOpt.state &= ~(State_Enabled | State_Sunken); + + if (styleHint(SH_ComboBox_Popup, option, widget)) { + arrowOpt.rect.translate(0, -3); + drawPrimitive(PE_IndicatorArrowUp, &arrowOpt, painter, widget); + arrowOpt.rect.translate(0, 6); + drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget); + } else { + drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget); + } + painter->restore(); + } + break; + + case CC_ScrollBar: + if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + // Make a copy here and reset it for each primitive. + QStyleOptionSlider newScrollbar = *scrollbar; + State saveFlags = scrollbar->state; + if (scrollbar->minimum == scrollbar->maximum) + saveFlags &= ~State_Enabled; + StyleHelper::rectWithLeftLine(widget, painter, newScrollbar.rect); + + if (scrollbar->subControls & SC_ScrollBarSubLine) { + newScrollbar.state = saveFlags; + newScrollbar.rect = proxy()->subControlRect(control, &newScrollbar, SC_ScrollBarSubLine, widget); + if (newScrollbar.rect.isValid()) { + if (!(scrollbar->activeSubControls & SC_ScrollBarSubLine)) + newScrollbar.state &= ~(State_Sunken | State_MouseOver); + drawControl(CE_ScrollBarSubLine, &newScrollbar, painter, widget); + } + } + if (scrollbar->subControls & SC_ScrollBarAddLine) { + newScrollbar.rect = scrollbar->rect; + newScrollbar.state = saveFlags; + newScrollbar.rect = proxy()->subControlRect(control, &newScrollbar, SC_ScrollBarAddLine, widget); + if (newScrollbar.rect.isValid()) { + if (!(scrollbar->activeSubControls & SC_ScrollBarAddLine)) + newScrollbar.state &= ~(State_Sunken | State_MouseOver); + drawControl(CE_ScrollBarAddLine, &newScrollbar, painter, widget); + } + } + if (scrollbar->subControls & SC_ScrollBarSlider) { + newScrollbar.rect = scrollbar->rect; + newScrollbar.state = saveFlags; + newScrollbar.rect = proxy()->subControlRect(control, &newScrollbar, SC_ScrollBarSlider, widget); + if (newScrollbar.rect.isValid()) { + if (!(scrollbar->activeSubControls & SC_ScrollBarSlider)) + newScrollbar.state &= ~(State_Sunken | State_MouseOver); + drawControl(CE_ScrollBarSlider, &newScrollbar, painter, widget); + } + } + } + break; + default: + d->style->drawComplexControl(control, option, painter, widget); + break; + } +} + +// Mac style reimplements this to control the +// focus widget among other things +bool ManhattanStyle::event(QEvent *e) +{ + Q_ASSERT(d->style); + return d->style->event(e); +} diff --git a/library/style/manhattanstyle.h b/library/style/manhattanstyle.h new file mode 100644 index 0000000..527b0b4 --- /dev/null +++ b/library/style/manhattanstyle.h @@ -0,0 +1,94 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef MANHATTANSTYLE_H +#define MANHATTANSTYLE_H + +#include <QtGui/QWindowsStyle> + +QT_BEGIN_NAMESPACE +class QLinearGradient; +class QBrush; +QT_END_NAMESPACE + +class ManhattanStylePrivate; + +class ManhattanStyle : public QWindowsStyle +{ + Q_OBJECT + +public: + ManhattanStyle(const QString &); + + ~ManhattanStyle(); + + QStyle *systemStyle() const; + + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; + void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const; + + QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const; + QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const; + QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const; + + SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget = 0) const; + QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = 0) const; + int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const; + QRect itemRect(QPainter *p, const QRect &r, int flags, bool enabled, const QPixmap *pixmap, const QString &text, int len = -1) const; + QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const; + + int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; + + QPalette standardPalette() const; + + void polish(QWidget *widget); + void polish(QPalette &pal); + void polish(QApplication *app); + + void unpolish(QWidget *widget); + void unpolish(QApplication *app); + +protected: + bool event(QEvent *e); + +protected Q_SLOTS: + QIcon standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + int layoutSpacingImplementation(QSizePolicy::ControlType control1, + QSizePolicy::ControlType control2, + Qt::Orientation orientation, + const QStyleOption *option = 0, + const QWidget *widget = 0) const; + +private: + ManhattanStylePrivate *d; + Q_DISABLE_COPY(ManhattanStyle) +}; + +#endif // MANHATTANSTYLE_H diff --git a/library/style/qtcassert.h b/library/style/qtcassert.h new file mode 100644 index 0000000..a03f5f2 --- /dev/null +++ b/library/style/qtcassert.h @@ -0,0 +1,45 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef QTC_ASSERT_H +#define QTC_ASSERT_H + +#include <QtCore/QDebug> + +#define QTC_ASSERT_STRINGIFY_INTERNAL(x) #x +#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_INTERNAL(x) + +// we do not use the 'do {...} while (0)' idiom here to be able to use +// 'break' and 'continue' as 'actions'. + +#define QTC_ASSERT(cond, action) \ + if(cond){}else{qDebug()<<"ASSERTION " #cond " FAILED AT " __FILE__ ":" QTC_ASSERT_STRINGIFY(__LINE__);action;} + +#endif // QTC_ASSERT_H + diff --git a/library/style/style.pri b/library/style/style.pri new file mode 100644 index 0000000..f50e4bf --- /dev/null +++ b/library/style/style.pri @@ -0,0 +1,16 @@ +INCLUDEPATH += src/ui/style +DEPENDPATH += src/ui/style +HEADERS += manhattanstyle.h \ + stylehelper.h \ + styleanimator.h \ + qtcassert.h \ + styledbar.h \ + fancylineedit.h \ + filterlineedit.h +SOURCES += manhattanstyle.cpp \ + stylehelper.cpp \ + styleanimator.cpp \ + styledbar.cpp \ + fancylineedit.cpp \ + filterlineedit.cpp +RESOURCES += style.qrc diff --git a/library/style/style.qrc b/library/style/style.qrc new file mode 100644 index 0000000..77e34eb --- /dev/null +++ b/library/style/style.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/style"> + <file>images/advanced.png</file> + <file>images/closebutton.png</file> + <file>images/reset.png</file> + <file>images/favoriteScripts.png</file> + </qresource> +</RCC> diff --git a/library/style/styleanimator.cpp b/library/style/styleanimator.cpp new file mode 100644 index 0000000..14de4e2 --- /dev/null +++ b/library/style/styleanimator.cpp @@ -0,0 +1,154 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "styleanimator.h" + +#include <QtGui/QStyleOption> + +Animation * StyleAnimator::widgetAnimation(const QWidget *widget) const +{ + if (!widget) + return 0; + foreach (Animation *a, animations) { + if (a->widget() == widget) + return a; + } + return 0; +} + +void Animation::paint(QPainter *painter, const QStyleOption *option) +{ + Q_UNUSED(option) + Q_UNUSED(painter) +} + +void Animation::drawBlendedImage(QPainter *painter, QRect rect, float alpha) +{ + if (m_secondaryImage.isNull() || m_primaryImage.isNull()) + return; + + if (m_tempImage.isNull()) + m_tempImage = m_secondaryImage; + + const int a = qRound(alpha*256); + const int ia = 256 - a; + const int sw = m_primaryImage.width(); + const int sh = m_primaryImage.height(); + const int bpl = m_primaryImage.bytesPerLine(); + switch (m_primaryImage.depth()) { + case 32: + { + uchar *mixed_data = m_tempImage.bits(); + const uchar *back_data = m_primaryImage.bits(); + const uchar *front_data = m_secondaryImage.bits(); + for (int sy = 0; sy < sh; sy++) { + quint32 *mixed = (quint32*)mixed_data; + const quint32* back = (const quint32*)back_data; + const quint32* front = (const quint32*)front_data; + for (int sx = 0; sx < sw; sx++) { + quint32 bp = back[sx]; + quint32 fp = front[sx]; + mixed[sx] = qRgba ((qRed(bp)*ia + qRed(fp)*a)>>8, + (qGreen(bp)*ia + qGreen(fp)*a)>>8, + (qBlue(bp)*ia + qBlue(fp)*a)>>8, + (qAlpha(bp)*ia + qAlpha(fp)*a)>>8); + } + mixed_data += bpl; + back_data += bpl; + front_data += bpl; + } + } + default: + break; + } + painter->drawImage(rect, m_tempImage); +} + +void Transition::paint(QPainter *painter, const QStyleOption *option) +{ + float alpha = 1.0; + if (m_duration > 0) { + QTime current = QTime::currentTime(); + + if (m_startTime > current) + m_startTime = current; + + int timeDiff = m_startTime.msecsTo(current); + alpha = timeDiff/(float)m_duration; + if (timeDiff > m_duration) { + m_running = false; + alpha = 1.0; + } + } + else { + m_running = false; + } + drawBlendedImage(painter, option->rect, alpha); +} + +void StyleAnimator::timerEvent(QTimerEvent *) +{ + for (int i = animations.size() - 1 ; i >= 0 ; --i) { + if (animations[i]->widget()) + animations[i]->widget()->update(); + + if (!animations[i]->widget() || + !animations[i]->widget()->isEnabled() || + !animations[i]->widget()->isVisible() || + animations[i]->widget()->window()->isMinimized() || + !animations[i]->running()) + { + Animation *a = animations.takeAt(i); + delete a; + } + } + if (animations.size() == 0 && animationTimer.isActive()) { + animationTimer.stop(); + } +} + +void StyleAnimator::stopAnimation(const QWidget *w) +{ + for (int i = animations.size() - 1 ; i >= 0 ; --i) { + if (animations[i]->widget() == w) { + Animation *a = animations.takeAt(i); + delete a; + break; + } + } +} + +void StyleAnimator::startAnimation(Animation *t) +{ + stopAnimation(t->widget()); + animations.append(t); + if (animations.size() > 0 && !animationTimer.isActive()) { + animationTimer.start(35, this); + } +} diff --git a/library/style/styleanimator.h b/library/style/styleanimator.h new file mode 100644 index 0000000..5b81827 --- /dev/null +++ b/library/style/styleanimator.h @@ -0,0 +1,101 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ANIMATION_H +#define ANIMATION_H + +#include <QtCore/QPointer> +#include <QtCore/QTime> +#include <QtCore/QBasicTimer> +#include <QtGui/QStyle> +#include <QtGui/QPainter> +#include <QtGui/QWidget> + +/* + * This is a set of helper classes to allow for widget animations in + * the style. Its mostly taken from Vista style so it should be fully documented + * there. + * + */ + +class Animation +{ +public : + Animation() : m_running(true) { } + virtual ~Animation() { } + QWidget * widget() const { return m_widget; } + bool running() const { return m_running; } + const QTime &startTime() const { return m_startTime; } + void setRunning(bool val) { m_running = val; } + void setWidget(QWidget *widget) { m_widget = widget; } + void setStartTime(const QTime &startTime) { m_startTime = startTime; } + virtual void paint(QPainter *painter, const QStyleOption *option); + +protected: + void drawBlendedImage(QPainter *painter, QRect rect, float value); + QTime m_startTime; + QPointer<QWidget> m_widget; + QImage m_primaryImage; + QImage m_secondaryImage; + QImage m_tempImage; + bool m_running; +}; + +// Handles state transition animations +class Transition : public Animation +{ +public : + Transition() : Animation() {} + virtual ~Transition() {} + void setDuration(int duration) { m_duration = duration; } + void setStartImage(const QImage &image) { m_primaryImage = image; } + void setEndImage(const QImage &image) { m_secondaryImage = image; } + virtual void paint(QPainter *painter, const QStyleOption *option); + int duration() const { return m_duration; } + int m_duration; //set time in ms to complete a state transition +}; + +class StyleAnimator : public QObject +{ + Q_OBJECT + +public: + StyleAnimator(QObject *parent = 0) : QObject(parent) {} + + void timerEvent(QTimerEvent *); + void startAnimation(Animation *); + void stopAnimation(const QWidget *); + Animation* widgetAnimation(const QWidget *) const; + +private: + QBasicTimer animationTimer; + QList <Animation*> animations; +}; + +#endif // ANIMATION_H diff --git a/library/style/styledbar.cpp b/library/style/styledbar.cpp new file mode 100644 index 0000000..ad7416d --- /dev/null +++ b/library/style/styledbar.cpp @@ -0,0 +1,93 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "styledbar.h" + +#include "stylehelper.h" + +#include <QtCore/QVariant> +#include <QtGui/QPainter> +#include <QtGui/QPixmapCache> +#include <QtGui/QStyle> +#include <QtGui/QStyleOption> + +StyledBar::StyledBar(QWidget *parent) + : QWidget(parent) +{ + setProperty("panelwidget", true); + setProperty("panelwidget_singlerow", true); + setProperty("lightColored", false); +} + +void StyledBar::setSingleRow(bool singleRow) +{ + setProperty("panelwidget_singlerow", singleRow); +} + +bool StyledBar::isSingleRow() const +{ + return property("panelwidget_singlerow").toBool(); +} + +void StyledBar::setLightColored(bool lightColored) +{ + setProperty("lightColored", lightColored); +} + +bool StyledBar::isLightColored() const +{ + return property("lightColored").toBool(); +} + +void StyledBar::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + QStyleOption option; + option.rect = rect(); + option.state = QStyle::State_Horizontal; + style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this); +} + +StyledSeparator::StyledSeparator(QWidget *parent) + : QWidget(parent) +{ + setFixedWidth(10); +} + +void StyledSeparator::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + QStyleOption option; + option.rect = rect(); + option.state = QStyle::State_Horizontal; + option.palette = palette(); + style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &option, &painter, this); +} diff --git a/library/style/styledbar.h b/library/style/styledbar.h new file mode 100644 index 0000000..72469f6 --- /dev/null +++ b/library/style/styledbar.h @@ -0,0 +1,57 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef STYLEDBAR_H +#define STYLEDBAR_H + +#include <QtGui/QWidget> + +class StyledBar : public QWidget +{ +public: + StyledBar(QWidget *parent = 0); + void setSingleRow(bool singleRow); + bool isSingleRow() const; + + void setLightColored(bool lightColored); + bool isLightColored() const; + +protected: + void paintEvent(QPaintEvent *event); +}; + +class StyledSeparator : public QWidget +{ +public: + StyledSeparator(QWidget *parent = 0); +protected: + void paintEvent(QPaintEvent *event); +}; + +#endif // STYLEDBAR_H diff --git a/library/style/stylehelper.cpp b/library/style/stylehelper.cpp new file mode 100644 index 0000000..1983ede --- /dev/null +++ b/library/style/stylehelper.cpp @@ -0,0 +1,296 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "stylehelper.h" + +#include <QtGui/QPixmapCache> +#include <QtGui/QWidget> +#include <QtCore/QRect> +#include <QtGui/QPainter> +#include <QtGui/QApplication> +#include <QtGui/QPalette> + +// Clamps float color values within (0, 255) +static int clamp(float x) +{ + const int val = x > 255 ? 255 : static_cast<int>(x); + return val < 0 ? 0 : val; +} + +// Clamps float color values within (0, 255) +/* +static int range(float x, int min, int max) +{ + int val = x > max ? max : x; + return val < min ? min : val; +} +*/ + +QColor StyleHelper::mergedColors(const QColor &colorA, const QColor &colorB, int factor) +{ + const int maxFactor = 100; + QColor tmp = colorA; + tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor); + tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor); + tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor); + return tmp; +} + +qreal StyleHelper::sidebarFontSize() +{ +#if defined(Q_WS_MAC) + return 9; +#else + return 7.5; +#endif +} + +QPalette StyleHelper::sidebarFontPalette(const QPalette &original) +{ + QPalette palette = original; + palette.setColor(QPalette::Active, QPalette::Text, panelTextColor()); + palette.setColor(QPalette::Active, QPalette::WindowText, panelTextColor()); + palette.setColor(QPalette::Inactive, QPalette::Text, panelTextColor().darker()); + palette.setColor(QPalette::Inactive, QPalette::WindowText, panelTextColor().darker()); + return palette; +} + +QColor StyleHelper::panelTextColor(bool lightColored) +{ + //qApp->palette().highlightedText().color(); + if (!lightColored) + return Qt::white; + else + return Qt::black; +} + +QColor StyleHelper::m_baseColor(0x666666); + +QColor StyleHelper::baseColor(bool lightColored) +{ + if (!lightColored) + return m_baseColor; + else + return m_baseColor.lighter(230); +} + +QColor StyleHelper::highlightColor(bool lightColored) +{ + QColor result = baseColor(lightColored); + if (!lightColored) + result.setHsv(result.hue(), + clamp(result.saturation()), + clamp(result.value() * 1.16)); + else + result.setHsv(result.hue(), + clamp(result.saturation()), + clamp(result.value() * 1.06)); + return result; +} + +QColor StyleHelper::shadowColor(bool lightColored) +{ + QColor result = baseColor(lightColored); + result.setHsv(result.hue(), + clamp(result.saturation() * 1.1), + clamp(result.value() * 0.70)); + return result; +} + +QColor StyleHelper::borderColor(bool lightColored) +{ + QColor result = baseColor(lightColored); + result.setHsv(result.hue(), + result.saturation(), + result.value() / 2); + return result; +} + +void StyleHelper::setBaseColor(const QColor &color) +{ + if (color.isValid() && color != m_baseColor) { + m_baseColor = color; + foreach (QWidget *w, QApplication::topLevelWidgets()) + w->update(); + } +} + +static void verticalGradientHelper(QPainter *p, const QRect &spanRect, const QRect &rect, bool lightColored) +{ + QColor base = StyleHelper::baseColor(lightColored); + QColor highlight = StyleHelper::highlightColor(lightColored); + QColor shadow = StyleHelper::shadowColor(lightColored); + QLinearGradient grad(spanRect.topRight(), spanRect.topLeft()); + grad.setColorAt(0, highlight); + grad.setColorAt(0.301, base); + grad.setColorAt(1, shadow); + p->fillRect(rect, grad); + + QColor light(255, 255, 255, 80); + p->setPen(light); + p->drawLine(rect.topRight() - QPoint(1, 0), rect.bottomRight() - QPoint(1, 0)); +} + +void StyleHelper::verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored) +{ + if (StyleHelper::usePixmapCache()) { + QString key; + QColor keyColor = StyleHelper::baseColor(lightColored); + key.sprintf("mh_vertical %d %d %d %d %d", + spanRect.width(), spanRect.height(), clipRect.width(), + clipRect.height(), keyColor.rgb());; + + QPixmap pixmap; + if (!QPixmapCache::find(key, pixmap)) { + pixmap = QPixmap(clipRect.size()); + QPainter p(&pixmap); + QRect rect(0, 0, clipRect.width(), clipRect.height()); + verticalGradientHelper(&p, spanRect, rect, lightColored); + p.end(); + QPixmapCache::insert(key, pixmap); + } + + painter->drawPixmap(clipRect.topLeft(), pixmap); + } else { + verticalGradientHelper(painter, spanRect, clipRect, lightColored); + } +} + +static void horizontalGradientHelper(QPainter *p, const QRect &spanRect, const +QRect &rect, bool lightColored) +{ + QColor base = StyleHelper::baseColor(lightColored); + QColor highlight = StyleHelper::highlightColor(lightColored); + QColor shadow = StyleHelper::shadowColor(lightColored); + QLinearGradient grad(rect.topLeft(), rect.bottomLeft()); + grad.setColorAt(0, highlight.lighter(120)); + if (rect.height() == StyleHelper::navigationWidgetHeight()) { + grad.setColorAt(0.4, highlight); + grad.setColorAt(0.401, base); + } + grad.setColorAt(1, shadow); + p->fillRect(rect, grad); + + QLinearGradient shadowGradient(spanRect.topLeft(), spanRect.topRight()); + shadowGradient.setColorAt(0, QColor(0, 0, 0, 30)); + QColor lighterHighlight; + if (!lightColored) + lighterHighlight = highlight.lighter(130); + else + lighterHighlight = highlight.lighter(90); + lighterHighlight.setAlpha(100); + shadowGradient.setColorAt(0.7, lighterHighlight); + shadowGradient.setColorAt(1, QColor(0, 0, 0, 40)); + p->fillRect(rect, shadowGradient); +} + +void StyleHelper::horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored) +{ + if (StyleHelper::usePixmapCache()) { + QString key; + QColor keyColor = StyleHelper::baseColor(lightColored); + key.sprintf("mh_horizontal %d %d %d %d %d", + spanRect.width(), spanRect.height(), clipRect.width(), + clipRect.height(), keyColor.rgb()); + + QPixmap pixmap; + if (!QPixmapCache::find(key, pixmap)) { + pixmap = QPixmap(clipRect.size()); + QPainter p(&pixmap); + QRect rect = QRect(0, 0, clipRect.width(), clipRect.height()); + horizontalGradientHelper(&p, spanRect, rect, lightColored); + p.end(); + QPixmapCache::insert(key, pixmap); + } + + painter->drawPixmap(clipRect.topLeft(), pixmap); + + } else { + horizontalGradientHelper(painter, spanRect, clipRect, lightColored); + } +} + +static void menuGradientHelper(QPainter *p, const QRect &spanRect, const QRect &rect) +{ + QLinearGradient grad(spanRect.topLeft(), spanRect.bottomLeft()); + QColor menuColor = StyleHelper::mergedColors(StyleHelper::baseColor(), QColor(244, 244, 244), 25); + grad.setColorAt(0, menuColor.lighter(112)); + grad.setColorAt(1, menuColor); + p->fillRect(rect, grad); +} + +void StyleHelper::menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect) +{ + if (StyleHelper::usePixmapCache()) { + QString key; + key.sprintf("mh_menu %d %d %d %d %d", + spanRect.width(), spanRect.height(), clipRect.width(), + clipRect.height(), StyleHelper::baseColor().rgb()); + + QPixmap pixmap; + if (!QPixmapCache::find(key, pixmap)) { + pixmap = QPixmap(clipRect.size()); + QPainter p(&pixmap); + QRect rect = QRect(0, 0, clipRect.width(), clipRect.height()); + menuGradientHelper(&p, spanRect, rect); + p.end(); + QPixmapCache::insert(key, pixmap); + } + + painter->drawPixmap(clipRect.topLeft(), pixmap); + } else { + menuGradientHelper(painter, spanRect, clipRect); + } +} + +void StyleHelper::rectWithLeftLine(const QWidget *widget, QPainter *painter, const QRect &rect) +{ + painter->save(); + painter->setBrush(QBrush(widget->palette().background())); + painter->setPen(Qt::NoPen); + painter->drawRect(rect); + QPen pen = painter->pen(); + pen.setColor(highlightColor().lighter()); + pen.setStyle(Qt::SolidLine); + painter->setPen(pen); + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + painter->restore(); +} + +void StyleHelper::drawSlider(QPainter *painter, const QRect &rect) +{ + QColor base = StyleHelper::baseColor(); + QLinearGradient grad(rect.topRight(), rect.topLeft()); + grad.setColorAt(0, base.lighter()); + grad.setColorAt(1, base.lighter(190)); + painter->setRenderHint(QPainter::Antialiasing); + painter->setBrush(grad); + painter->setPen(Qt::NoPen); + painter->drawRoundedRect(rect, 3, 3); +} diff --git a/library/style/stylehelper.h b/library/style/stylehelper.h new file mode 100644 index 0000000..69765e2 --- /dev/null +++ b/library/style/stylehelper.h @@ -0,0 +1,77 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef STYLEHELPER_H +#define STYLEHELPER_H + +#include <QtGui/QColor> + +QT_BEGIN_NAMESPACE +class QPalette; +class QPainter; +class QRect; +QT_END_NAMESPACE + +// Helper class holding all custom color values + +class StyleHelper +{ +public: + // Height of the project explorer navigation bar + static int navigationWidgetHeight() { return 24; } + static qreal sidebarFontSize(); + static QPalette sidebarFontPalette(const QPalette &original); + + // This is our color table, all colors derive from baseColor + static QColor baseColor(bool lightColored = false); + static QColor panelTextColor(bool lightColored = false); + static QColor highlightColor(bool lightColored = false); + static QColor shadowColor(bool lightColored = false); + static QColor borderColor(bool lightColored = false); + static QColor buttonTextColor() { return QColor(0x4c4c4c); } + static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50); + + // Sets the base color and makes sure all top level widgets are updated + static void setBaseColor(const QColor &color); + + // Gradients used for panels + static void horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false); + static void verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false); + static void menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect); + + static void rectWithLeftLine(const QWidget *widget, QPainter *painter, const QRect &rect); + static void drawSlider(QPainter *painter, const QRect &rect); + + // Pixmap cache should only be enabled for X11 due to slow gradients + static bool usePixmapCache() { return true; } + +private: + static QColor m_baseColor; +}; +#endif // STYLEHELPER_H diff --git a/library/toolbox.cpp b/library/toolbox.cpp new file mode 100644 index 0000000..eb88a45 --- /dev/null +++ b/library/toolbox.cpp @@ -0,0 +1,366 @@ +#include "toolbox.h" +#include "style/styledbar.h" + +#include <QtCore/QStringList> +#include <QtGui/QPushButton> +#include <QtGui/QToolButton> +#include <QtGui/QLabel> +#include <QtGui/QVBoxLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QSpacerItem> + +ToolBox::ToolBox(bool pagesOpenOnInsertion, QWidget *parent, Qt::WindowFlags f) + : QFrame(parent, f) + , mLayout(0) + , mLargestMinimalInputWidth(0) + , mDefaultPagesOpen(pagesOpenOnInsertion) +{ + mLayout = new QVBoxLayout(); + mLayout->setAlignment(Qt::AlignTop); + mLayout->setSpacing(0); + mLayout->setMargin(0); + mLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding)); + setLayout(mLayout); +} + +ToolBox::~ToolBox() +{ +} + +bool ToolBox::addPage(const QString &title, const QList<OptionsItem *> &options) +{ + return insertPage(-1, title, options); +} +bool ToolBox::insertPage(int index, const QString &title, const QList<OptionsItem *> &options) +{ + if (index == -1) + index = layout()->count() - 1; //As the spacer is the layout's last item + if (index < 0 || index > layout()->count() - 1) + return false; + ToolBoxPage *page = new ToolBoxPage(title, options, this); + page->setStyle(style()); + mLayout->insertWidget(index, page); + mPages.insert(index, page); + connect(page, SIGNAL(minimalInputWidthChanged(int)), SLOT(processPageMinimalInputWidth(int))); + page->init(); + if (mDefaultPagesOpen && page->isHidden()) + page->showContent(true); + return true; +} + +bool ToolBox::insertPageIntoLayout(int index, ToolBoxPage *page) +{ + if (index == -1) + index = layout()->count() - 1; //As the spacer is the layout's last item + if (index < 0 || index > layout()->count() - 1) + return false; + mLayout->insertWidget(index, page); + return true; +} + +bool ToolBox::removePageFromLayout(ToolBoxPage *page) +{ + int pageIndex = mLayout->indexOf(page); + if (pageIndex == -1) + return false; + mLayout->removeWidget(page); + return true; +} + +void ToolBox::filtersChanged(const QString &filters) +{ + QStringList filterList = filters.split(' ', QString::SkipEmptyParts); + int i = 0; + foreach(ToolBoxPage *page, mPages) { + int itemCount = 0; + itemCount = page->filtersChanged(filterList); + int pageIndex = mLayout->indexOf(page); + // Increase i a) if the layout already contains the page and it is not removed + // or b) if the page is added. Thereby we keep the order of the toolboxpages. + if (pageIndex != -1) + { + if (itemCount == 0) { + removePageFromLayout(page); + page->setVisible(false); + } else { + i++; + } + } + else if (itemCount > 0 && pageIndex == -1) { + insertPageIntoLayout(i, page); + page->setVisible(true); + i++; + } + } +} + +void ToolBox::processPageMinimalInputWidth(int newWidth) +{ + if (newWidth > mLargestMinimalInputWidth) + { + mLargestMinimalInputWidth = newWidth; + foreach (ToolBoxPage *page, mPages) + page->setFixedInputWidth(newWidth); + } +} + +ToolBoxPage::ToolBoxPage(const QString &title, const QList<OptionsItem *> &options, ToolBox *box) + : QFrame(box) + , mButton(0) + , mPage(0) + , mInnerLayout(0) + , mHeaderLayout(0) + , mOptions(options) + , mAdvancedMode(false) + , mExplicitOpen(false) + , mMinimalInputWidth(0) +{ + setFrameShadow(QFrame::Raised); + + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->setMargin(0); + setLayout(vLayout); + + mButton = new QToolButton(this); + mButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + mButton->setText(title); + mButton->setArrowType(Qt::RightArrow); + mButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + mButton->setStyle(box->style()); + connect(mButton, SIGNAL(clicked()), SLOT(toggleOpenExplicitly())); + mHeaderLayout = new QHBoxLayout(); + mHeaderLayout->setSpacing(0); + mHeaderLayout->setContentsMargins(0,0,0,0); + mHeaderLayout->addWidget(mButton); + StyledBar *top = new StyledBar; + top->setStyle(box->style()); + top->setLightColored(true); + top->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + top->setLayout(mHeaderLayout); + vLayout->addWidget(top); + + mPage = new QWidget(this); + mInnerLayout = new QFormLayout(); + mInnerLayout->setVerticalSpacing(9); + mInnerLayout->setRowWrapPolicy(QFormLayout::WrapLongRows); + mInnerLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + mInnerLayout->setLabelAlignment(Qt::AlignLeft); + mPage->setLayout(mInnerLayout); + mPage->hide(); +} + +ToolBoxPage::~ToolBoxPage() +{ +} + +void ToolBoxPage::init() +{ + //Initially add all the "basic" items to the page, even if nothing is visible + int foundItems = findUnfilteredItems(); + //If the number of unfiltered items is smaller than the one of the given options, + //there have to be advanced items + if (foundItems < mOptions.count()) + addAdvancedButtonToHeader(); + emit minimalInputWidthChanged(mMinimalInputWidth); +} + +void ToolBoxPage::showContent(bool show) +{ + QVBoxLayout *vLayout = qobject_cast<QVBoxLayout*>(layout()); + if (show) { + if (vLayout->indexOf(mPage) == -1) + vLayout->addWidget(mPage); + mPage->show(); + mButton->setArrowType(Qt::DownArrow); + } else { + if (vLayout->indexOf(mPage) != -1) + vLayout->removeWidget(mPage); + mPage->hide(); + mButton->setArrowType(Qt::RightArrow); + } +} + +void ToolBoxPage::toggleOpenExplicitly() +{ + if (mPage->isHidden()) + mExplicitOpen = true; + else + mExplicitOpen = false; + showContent(mExplicitOpen); +} + +void ToolBoxPage::setAdvanced(bool advanced) +{ + mAdvancedMode = advanced; + if (mLastFilters.isEmpty()) { + findUnfilteredItems(); + showContent(true); + } +} + +void ToolBoxPage::addItem(OptionsItem *item) +{ + insertItem(-1, item); +} + +void ToolBoxPage::insertItem(int row, OptionsItem *item) +{ + if (row == -1) + row = mInnerLayout->count(); + if (item->type() == OptionsItem::FullWidthType) + mInnerLayout->insertRow(row, item->inputWidget()); + else { + item->inputLayout()->setParent(0); + mInnerLayout->insertRow(row, item->label(), item->inputLayout()); + } + item->setVisible(true); + + if (item->type() == OptionsItem::AdvancedType) { + connect(item, SIGNAL(toggleAdvanced(OptionsItem *)), + this, SLOT(advancedToggled(OptionsItem *))); + } + int width = item->inputWidget()->sizeHint().width(); + if (item->type() != OptionsItem::FullWidthType + && width > mMinimalInputWidth) + mMinimalInputWidth = width; +} + +void ToolBoxPage::addItemsAndSpacer(QList<OptionsItem *> items) +{ + foreach (OptionsItem *item, items) + addItem(item); + if (mInnerLayout->count() > 0) + mInnerLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); +} + +void ToolBoxPage::setFixedInputWidth(int newInputWidth) +{ + // force size + foreach (OptionsItem *item, mOptions) { + if (item->type() != OptionsItem::FullWidthType) + item->inputWidget()->setFixedWidth(newInputWidth); + } +} + +void ToolBoxPage::addAdvancedButtonToHeader() +{ + if (mHeaderLayout->count() == 1) { + QToolButton *advancedButton = new QToolButton(); + advancedButton->setCheckable(true); + advancedButton->setIcon(QIcon(":/style/images/advanced.png")); + mHeaderLayout->addWidget(advancedButton); + connect(advancedButton, SIGNAL(toggled(bool)), SLOT(setAdvanced(bool))); + } +} + +unsigned int ToolBoxPage::filtersChanged(const QStringList &filters) +{ + mLastFilters = filters; + int foundItems = 0; + if (filters.length() == 0) { + foundItems = findUnfilteredItems(); + showContent(mExplicitOpen); + } else { + foundItems = findFilteredItems(filters); + if (foundItems > 0) + showContent(true); + } + return foundItems; +} + +bool ToolBoxPage::filterItem(const QStringList &filters, OptionsItem *option) +{ + // If the option has an advanced page and this page is opened, close it before applying the filter + if (option->type() == OptionsItem::AdvancedType && !option->advancedPage()->inputWidget()->isHidden()) + advancedToggled(option); + if (option->isExplicitlyHidden()) + return false; + + option->setVisible(false); + foreach (const QString &filter, filters) { + if (option->matchTag(filter)) { + addItem(option); + return true; + } + } + return false; +} + +unsigned int ToolBoxPage::findFilteredItems(const QStringList &filters) +{ + // remove current options + while (mInnerLayout->count()) + mInnerLayout->takeAt(0); + + // add matching + QList<OptionsItem *> shownItems; + foreach(OptionsItem *item, mOptions) { + if (item->type() == OptionsItem::AdvancedType) { + if (!item->advancedPage()->inputWidget()->isHidden()) + advancedToggled(item); + disconnect(item, SIGNAL(toggleAdvanced(OptionsItem *)), + this, SLOT(advancedToggled(OptionsItem *))); + } + if (filterItem(filters, item)) { + shownItems += item; + } + } + + addItemsAndSpacer(shownItems); + + return shownItems.count(); +} + +unsigned int ToolBoxPage::findUnfilteredItems() +{ + //If a filter is applied, just ignore the call + if (mLastFilters.length() > 0) + return 0; + + while (mInnerLayout->count()) + mInnerLayout->takeAt(0); + + QList<OptionsItem *> shownItems; + foreach(OptionsItem *item, mOptions) { + if (item && item->type() == OptionsItem::AdvancedType) { + if (!item->advancedPage()->inputWidget()->isHidden()) + advancedToggled(item); + disconnect(item, SIGNAL(toggleAdvanced(OptionsItem *)), + this, SLOT(advancedToggled(OptionsItem *))); + } + if ((!mAdvancedMode && item->isAdvanced()) || item->isExplicitlyHidden()) + { + item->setVisible(false); + continue; + } + + shownItems += item; + + } + + addItemsAndSpacer(shownItems); + + return shownItems.count(); +} + +void ToolBoxPage::advancedToggled(OptionsItem *item) +{ + QAbstractButton *clickedButton = qobject_cast<QAbstractButton *>(item->inputWidget()); + if (clickedButton->text() == tr("Show")) + clickedButton->setText(tr("Hide")); + else + clickedButton->setText(tr("Show")); + + QWidget *advancedInput = item->advancedPage()->inputWidget(); + if (!advancedInput->isHidden()) + { + mInnerLayout->removeWidget(advancedInput); + advancedInput->hide(); + } else { + int row = 0; + mInnerLayout->getLayoutPosition(item->inputLayout(), &row, 0); + ++row; + mInnerLayout->insertRow(row, advancedInput); + advancedInput->show(); + } +} diff --git a/library/toolbox.h b/library/toolbox.h new file mode 100644 index 0000000..6ce7425 --- /dev/null +++ b/library/toolbox.h @@ -0,0 +1,92 @@ +#ifndef TOOLBOX_H +#define TOOLBOX_H + +#include "optionsitem.h" + +#include <QtGui/QFrame> +#include <QtGui/QWidget> +#include <QtCore/QList> + +class ToolBoxPage; +class QToolButton; +class QFormLayout; +class OptionsItem; +class QStringList; +class QVBoxLayout; +class QHBoxLayout; + +class ToolBox : public QFrame +{ + Q_OBJECT +public: + + explicit ToolBox(bool pagesOpenOnInsertion = false, QWidget *parent = 0, Qt::WindowFlags f = 0); + virtual ~ToolBox(); + +public: + bool addPage(const QString &title, const QList<OptionsItem *> &options); + bool insertPage(int index, const QString &title, const QList<OptionsItem *> &options); + + void filtersChanged(const QString &filters); + +private: + bool insertPageIntoLayout(int index, ToolBoxPage *page); + bool removePageFromLayout(ToolBoxPage *page); + QVBoxLayout *mLayout; + int mLargestMinimalInputWidth; + + bool mDefaultPagesOpen; + QList<ToolBoxPage *> mPages; + +private slots: + void processPageMinimalInputWidth(int newWidth); +}; + +class ToolBoxPage : public QFrame +{ + Q_OBJECT + friend class ToolBox; +public: + ToolBoxPage(const QString &title, const QList<OptionsItem *> &options, ToolBox *box); + virtual ~ToolBoxPage(); + +public slots: + unsigned int filtersChanged(const QStringList &filters); + void advancedToggled(OptionsItem *item); + +private: + QToolButton *mButton; + QWidget *mPage; + QFormLayout *mInnerLayout; + QHBoxLayout *mHeaderLayout; + QList<OptionsItem *> mOptions; + bool mAdvancedMode; + QStringList mLastFilters; + bool mExplicitOpen; + int mMinimalInputWidth; + + void init(); + void addAdvancedButtonToHeader(); + void addItem(OptionsItem *item); + void insertItem(int row, OptionsItem *item); + + void showContent(bool show); + + bool filterItem(const QStringList &filters, OptionsItem * option); + + unsigned int findFilteredItems(const QStringList &filters); + unsigned int findUnfilteredItems(); + + void addItemsAndSpacer(QList<OptionsItem *> items); + + void setFixedInputWidth(int newInputWidth); + +private slots: + void toggleOpenExplicitly(); + void setAdvanced(bool advanced); + +signals: + void minimalInputWidthChanged(int newWidth); +}; + +#endif //TOOLBOX_H |
