diff --git a/components/qtmaterialselectfield.cpp b/components/qtmaterialselectfield.cpp new file mode 100644 index 0000000..25299d1 --- /dev/null +++ b/components/qtmaterialselectfield.cpp @@ -0,0 +1,373 @@ +#include "xx/qtmaterialselectfield.h" +#include "xx/qtmaterialselectfield_p.h" +#include +#include +#include +#include +#include +#include "xxlib/qtmaterialstyle.h" +#include "xx/qtmaterialmenuitem.h" +#include "xx/qtmaterialcollapsiblemenu.h" +#include "xxlib/qtmaterialoverlaywidget.h" + +/*! + * \class QtMaterialSelectFieldPrivate + * \internal + */ + +QtMaterialSelectFieldPrivate::QtMaterialSelectFieldPrivate(QtMaterialSelectField *q) + : q_ptr(q) +{ +} + +QtMaterialSelectFieldPrivate::~QtMaterialSelectFieldPrivate() +{ +} + +void QtMaterialSelectFieldPrivate::init() +{ + Q_Q(QtMaterialSelectField); + + menuOverlay = new QtMaterialOverlayWidget(q); + menu = new QtMaterialCollapsibleMenu; + selectedIndex = -1; + useThemeColors = true; + + q->setStyle(&QtMaterialStyle::instance()); + + QFontDatabase db; + QFont font(db.font("Roboto", "Regular", 11)); + q->setFont(font); + + menuOverlay->setParent(q->parentWidget()); + menuOverlay->setAttribute(Qt::WA_TransparentForMouseEvents); + menuOverlay->installEventFilter(q); + + menu->setParent(menuOverlay); + menu->setMaximumHeight(300); + menu->setCollapsedXScale(1); + menu->setExpandYDuration(280); + menu->setExpandYEasingCurve(QEasingCurve::OutQuad); + + QObject::connect(menu, SIGNAL(aboutToCollapse()), q, SLOT(makeTransparent())); + QObject::connect(menu, SIGNAL(wasExpanded()), q, SLOT(makeOpaque())); + QObject::connect(menu, SIGNAL(aboutToExpand()), menuOverlay, SLOT(raise())); + QObject::connect(menu, SIGNAL(itemClicked(int)), q, SLOT(setSelectedIndex(int))); + QObject::connect(menu, SIGNAL(itemClicked(int)), q, SLOT(collapseDelayed())); + QObject::connect(menu, SIGNAL(itemClicked(int)), q, SIGNAL(itemSelected(int))); +} + +/*! + * \class QtMaterialSelectField + */ + +QtMaterialSelectField::QtMaterialSelectField(QWidget *parent) + : QWidget(parent), + d_ptr(new QtMaterialSelectFieldPrivate(this)) +{ + d_func()->init(); +} + +QtMaterialSelectField::~QtMaterialSelectField() +{ +} + +/*! + * \reimp + */ +QSize QtMaterialSelectField::sizeHint() const +{ + return QSize(300, 30); +} + +void QtMaterialSelectField::addItem(const QString &text) +{ + Q_D(QtMaterialSelectField); + + QtMaterialMenuItem *item = new QtMaterialMenuItem; + item->setText(text); + item->setHaloVisible(false); + + d->menu->addMenuItem(item); +} + +QtMaterialMenuItem *QtMaterialSelectField::itemAt(int index) const +{ + Q_D(const QtMaterialSelectField); + + return d->menu->menuItemAt(index); +} + +void QtMaterialSelectField::setPlaceholderText(const QString &text) +{ + Q_D(QtMaterialSelectField); + + d->placeholderText = text; + update(); +} + +QString QtMaterialSelectField::placeholderText() const +{ + Q_D(const QtMaterialSelectField); + + return d->placeholderText; +} + +void QtMaterialSelectField::setUseThemeColors(bool value) +{ + Q_D(QtMaterialSelectField); + + if (d->useThemeColors == value) { + return; + } + + d->useThemeColors = value; + update(); +} + +bool QtMaterialSelectField::useThemeColors() const +{ + Q_D(const QtMaterialSelectField); + + return d->useThemeColors; +} + +void QtMaterialSelectField::setUnderlineColor(const QColor &color) +{ + Q_D(QtMaterialSelectField); + + d->underlineColor = color; + setUseThemeColors(false); +} + +QColor QtMaterialSelectField::underlineColor() const +{ + Q_D(const QtMaterialSelectField); + + if (d->useThemeColors || !d->underlineColor.isValid()) { + return QtMaterialStyle::instance().themeColor("border"); + } + return d->underlineColor; +} + +void QtMaterialSelectField::setPlaceholderColor(const QColor &color) +{ + Q_D(QtMaterialSelectField); + + d->placeholderColor = color; + setUseThemeColors(false); +} + +QColor QtMaterialSelectField::placeholderColor() const +{ + Q_D(const QtMaterialSelectField); + + if (d->useThemeColors || !d->placeholderColor.isValid()) { + return QtMaterialStyle::instance().themeColor("accent3"); + } + return d->placeholderColor; +} + +void QtMaterialSelectField::setForegroundColor(const QColor &color) +{ + Q_D(QtMaterialSelectField); + + d->foregroundColor = color; + setUseThemeColors(false); +} + +QColor QtMaterialSelectField::foregroundColor() const +{ + Q_D(const QtMaterialSelectField); + + if (d->useThemeColors || !d->foregroundColor.isValid()) { + return QtMaterialStyle::instance().themeColor("text"); + } + return d->foregroundColor; +} + +void QtMaterialSelectField::setHighlightedColor(const QColor &color) +{ + Q_D(QtMaterialSelectField); + + d->highlightedColor = color; + setUseThemeColors(false); +} + +QColor QtMaterialSelectField::highlightedColor() const +{ + Q_D(const QtMaterialSelectField); + + if (d->useThemeColors || !d->highlightedColor.isValid()) { + return QtMaterialStyle::instance().themeColor("primary1"); + } + return d->highlightedColor; +} + +void QtMaterialSelectField::setDisabledColor(const QColor &color) +{ + Q_D(QtMaterialSelectField); + + d->disabledColor = color; + setUseThemeColors(false); +} + +QColor QtMaterialSelectField::disabledColor() const +{ + Q_D(const QtMaterialSelectField); + + if (d->useThemeColors || !d->disabledColor.isValid()) { + return QtMaterialStyle::instance().themeColor("disabled"); + } + return d->disabledColor; +} + +void QtMaterialSelectField::setSelectedIndex(int index) +{ + Q_D(QtMaterialSelectField); + + QtMaterialMenuItem *menuItem; + + if (d->selectedIndex > -1 && (menuItem = d->menu->menuItemAt(d->selectedIndex))) { + menuItem->setHighlighted(false); + } + if (index > -1 && (menuItem = d->menu->menuItemAt(index))) { + menuItem->setHighlighted(true); + d->selectedText = menuItem->text(); + } + d->selectedIndex = index; + update(); +} + +void QtMaterialSelectField::clearSelection() +{ + Q_D(QtMaterialSelectField); + + setSelectedIndex(-1); + d->selectedText.clear(); +} + +void QtMaterialSelectField::makeTransparent() +{ + Q_D(QtMaterialSelectField); + + d->menuOverlay->setAttribute(Qt::WA_TransparentForMouseEvents, true); +} + +void QtMaterialSelectField::makeOpaque() +{ + Q_D(QtMaterialSelectField); + + d->menuOverlay->setAttribute(Qt::WA_TransparentForMouseEvents, false); +} + +void QtMaterialSelectField::collapseDelayed() +{ + Q_D(QtMaterialSelectField); + + QTimer::singleShot(100, d->menu, SLOT(collapse())); +} + +/*! + * \reimp + */ +bool QtMaterialSelectField::event(QEvent *event) +{ + Q_D(QtMaterialSelectField); + + switch (event->type()) + { + case QEvent::Move: + case QEvent::Resize: + { + const QSize sh = d->menu->sizeHint(); + d->menu->setGeometry(x(), y(), width(), sh.height()); + break; + } + case QEvent::MouseButtonRelease: + { + if (isEnabled()) { + QtMaterialMenuItem *item; + for (int i = 0; i < d->menu->itemCount(); ++i) { + item = d->menu->menuItemAt(i); + if (item->isHighlighted()) { + item->setForegroundColor(highlightedColor()); + } else { + item->setForegroundColor(foregroundColor()); + } + } + d->menu->expand(); + } + break; + } + case QEvent::ParentChange: + { + QWidget *widget; + if ((widget = parentWidget())) { + d->menuOverlay->setParent(widget); + } + break; + } + default: + break; + } + return QWidget::event(event); +} + +/*! + * \reimp + */ +bool QtMaterialSelectField::eventFilter(QObject *obj, QEvent *event) +{ + Q_D(QtMaterialSelectField); + + if (QEvent::MouseButtonPress == event->type()) { + d->menu->collapse(); + } + return QWidget::eventFilter(obj, event); +} + +/*! + * \reimp + */ +void QtMaterialSelectField::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + Q_D(QtMaterialSelectField); + + QPainter painter(this); + + const int y = height()-1; + const int wd = width()-5; + + if (d->selectedText.isEmpty() && !d->placeholderText.isEmpty()) { + if (isEnabled()) { + painter.setPen(placeholderColor()); + } else { + painter.setPen(disabledColor()); + } + painter.drawText(2, y-8, d->placeholderText); + } else { + painter.drawText(2, y-8, d->selectedText); + } + + QPen pen; + pen.setWidth(1); + pen.setColor(underlineColor()); + painter.setPen(pen); + painter.setOpacity(1); + painter.drawLine(2.5, y, wd, y); + + if (isEnabled()) + { + static const int points[] = { wd-14, 12, wd-4, 12, wd-9, 18 }; + + QPolygon polygon; + polygon.setPoints(3, points); + + painter.setPen(Qt::NoPen); + painter.setBrush(underlineColor()); + painter.drawPolygon(polygon); + } +} diff --git a/components/qtmaterialselectfield.h b/components/qtmaterialselectfield.h new file mode 100644 index 0000000..fc263e4 --- /dev/null +++ b/components/qtmaterialselectfield.h @@ -0,0 +1,67 @@ +#ifndef QTMATERIALSELECTFIELD_H +#define QTMATERIALSELECTFIELD_H + +#include + +class QtMaterialSelectFieldPrivate; +class QtMaterialMenuItem; + +class QtMaterialSelectField : public QWidget +{ + Q_OBJECT + +public: + explicit QtMaterialSelectField(QWidget *parent = 0); + ~QtMaterialSelectField(); + + QSize sizeHint() const Q_DECL_OVERRIDE; + + void addItem(const QString &text); + QtMaterialMenuItem *itemAt(int index) const; + + void setPlaceholderText(const QString &text); + QString placeholderText() const; + + void setUseThemeColors(bool value); + bool useThemeColors() const; + + void setUnderlineColor(const QColor &color); + QColor underlineColor() const; + + void setPlaceholderColor(const QColor &color); + QColor placeholderColor() const; + + void setForegroundColor(const QColor &color); + QColor foregroundColor() const; + + void setHighlightedColor(const QColor &color); + QColor highlightedColor() const; + + void setDisabledColor(const QColor &color); + QColor disabledColor() const; + +signals: + void itemSelected(int index); + +public slots: + void setSelectedIndex(int index); + void clearSelection(); + +protected slots: + void makeTransparent(); + void makeOpaque(); + void collapseDelayed(); + +protected: + bool event(QEvent *event) Q_DECL_OVERRIDE; + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + + const QScopedPointer d_ptr; + +private: + Q_DISABLE_COPY(QtMaterialSelectField) + Q_DECLARE_PRIVATE(QtMaterialSelectField) +}; + +#endif // QTMATERIALSELECTFIELD_H diff --git a/components/qtmaterialselectfield_p.h b/components/qtmaterialselectfield_p.h new file mode 100644 index 0000000..1e7164d --- /dev/null +++ b/components/qtmaterialselectfield_p.h @@ -0,0 +1,37 @@ +#ifndef QTMATERIALSELECTFIELD_P_H +#define QTMATERIALSELECTFIELD_P_H + +#include +#include +#include + +class QtMaterialSelectField; +class QtMaterialOverlayWidget; +class QtMaterialCollapsibleMenu; + +class QtMaterialSelectFieldPrivate +{ + Q_DISABLE_COPY(QtMaterialSelectFieldPrivate) + Q_DECLARE_PUBLIC(QtMaterialSelectField) + +public: + QtMaterialSelectFieldPrivate(QtMaterialSelectField *q); + ~QtMaterialSelectFieldPrivate(); + + void init(); + + QtMaterialSelectField *const q_ptr; + QtMaterialOverlayWidget *menuOverlay; + QtMaterialCollapsibleMenu *menu; + QString selectedText; + QString placeholderText; + QColor underlineColor; + QColor placeholderColor; + QColor foregroundColor; + QColor highlightedColor; + QColor disabledColor; + int selectedIndex; + bool useThemeColors; +}; + +#endif // QTMATERIALSELECTFIELD_P_H diff --git a/examples/selectfieldsettingseditor.cpp b/examples/selectfieldsettingseditor.cpp new file mode 100644 index 0000000..2e3c374 --- /dev/null +++ b/examples/selectfieldsettingseditor.cpp @@ -0,0 +1,105 @@ +#include "yy/selectfieldsettingseditor.h" +#include +#include +#include +#include "xx/qtmaterialselectfield.h" +#include "xx/qtmaterialmenuitem.h" + +SelectFieldSettingsEditor::SelectFieldSettingsEditor(QWidget *parent) + : QWidget(parent), + ui(new Ui::SelectFieldSettingsForm), + m_selectField(new QtMaterialSelectField) +{ + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + QWidget *widget = new QWidget; + layout->addWidget(widget); + + QWidget *canvas = new QWidget; + canvas->setStyleSheet("QWidget { background: white; }"); + layout->addWidget(canvas); + + ui->setupUi(widget); + layout->setContentsMargins(20, 20, 20, 20); + + layout = new QVBoxLayout; + canvas->setLayout(layout); + layout->addWidget(m_selectField); + layout->setAlignment(m_selectField, Qt::AlignCenter); + + m_selectField->setPlaceholderText("Please select your favorite language"); + + { + m_selectField->addItem("C"); + m_selectField->addItem("C++"); + m_selectField->addItem("PHP"); + m_selectField->addItem("Haskell"); + m_selectField->addItem("JavaScript"); + m_selectField->addItem("ECMAScript"); + m_selectField->addItem("OCaml"); + m_selectField->addItem("Python"); + m_selectField->addItem("F#"); + m_selectField->addItem("Clojure"); + m_selectField->addItem("Java"); + + m_selectField->itemAt(2)->setDisabled(true); + } + + setupForm(); + + connect(ui->disabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->useThemeColorsCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->foregroundColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->underlineColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->placeholderColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->highlightedColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->disabledColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->placeholderLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateWidget())); + connect(ui->clearSelectionToolButton, SIGNAL(clicked(bool)), m_selectField, SLOT(clearSelection())); +} + +SelectFieldSettingsEditor::~SelectFieldSettingsEditor() +{ + delete ui; +} + +void SelectFieldSettingsEditor::setupForm() +{ + ui->disabledCheckBox->setChecked(!m_selectField->isEnabled()); + ui->useThemeColorsCheckBox->setChecked(m_selectField->useThemeColors()); + ui->placeholderLineEdit->setText(m_selectField->placeholderText()); +} + +void SelectFieldSettingsEditor::updateWidget() +{ + m_selectField->setDisabled(ui->disabledCheckBox->isChecked()); + m_selectField->setUseThemeColors(ui->useThemeColorsCheckBox->isChecked()); + m_selectField->setPlaceholderText(ui->placeholderLineEdit->text()); +} + +void SelectFieldSettingsEditor::selectColor() +{ + QColorDialog dialog; + if (dialog.exec()) { + QColor color = dialog.selectedColor(); + QString senderName = sender()->objectName(); + if ("foregroundColorToolButton" == senderName) { + m_selectField->setForegroundColor(color); + ui->foregroundColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("underlineColorToolButton" == senderName) { + m_selectField->setUnderlineColor(color); + ui->underlineColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("placeholderColorToolButton" == senderName) { + m_selectField->setPlaceholderColor(color); + ui->placeholderColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("highlightedColorToolButton" == senderName) { + m_selectField->setHighlightedColor(color); + ui->highlightedColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("disabledColorToolButton" == senderName) { + m_selectField->setDisabledColor(color); + ui->disabledColorLineEdit->setText(color.name(QColor::HexRgb)); + } + } + setupForm(); +} diff --git a/examples/selectfieldsettingseditor.h b/examples/selectfieldsettingseditor.h new file mode 100644 index 0000000..34506d9 --- /dev/null +++ b/examples/selectfieldsettingseditor.h @@ -0,0 +1,27 @@ +#ifndef SELECTFIELDSETTINGSEDITOR_H +#define SELECTFIELDSETTINGSEDITOR_H + +#include +#include "ui_selectfieldsettingsform.h" + +class QtMaterialSelectField; + +class SelectFieldSettingsEditor : public QWidget +{ + Q_OBJECT + +public: + explicit SelectFieldSettingsEditor(QWidget *parent = 0); + ~SelectFieldSettingsEditor(); + +protected slots: + void setupForm(); + void updateWidget(); + void selectColor(); + +private: + Ui::SelectFieldSettingsForm *const ui; + QtMaterialSelectField *const m_selectField; +}; + +#endif // SELECTFIELDSETTINGSEDITOR_H diff --git a/examples/selectfieldsettingsform.ui b/examples/selectfieldsettingsform.ui new file mode 100644 index 0000000..f12a34a --- /dev/null +++ b/examples/selectfieldsettingsform.ui @@ -0,0 +1,182 @@ + + + SelectFieldSettingsForm + + + + 0 + 0 + 511 + 388 + + + + Form + + + + + 0 + 0 + 202 + 253 + + + + + + + Disabled + + + + + + + + + + Foreground color + + + + + + + Underline color + + + + + + + Highlighted color + + + + + + + Disabled color + + + + + + + Placeholder text + + + + + + + Clear selection + + + + + + + + + + + + ... + + + + + + + + + + + + + + ... + + + + + + + + + + + + + + ... + + + + + + + + + + + + + + ... + + + + + + + + + + + + ... + + + + + + + Use theme colors + + + + + + + + + + Placeholder color + + + + + + + + + + + + ... + + + + + + + + formLayoutWidget + backgroundColorLabel + + + +