diff --git a/components/qtmaterialautocomplete.cpp b/components/qtmaterialautocomplete.cpp index 3fb7c5d..8853c10 100644 --- a/components/qtmaterialautocomplete.cpp +++ b/components/qtmaterialautocomplete.cpp @@ -1,2 +1,203 @@ #include "qtmaterialautocomplete.h" #include "qtmaterialautocomplete_p.h" +#include +#include +#include +#include "qtmaterialflatbutton.h" + +QtMaterialAutoCompletePrivate::QtMaterialAutoCompletePrivate(QtMaterialAutoComplete *q) + : QtMaterialTextFieldPrivate(q) +{ +} + +QtMaterialAutoCompletePrivate::~QtMaterialAutoCompletePrivate() +{ +} + +void QtMaterialAutoCompletePrivate::init() +{ + Q_Q(QtMaterialAutoComplete); + + menu = new QWidget; + menuLayout = new QVBoxLayout; + maxWidth = 0; + + menu->setParent(q->parentWidget()); + + QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect; + effect->setBlurRadius(11); + effect->setColor(QColor(0, 0, 0, 50)); + effect->setOffset(0, 3); + + menu->setGraphicsEffect(effect); + menu->setLayout(menuLayout); + menu->setVisible(false); + + menuLayout->setContentsMargins(0, 0, 0, 0); + menuLayout->setSpacing(0); + + QObject::connect(q, SIGNAL(textChanged(QString)), q, SLOT(updateResults(QString))); + + // + + QStringList states = + { "Alabama" + , "Alaska" + , "American Samoa" + , "Arizona" + , "Arkansas" + , "California" + , "Colorado" + , "Connecticut" + , "Delaware" + , "District of Columbia" + , "Florida" + , "Georgia" + , "Guam" + , "Hawaii" + , "Idaho" + , "Illinois" + , "Indiana" + , "Iowa" + , "Kansas" + , "Kentucky" + , "Louisiana" + , "Maine" + , "Maryland" + , "Massachusetts" + , "Michigan" + , "Minnesota" + , "Mississippi" + , "Missouri" + , "Montana" + , "Nebraska" + , "Nevada" + , "New Hampshire" + , "New Jersey" + , "New Mexico" + , "New York" + , "North Carolina" + , "North Dakota" + , "Northern Marianas Islands" + , "Ohio" + , "Oklahoma" + , "Oregon" + , "Pennsylvania" + , "Puerto Rico" + , "Rhode Island" + , "South Carolina" + , "South Dakota" + , "Tennessee" + , "Texas" + , "Utah" + , "Vermont" + , "Virginia" + , "Virgin Islands" + , "Washington" + , "West Virginia" + , "Wisconsin" + , "Wyoming" + }; + foreach (QString state, states) { + dataSource.push_back(state); + } +} + +QtMaterialAutoComplete::QtMaterialAutoComplete(QWidget *parent) + : QtMaterialTextField(*new QtMaterialAutoCompletePrivate(this), parent) +{ + d_func()->init(); +} + +QtMaterialAutoComplete::~QtMaterialAutoComplete() +{ +} + +void QtMaterialAutoComplete::updateResults(QString text) +{ + Q_D(QtMaterialAutoComplete); + + QStringList results; + QString trimmed(text.trimmed()); + + if (!trimmed.isEmpty()) { + QString lookup(trimmed.toLower()); + QStringList::iterator i; + for (i = d->dataSource.begin(); i != d->dataSource.end(); ++i) { + if (i->toLower().startsWith(lookup)) { + results.push_back(*i); + } + } + } + + const int diff = results.length() - d->menuLayout->count(); + QFont font("Roboto", 12, QFont::Normal); + + if (diff > 0) { + for (int c = 0; c < diff; c++) { + QtMaterialFlatButton *item = new QtMaterialFlatButton; + item->setFont(font); + item->setTextAlignment(Qt::AlignLeft); + item->setCornerRadius(0); + item->setHaloVisible(false); + item->setFixedHeight(50); + d->menuLayout->addWidget(item); + } + } else if (diff < 0) { + for (int c = 0; c < -diff; c++) { + QWidget *widget = d->menuLayout->itemAt(0)->widget(); + if (widget) { + d->menuLayout->removeWidget(widget); + delete widget; + } + } + } + + QFontMetrics *fm = new QFontMetrics(font); + d->maxWidth = 0; + + for (int i = 0; i < results.count(); ++i) { + QWidget *widget = d->menuLayout->itemAt(i)->widget(); + QtMaterialFlatButton *item; + if ((item = static_cast(widget))) { + QString text = results.at(i); + QRect rect = fm->boundingRect(text); + d->maxWidth = qMax(d->maxWidth, rect.width()); + item->setText(text); + } + } + + if (!results.count()) { + d->menu->hide(); + } else if (d->menu->isHidden()) { + d->menu->show(); + } + + d->menu->setFixedHeight(results.length()*50); + d->menu->setFixedWidth(qMax(d->maxWidth + 24, width())); + d->menu->update(); +} + +bool QtMaterialAutoComplete::QtMaterialAutoComplete::event(QEvent *event) +{ + Q_D(QtMaterialAutoComplete); + + switch (event->type()) + { + case QEvent::Move: + case QEvent::Resize: { + d->menu->move(pos() + QPoint(0, height() + 6)); + break; + } + case QEvent::ParentChange: { + QWidget *widget = static_cast(parent()); + if (widget) { + d->menu->setParent(widget); + } + break; + } + default: + break; + } + return QtMaterialTextField::event(event); +} diff --git a/components/qtmaterialautocomplete.h b/components/qtmaterialautocomplete.h index 81f0e3d..4e6771f 100644 --- a/components/qtmaterialautocomplete.h +++ b/components/qtmaterialautocomplete.h @@ -1,4 +1,27 @@ #ifndef QTMATERIALAUTOCOMPLETE_H #define QTMATERIALAUTOCOMPLETE_H +#include "qtmaterialtextfield.h" + +class QtMaterialAutoCompletePrivate; + +class QtMaterialAutoComplete : public QtMaterialTextField +{ + Q_OBJECT + +public: + explicit QtMaterialAutoComplete(QWidget *parent = 0); + ~QtMaterialAutoComplete(); + +protected slots: + void updateResults(QString text); + +protected: + bool event(QEvent *event) Q_DECL_OVERRIDE; + +private: + Q_DISABLE_COPY(QtMaterialAutoComplete) + Q_DECLARE_PRIVATE(QtMaterialAutoComplete) +}; + #endif // QTMATERIALAUTOCOMPLETE_H diff --git a/components/qtmaterialautocomplete_p.h b/components/qtmaterialautocomplete_p.h index 66d25c8..8bec9f9 100644 --- a/components/qtmaterialautocomplete_p.h +++ b/components/qtmaterialautocomplete_p.h @@ -1,4 +1,27 @@ #ifndef QTMATERIALAUTOCOMPLETE_P_H #define QTMATERIALAUTOCOMPLETE_P_H +#include "qtmaterialtextfield_p.h" + +class QWidget; +class QVBoxLayout; +class QtMaterialAutoCompleteOverlay; + +class QtMaterialAutoCompletePrivate : public QtMaterialTextFieldPrivate +{ + Q_DISABLE_COPY(QtMaterialAutoCompletePrivate) + Q_DECLARE_PUBLIC(QtMaterialAutoComplete) + +public: + QtMaterialAutoCompletePrivate(QtMaterialAutoComplete *q); + virtual ~QtMaterialAutoCompletePrivate(); + + void init(); + + QWidget *menu; + QVBoxLayout *menuLayout; + QStringList dataSource; + int maxWidth; +}; + #endif // QTMATERIALAUTOCOMPLETE_P_H diff --git a/components/qtmaterialtextfield.cpp b/components/qtmaterialtextfield.cpp index 5301c73..080da82 100644 --- a/components/qtmaterialtextfield.cpp +++ b/components/qtmaterialtextfield.cpp @@ -248,6 +248,13 @@ bool QtMaterialTextField::hasInputLine() const return d->showInputLine; } +QtMaterialTextField::QtMaterialTextField(QtMaterialTextFieldPrivate &d, QWidget *parent) + : QLineEdit(parent), + d_ptr(&d) +{ + d_func()->init(); +} + /*! * \reimp */ diff --git a/components/qtmaterialtextfield.h b/components/qtmaterialtextfield.h index 0d09a57..dead5cc 100644 --- a/components/qtmaterialtextfield.h +++ b/components/qtmaterialtextfield.h @@ -46,6 +46,8 @@ public: bool hasInputLine() const; protected: + QtMaterialTextField(QtMaterialTextFieldPrivate &d, QWidget *parent = 0); + bool event(QEvent *event) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; diff --git a/components/qtmaterialtextfield_p.h b/components/qtmaterialtextfield_p.h index aab57d7..9e8c835 100644 --- a/components/qtmaterialtextfield_p.h +++ b/components/qtmaterialtextfield_p.h @@ -15,7 +15,7 @@ class QtMaterialTextFieldPrivate public: QtMaterialTextFieldPrivate(QtMaterialTextField *q); - ~QtMaterialTextFieldPrivate(); + virtual ~QtMaterialTextFieldPrivate(); void init(); diff --git a/examples/autocompletesettingseditor.cpp b/examples/autocompletesettingseditor.cpp new file mode 100644 index 0000000..6392a9a --- /dev/null +++ b/examples/autocompletesettingseditor.cpp @@ -0,0 +1,212 @@ +#include "autocompletesettingseditor.h" +#include +#include +#include + +#include +#include +#include +#include "qtmaterialflatbutton.h" +#include + +AutoCompleteSettingsEditor::AutoCompleteSettingsEditor(QWidget *parent) + : QWidget(parent), + //ui(new Ui::AutoCompleteSettingsForm), + m_autocomplete(new QtMaterialAutoComplete) +{ + 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); + + + /* + Xyz *xyz = new Xyz(m_autocomplete); + xyz->setParent(canvas); + */ + + + //Menu *menu = new Menu; + //menu->setParent(xyz); + + //menu->move(220, 140); + //menu->move(pos()); + + //qDebug() << menu->parentWidget()->mapFromGlobal(QPoint(0, 0)); + //qDebug() << menu->mapToGlobal(QPoint(0, 0)); + + layout->addWidget(m_autocomplete); + layout->setAlignment(m_autocomplete, Qt::AlignCenter); + + setupForm(); + + //m_autocomplete->installEventFilter(xyz); +} + +AutoCompleteSettingsEditor::~AutoCompleteSettingsEditor() +{ + //delete ui; +} + +void AutoCompleteSettingsEditor::setupForm() +{ +} + +void AutoCompleteSettingsEditor::updateWidget() +{ +} + +void AutoCompleteSettingsEditor::selectColor() +{ +} + +// ---- + +Xyz::Xyz(QtMaterialAutoComplete *input, QWidget *parent) + : QtMaterialOverlayWidget(parent), + m_input(input), + m_menu(new Menu) +{ + m_menu->setParent(this); +} + +Xyz::~Xyz() +{ +} + +bool Xyz::eventFilter(QObject *obj, QEvent *event) +{ + switch (event->type()) + { + case QEvent::Move: + case QEvent::Resize: { + QtMaterialAutoComplete *widget = static_cast(obj); + if (widget) { + m_menu->move(widget->pos() + QPoint(0, m_input->height() + 6)); + m_menu->setFixedWidth(m_input->width()); + } + break; + } + case QEvent::ParentChange: + qDebug() << "Parent change"; + default: + break; + } + return QtMaterialOverlayWidget::eventFilter(obj, event); +} + +void Xyz::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + QPainter painter(this); + + QPen pen; + pen.setColor(Qt::red); + pen.setWidth(8); + + painter.setPen(pen); + + painter.drawRect(rect()); +} + + +Menu::Menu(QWidget *parent) + : QWidget(parent) +{ + QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect; + effect->setBlurRadius(11); + effect->setColor(QColor(0, 0, 0, 50)); + effect->setOffset(0, 3); + + setGraphicsEffect(effect); + + setMinimumWidth(300); + + QVBoxLayout *menuLayout = new QVBoxLayout; + menuLayout->setContentsMargins(0, 8, 0, 8); + + setLayout(menuLayout); + + QtMaterialFlatButton *fb1 = new QtMaterialFlatButton("Maps"); + QtMaterialFlatButton *fb2 = new QtMaterialFlatButton("Books"); + QtMaterialFlatButton *fb3 = new QtMaterialFlatButton("Flights"); + + QFont font("Roboto", 12, QFont::Normal); + //fb1->setIcon(QtMaterialTheme::icon("toggle", "star")); + + fb1->setFont(font); + fb2->setFont(font); + fb3->setFont(font); + + fb1->setTextAlignment(Qt::AlignLeft); + fb2->setTextAlignment(Qt::AlignLeft); + fb3->setTextAlignment(Qt::AlignLeft); + + fb1->setMinimumHeight(50); + fb2->setMinimumHeight(50); + fb3->setMinimumHeight(50); + + fb1->setHaloVisible(false); + fb2->setHaloVisible(false); + fb3->setHaloVisible(false); + + menuLayout->addWidget(fb1); + menuLayout->addWidget(fb2); + menuLayout->addWidget(fb3); + + menuLayout->setSpacing(0); + + //setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); +} + +Menu::~Menu() +{ +} + +//QSize Menu::sizeHint() const +//{ +// return QSize(300, 100); +//} + +bool Menu::event(QEvent *event) +{ + switch (event->type()) + { + case QEvent::Move: + case QEvent::Resize: + break; + case QEvent::ParentChange: + default: + break; + } + return QWidget::event(event); +} + +void Menu::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + QPainter painter(this); + + //painter.fillRect(rect(), Qt::white); + + //QPen pen; + //pen.setColor(Qt::blue); + //pen.setWidth(4); + + //painter.setPen(pen); + + //painter.drawRect(rect()); +} diff --git a/examples/autocompletesettingseditor.h b/examples/autocompletesettingseditor.h new file mode 100644 index 0000000..042c340 --- /dev/null +++ b/examples/autocompletesettingseditor.h @@ -0,0 +1,63 @@ +#ifndef AUTOCOMPLETESETTINGSEDITOR_H +#define AUTOCOMPLETESETTINGSEDITOR_H + +#include +//#include "ui_autocompletesettingsform.h" + +#include "lib/qtmaterialoverlaywidget.h" + +class QtMaterialAutoComplete; + +class AutoCompleteSettingsEditor : public QWidget +{ + Q_OBJECT + +public: + explicit AutoCompleteSettingsEditor(QWidget *parent = 0); + ~AutoCompleteSettingsEditor(); + +protected slots: + void setupForm(); + void updateWidget(); + void selectColor(); + +private: + //Ui::AutoCompleteSettingsForm *const ui; + QtMaterialAutoComplete *const m_autocomplete; +}; + +class Menu; + +class Xyz : public QtMaterialOverlayWidget +{ + Q_OBJECT + +public: + explicit Xyz(QtMaterialAutoComplete *input, QWidget *parent = 0); + ~Xyz(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + +private: + QtMaterialAutoComplete *const m_input; + Menu *const m_menu; +}; + +class Menu : public QWidget +{ + Q_OBJECT + +public: + Menu(QWidget *parent = 0); + ~Menu(); + + //QSize sizeHint() const Q_DECL_OVERRIDE; + +protected: + bool event(QEvent *event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; +}; + +#endif // AUTOCOMPLETESETTINGSEDITOR_H diff --git a/examples/examples.pro b/examples/examples.pro index 747871a..7d3c959 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -21,7 +21,8 @@ SOURCES = mainwindow.cpp \ dialogsettingseditor.cpp \ drawersettingseditor.cpp \ scrollbarsettingseditor.cpp \ - appbarsettingseditor.cpp + appbarsettingseditor.cpp \ + autocompletesettingseditor.cpp HEADERS = mainwindow.h \ avatarsettingseditor.h \ badgesettingseditor.h \ @@ -41,7 +42,8 @@ HEADERS = mainwindow.h \ dialogsettingseditor.h \ drawersettingseditor.h \ scrollbarsettingseditor.h \ - appbarsettingseditor.h + appbarsettingseditor.h \ + autocompletesettingseditor.h LIBS += $$top_builddir/components/$(OBJECTS_DIR)/libcomponents.a INCLUDEPATH += $$top_srcdir/components/ TARGET = examples-exe diff --git a/examples/mainwindow.cpp b/examples/mainwindow.cpp index b6683ec..404bfd7 100644 --- a/examples/mainwindow.cpp +++ b/examples/mainwindow.cpp @@ -21,6 +21,7 @@ #include "drawersettingseditor.h" #include "scrollbarsettingseditor.h" #include "appbarsettingseditor.h" +#include "autocompletesettingseditor.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -59,8 +60,10 @@ MainWindow::MainWindow(QWidget *parent) DrawerSettingsEditor *drawer = new DrawerSettingsEditor; ScrollBarSettingsEditor *scrollBar = new ScrollBarSettingsEditor; AppBarSettingsEditor *appBar = new AppBarSettingsEditor; + AutoCompleteSettingsEditor *autocomplete = new AutoCompleteSettingsEditor; stack->addWidget(appBar); + stack->addWidget(autocomplete); stack->addWidget(avatar); stack->addWidget(badge); stack->addWidget(checkbox); @@ -81,6 +84,7 @@ MainWindow::MainWindow(QWidget *parent) stack->addWidget(toggle); list->addItem("App Bar"); + list->addItem("Auto Complete"); list->addItem("Avatar"); list->addItem("Badge"); list->addItem("Checkbox");