From 84c15aecc7d296d25b7fd5ead6730f8d132d350f Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Sun, 25 May 2014 11:16:36 +0200 Subject: Adds a initial implementation of a Form, as a proof-of-concept. --- CMakeLists.txt | 2 + boost_any_qvariant_convert.hpp | 120 ++++++---------------------- form.hpp | 176 +++++++++++++++++++++++++++++++++++++++++ friendly_fusion.hpp | 36 +++++++++ fusion_static_dispatch.hpp | 23 ++---- gui_item_delegate.cpp | 5 ++ gui_item_delegate.hpp | 1 + main.cpp | 4 + 8 files changed, 257 insertions(+), 110 deletions(-) create mode 100644 form.hpp 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 -template -QVariant to_qvariant(boost::any const& x) -{ - return QVariant::fromValue(boost::any_cast(x)); -} - -template -QVariant to_qvariant(boost::any const& x) -{ - typedef friendly_fusion::result_of::begin begin; - typedef friendly_fusion::result_of::advance_c adv_it; - typedef friendly_fusion::result_of::deref deref; - typedef typename std::decay::type value_type; - return to_qvariant(x); -} - -#if defined( __GNUC__ ) && !defined( __clang__ ) -template -std::function to_qvariant_lambda() -{ - return [](boost::any const& any) - { - return to_qvariant(any); - }; -} - -#endif //defined( __GNUC__ ) && !defined( __clang__ ) - -template -QVariant to_qvariant(boost::any const& any, int index, indices) -{ - typedef std::function element_type; - static element_type table[] = +template +struct ToQvariantFunctor { + + typedef QVariant return_type; + + template + 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() - ... -#else - [](boost::any const& any){return to_qvariant(any);} - ... -#endif //defined( __GNUC__ ) && !defined( __clang__ ) - }; + typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex::type value_type; + + return QVariant::fromValue(boost::any_cast(any)); + } - return table[index](any); -} +}; template QVariant to_qvariant(boost::any const& x, int index) { - typedef typename friendly_fusion::result_of::size::type seq_size; - typedef typename build_indices::type indices_type; - - return to_qvariant(x, index, indices_type{}); + return apply_functor_to_member(index, x); } -template -boost::any to_boost_any(QVariant const& x) -{ - return boost::any(x.value()); -} - -template -boost::any to_boost_any(QVariant const& x) -{ - typedef friendly_fusion::result_of::begin begin; - typedef friendly_fusion::result_of::advance_c adv_it; - typedef friendly_fusion::result_of::deref deref; - typedef typename std::decay::type value_type; - return to_boost_any(x); -} - -#if defined( __GNUC__ ) && !defined( __clang__ ) -template -std::function to_boost_any_lambda() -{ - return [](QVariant const& value) - { - return to_boost_any(value); - }; -} -#endif //defined( __GNUC__ ) && !defined( __clang__ ) - -template -boost::any to_boost_any(QVariant const& value, int index, indices) +template +struct ToBoostAnyFunctor { - typedef std::function element_type; - static element_type table[] = + typedef boost::any return_type; + + template + 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() - ... -#else - [](QVariant const& value){return to_boost_any(value);} - ... -#endif //defined( __GNUC__ ) && !defined( __clang__ ) - }; - - return table[index](value); -} + typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex::type value_type; + + return boost::any(variant.value()); + } +}; template boost::any to_boost_any(QVariant const& x, int index) { - typedef typename friendly_fusion::result_of::size::type seq_size; - typedef typename build_indices::type indices_type; - - return to_boost_any(x, index, indices_type{}); + return apply_functor_to_member(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 +#include +#include +#include +#include + +#include +#include + +template +struct QValidator_impl +{ + static constexpr bool needed = false; + typedef void type; +}; + +template <> +struct QValidator_impl +{ + static constexpr bool needed = true; + typedef QIntValidator type; +}; + +template <> +struct QValidator_impl +{ + static constexpr bool needed = true; + typedef QDoubleValidator type; +}; + +template +struct QValidatorFor +{ + static constexpr bool needed = QValidator_impl::value, std::is_floating_point::value>::needed; + typedef typename QValidator_impl::value, std::is_floating_point::value>::type type; +}; + +template +struct CreateWidget +{ + typedef QLineEdit* return_type; + + template + static typename std::enable_if::type + set_validator_if_needed(QLineEdit* edit) + { + edit->setValidator(new V()); + } + + template + static typename std::enable_if::type + set_validator_if_needed(QLineEdit*) + { + return; + } + + template + static return_type call() + { + QLineEdit* edit = new QLineEdit(); + + typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex::type value_type; + + typedef QValidatorFor QValiGen; + + set_validator_if_needed(edit); + edit->setReadOnly(is_const(I)); + return edit; + } +}; + +template +struct StringToBoostAny { + + typedef boost::any return_type; + + template + static return_type call(std::string str) + { + typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex::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 cb; + + FormUpdateHandler(QLineEdit* edit, std::function 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 +struct Form : public QFormLayout{ + + std::shared_ptr model; + QMdiArea* area; + std::vector> updatehandlers; + std::map> line_edits; + GuiItemDelegate delegate; + + Form(std::shared_ptr 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(j); + updatehandlers.push_back(std::make_shared(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(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(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, public boost: } +namespace utils { + +template +class DecayedTypeOfAtIndex { + typedef friendly_fusion::result_of::begin begin; + typedef friendly_fusion::result_of::advance_c adv_it; + typedef friendly_fusion::result_of::deref deref; + typedef std::decay decayed; + +public: + typedef typename decayed::type type; +}; + +template +class RefTypeOfAtIndex { + typedef friendly_fusion::result_of::begin begin; + typedef friendly_fusion::result_of::advance_c adv_it; + typedef friendly_fusion::result_of::deref deref; + +public: + typedef typename deref::type type; +}; + +template +class UnrefTypeOfAtIndex { + typedef friendly_fusion::result_of::begin begin; + typedef friendly_fusion::result_of::advance_c adv_it; + typedef friendly_fusion::result_of::deref deref; + typedef std::remove_reference 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::return_type apply_functor_to_member_impl(indices, int { typedef std::function::return_type(Args...)> f_type; static f_type array[] = { - (std::function::return_type(Args...)>) F::template call + F::template call ... }; @@ -31,7 +31,7 @@ typename F::return_type apply_functor_to_member_impl(indices, { typedef std::function::return_type(Arg1&, Args...)> f_type; static f_type array[] = { - (std::function::return_type(Arg1&, Args...)>) F::template call + F::template call ... }; @@ -58,12 +58,9 @@ struct is_const_functor template static return_type call() { - typedef friendly_fusion::result_of::begin begin; - typedef friendly_fusion::result_of::advance_c adv_it; - typedef friendly_fusion::result_of::deref deref; - typedef std::remove_reference unreferenced_type; + typedef typename friendly_fusion::utils::UnrefTypeOfAtIndex::type unref_type; - return std::is_const::value; + return std::is_const::value; } }; @@ -105,7 +102,6 @@ typename std::enable_if::type assign(T& lh, V rh) lh = rh; } - template struct set_nth_functor { @@ -114,13 +110,10 @@ struct set_nth_functor template static return_type call(T& t, boost::any const& value) { - typedef friendly_fusion::result_of::begin begin; - typedef friendly_fusion::result_of::advance_c adv_it; - typedef friendly_fusion::result_of::deref deref; - typedef typename std::decay::type value_type; - typedef typename std::remove_reference::type unreferenced_type; + typedef typename friendly_fusion::utils::DecayedTypeOfAtIndex::type value_type; + typedef typename friendly_fusion::utils::UnrefTypeOfAtIndex::type unref_type; - assign::value>(friendly_fusion::deref(friendly_fusion::advance_c(friendly_fusion::begin(t))), boost::any_cast(value)); + assign::value>(friendly_fusion::deref(friendly_fusion::advance_c(friendly_fusion::begin(t))), boost::any_cast(value)); } }; @@ -154,7 +147,7 @@ struct get_nth_name_functor> if(I < size_of_T){ return apply_functor_to_member(I); } else { - return apply_functor_to_member(I); + return apply_functor_to_member(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 @@ -73,6 +74,9 @@ int main() auto widget2 = make_qt_widget(model); auto widget3 = make_qt_widget(mapping); + Form form(model); + + w.add_widget(form.get_widget()); w.add_widget(widget1.get()); w.add_widget(widget2.get()); w.add_widget(widget3.get()); -- cgit v1.2.3-70-g09d2