summaryrefslogtreecommitdiff
path: root/form.hpp
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2014-05-25 11:16:36 +0200
committerDennis Brentjes <d.brentjes@gmail.com>2014-05-25 11:16:36 +0200
commit84c15aecc7d296d25b7fd5ead6730f8d132d350f (patch)
treee5e435007c97105ad819f0df84da3027d2e82d9d /form.hpp
parentd4ea872acfee5d4bf563334181400a9fef7d5add (diff)
downloadgeneric-gui-84c15aecc7d296d25b7fd5ead6730f8d132d350f.tar.gz
generic-gui-84c15aecc7d296d25b7fd5ead6730f8d132d350f.tar.bz2
generic-gui-84c15aecc7d296d25b7fd5ead6730f8d132d350f.zip
Adds a initial implementation of a Form, as a proof-of-concept.
Diffstat (limited to 'form.hpp')
-rw-r--r--form.hpp176
1 files changed, 176 insertions, 0 deletions
diff --git a/form.hpp b/form.hpp
new file mode 100644
index 0000000..15605a1
--- /dev/null
+++ b/form.hpp
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "fusion_static_dispatch.hpp"
+#include "gui_item_delegate.hpp"
+#include "boost_any_qvariant_convert.hpp"
+
+#include <QMdiArea>
+#include <QFormLayout>
+#include <QLineEdit>
+#include <QLabel>
+#include <QValidator>
+
+#include <memory>
+#include <sstream>
+
+template <bool is_int, bool is_float>
+struct QValidator_impl
+{
+ static constexpr bool needed = false;
+ typedef void type;
+};
+
+template <>
+struct QValidator_impl<true, false>
+{
+ static constexpr bool needed = true;
+ typedef QIntValidator type;
+};
+
+template <>
+struct QValidator_impl<false, true>
+{
+ static constexpr bool needed = true;
+ typedef QDoubleValidator type;
+};
+
+template <typename T>
+struct QValidatorFor
+{
+ static constexpr bool needed = QValidator_impl<std::is_integral<T>::value, std::is_floating_point<T>::value>::needed;
+ typedef typename QValidator_impl<std::is_integral<T>::value, std::is_floating_point<T>::value>::type type;
+};
+
+template <typename T>
+struct CreateWidget
+{
+ typedef QLineEdit* return_type;
+
+ template <bool allocate, typename V>
+ static typename std::enable_if<allocate, void>::type
+ set_validator_if_needed(QLineEdit* edit)
+ {
+ edit->setValidator(new V());
+ }
+
+ template <bool allocate, typename V>
+ static typename std::enable_if<!allocate, void>::type
+ set_validator_if_needed(QLineEdit*)
+ {
+ return;
+ }
+
+ template <int I>
+ static return_type call()
+ {
+ QLineEdit* edit = new QLineEdit();
+
+ typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex<T, I>::type value_type;
+
+ typedef QValidatorFor<value_type> QValiGen;
+
+ set_validator_if_needed<QValiGen::needed, typename QValiGen::type>(edit);
+ edit->setReadOnly(is_const<T>(I));
+ return edit;
+ }
+};
+
+template <typename T>
+struct StringToBoostAny {
+
+ typedef boost::any return_type;
+
+ template <int I>
+ static return_type call(std::string str)
+ {
+ typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex<T, I>::type value_type;
+
+ std::stringstream ss(str);
+
+ value_type x;
+ ss >> x;
+
+ return boost::any(x);
+ }
+};
+
+class FormUpdateHandler : public QObject
+{
+
+ Q_OBJECT
+
+public:
+ QLineEdit* edit;
+ std::function<void(std::string)> cb;
+
+ FormUpdateHandler(QLineEdit* edit, std::function<void(std::string)> cb)
+ : edit(edit)
+ , cb(cb)
+ {
+ connect(edit, SIGNAL(textEdited(QString const&)),
+ this, SLOT(edited(QString const&)));
+ }
+
+private slots:
+ void edited(QString const& str)
+ {
+ cb(str.toStdString());
+ }
+
+};
+
+template <typename T>
+struct Form : public QFormLayout{
+
+ std::shared_ptr<T> model;
+ QMdiArea* area;
+ std::vector<std::shared_ptr<FormUpdateHandler>> updatehandlers;
+ std::map<int, std::map<int, QLineEdit*>> line_edits;
+ GuiItemDelegate delegate;
+
+ Form(std::shared_ptr<T> model)
+ : model(model)
+ , area(new QMdiArea())
+ , updatehandlers()
+ , line_edits()
+ , delegate()
+ {
+ area->setLayout(this);
+ setup_gui();
+ fill_data();
+ }
+
+ 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
+ );
+ }
+ }
+ }
+
+ 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)));
+ }
+ }
+ }
+
+ void update_nth(int row, int column, std::string str)
+ {
+ model->set_cell(row, column, apply_functor_to_member<typename T::row_type, StringToBoostAny>(column, str));
+ }
+
+ QWidget* get_widget()
+ {
+ return area;
+ }
+};