summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2014-05-27 16:14:46 +0200
committerDennis Brentjes <d.brentjes@gmail.com>2014-05-27 16:14:46 +0200
commit79af684323abfa10abfc31003ab47fd89a03d625 (patch)
treebfcdcff6b2fea6d1d3481d87629b90f239b86d1f
parent84c15aecc7d296d25b7fd5ead6730f8d132d350f (diff)
downloadgeneric-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.hpp198
-rw-r--r--fusion_model.hpp12
-rw-r--r--fusion_outputter.hpp4
-rw-r--r--main.cpp31
-rw-r--r--main_window.cpp1
5 files changed, 207 insertions, 39 deletions
diff --git a/form.hpp b/form.hpp
index 15605a1..e90a3da 100644
--- a/form.hpp
+++ b/form.hpp
@@ -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;
diff --git a/main.cpp b/main.cpp
index 43f8513..b631722 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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);