summaryrefslogtreecommitdiff
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
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.
-rw-r--r--CMakeLists.txt2
-rw-r--r--boost_any_qvariant_convert.hpp120
-rw-r--r--form.hpp176
-rw-r--r--friendly_fusion.hpp36
-rw-r--r--fusion_static_dispatch.hpp23
-rw-r--r--gui_item_delegate.cpp5
-rw-r--r--gui_item_delegate.hpp1
-rw-r--r--main.cpp4
8 files changed, 257 insertions, 110 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 307d2a7..1e207d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,6 +41,7 @@ include_directories(SYSTEM ${Qt5Core_INCLUDE_DIRS})
qt5_wrap_cpp(qt_sources
gui_item_delegate.hpp
+ form.hpp
)
add_executable(generic_gui
@@ -52,6 +53,7 @@ add_executable(generic_gui
meta_types.hpp
boost_any_qvariant_convert.hpp
fusion_outputter.hpp
+ form.hpp
gui_item_delegate.hpp gui_item_delegate.cpp
main_window.hpp main_window.cpp
${qt_sources}
diff --git a/boost_any_qvariant_convert.hpp b/boost_any_qvariant_convert.hpp
index 1f6e2be..8770919 100644
--- a/boost_any_qvariant_convert.hpp
+++ b/boost_any_qvariant_convert.hpp
@@ -9,113 +9,43 @@
#include <string>
-template<typename value_type>
-QVariant to_qvariant(boost::any const& x)
-{
- return QVariant::fromValue<value_type>(boost::any_cast<value_type>(x));
-}
-
-template <typename T, int n>
-QVariant to_qvariant(boost::any const& x)
-{
- typedef friendly_fusion::result_of::begin<T> begin;
- typedef friendly_fusion::result_of::advance_c<typename begin::type, n> adv_it;
- typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
- typedef typename std::decay<typename deref::type>::type value_type;
- return to_qvariant<value_type>(x);
-}
-
-#if defined( __GNUC__ ) && !defined( __clang__ )
-template <typename T, int index>
-std::function<QVariant(boost::any const&)> to_qvariant_lambda()
-{
- return [](boost::any const& any)
- {
- return to_qvariant<T, index>(any);
- };
-}
-
-#endif //defined( __GNUC__ ) && !defined( __clang__ )
-
-template<typename T, int... Indices>
-QVariant to_qvariant(boost::any const& any, int index, indices<Indices...>)
-{
- typedef std::function<QVariant(boost::any const&)> element_type;
- static element_type table[] =
+template <typename T>
+struct ToQvariantFunctor {
+
+ typedef QVariant return_type;
+
+ template <int I>
+ static return_type call(boost::any const& any)
{
-#if defined( __GNUC__ ) && !defined( __clang__ )
- //Workaround for gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
- to_qvariant_lambda<T, Indices>()
- ...
-#else
- [](boost::any const& any){return to_qvariant<T, Indices>(any);}
- ...
-#endif //defined( __GNUC__ ) && !defined( __clang__ )
- };
+ typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex<T, I>::type value_type;
+
+ return QVariant::fromValue<value_type>(boost::any_cast<value_type>(any));
+ }
- return table[index](any);
-}
+};
template <typename T>
QVariant to_qvariant(boost::any const& x, int index)
{
- typedef typename friendly_fusion::result_of::size<T>::type seq_size;
- typedef typename build_indices<seq_size::value>::type indices_type;
-
- return to_qvariant<T>(x, index, indices_type{});
+ return apply_functor_to_member<T, ToQvariantFunctor>(index, x);
}
-template<typename value_type>
-boost::any to_boost_any(QVariant const& x)
-{
- return boost::any(x.value<value_type>());
-}
-
-template <typename T, int n>
-boost::any to_boost_any(QVariant const& x)
-{
- typedef friendly_fusion::result_of::begin<T> begin;
- typedef friendly_fusion::result_of::advance_c<typename begin::type, n> adv_it;
- typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
- typedef typename std::decay<typename deref::type>::type value_type;
- return to_boost_any<value_type>(x);
-}
-
-#if defined( __GNUC__ ) && !defined( __clang__ )
-template <typename T, int index>
-std::function<boost::any(QVariant const&)> to_boost_any_lambda()
-{
- return [](QVariant const& value)
- {
- return to_boost_any<T, index>(value);
- };
-}
-#endif //defined( __GNUC__ ) && !defined( __clang__ )
-
-template<typename T, int... Indices>
-boost::any to_boost_any(QVariant const& value, int index, indices<Indices...>)
+template <typename T>
+struct ToBoostAnyFunctor
{
- typedef std::function<boost::any(QVariant const&)> element_type;
- static element_type table[] =
+ typedef boost::any return_type;
+
+ template <int I>
+ static return_type call(QVariant const& variant)
{
-#if defined( __GNUC__ ) && !defined( __clang__ )
- //Workaround for gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
- to_boost_any_lambda<T, Indices>()
- ...
-#else
- [](QVariant const& value){return to_boost_any<T, Indices>(value);}
- ...
-#endif //defined( __GNUC__ ) && !defined( __clang__ )
- };
-
- return table[index](value);
-}
+ typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex<T, I>::type value_type;
+
+ return boost::any(variant.value<value_type>());
+ }
+};
template <typename T>
boost::any to_boost_any(QVariant const& x, int index)
{
- typedef typename friendly_fusion::result_of::size<T>::type seq_size;
- typedef typename build_indices<seq_size::value>::type indices_type;
-
- return to_boost_any<T>(x, index, indices_type{});
+ return apply_functor_to_member<T, ToBoostAnyFunctor>(index, x);
} \ No newline at end of file
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;
+ }
+};
diff --git a/friendly_fusion.hpp b/friendly_fusion.hpp
index b014bd8..09ec920 100644
--- a/friendly_fusion.hpp
+++ b/friendly_fusion.hpp
@@ -126,4 +126,40 @@ struct struct_member_name : private traits::is_sequence<T, false>, public boost:
}
+namespace utils {
+
+template<typename T, int I>
+class DecayedTypeOfAtIndex {
+ typedef friendly_fusion::result_of::begin<T> begin;
+ typedef friendly_fusion::result_of::advance_c<typename begin::type, I> adv_it;
+ typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
+ typedef std::decay<typename deref::type> decayed;
+
+public:
+ typedef typename decayed::type type;
+};
+
+template<typename T, int I>
+class RefTypeOfAtIndex {
+ typedef friendly_fusion::result_of::begin<T> begin;
+ typedef friendly_fusion::result_of::advance_c<typename begin::type, I> adv_it;
+ typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
+
+public:
+ typedef typename deref::type type;
+};
+
+template<typename T, int I>
+class UnrefTypeOfAtIndex {
+ typedef friendly_fusion::result_of::begin<T> begin;
+ typedef friendly_fusion::result_of::advance_c<typename begin::type, I> adv_it;
+ typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
+ typedef std::remove_reference<typename deref::type> unrefed;
+
+public:
+ typedef typename unrefed::type type;
+};
+
+}
+
} \ No newline at end of file
diff --git a/fusion_static_dispatch.hpp b/fusion_static_dispatch.hpp
index 6b3ad42..5db3e16 100644
--- a/fusion_static_dispatch.hpp
+++ b/fusion_static_dispatch.hpp
@@ -19,7 +19,7 @@ typename F<U>::return_type apply_functor_to_member_impl(indices<Indices...>, int
{
typedef std::function<typename F<U>::return_type(Args...)> f_type;
static f_type array[] = {
- (std::function<typename F<U>::return_type(Args...)>) F<U>::template call<Indices>
+ F<U>::template call<Indices>
...
};
@@ -31,7 +31,7 @@ typename F<Arg1>::return_type apply_functor_to_member_impl(indices<Indices...>,
{
typedef std::function<typename F<Arg1>::return_type(Arg1&, Args...)> f_type;
static f_type array[] = {
- (std::function<typename F<Arg1>::return_type(Arg1&, Args...)>) F<Arg1>::template call<Indices>
+ F<Arg1>::template call<Indices>
...
};
@@ -58,12 +58,9 @@ struct is_const_functor
template <int I>
static return_type call()
{
- typedef friendly_fusion::result_of::begin<T> begin;
- typedef friendly_fusion::result_of::advance_c<typename begin::type, I> adv_it;
- typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
- typedef std::remove_reference<typename deref::type> unreferenced_type;
+ typedef typename friendly_fusion::utils::UnrefTypeOfAtIndex<T, I>::type unref_type;
- return std::is_const<typename unreferenced_type::type>::value;
+ return std::is_const<unref_type>::value;
}
};
@@ -105,7 +102,6 @@ typename std::enable_if<!b, void>::type assign(T& lh, V rh)
lh = rh;
}
-
template <typename T>
struct set_nth_functor
{
@@ -114,13 +110,10 @@ struct set_nth_functor
template <int I>
static return_type call(T& t, boost::any const& value)
{
- typedef friendly_fusion::result_of::begin<T> begin;
- typedef friendly_fusion::result_of::advance_c<typename begin::type, I> adv_it;
- typedef friendly_fusion::result_of::deref<typename adv_it::type> deref;
- typedef typename std::decay<typename deref::type>::type value_type;
- typedef typename std::remove_reference<typename deref::type>::type unreferenced_type;
+ typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex<T, I>::type value_type;
+ typedef typename friendly_fusion::utils::UnrefTypeOfAtIndex<T, I>::type unref_type;
- assign<std::is_const<unreferenced_type>::value>(friendly_fusion::deref(friendly_fusion::advance_c<I>(friendly_fusion::begin(t))), boost::any_cast<value_type>(value));
+ assign<std::is_const<unref_type>::value>(friendly_fusion::deref(friendly_fusion::advance_c<I>(friendly_fusion::begin(t))), boost::any_cast<value_type>(value));
}
};
@@ -154,7 +147,7 @@ struct get_nth_name_functor<boost::fusion::joint_view<T,U>>
if(I < size_of_T){
return apply_functor_to_member<T, get_nth_name_functor>(I);
} else {
- return apply_functor_to_member<U, get_nth_name_functor>(I);
+ return apply_functor_to_member<U, get_nth_name_functor>(I - size_of_T);
}
}
};
diff --git a/gui_item_delegate.cpp b/gui_item_delegate.cpp
index 2eafa44..b3d9094 100644
--- a/gui_item_delegate.cpp
+++ b/gui_item_delegate.cpp
@@ -47,3 +47,8 @@ QString GuiItemDelegate::displayText(const QVariant &value, const QLocale &local
}
return ret;
}
+
+QString GuiItemDelegate::displayText(const QVariant &value)
+{
+ return displayText(value, QLocale());
+}
diff --git a/gui_item_delegate.hpp b/gui_item_delegate.hpp
index b0f52a7..23adcf3 100644
--- a/gui_item_delegate.hpp
+++ b/gui_item_delegate.hpp
@@ -12,6 +12,7 @@ public:
virtual void setModelData(QWidget* widget, QAbstractItemModel* model, QModelIndex const& index) const override final;
virtual void setEditorData(QWidget* widget, QModelIndex const& index) const override final;
virtual QString displayText(const QVariant &value, const QLocale &locale) const override final;
+ QString displayText(const QVariant &value);
signals:
diff --git a/main.cpp b/main.cpp
index d817367..43f8513 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4,6 +4,7 @@
#include "qt_adapter.hpp"
#include "meta_types.hpp"
#include "fusion_outputter.hpp"
+#include "form.hpp"
#include <boost/fusion/adapted.hpp>
@@ -73,6 +74,9 @@ int main()
auto widget2 = make_qt_widget(model);
auto widget3 = make_qt_widget(mapping);
+ Form<DataModel> form(model);
+
+ w.add_widget(form.get_widget());
w.add_widget(widget1.get());
w.add_widget(widget2.get());
w.add_widget(widget3.get());