diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2014-05-25 11:16:36 +0200 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2014-05-25 11:16:36 +0200 |
| commit | 84c15aecc7d296d25b7fd5ead6730f8d132d350f (patch) | |
| tree | e5e435007c97105ad819f0df84da3027d2e82d9d | |
| parent | d4ea872acfee5d4bf563334181400a9fef7d5add (diff) | |
| download | generic-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.txt | 2 | ||||
| -rw-r--r-- | boost_any_qvariant_convert.hpp | 120 | ||||
| -rw-r--r-- | form.hpp | 176 | ||||
| -rw-r--r-- | friendly_fusion.hpp | 36 | ||||
| -rw-r--r-- | fusion_static_dispatch.hpp | 23 | ||||
| -rw-r--r-- | gui_item_delegate.cpp | 5 | ||||
| -rw-r--r-- | gui_item_delegate.hpp | 1 | ||||
| -rw-r--r-- | main.cpp | 4 |
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: @@ -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()); |
