[options] Implement widget-changed callbacks.

Enables full functionality for complex-boolean and multichoice-callback
options.

Note that setter-function callback isn't used in any GnuCash code so it
is not implemented and is not present in the register-callback functions.
This commit is contained in:
John Ralls 2022-07-26 14:54:10 -07:00
parent 552aa438ff
commit da0eff2cac
6 changed files with 108 additions and 42 deletions

View File

@ -929,6 +929,17 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
return gnc_relative_date_to_time64(scm_relative_date_get_period(date));
}
void gnc_register_complex_boolean_option(GncOptionDBPtr&, const char*,
const char*, const char*,
const char*, bool, SCM);
void gnc_register_multichoice_callback_option(GncOptionDBPtr&, const char*,
const char*, const char*,
const char*, const char*,
GncMultichoiceOptionChoices&&,
SCM);
%} //%header
%ignore GncOptionMultichoiceKeyType;
@ -1531,8 +1542,67 @@ inline SCM return_scm_value(ValueType value)
return SCM_BOOL_F;
}, swig_get_option($self));
}
};
%inline %{
/**
* Create a new complex boolean option and register it in the options database.
*
* @param db A GncOptionDB* for calling from C. Caller retains ownership.
* @param section The database section for the option.
* @param name The option name.
* @param doc_string A description of the option. This will be used in tooltips and should be marked for translation.
* @param value The initial and default value for the option.
* @param widget_changed_cb A Scheme callback to run from the UIItem's "changed" signal.
*/
void gnc_register_complex_boolean_option(GncOptionDBPtr& db,
const char* section, const char* name,
const char* key,
const char* doc_string,
bool value, SCM widget_changed_cb)
{
GncOption option{section, name, key, doc_string, value,
GncOptionUIType::BOOLEAN};
option.set_widget_changed (widget_changed_cb);
db->register_option(section, std::move(option));
}
/**
* Create a new multichoice option and register it in the options database.
*
* @param db A GncOptionDB* for calling from C. Caller retains ownership.
* @param section The database section for the option.
* @param name The option name.
* @param doc_string A description of the option. This will be used in tooltips and should be marked for translation.
* @param value The set of possible values for the option. Only one can be selected. Note that the value will be moved from the parameter and using the parameter after this call will result in undefined behavior.
* @param widget_changed_cb A Scheme callback to run from the UIItem's "changed" signal.
*/
void
gnc_register_multichoice_callback_option(GncOptionDBPtr& db,
const char* section,
const char* name, const char* key,
const char* doc_string,
const char* default_val,
GncMultichoiceOptionChoices&& choices,
SCM widget_changed_cb)
{
std::string defval{default_val};
auto found{std::find_if(choices.begin(), choices.end(),
[&defval](auto& choice)->bool {
return defval == std::get<0>(choice);
})};
if (found == choices.end())
defval = (choices.empty() ? std::string{"None"} :
std::get<0>(choices.at(0)));
GncOption option{GncOptionMultichoiceValue{section, name, key, doc_string,
defval.c_str(), std::move(choices)}};
option.set_widget_changed(widget_changed_cb);
db->register_option(section, std::move(option));
}
%}
%extend GncOptionDB {
%template(set_option_string) set_option<std::string>;
%template(set_option_int) set_option<int>;

View File

@ -180,6 +180,11 @@ GncOptionGtkUIItem::set_widget(GtkWidget* widget)
m_widget = static_cast<GtkWidget*>(g_object_ref(widget));
}
SCM
GncOptionGtkUIItem::get_widget_scm_value(const GncOption& option) const
{
return SCM_BOOL_F;
}
static void dialog_reset_cb(GtkWidget * w, gpointer data);
static void dialog_list_select_cb (GtkTreeSelection *selection, gpointer data);
@ -238,7 +243,15 @@ void
gnc_option_changed_widget_cb(GtkWidget *widget, GncOption* option)
{
if (!option) return;
const_cast<GncOptionUIItem*>(option->get_ui_item())->set_dirty(true);
auto ui_item{option->get_ui_item()};
auto widget_changed_cb{option->get_widget_changed()};
auto gtk_ui_item{dynamic_cast<GncOptionGtkUIItem*>(ui_item)};
if (widget_changed_cb && gtk_ui_item)
{
SCM widget_value{gtk_ui_item->get_widget_scm_value(*option)};
scm_call_1(static_cast<SCM>(widget_changed_cb), widget_value);
}
const_cast<GncOptionUIItem*>(ui_item)->set_dirty(true);
dialog_changed_internal(widget, true);
}
@ -445,6 +458,11 @@ dialog_append_page(GncOptionsDialog* dlg, GncOptionSectionPtr& section)
GTK_WIDGET(page_content_box), page_label);
/* Switch to selection from a list if the page count threshold is reached */
/* Run any callbacks on the default widget values. */
section->foreach_option(
[](GncOption& option) {
gnc_option_changed_option_cb(nullptr, &option);
});
return setup_notebook_pages(dlg, page_content_box, name);
}
@ -838,6 +856,12 @@ public:
auto widget{GTK_TOGGLE_BUTTON(get_widget())};
option.set_value(static_cast<bool>(gtk_toggle_button_get_active(widget)));
}
SCM get_widget_scm_value(const GncOption& option) const override
{
auto widget{GTK_TOGGLE_BUTTON(get_widget())};
return gtk_toggle_button_get_active(widget) ?
SCM_BOOL_T : SCM_BOOL_F;
}
};
template <> GtkWidget *
@ -1102,6 +1126,13 @@ public:
auto widget{GTK_COMBO_BOX(get_widget())};
option.set_value<uint16_t>(static_cast<uint16_t>(gtk_combo_box_get_active(widget)));
}
SCM get_widget_scm_value(const GncOption& option) const override
{
auto widget{GTK_COMBO_BOX(get_widget())};
auto id{gtk_combo_box_get_active(widget)};
auto value{option.permissible_value(id)};
return scm_from_utf8_symbol(value);
}
};
template<> GtkWidget*

