+ double step = 1.0 / double(fraction);
+ unsigned int digits = 0;
+ for (; fraction > 1; fraction /= 10) {
+ ++digits;
+ }
+ auto spin = ui::SpinButton(ui::Adjustment(value, lower, upper, step, 10, 0), step, digits);
+ spin.show();
+ spin.dimensions(64, -1);
+ return spin;
+}
+
+class DialogSpinnerRow {
+public:
+ DialogSpinnerRow(ui::Widget row, ui::SpinButton spin) : m_row(row), m_spin(spin)
+ {
+ }
+
+ ui::Widget m_row;
+ ui::SpinButton m_spin;
+};
+
+DialogSpinnerRow DialogSpinnerRow_new(const char *name, double value, double lower, double upper, int fraction)
+{
+ auto alignment = ui::Alignment(0.0, 0.5, 0.0, 0.0);
+ alignment.show();
+
+ auto spin = DialogSpinner_new(value, lower, upper, fraction);
+ alignment.add(spin);
+
+ return DialogSpinnerRow(ui::Widget(DialogRow_new(name, alignment)), spin);
+}
+
+
+struct BoolToggle {
+ static void Export(const ui::ToggleButton &self, const Callback<void(bool)> &returnz)
+ {
+ returnz(self.active());
+ }
+
+ static void Import(ui::ToggleButton &self, bool value)
+ {
+ self.active(value);
+ }
+};
+
+using BoolToggleImportExport = PropertyAdaptor<ui::ToggleButton, bool, BoolToggle>;
+
+struct IntEntry {
+ static void Export(const ui::Entry &self, const Callback<void(int)> &returnz)
+ {
+ returnz(atoi(gtk_entry_get_text(self)));
+ }
+
+ static void Import(ui::Entry &self, int value)
+ {
+ entry_set_int(self, value);
+ }
+};
+
+using IntEntryImportExport = PropertyAdaptor<ui::Entry, int, IntEntry>;
+
+struct IntRadio {
+ static void Export(const ui::RadioButton &self, const Callback<void(int)> &returnz)
+ {
+ returnz(radio_button_get_active(self));
+ }
+
+ static void Import(ui::RadioButton &self, int value)
+ {
+ radio_button_set_active(self, value);
+ }
+};
+
+using IntRadioImportExport = PropertyAdaptor<ui::RadioButton, int, IntRadio>;
+
+struct IntCombo {
+ static void Export(const ui::ComboBox &self, const Callback<void(int)> &returnz)
+ {
+ returnz(gtk_combo_box_get_active(self));
+ }
+
+ static void Import(ui::ComboBox &self, int value)
+ {
+ gtk_combo_box_set_active(self, value);
+ }
+};
+
+using IntComboImportExport = PropertyAdaptor<ui::ComboBox, int, IntCombo>;
+
+struct IntAdjustment {
+ static void Export(const ui::Adjustment &self, const Callback<void(int)> &returnz)
+ {
+ returnz(int(gtk_adjustment_get_value(self)));
+ }
+
+ static void Import(ui::Adjustment &self, int value)
+ {
+ gtk_adjustment_set_value(self, value);
+ }
+};
+
+using IntAdjustmentImportExport = PropertyAdaptor<ui::Adjustment, int, IntAdjustment>;
+
+struct IntSpinner {
+ static void Export(const ui::SpinButton &self, const Callback<void(int)> &returnz)
+ {
+ returnz(gtk_spin_button_get_value_as_int(self));
+ }
+
+ static void Import(ui::SpinButton &self, int value)
+ {
+ gtk_spin_button_set_value(self, value);
+ }
+};
+
+using IntSpinnerImportExport = PropertyAdaptor<ui::SpinButton, int, IntSpinner>;
+
+struct TextEntry {
+ static void Export(const ui::Entry &self, const Callback<void(const char *)> &returnz)
+ {
+ returnz(gtk_entry_get_text(self));
+ }
+
+ static void Import(ui::Entry &self, const char *value)
+ {
+ self.text(value);
+ }
+};
+
+using TextEntryImportExport = PropertyAdaptor<ui::Entry, const char *, TextEntry>;
+
+struct SizeEntry {
+ static void Export(const ui::Entry &self, const Callback<void(std::size_t)> &returnz)
+ {
+ int value = atoi(gtk_entry_get_text(self));
+ if (value < 0) {
+ value = 0;
+ }
+ returnz(value);
+ }
+
+ static void Import(ui::Entry &self, std::size_t value)
+ {
+ entry_set_int(self, int(value));
+ }
+};
+
+using SizeEntryImportExport = PropertyAdaptor<ui::Entry, std::size_t, SizeEntry>;
+
+struct FloatEntry {
+ static void Export(const ui::Entry &self, const Callback<void(float)> &returnz)
+ {
+ returnz(float(atof(gtk_entry_get_text(self))));
+ }
+
+ static void Import(ui::Entry &self, float value)
+ {
+ entry_set_float(self, value);
+ }
+};
+
+using FloatEntryImportExport = PropertyAdaptor<ui::Entry, float, FloatEntry>;
+
+struct FloatSpinner {
+ static void Export(const ui::SpinButton &self, const Callback<void(float)> &returnz)
+ {
+ returnz(float(gtk_spin_button_get_value(self)));
+ }
+
+ static void Import(ui::SpinButton &self, float value)
+ {
+ gtk_spin_button_set_value(self, value);
+ }
+};
+
+using FloatSpinnerImportExport = PropertyAdaptor<ui::SpinButton, float, FloatSpinner>;
+
+
+template<typename T>
+class CallbackDialogData : public DLG_DATA {
+ Property<T> m_pWidget;
+ Property<T> m_pData;
+
+public:
+ CallbackDialogData(const Property<T> &pWidget, const Property<T> &pData)
+ : m_pWidget(pWidget), m_pData(pData)
+ {
+ }
+
+ void release()
+ {
+ delete this;
+ }
+
+ void importData() const
+ {
+ m_pData.get(m_pWidget.set);
+ }
+
+ void exportData() const
+ {
+ m_pWidget.get(m_pData.set);
+ }
+};
+
+template<class Widget>
+void AddDataCustom(DialogDataList &self, typename Widget::Type widget, Property<typename Widget::Other> const &property)
+{
+ using Self = typename Widget::Type;
+ using T = typename Widget::Other;
+ using native = typename std::remove_pointer<typename Self::native>::type;
+ struct Wrapper {
+ static void Export(const native &self, const Callback<void(T)> &returnz)
+ {
+ native *p = &const_cast<native &>(self);
+ auto widget = Self::from(p);
+ Widget::Get::thunk_(widget, returnz);
+ }
+
+ static void Import(native &self, T value)
+ {
+ native *p = &self;
+ auto widget = Self::from(p);
+ Widget::Set::thunk_(widget, value);
+ }
+ };
+ self.push_back(new CallbackDialogData<typename Widget::Other>(
+ make_property<PropertyAdaptor<native, T, Wrapper>>(*static_cast<native *>(widget)),
+ property
+ ));
+}
+
+template<class Widget, class D>
+void AddData(DialogDataList &self, typename Widget::Type widget, D &data)
+{
+ AddDataCustom<Widget>(self, widget, make_property<PropertyAdaptor<D, typename Widget::Other>>(data));
+}