diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2014-05-27 16:14:46 +0200 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2014-05-27 16:14:46 +0200 |
| commit | 79af684323abfa10abfc31003ab47fd89a03d625 (patch) | |
| tree | bfcdcff6b2fea6d1d3481d87629b90f239b86d1f | |
| parent | 84c15aecc7d296d25b7fd5ead6730f8d132d350f (diff) | |
| download | generic-gui-79af684323abfa10abfc31003ab47fd89a03d625.tar.gz generic-gui-79af684323abfa10abfc31003ab47fd89a03d625.tar.bz2 generic-gui-79af684323abfa10abfc31003ab47fd89a03d625.zip | |
Tweaked the forms look and feal a bit and changed the way models are created.
| -rw-r--r-- | form.hpp | 198 | ||||
| -rw-r--r-- | fusion_model.hpp | 12 | ||||
| -rw-r--r-- | fusion_outputter.hpp | 4 | ||||
| -rw-r--r-- | main.cpp | 31 | ||||
| -rw-r--r-- | main_window.cpp | 1 |
5 files changed, 207 insertions, 39 deletions
@@ -3,12 +3,15 @@ #include "fusion_static_dispatch.hpp" #include "gui_item_delegate.hpp" #include "boost_any_qvariant_convert.hpp" +#include "fusion_model.hpp" #include <QMdiArea> +#include <QVBoxLayout> #include <QFormLayout> #include <QLineEdit> #include <QLabel> #include <QValidator> +#include <QPushButton> #include <memory> #include <sstream> @@ -88,12 +91,30 @@ struct StringToBoostAny { std::stringstream ss(str); value_type x; - ss >> x; + ss >> std::boolalpha >> x; return boost::any(x); } }; +template <typename T> +struct BoostAnyToString { + + typedef std::string return_type; + + template <int I> + static return_type call(boost::any any) + { + typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex<T, I>::type value_type; + + std::stringstream ss; + ss << std::boolalpha << boost::any_cast<value_type>(any); + + return ss.str(); + } + +}; + class FormUpdateHandler : public QObject { @@ -107,8 +128,10 @@ public: : edit(edit) , cb(cb) { - connect(edit, SIGNAL(textEdited(QString const&)), - this, SLOT(edited(QString const&))); + connect( + edit, SIGNAL(textEdited(QString const&)), + this, SLOT(edited(QString const&)) + ); } private slots: @@ -119,54 +142,173 @@ private slots: }; +//This base is required because an QObject may not be templated and Form is a class template. +//Slots can be virtual however. +class QtFormBase : public QObject +{ + + Q_OBJECT + +protected slots: + virtual void prev_clicked() = 0; + virtual void jump() = 0; + virtual void next_clicked() = 0; +}; + template <typename T> -struct Form : public QFormLayout{ +struct Form : public QtFormBase, public FusionModelObserver { std::shared_ptr<T> model; QMdiArea* area; + QVBoxLayout* layout; + QFormLayout* form_layout; + QHBoxLayout* button_layout; + QPushButton* prev; + QLineEdit* jump_edit; + QPushButton* next; std::vector<std::shared_ptr<FormUpdateHandler>> updatehandlers; - std::map<int, std::map<int, QLineEdit*>> line_edits; - GuiItemDelegate delegate; + std::map<int, QLineEdit*> line_edits; + + int current_index; Form(std::shared_ptr<T> model) : model(model) , area(new QMdiArea()) + , layout(new QVBoxLayout()) + , form_layout(new QFormLayout()) + , button_layout(new QHBoxLayout()) + , prev(new QPushButton("&Previous")) + , jump_edit(new QLineEdit()) + , next(new QPushButton("&Next")) , updatehandlers() , line_edits() - , delegate() + , current_index(0) { - area->setLayout(this); + layout->setAlignment(Qt::AlignTop); + + prev->setMaximumWidth(150); + + jump_edit->setValidator(new QIntValidator()); + jump_edit->setMaximumWidth(100); + + next->setMaximumWidth(150); + + layout->addLayout(form_layout); + layout->addLayout(button_layout); + + button_layout->addWidget(prev); + button_layout->addWidget(jump_edit); + button_layout->addWidget(next); + button_layout->setAlignment(Qt::AlignHCenter); + + area->setLayout(layout); + setup_gui(); fill_data(); + + area->updateGeometry(); + + set_button_state(); + connect( + prev, SIGNAL(clicked()), + this, SLOT(prev_clicked()) + ); + + connect( + jump_edit, SIGNAL(editingFinished()), + this, SLOT(jump()) + ); + + connect( + next, SIGNAL(clicked()), + this, SLOT(next_clicked()) + ); + + set_current_index(0); } void setup_gui() { - for(int i = 0; i < model->row_count(); ++i) { - for(int j = 0; j < model->column_count(); j++) { - QLineEdit* edit = apply_functor_to_member<typename T::row_type, CreateWidget>(j); - updatehandlers.push_back(std::make_shared<FormUpdateHandler>(edit, [i, j, this](std::string str){update_nth(i, j, str);})); - line_edits[i][j] = edit; - this->addRow( - new QLabel(QString::fromStdString(model->field_name(j))), - edit - ); - } + for(int j = 0; j < model->column_count(); j++) { + QLineEdit* edit = apply_functor_to_member<typename T::row_type, CreateWidget>(j); + updatehandlers.push_back(std::make_shared<FormUpdateHandler>(edit, [j, this](std::string str){update_nth_in_model(j, str);})); + line_edits[j] = edit; + form_layout->addRow( + new QLabel(QString::fromStdString(model->field_name(j))), + edit + ); } } + void update_pos(int i, int j) + { + line_edits[j]->setText(QString::fromStdString(apply_functor_to_member<typename T::row_type, BoostAnyToString>(j, model->get_cell(i, j)))); + } + void fill_data() { - for(int i = 0; i < model->row_count(); ++i) { - for(int j = 0; j < model->column_count(); j++) { - line_edits[i][j]->setText(delegate.displayText(to_qvariant<typename T::row_type>(model->get_cell(i, j), j))); - } + for(int j = 0; j < model->column_count(); j++) { + update_pos(current_index, j); } } - void update_nth(int row, int column, std::string str) + void set_button_state() + { + prev->setEnabled(current_index != 0); + next->setEnabled(current_index != model->row_count() - 1); + } + + void update_nth_in_model(int entry, std::string str) + { + model->set_cell(current_index, entry, apply_functor_to_member<typename T::row_type, StringToBoostAny>(entry, str)); + } + + void set_current_index(int i) { - model->set_cell(row, column, apply_functor_to_member<typename T::row_type, StringToBoostAny>(column, str)); + current_index = i; + fill_data(); + set_button_state(); + jump_edit->setText(QString::number(i + 1)); + } + + int clamp_index(int i) + { + if(i < 0) { + i = 0; + } + + if(i > model->row_count() - 1) { + i = model->row_count() - 1; + } + + return i; + } + + //Observer interface + virtual void cell_changed(int form_id, int entry) override final + { + update_pos(form_id, entry); + } + + //Gui interface. + virtual void prev_clicked() override final + { + int i = clamp_index(current_index - 1); + set_current_index(i); + } + + virtual void jump() override final + { + int jump_to = jump_edit->text().toInt() - 1; + int i = clamp_index(jump_to); + + set_current_index(i); + } + + virtual void next_clicked() override final + { + int i = clamp_index(current_index + 1); + set_current_index(i); } QWidget* get_widget() @@ -174,3 +316,11 @@ struct Form : public QFormLayout{ return area; } }; + +template <typename Model> +std::shared_ptr<Form<Model>> make_form(std::shared_ptr<Model> model) +{ + auto ret = std::make_shared<Form<Model>>(model); + model->add_observer(ret); + return ret; +} diff --git a/fusion_model.hpp b/fusion_model.hpp index 3d84c87..d2fe950 100644 --- a/fusion_model.hpp +++ b/fusion_model.hpp @@ -94,9 +94,11 @@ struct FusionModel<std::vector<T>> : public FusionModelInterface<true, false> typedef std::vector<T> data_type; typedef T row_type; - std::vector<T> data; + std::vector<T>& data; - FusionModel() = default; + FusionModel(std::vector<T>& data) + : data(data) + {} virtual size_t row_count() const override final { @@ -133,9 +135,11 @@ struct FusionModel<std::map<std::string, T>> : public FusionModelInterface<true, typedef std::map<std::string, T> data_type; typedef T row_type; - std::map<std::string, T> data; + std::map<std::string, T>& data; - FusionModel() = default; + FusionModel(std::map<std::string, T>& data) + : data(data) + {} virtual size_t row_count() const override final { diff --git a/fusion_outputter.hpp b/fusion_outputter.hpp index 3c3d5c4..a1a6927 100644 --- a/fusion_outputter.hpp +++ b/fusion_outputter.hpp @@ -39,8 +39,6 @@ struct Outputter { return os; } - - }; template <typename T, typename U> @@ -48,7 +46,7 @@ std::ostream& operator<<(std::ostream& os, std::map<T, U> map) { os << "{" << std::endl; for (auto&& x : map) { - os << "\t{" << x.first << ", " << x.second << "}" << std::endl; + os << "\t{" << x.first << ", " << "{" << x.second << "}}" << std::endl; } os << "}" << std::endl; return os; @@ -12,6 +12,7 @@ struct Data { const std::string name; + std::string gender; uint32_t number; const double ratio1; double ratio2; @@ -21,6 +22,7 @@ struct Data { BOOST_FUSION_ADAPT_STRUCT( Data, (const std::string, name) + (std::string, gender) (uint32_t, number) (const double, ratio1) (double,ratio2) @@ -28,13 +30,26 @@ BOOST_FUSION_ADAPT_STRUCT( ) struct DataModel : public FusionModel<std::vector<Data>> { + + std::vector<Data> model; + + DataModel() + : FusionModel(model) + {} + void add_data(Data d) { - data.push_back(d); + model.push_back(d); } - }; -struct DataMapping :public FusionModel<std::map<std::string, Data>> { +struct DataMapping : public FusionModel<std::map<std::string, Data>> { + + std::map<std::string, Data> model; + + DataMapping() + : FusionModel(model) + {} + void add_data(std::string key, Data value) { call_on_observers(&FusionModelObserver::append_row_begin); @@ -52,9 +67,9 @@ struct CustomDataModelWidget : public WidgetType<DataModel>::type int main() { - Data d1{"Pietje", 2, 3.333, 0.333, true}; - Data d2{"Jantje", 3, 1.5, 0.5, false}; - Data d3{"Sjaakje", 1, 0.1337, 0.0337, false}; + Data d1{"Jan", "Male", 1, 3.333, 0.333, true}; + Data d2{"Piet", "Male",2, 1.5, 0.5, false}; + Data d3{"Klaas", "Confused", 3, 0.1337, 0.0337, false}; auto model = std::make_shared<DataModel>(); @@ -74,9 +89,9 @@ int main() auto widget2 = make_qt_widget(model); auto widget3 = make_qt_widget(mapping); - Form<DataModel> form(model); + auto form = make_form(model); - w.add_widget(form.get_widget()); + w.add_widget(form->get_widget()); w.add_widget(widget1.get()); w.add_widget(widget2.get()); w.add_widget(widget3.get()); diff --git a/main_window.cpp b/main_window.cpp index 65daf3e..2affa7f 100644 --- a/main_window.cpp +++ b/main_window.cpp @@ -7,6 +7,7 @@ MainWindow::MainWindow() , area(new QMdiArea()) , layout(new QVBoxLayout()) { + layout->setAlignment(Qt::AlignTop); area->setLayout(layout); w.setCentralWidget(area); |