View File

@ -32,6 +32,7 @@
#include <vector>
#include <libguile.h>
#include <gnc-option-uitype.hpp>
#include <gnc-option-ui.hpp>
@ -92,6 +93,7 @@ public:
void clear_ui_item() override;
void set_widget(GtkWidget* widget);
virtual GtkWidget* const get_widget() const { return m_widget; }
virtual SCM get_widget_scm_value(const GncOption&) const;
static WidgetCreateFunc option_widget_factory(GncOption& option,
GtkGrid* page,
GtkLabel* name,

View File

@ -197,11 +197,14 @@ public:
*/
std::istream& in_stream(std::istream& iss);
friend GncOptionVariant& swig_get_option(GncOption*);
void set_widget_changed (void* cb) { m_widget_changed = cb; }
void* get_widget_changed () { return m_widget_changed; }
private:
inline static const std::string c_empty_string{""};
GncOptionVariantPtr m_option;
GncOptionUIItemPtr m_ui_item{nullptr};
/* This is a hack to reserve space for a Guile callback pointer. */
void* m_widget_changed{};
};
inline bool

View File

@ -643,17 +643,6 @@ gnc_register_simple_boolean_option(GncOptionDB* db,
db->register_option(section, std::move(option));
}
void
gnc_register_complex_boolean_option(GncOptionDB* db,
const char* section, const char* name,
const char* key, const char* doc_string,
bool value)
{
GncOption option{section, name, key, doc_string, value,
GncOptionUIType::BOOLEAN};
db->register_option(section, std::move(option));
}
void
gnc_register_pixmap_option(GncOptionDB* db, const char* section,
const char* name, const char* key,

View File

@ -232,35 +232,6 @@ inline void gnc_register_simple_boolean_option(const GncOptionDBPtr& db,
doc_string, value);
}
/**
* Create a new complex boolean option and register it in the options database.
*
* @param db A GncOptionDB* for calling from C. Caller retains ownership.
* @param section The database section for the option.
* @param name The option name.
* @param doc_string A description of the option. This will be used in tooltips and should be marked for translation.
* @param value The initial and default value for the option.
*/
void gnc_register_complex_boolean_option(GncOptionDB* db,
const char* section, const char* name,
const char* key,
const char* doc_string,
bool value);
/**
* As above but takes a const GncOptionDBPtr& (const std::unique_ptr<GncOptionDB>&) for calling from C++.
*/
inline void gnc_register_complex_boolean_option(const GncOptionDBPtr& db,
const char* section,
const char* name,
const char* key,
const char* doc_string,
bool value)
{
gnc_register_complex_boolean_option(db.get(), section, name, key,
doc_string, value);
}
/**
* Create a new pixmap option and register it in the options database.
*