25 #include "gnc-option-gtk-ui.hpp" 32 #include "gnc-account-sel.h" 34 #include "gnc-commodity-edit.h" 35 #include "gnc-date-edit.h" 36 #include "gnc-date-format.h" 37 #include "gnc-general-select.h" 41 #include "misc-gnome-utils.h" 51 static QofLogModule log_module = GNC_MOD_GUI;
54 std::vector<WidgetCreateFunc> GncOptionUIFactory::s_registry{
static_cast<size_t>(GncOptionUIType::MAX_VALUE)};
55 bool GncOptionUIFactory::s_initialized{
false};
56 static void gnc_options_ui_factory_initialize (
void);
61 s_registry[
static_cast<size_t>(type)] = func;
69 gnc_options_ui_factory_initialize();
72 auto type{option.get_ui_type()};
73 auto func{s_registry[
static_cast<size_t>(type)]};
75 func(option, page, row);
77 PERR(
"No function registered for type %d", static_cast<int>(type));
80 GncOptionGtkUIItem::GncOptionGtkUIItem(GtkWidget* widget,
83 m_widget{
static_cast<GtkWidget*
>(g_object_ref(widget))} {}
87 m_widget{
static_cast<GtkWidget*
>(g_object_ref(item.get_widget()))} {}
89 GncOptionGtkUIItem::~GncOptionGtkUIItem()
92 g_object_unref(m_widget);
99 gtk_widget_set_sensitive (m_widget, selectable);
106 g_object_unref(m_widget);
111 GncOptionGtkUIItem::set_widget(GtkWidget* widget)
113 if (get_ui_type() == GncOptionUIType::INTERNAL)
115 std::string error{
"INTERNAL option, setting the UI item forbidden."};
116 throw std::logic_error(error);
120 g_object_unref(m_widget);
122 m_widget =
static_cast<GtkWidget*
>(g_object_ref(widget));
126 GncOptionGtkUIItem::get_widget_scm_value(
const GncOption& option)
const 134 static inline GtkWidget*
const 135 option_get_gtk_widget(
const GncOption* option)
137 if (!option)
return nullptr;
140 return ui_item->get_widget();
146 wrap_check_button (
const GncOption& option, GtkWidget* widget, GtkGrid* page_box,
int row)
148 auto enclosing{gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5)};
149 gtk_box_set_homogeneous (GTK_BOX (enclosing), FALSE);
150 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
151 set_tool_tip(option, enclosing);
152 gtk_widget_show_all(enclosing);
154 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
162 void set_ui_item_from_option(
GncOption& option) noexcept
override 164 auto widget{GTK_TOGGLE_BUTTON(get_widget())};
165 gtk_toggle_button_set_active(widget, option.get_value<
bool>());
167 void set_option_from_ui_item(
GncOption& option) noexcept
override 169 auto widget{GTK_TOGGLE_BUTTON(get_widget())};
170 option.set_value(static_cast<bool>(gtk_toggle_button_get_active(widget)));
172 SCM get_widget_scm_value(
const GncOption& option)
const override 174 auto widget{GTK_TOGGLE_BUTTON(get_widget())};
175 return gtk_toggle_button_get_active(widget) ?
176 SCM_BOOL_T : SCM_BOOL_F;
181 create_option_widget<GncOptionUIType::BOOLEAN> (
GncOption& option,
182 GtkGrid* page_box,
int row)
185 char *local_name{
nullptr};
186 auto name{option.get_name().c_str()};
188 local_name = _(name);
189 auto widget{gtk_check_button_new_with_label (local_name)};
191 auto ui_item{std::make_unique<GncGtkBooleanUIItem>(widget)};
193 option.set_ui_item(std::move(ui_item));
194 option.set_ui_item_from_option();
196 g_signal_connect(G_OBJECT(widget),
"toggled",
197 G_CALLBACK(gnc_option_changed_widget_cb), &option);
199 wrap_check_button(option, widget, page_box, row);
207 void set_ui_item_from_option(
GncOption& option) noexcept
override 209 auto widget{GTK_ENTRY(get_widget())};
210 gtk_entry_set_text(widget, option.get_value<std::string>().c_str());
212 void set_option_from_ui_item(
GncOption& option) noexcept
override 214 auto widget{GTK_ENTRY(get_widget())};
215 option.set_value(std::string{gtk_entry_get_text(widget)});
220 create_option_widget<GncOptionUIType::STRING> (
GncOption& option,
221 GtkGrid *page_box,
int row)
223 auto enclosing{gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5)};
224 gtk_widget_set_hexpand (GTK_WIDGET(enclosing), TRUE);
225 gtk_box_set_homogeneous (GTK_BOX (enclosing), FALSE);
226 auto widget = gtk_entry_new();
227 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
228 gtk_entry_set_alignment (GTK_ENTRY(widget), 1.0);
229 auto ui_item{std::make_unique<GncGtkStringUIItem>(widget)};
231 option.set_ui_item(std::move(ui_item));
232 option.set_ui_item_from_option();
234 g_signal_connect(G_OBJECT(widget),
"changed",
235 G_CALLBACK(gnc_option_changed_widget_cb), &option);
236 gtk_box_pack_start(GTK_BOX(enclosing), widget, TRUE, TRUE, 0);
237 set_name_label(option, page_box, row,
true);
238 set_tool_tip(option, enclosing);
239 gtk_widget_show_all(enclosing);
240 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
248 void set_ui_item_from_option(
GncOption& option) noexcept
override 250 auto widget{GTK_TEXT_VIEW(get_widget())};
251 xxxgtk_textview_set_text(widget, option.get_value<std::string>().c_str());
253 void set_option_from_ui_item(
GncOption& option) noexcept
override 255 auto widget{GTK_TEXT_VIEW(get_widget())};
256 auto str{xxxgtk_textview_get_text(widget)};
257 option.set_value(std::string{str});
263 create_option_widget<GncOptionUIType::TEXT> (
GncOption& option, GtkGrid *page_box,
int row)
265 auto scroll = gtk_scrolled_window_new(NULL, NULL);
266 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
268 GTK_POLICY_AUTOMATIC);
269 gtk_container_set_border_width(GTK_CONTAINER(scroll), 2);
271 auto frame = gtk_frame_new(NULL);
272 gtk_container_add(GTK_CONTAINER(frame), scroll);
274 auto enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
275 gtk_widget_set_vexpand (GTK_WIDGET(enclosing), TRUE);
276 gtk_widget_set_hexpand (GTK_WIDGET(enclosing), TRUE);
277 gtk_box_set_homogeneous (GTK_BOX (enclosing), FALSE);
278 auto widget = gtk_text_view_new();
279 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget), GTK_WRAP_WORD);
280 gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), TRUE);
281 gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW(widget), FALSE);
283 auto ui_item{std::make_unique<GncGtkTextUIItem>(widget)};
284 auto text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
285 option.set_ui_item(std::move(ui_item));
286 option.set_ui_item_from_option();
288 g_signal_connect(G_OBJECT(text_buffer),
"changed",
289 G_CALLBACK(gnc_option_changed_option_cb), &option);
290 gtk_container_add (GTK_CONTAINER (scroll), widget);
291 gtk_box_pack_start(GTK_BOX(enclosing), frame, TRUE, TRUE, 0);
292 set_name_label(option, page_box, row,
true);
293 set_tool_tip(option, enclosing);
294 gtk_widget_show_all(enclosing);
295 grid_attach_widget(GTK_GRID(page_box), enclosing, row);
303 void set_ui_item_from_option(
GncOption& option) noexcept
override 305 auto widget{GNC_CURRENCY_EDIT(get_widget())};
306 auto currency{option.get_value<gnc_commodity*>()};
311 void set_option_from_ui_item(
GncOption& option) noexcept
override 313 auto widget{GNC_CURRENCY_EDIT(get_widget())};
315 option.set_value<gnc_commodity*>(currency);
320 create_option_widget<GncOptionUIType::CURRENCY> (
GncOption& option, GtkGrid *page_box,
324 auto ui_item{std::make_unique<GncGtkCurrencyUIItem>(widget)};
325 option.set_ui_item(std::move(ui_item));
326 option.set_ui_item_from_option();
328 g_signal_connect(G_OBJECT(widget),
"changed",
329 G_CALLBACK(gnc_option_changed_widget_cb), &option);
330 wrap_widget(option, widget, page_box, row);
338 void set_ui_item_from_option(
GncOption& option) noexcept
override 340 auto widget{GNC_GENERAL_SELECT(get_widget())};
341 auto commodity{option.get_value<gnc_commodity*>()};
344 gnc_general_select_set_selected(widget, GNC_COMMODITY(commodity));
346 void set_option_from_ui_item(
GncOption& option) noexcept
override 348 auto widget{GNC_GENERAL_SELECT(get_widget())};
349 auto commodity{gnc_general_select_get_selected(widget)};
350 option.set_value<gnc_commodity*>(GNC_COMMODITY(commodity));
355 create_option_widget<GncOptionUIType::COMMODITY> (
GncOption& option, GtkGrid *page_box,
358 auto widget = gnc_general_select_new(GNC_GENERAL_SELECT_TYPE_SELECT,
359 gnc_commodity_edit_get_string,
360 gnc_commodity_edit_new_select,
363 auto ui_item{std::make_unique<GncGtkCommodityUIItem>(widget)};
364 option.set_ui_item(std::move(ui_item));
365 option.set_ui_item_from_option();
366 g_signal_connect(G_OBJECT(GNC_GENERAL_SELECT(widget)->entry),
"changed",
367 G_CALLBACK(gnc_option_changed_widget_cb), &option);
368 wrap_widget(option, widget, page_box, row);
372 create_multichoice_widget(
GncOption& option)
376 g_return_val_if_fail(num_values >= 0, NULL);
377 auto renderer = gtk_cell_renderer_text_new();
378 auto store = gtk_list_store_new(1, G_TYPE_STRING);
380 for (decltype(num_values) i = 0; i < num_values; i++)
384 gtk_list_store_append (store, &iter);
385 gtk_list_store_set(store, &iter, 0,
386 (itemstring && *itemstring) ? _(itemstring) :
"", -1);
389 auto widget{GTK_WIDGET(gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)))};
390 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(widget), renderer, TRUE);
391 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(widget),
392 renderer,
"text", 0);
393 g_object_unref(store);
403 void set_ui_item_from_option(
GncOption& option) noexcept
override 405 auto widget{GTK_COMBO_BOX(get_widget())};
406 gtk_combo_box_set_active(widget, option.get_value<uint16_t>());
408 void set_option_from_ui_item(
GncOption& option) noexcept
override 410 auto widget{GTK_COMBO_BOX(get_widget())};
411 option.set_value<uint16_t>(
static_cast<uint16_t
>(gtk_combo_box_get_active(widget)));
413 SCM get_widget_scm_value(
const GncOption& option)
const override 415 auto widget{GTK_COMBO_BOX(get_widget())};
416 auto id{gtk_combo_box_get_active(widget)};
418 return scm_from_utf8_symbol(value);
423 create_option_widget<GncOptionUIType::MULTICHOICE> (
GncOption& option, GtkGrid *page_box,
426 auto widget{create_multichoice_widget(option)};
427 auto ui_item{std::make_unique<GncGtkMultichoiceUIItem>(widget)};
428 option.set_ui_item(std::move(ui_item));
429 option.set_ui_item_from_option();
430 g_signal_connect(G_OBJECT(widget),
"changed",
431 G_CALLBACK(gnc_option_changed_widget_cb), &option);
432 wrap_widget(option, widget, page_box, row);
441 virtual void set_entry_from_option(
GncOption& option) = 0;
442 virtual void set_option_from_entry(
GncOption& option) = 0;
444 virtual GtkWidget* get_entry() = 0;
446 virtual GtkWidget* get_widget() = 0;
447 virtual void toggle_relative(
bool) {}
448 virtual void block_signals(
bool) = 0;
452 using GncDateEntryPtr = std::unique_ptr<GncDateEntry>;
459 void set_entry_from_option(
GncOption& option)
override;
460 void set_option_from_entry(
GncOption& option)
override;
461 GtkWidget* get_entry()
override {
return GTK_WIDGET(m_entry); }
462 GtkWidget* get_widget()
override {
return GTK_WIDGET(m_entry); }
463 void block_signals(
bool)
override;
466 unsigned long m_handler_id;
469 AbsoluteDateEntry::AbsoluteDateEntry(
GncOption& option) :
470 m_entry{GNC_DATE_EDIT(gnc_date_edit_new(time(NULL), FALSE, FALSE))}
472 auto entry = GNC_DATE_EDIT(m_entry)->date_entry;
473 m_handler_id = g_signal_connect(G_OBJECT(entry),
"changed",
474 G_CALLBACK(gnc_option_changed_option_cb),
479 AbsoluteDateEntry::block_signals(
bool block)
481 auto entry{G_OBJECT(GNC_DATE_EDIT(m_entry)->date_entry)};
483 g_signal_handler_block(entry, m_handler_id);
485 g_signal_handler_unblock(entry, m_handler_id);
489 AbsoluteDateEntry::set_entry_from_option(
GncOption& option)
491 gnc_date_edit_set_time(m_entry, option.get_value<
time64>());
495 AbsoluteDateEntry::set_option_from_entry(
GncOption& option)
497 option.set_value<
time64>(gnc_date_edit_get_date(m_entry));
505 void set_entry_from_option(
GncOption& option)
override;
506 void set_option_from_entry(
GncOption& option)
override;
507 GtkWidget* get_widget()
override {
return m_entry; }
508 GtkWidget* get_entry()
override {
return m_entry; }
509 void block_signals(
bool)
override;
512 unsigned long m_handler_id;
516 RelativeDateEntry::RelativeDateEntry(
GncOption& option)
519 auto renderer = gtk_cell_renderer_text_new();
520 auto store = gtk_list_store_new(1, G_TYPE_STRING);
523 for (decltype(num) index = 0; index < num; ++index)
526 gtk_list_store_append (store, &iter);
527 gtk_list_store_set (store, &iter, 0,
532 m_entry = GTK_WIDGET(gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)));
533 gtk_combo_box_set_active(GTK_COMBO_BOX(m_entry), 0);
534 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(m_entry), renderer, TRUE);
535 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(m_entry),
536 renderer,
"text", 0);
538 g_object_unref(store);
540 m_handler_id = g_signal_connect(G_OBJECT(m_entry),
"changed",
541 G_CALLBACK(gnc_option_changed_widget_cb),
546 RelativeDateEntry::set_entry_from_option(
GncOption& option)
548 gtk_combo_box_set_active(GTK_COMBO_BOX(m_entry), option.get_value<uint16_t>());
552 RelativeDateEntry::set_option_from_entry(
GncOption& option)
554 option.set_value<uint16_t>(gtk_combo_box_get_active(GTK_COMBO_BOX(m_entry)));
558 RelativeDateEntry::block_signals(
bool block)
561 g_signal_handler_block(m_entry, m_handler_id);
563 g_signal_handler_unblock(m_entry, m_handler_id);
566 using AbsoluteDateEntryPtr = std::unique_ptr<AbsoluteDateEntry>;
567 using RelativeDateEntryPtr = std::unique_ptr<RelativeDateEntry>;
574 void set_entry_from_option(
GncOption& option)
override;
575 void set_option_from_entry(
GncOption& option)
override;
576 GtkWidget* get_widget()
override {
return m_widget; }
577 GtkWidget* get_entry()
override;
578 void toggle_relative(
bool use_absolute)
override;
579 void block_signals(
bool)
override;
582 GtkWidget* m_abs_button;
583 AbsoluteDateEntryPtr m_abs_entry;
584 GtkWidget* m_rel_button;
585 RelativeDateEntryPtr m_rel_entry;
586 bool m_use_absolute =
true;
587 unsigned long m_abs_hdlr;
588 unsigned long m_rel_hdlr;
591 static void date_set_absolute_cb(GtkWidget *widget, gpointer data1);
592 static void date_set_relative_cb(GtkWidget *widget, gpointer data1);
594 BothDateEntry::BothDateEntry(
GncOption& option) :
595 m_widget{gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5)},
596 m_abs_button{gtk_radio_button_new(NULL)},
597 m_abs_entry{std::make_unique<AbsoluteDateEntry>(option)},
599 gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(m_abs_button))},
600 m_rel_entry{std::make_unique<RelativeDateEntry>(option)}
602 gtk_box_set_homogeneous (GTK_BOX(m_widget), FALSE);
603 m_abs_hdlr = g_signal_connect(G_OBJECT(m_abs_button),
"toggled",
604 G_CALLBACK(date_set_absolute_cb), &option);
605 m_rel_hdlr = g_signal_connect(G_OBJECT(m_rel_button),
"toggled",
606 G_CALLBACK(date_set_relative_cb), &option);
608 gtk_box_pack_start(GTK_BOX(m_widget),
609 m_abs_button, FALSE, FALSE, 0);
610 gtk_box_pack_start(GTK_BOX(m_widget),
611 m_abs_entry->get_entry(), FALSE, FALSE, 0);
612 gtk_box_pack_start(GTK_BOX(m_widget),
613 m_rel_button, FALSE, FALSE, 0);
614 gtk_box_pack_start(GTK_BOX(m_widget),
615 m_rel_entry->get_entry(), FALSE, FALSE, 0);
620 BothDateEntry::get_entry()
622 return m_use_absolute ? m_abs_entry->get_entry() : m_rel_entry->get_entry();
626 BothDateEntry::toggle_relative(
bool use_absolute)
628 m_use_absolute = use_absolute;
630 gtk_widget_set_sensitive(GTK_WIDGET(m_abs_entry->get_widget()),
632 gtk_widget_set_sensitive(GTK_WIDGET(m_rel_entry->get_widget()),
637 BothDateEntry::set_entry_from_option(
GncOption& option)
642 m_abs_entry->set_entry_from_option(option);
644 m_rel_entry->set_entry_from_option(option);
645 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_rel_button),
647 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_abs_button),
650 toggle_relative(m_use_absolute);
654 BothDateEntry::set_option_from_entry(
GncOption& option)
657 m_abs_entry->set_option_from_entry(option);
659 m_rel_entry->set_option_from_entry(option);
663 BothDateEntry::block_signals(
bool block)
667 g_signal_handler_block(m_abs_button, m_abs_hdlr);
668 g_signal_handler_block(m_rel_button, m_rel_hdlr);
672 g_signal_handler_unblock(m_abs_button, m_abs_hdlr);
673 g_signal_handler_unblock(m_rel_button, m_rel_hdlr);
675 m_abs_entry->block_signals(block);
676 m_rel_entry->block_signals(block);
685 void clear_ui_item()
override { m_entry =
nullptr; }
686 void set_ui_item_from_option(
GncOption& option) noexcept
override 689 m_entry->set_entry_from_option(option);
691 void set_option_from_ui_item(
GncOption& option) noexcept
override 694 m_entry->set_option_from_entry(option);
696 GtkWidget* get_widget()
const override 698 return m_entry->get_widget();
702 GncDateEntryPtr m_entry;
706 date_set_absolute_cb(GtkWidget *widget, gpointer data1)
708 GncOption* option =
static_cast<decltype(option)
>(data1);
709 auto ui_item = option->get_ui_item();
710 if (
auto date_ui = dynamic_cast<const GncOptionDateUIItem* const>(ui_item))
713 gnc_option_changed_option_cb(widget, option);
718 date_set_relative_cb(GtkWidget *widget, gpointer data1)
720 GncOption* option =
static_cast<decltype(option)
>(data1);
721 auto ui_item = option->get_ui_item();
722 if (
auto date_ui = dynamic_cast<const GncOptionDateUIItem* const>(ui_item))
725 gnc_option_changed_option_cb(widget, option);
730 create_date_option_widget(
GncOption& option, GtkGrid *page_box,
int row)
732 GtkWidget *enclosing{
nullptr};
733 auto type = option.get_ui_type();
736 case GncOptionUIType::DATE_ABSOLUTE:
737 option.set_ui_item(std::make_unique<GncOptionDateUIItem>(std::make_unique<AbsoluteDateEntry>(option), type));
739 case GncOptionUIType::DATE_RELATIVE:
740 option.set_ui_item(std::make_unique<GncOptionDateUIItem>(std::make_unique<RelativeDateEntry>(option), type));
742 case GncOptionUIType::DATE_BOTH:
743 option.set_ui_item(std::make_unique<GncOptionDateUIItem>(std::make_unique<BothDateEntry>(option), type));
746 PERR(
"Attempted to create date option widget with wrong UI type %d",
747 static_cast<int>(type));
751 auto widget{option_get_gtk_widget(&option)};
752 if (type == GncOptionUIType::DATE_RELATIVE)
754 enclosing = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
755 gtk_box_set_homogeneous(GTK_BOX (enclosing), FALSE);
757 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
761 enclosing = gtk_frame_new(
nullptr);
762 g_object_set(G_OBJECT(widget),
"margin", 3, NULL);
764 gtk_container_add (GTK_CONTAINER(enclosing), widget);
767 gtk_widget_set_halign (GTK_WIDGET(enclosing), GTK_ALIGN_START);
768 set_name_label(option, page_box, row,
false);
769 set_tool_tip(option, enclosing);
770 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
773 if (
auto date_ui{ui_item ? ui_item->get_entry() :
nullptr})
775 date_ui->block_signals(
true);
776 date_ui->set_entry_from_option(option);
777 date_ui->block_signals(
false);
780 gtk_widget_show_all(enclosing);
784 create_option_widget<GncOptionUIType::DATE_ABSOLUTE>(
GncOption& option,
785 GtkGrid *page_box,
int row)
787 create_date_option_widget(option, page_box, row);
791 create_option_widget<GncOptionUIType::DATE_RELATIVE>(
GncOption& option,
792 GtkGrid *page_box,
int row)
794 create_date_option_widget(option, page_box, row);
798 create_option_widget<GncOptionUIType::DATE_BOTH>(
GncOption& option,
799 GtkGrid *page_box,
int row)
801 create_date_option_widget(option, page_box, row);
804 using GncOptionAccountList = std::vector<GncGUID>;
807 account_select_all_cb(GtkWidget *widget, gpointer data)
809 GncOption* option =
static_cast<decltype(option)
>(data);
810 GncTreeViewAccount *tree_view;
811 GtkTreeSelection *selection;
813 tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget (option));
814 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
815 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
816 gtk_tree_selection_select_all(selection);
817 gnc_option_changed_widget_cb(widget, option);
821 account_clear_all_cb(GtkWidget *widget, gpointer data)
823 GncOption* option =
static_cast<decltype(option)
>(data);
824 GncTreeViewAccount *tree_view;
825 GtkTreeSelection *selection;
827 tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget (option));
828 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
829 gtk_tree_selection_unselect_all(selection);
830 gnc_option_changed_widget_cb(widget, option);
834 account_select_children_cb(GtkWidget *widget, gpointer data)
836 GncOption* option =
static_cast<decltype(option)
>(data);
837 GncTreeViewAccount *tree_view;
838 GList *acct_list = NULL, *acct_iter = NULL;
840 tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget (option));
843 for (acct_iter = acct_list; acct_iter; acct_iter = acct_iter->next)
846 g_list_free (acct_list);
850 account_set_default_cb(GtkWidget* widget, gpointer data)
852 GncOption* option =
static_cast<decltype(option)
>(data);
853 account_clear_all_cb(widget, data);
854 option->set_value(option->get_default_value<GncOptionAccountList>());
855 option->set_ui_item_from_option();
859 show_hidden_toggled_cb(GtkWidget *widget,
GncOption* option)
861 if (option->get_ui_type() != GncOptionUIType::ACCOUNT_LIST &&
862 option->get_ui_type() != GncOptionUIType::ACCOUNT_SEL)
865 auto tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget(option));
868 avi.show_hidden = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
870 gnc_option_changed_widget_cb(widget, option);
878 void set_ui_item_from_option(
GncOption& option) noexcept
override 880 auto widget{GNC_TREE_VIEW_ACCOUNT(get_widget())};
881 GList *acc_list =
nullptr;
882 const GncOptionAccountList& accounts =
883 option.get_value<GncOptionAccountList>();
884 auto book{gnc_get_current_book()};
885 for (
auto guid : accounts)
888 acc_list = g_list_prepend(acc_list, account);
890 acc_list = g_list_reverse(acc_list);
892 g_list_free(acc_list);
894 void set_option_from_ui_item(
GncOption& option) noexcept
override 896 auto widget{GNC_TREE_VIEW_ACCOUNT(get_widget())};
898 GncOptionAccountList acc_vec;
899 acc_vec.reserve(g_list_length(acc_list));
900 for (
auto node = acc_list; node; node = g_list_next(node))
903 acc_vec.push_back(*guid);
905 g_list_free(acc_list);
906 option.set_value(acc_vec);
911 create_account_widget(
GncOption& option,
char *name)
913 bool multiple_selection;
914 GtkWidget *scroll_win;
920 GList *acct_type_list;
921 GtkTreeSelection *selection;
926 frame = gtk_frame_new(name);
928 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
929 gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE);
931 gtk_container_add(GTK_CONTAINER(frame), vbox);
934 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), FALSE);
935 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
936 if (multiple_selection)
937 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
939 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
950 avi.include_type[i] = FALSE;
951 avi.show_hidden = TRUE;
953 for (node = acct_type_list; node; node = node->next)
955 GNCAccountType type =
static_cast<decltype(type)
>(GPOINTER_TO_INT (node->data));
957 avi.include_type[type] = TRUE;
961 g_list_free (acct_type_list);
971 avi.include_type[i] = TRUE;
972 avi.show_hidden = TRUE;
976 scroll_win = gtk_scrolled_window_new(NULL, NULL);
977 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
978 GTK_POLICY_AUTOMATIC,
979 GTK_POLICY_AUTOMATIC);
981 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
982 gtk_container_set_border_width(GTK_CONTAINER(scroll_win), 5);
984 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
985 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
986 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 10);
988 option.set_ui_item(std::make_unique<GncGtkAccountListUIItem>(tree));
989 option.set_ui_item_from_option();
991 if (multiple_selection)
993 button = gtk_button_new_with_label(_(
"Select All"));
994 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
995 gtk_widget_set_tooltip_text(button, _(
"Select all accounts."));
997 g_signal_connect(G_OBJECT(button),
"clicked",
998 G_CALLBACK(account_select_all_cb), &option);
1000 button = gtk_button_new_with_label(_(
"Clear All"));
1001 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1002 gtk_widget_set_tooltip_text(button, _(
"Clear the selection and unselect all accounts."));
1004 g_signal_connect(G_OBJECT(button),
"clicked",
1005 G_CALLBACK(account_clear_all_cb), &option);
1007 button = gtk_button_new_with_label(_(
"Select Children"));
1008 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1009 gtk_widget_set_tooltip_text(button, _(
"Select all descendents of selected account."));
1011 g_signal_connect(G_OBJECT(button),
"clicked",
1012 G_CALLBACK(account_select_children_cb), &option);
1015 button = gtk_button_new_with_label(_(
"Select Default"));
1016 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1017 gtk_widget_set_tooltip_text(button, _(
"Select the default account selection."));
1019 g_signal_connect(G_OBJECT(button),
"clicked",
1020 G_CALLBACK(account_set_default_cb), &option);
1022 gtk_widget_set_margin_start (GTK_WIDGET(bbox), 6);
1023 gtk_widget_set_margin_end (GTK_WIDGET(bbox), 6);
1025 if (multiple_selection)
1029 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1030 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
1031 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1034 button = gtk_check_button_new_with_label(_(
"Show Hidden Accounts"));
1035 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1036 gtk_widget_set_tooltip_text(button, _(
"Show accounts that have been marked hidden."));
1037 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
1038 g_signal_connect(G_OBJECT(button),
"toggled",
1039 G_CALLBACK(show_hidden_toggled_cb), &option);
1041 gtk_container_add(GTK_CONTAINER(scroll_win), tree);
1046 option_account_sel_changed_cb(GtkTreeSelection *sel, gpointer data)
1048 auto tree_view{gtk_tree_selection_get_tree_view(sel)};
1049 gnc_option_changed_widget_cb(GTK_WIDGET(tree_view),
1050 static_cast<GncOption*>(data));
1054 create_option_widget<GncOptionUIType::ACCOUNT_LIST>(
GncOption& option,
1055 GtkGrid *page_box,
int row)
1057 auto enclosing{create_account_widget(option,
nullptr)};
1058 gtk_widget_set_vexpand (GTK_WIDGET(enclosing), TRUE);
1059 gtk_widget_set_hexpand (GTK_WIDGET(enclosing), TRUE);
1060 set_name_label(option, page_box, row,
true);
1061 set_tool_tip(option, enclosing);
1062 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
1064 auto widget{option_get_gtk_widget(&option)};
1065 auto selection{gtk_tree_view_get_selection(GTK_TREE_VIEW(widget))};
1066 g_signal_connect(G_OBJECT(selection),
"changed",
1067 G_CALLBACK(option_account_sel_changed_cb), &option);
1068 gtk_widget_show_all(enclosing);
1076 void set_ui_item_from_option(
GncOption& option) noexcept
override 1078 auto widget{GNC_ACCOUNT_SEL(get_widget())};
1079 auto instance{option.get_value<
const Account*>()};
1081 gnc_account_sel_set_account(widget, const_cast<Account*>(instance), FALSE);
1083 void set_option_from_ui_item(
GncOption& option) noexcept
override 1085 auto widget{GNC_ACCOUNT_SEL(get_widget())};
1087 option.set_value(static_cast<const Account*>(gnc_account_sel_get_account(widget)));
1092 create_option_widget<GncOptionUIType::ACCOUNT_SEL> (
GncOption& option,
1093 GtkGrid *page_box,
int row)
1095 auto acct_type_list{option.account_type_list()};
1096 auto widget{gnc_account_sel_new()};
1097 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(widget),
1098 acct_type_list, NULL);
1099 g_list_free(acct_type_list);
1102 option.set_ui_item(std::make_unique<GncGtkAccountSelUIItem>(widget));
1103 option.set_ui_item_from_option();
1105 g_signal_connect(widget,
"account_sel_changed",
1106 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1107 wrap_widget(option, widget, page_box, row);
1109 gtk_container_child_set(GTK_CONTAINER(gtk_widget_get_parent(widget)),
1110 widget,
"fill", TRUE,
"expand", TRUE,
1115 list_changed_cb(GtkTreeSelection *selection,
GncOption* option)
1117 GtkTreeView *view = GTK_TREE_VIEW(option_get_gtk_widget (option));
1118 gnc_option_changed_widget_cb(GTK_WIDGET(view), option);
1122 list_select_all_cb(GtkWidget *widget, gpointer data)
1124 GncOption* option =
static_cast<decltype(option)
>(data);
1126 GtkTreeSelection *selection;
1128 view = GTK_TREE_VIEW(option_get_gtk_widget(option));
1129 selection = gtk_tree_view_get_selection(view);
1130 gtk_tree_selection_select_all(selection);
1131 gnc_option_changed_widget_cb(GTK_WIDGET(view), option);
1135 list_clear_all_cb(GtkWidget *widget, gpointer data)
1137 GncOption* option =
static_cast<decltype(option)
>(data);
1139 GtkTreeSelection *selection;
1141 view = GTK_TREE_VIEW(option_get_gtk_widget(option));
1142 selection = gtk_tree_view_get_selection(view);
1143 gtk_tree_selection_unselect_all(selection);
1144 gnc_option_changed_widget_cb(GTK_WIDGET(view), option);
1148 list_set_default_cb(GtkWidget *widget, gpointer data)
1150 GncOption* option =
static_cast<decltype(option)
>(data);
1151 list_clear_all_cb(widget, data);
1152 option->set_value(option->get_default_value<GncMultichoiceOptionIndexVec>());
1153 option->set_ui_item_from_option();
1162 void set_ui_item_from_option(
GncOption& option) noexcept
override 1164 auto widget{GTK_TREE_VIEW(get_widget())};
1165 auto selection{gtk_tree_view_get_selection(widget)};
1166 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1167 g_signal_handlers_block_by_func(selection, (gpointer)list_changed_cb, &option);
1168 gtk_tree_selection_unselect_all(selection);
1169 for (
auto index : option.get_value<GncMultichoiceOptionIndexVec>())
1171 auto path{gtk_tree_path_new_from_indices(index, -1)};
1172 gtk_tree_selection_select_path(selection, path);
1173 gtk_tree_path_free(path);
1175 g_signal_handlers_unblock_by_func(selection, (gpointer)list_changed_cb, &option);
1178 void set_option_from_ui_item(
GncOption& option) noexcept
override 1180 auto widget{GTK_TREE_VIEW(get_widget())};
1181 auto selection{gtk_tree_view_get_selection(widget)};
1182 auto selected_rows{gtk_tree_selection_get_selected_rows(selection,
nullptr)};
1183 GncMultichoiceOptionIndexVec vec;
1184 for (
auto row = selected_rows; row; row = g_list_next(row))
1186 auto path{
static_cast<GtkTreePath*
>(row->data)};
1187 auto indices{gtk_tree_path_get_indices(path)};
1188 vec.push_back(*indices);
1190 g_list_free_full(selected_rows, (GDestroyNotify)gtk_tree_path_free);
1191 option.set_value(vec);
1196 create_list_widget(
GncOption& option,
char *name)
1198 auto frame = gtk_frame_new(name);
1199 auto hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1200 gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
1201 gtk_container_add(GTK_CONTAINER(frame), hbox);
1203 auto store = gtk_list_store_new(1, G_TYPE_STRING);
1204 auto view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
1205 g_object_unref(store);
1206 auto renderer = gtk_cell_renderer_text_new();
1207 auto column = gtk_tree_view_column_new_with_attributes(
"", renderer,
1210 gtk_tree_view_append_column(view, column);
1211 gtk_tree_view_set_headers_visible(view, FALSE);
1214 for (decltype(num_values) i = 0; i < num_values; i++)
1218 auto string = (raw_string && *raw_string) ? _(raw_string) :
"";
1219 gtk_list_store_append(store, &iter);
1220 gtk_list_store_set(store, &iter, 0,
string ?
string :
"", -1);
1223 option.set_ui_item(std::make_unique<GncGtkListUIItem>(GTK_WIDGET(view)));
1224 option.set_ui_item_from_option();
1226 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(view), FALSE, FALSE, 0);
1228 auto selection = gtk_tree_view_get_selection(view);
1229 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1230 g_signal_connect(selection,
"changed",
1231 G_CALLBACK(list_changed_cb), &option);
1233 auto bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1234 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
1235 gtk_box_pack_end(GTK_BOX(hbox), bbox, FALSE, FALSE, 0);
1237 auto button = gtk_button_new_with_label(_(
"Select All"));
1238 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1239 gtk_widget_set_tooltip_text(button, _(
"Select all entries."));
1241 g_signal_connect(G_OBJECT(button),
"clicked",
1242 G_CALLBACK(list_select_all_cb), &option);
1244 button = gtk_button_new_with_label(_(
"Clear All"));
1245 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1246 gtk_widget_set_tooltip_text(button, _(
"Clear the selection and unselect all entries."));
1248 g_signal_connect(G_OBJECT(button),
"clicked",
1249 G_CALLBACK(list_clear_all_cb), &option);
1251 button = gtk_button_new_with_label(_(
"Select Default"));
1252 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1253 gtk_widget_set_tooltip_text(button, _(
"Select the default selection."));
1255 g_signal_connect(G_OBJECT(button),
"clicked",
1256 G_CALLBACK(list_set_default_cb), &option);
1258 g_object_set (G_OBJECT(hbox),
"margin", 3, NULL);
1264 create_option_widget<GncOptionUIType::LIST> (
GncOption& option,
1265 GtkGrid *page_box,
int row)
1268 auto enclosing{create_list_widget(option,
nullptr)};
1269 set_name_label(option, page_box, row,
true);
1270 set_tool_tip(option, enclosing);
1271 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
1272 gtk_widget_show(enclosing);
1280 void set_ui_item_from_option(
GncOption& option) noexcept
override 1283 if (option.is_alternate())
1284 value = static_cast<double>(option.get_value<
int>());
1286 value = option.get_value<
double>();
1288 gtk_spin_button_set_value(GTK_SPIN_BUTTON(get_widget()), value);
1290 void set_option_from_ui_item(
GncOption& option) noexcept
override 1292 auto value{gtk_spin_button_get_value(GTK_SPIN_BUTTON(get_widget()))};
1293 if (option.is_alternate())
1294 option.set_value<
int>(static_cast<int>(value));
1296 option.set_value<
double>(value);
1305 static GtkSpinButton*
1308 gdouble lower_bound = G_MINDOUBLE;
1309 gdouble upper_bound = G_MAXDOUBLE;
1310 gdouble step_size = 1.0;
1312 if (option.is_alternate())
1314 int tmp_lower_bound = G_MININT;
1315 int tmp_upper_bound = G_MAXINT;
1316 int tmp_step_size = 1.0;
1317 option.
get_limits<
int>(tmp_upper_bound, tmp_lower_bound, tmp_step_size);
1318 lower_bound =(double)tmp_lower_bound;
1319 upper_bound = (double)tmp_upper_bound;
1320 step_size = (double)tmp_step_size;
1323 option.
get_limits<
double>(upper_bound, lower_bound, step_size);
1325 auto adj = GTK_ADJUSTMENT(gtk_adjustment_new(lower_bound, lower_bound,
1326 upper_bound, step_size,
1330 size_t num_decimals = 0;
1331 for (
auto steps = step_size; steps < 1; steps *= 10)
1333 auto widget = gtk_spin_button_new(adj, step_size, num_decimals);
1334 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
1336 size_t num_digits = 0;
1337 for (
auto bigger = MAX(ABS(lower_bound), ABS(upper_bound));
1338 bigger >= 1; bigger /= 10.0)
1340 num_digits += num_decimals;
1341 gtk_entry_set_width_chars(GTK_ENTRY(widget), num_digits);
1342 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
1344 return GTK_SPIN_BUTTON(widget);
1348 create_option_widget<GncOptionUIType::NUMBER_RANGE> (
GncOption& option,
1349 GtkGrid *page_box,
int row)
1351 auto widget{create_range_spinner(option)};
1352 option.set_ui_item(std::make_unique<GncGtkNumberRangeUIItem>(GTK_WIDGET(widget)));
1353 option.set_ui_item_from_option();
1355 g_signal_connect(G_OBJECT(widget),
"changed",
1356 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1357 wrap_widget(option, GTK_WIDGET(widget), page_box, row);
1365 void set_ui_item_from_option(
GncOption& option) noexcept
override 1372 auto value{option.get_value<std::string>().substr(0,6)};
1373 auto rgba_str{g_strdup_printf(
"#%s", value.c_str())};
1374 if (gdk_rgba_parse(&color, rgba_str))
1376 auto color_button = GTK_COLOR_CHOOSER(get_widget());
1377 gtk_color_chooser_set_rgba(color_button, &color);
1381 void set_option_from_ui_item(
GncOption& option) noexcept
override 1384 auto color_button = GTK_COLOR_CHOOSER(get_widget());
1385 gtk_color_chooser_get_rgba(color_button, &color);
1386 auto rgba_str = g_strdup_printf(
"%2x%2x%2x%2x",
1387 (uint8_t)(color.red * 255),
1388 (uint8_t)(color.green * 255),
1389 (uint8_t)(color.blue * 255),
1390 (uint8_t)(color.alpha * 255));
1391 auto rgb_str = g_strdup_printf(
"%2x%2x%2x",
1392 (uint8_t)(color.red * 255),
1393 (uint8_t)(color.green * 255),
1394 (uint8_t)(color.blue * 255));
1396 option.set_value(std::string{rgb_str});
1403 create_option_widget<GncOptionUIType::COLOR> (
GncOption& option, GtkGrid *page_box,
int row)
1405 auto widget = gtk_color_button_new();
1406 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(widget), TRUE);
1408 option.set_ui_item(std::make_unique<GncGtkColorUIItem>(widget));
1409 option.set_ui_item_from_option();
1411 g_signal_connect(G_OBJECT(widget),
"color-set",
1412 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1413 wrap_widget(option, widget, page_box, row);
1421 void set_ui_item_from_option(
GncOption& option) noexcept
override 1423 GtkFontChooser *font_chooser = GTK_FONT_CHOOSER(get_widget());
1424 gtk_font_chooser_set_font(font_chooser,
1425 option.get_value<std::string>().c_str());
1428 void set_option_from_ui_item(
GncOption& option) noexcept
override 1430 GtkFontChooser *font_chooser = GTK_FONT_CHOOSER(get_widget());
1431 option.set_value(std::string{gtk_font_chooser_get_font(font_chooser)});
1436 create_option_widget<GncOptionUIType::FONT> (
GncOption& option, GtkGrid *page_box,
int row)
1438 auto widget{gtk_font_button_new()};
1439 g_object_set(G_OBJECT(widget),
1445 option.set_ui_item(std::make_unique<GncGtkFontUIItem>(widget));
1446 option.set_ui_item_from_option();
1447 g_signal_connect(G_OBJECT(widget),
"font-set",
1448 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1449 wrap_widget(option, widget, page_box, row);
1452 #define LAST_SELECTION "last-selection" 1455 update_preview_cb (GtkFileChooser *chooser,
void* data)
1457 g_return_if_fail(chooser != NULL);
1459 ENTER(
"chooser %p", chooser);
1460 auto filename = gtk_file_chooser_get_preview_filename(chooser);
1461 DEBUG(
"chooser preview name is %s.", filename ? filename :
"(null)");
1462 if (filename == NULL)
1464 filename = g_strdup(static_cast<const char*>(g_object_get_data(G_OBJECT(chooser), LAST_SELECTION)));
1465 DEBUG(
"using last selection of %s", filename ? filename :
"(null)");
1466 if (filename == NULL)
1468 LEAVE(
"no usable name");
1473 auto image = GTK_IMAGE(gtk_file_chooser_get_preview_widget(chooser));
1474 auto pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL);
1476 auto have_preview = (pixbuf != NULL);
1478 gtk_image_set_from_pixbuf(image, pixbuf);
1480 g_object_unref(pixbuf);
1482 gtk_file_chooser_set_preview_widget_active(chooser, have_preview);
1483 LEAVE(
"preview visible is %d", have_preview);
1487 change_image_cb (GtkFileChooser *chooser,
void* data)
1489 auto filename{gtk_file_chooser_get_preview_filename(chooser)};
1492 g_object_set_data_full(G_OBJECT(chooser), LAST_SELECTION, filename, g_free);
1500 void set_ui_item_from_option(
GncOption& option) noexcept
override 1502 auto string{option.get_value<std::string>()};
1503 if (!
string.empty())
1505 DEBUG(
"string = %s",
string.c_str());
1506 auto chooser{GTK_FILE_CHOOSER(get_widget())};
1507 gtk_file_chooser_select_filename(chooser,
string.c_str());
1508 auto filename{gtk_file_chooser_get_filename(chooser)};
1509 g_object_set_data_full(G_OBJECT(chooser), LAST_SELECTION,
1510 g_strdup(
string.c_str()), g_free);
1511 DEBUG(
"Set %s, retrieved %s",
string.c_str(),
1512 filename ? filename :
"(null)");
1513 update_preview_cb(chooser, &option);
1516 void set_option_from_ui_item(
GncOption& option) noexcept
override 1518 auto string = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(get_widget()));
1519 DEBUG(
"filename %s",
string ?
string :
"(null)");
1522 option.set_value(std::string{
string});
1529 create_option_widget<GncOptionUIType::PIXMAP> (
GncOption& option,
1530 GtkGrid *page_box,
int row)
1532 auto enclosing{gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5)};
1533 gtk_box_set_homogeneous(GTK_BOX(enclosing), FALSE);
1534 auto button{gtk_button_new_with_label(_(
"Clear"))};
1535 gtk_widget_set_tooltip_text(button, _(
"Clear any selected image file."));
1536 auto widget{ gtk_file_chooser_button_new(_(
"Select image"),
1537 GTK_FILE_CHOOSER_ACTION_OPEN)};
1538 gtk_widget_set_tooltip_text(widget, _(
"Select an image file."));
1539 g_object_set(G_OBJECT(widget),
1541 "preview-widget", gtk_image_new(),
1543 option.set_ui_item(std::make_unique<GncGtkPixmapUIItem>(widget));
1544 option.set_ui_item_from_option();
1546 g_signal_connect(G_OBJECT (widget),
"selection-changed",
1547 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1548 g_signal_connect(G_OBJECT (widget),
"selection-changed",
1549 G_CALLBACK(change_image_cb), &option);
1550 g_signal_connect(G_OBJECT (widget),
"update-preview",
1551 G_CALLBACK(update_preview_cb), &option);
1552 g_signal_connect_swapped(G_OBJECT (button),
"clicked",
1553 G_CALLBACK(gtk_file_chooser_unselect_all), widget);
1555 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
1556 gtk_box_pack_start(GTK_BOX(enclosing), button, FALSE, FALSE, 0);
1558 gtk_widget_show(widget);
1559 set_name_label(option, page_box, row,
false);
1560 set_tool_tip(option, enclosing);
1561 gtk_widget_show(enclosing);
1562 grid_attach_widget(page_box, enclosing, row);
1566 radiobutton_set_cb(GtkWidget *w, gpointer data)
1568 GncOption* option =
static_cast<decltype(option)
>(data);
1569 gpointer _current, _new_value;
1570 gint current, new_value;
1572 auto widget = option_get_gtk_widget(option);
1574 _current = g_object_get_data(G_OBJECT(widget),
"gnc_radiobutton_index");
1575 current = GPOINTER_TO_INT (_current);
1577 _new_value = g_object_get_data (G_OBJECT(w),
"gnc_radiobutton_index");
1578 new_value = GPOINTER_TO_INT (_new_value);
1580 if (current == new_value)
1583 g_object_set_data (G_OBJECT(widget),
"gnc_radiobutton_index",
1584 GINT_TO_POINTER(new_value));
1585 gnc_option_changed_widget_cb(widget, option);
1593 void set_ui_item_from_option(
GncOption& option) noexcept
override 1595 auto index{option.get_value<uint16_t>()};
1596 auto list{gtk_container_get_children(GTK_CONTAINER(get_widget()))};
1597 auto box{GTK_WIDGET(list->data)};
1600 list = gtk_container_get_children(GTK_CONTAINER(box));
1601 auto node{g_list_nth(list, index)};
1602 GtkButton* button{};
1605 button = GTK_BUTTON(node->data);
1609 PERR(
"Invalid Radio Button Selection %hu", index);
1614 auto val{g_object_get_data (G_OBJECT (button),
1615 "gnc_radiobutton_index")};
1616 g_return_if_fail (GPOINTER_TO_UINT (val) == index);
1618 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
1620 void set_option_from_ui_item(
GncOption& option) noexcept
override 1622 auto index{g_object_get_data(G_OBJECT(get_widget()),
1623 "gnc_radiobutton_index")};
1624 option.set_value<uint16_t>(GPOINTER_TO_INT(index));
1629 create_radiobutton_widget(
char *name,
GncOption& option)
1631 GtkWidget *frame, *box;
1632 GtkWidget *widget = NULL;
1636 g_return_val_if_fail(num_values >= 0, NULL);
1639 frame = gtk_frame_new (name);
1642 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
1643 gtk_box_set_homogeneous (GTK_BOX (box), FALSE);
1644 gtk_container_add (GTK_CONTAINER (frame), box);
1646 option.set_ui_item(std::make_unique<GncGtkPixmapUIItem>(frame));
1647 option.set_ui_item_from_option();
1650 for (decltype(num_values) i = 0; i < num_values; i++)
1655 gtk_radio_button_new_with_label_from_widget (widget ?
1656 GTK_RADIO_BUTTON (widget) :
1658 label && *label ? _(label) :
"");
1659 g_object_set_data (G_OBJECT (widget),
"gnc_radiobutton_index",
1660 GINT_TO_POINTER (i));
1661 g_signal_connect(G_OBJECT(widget),
"toggled",
1662 G_CALLBACK(radiobutton_set_cb), &option);
1663 gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
1670 create_option_widget<GncOptionUIType::RADIOBUTTON> (
GncOption& option, GtkGrid *page_box,
int row)
1672 auto enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
1673 gtk_box_set_homogeneous (GTK_BOX (enclosing), FALSE);
1674 set_name_label(option, page_box, row,
true);
1675 set_tool_tip(option, enclosing);
1676 auto widget = create_radiobutton_widget(NULL, option);
1677 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
1678 gtk_widget_show_all(enclosing);
1679 grid_attach_widget(page_box, enclosing, row);
1687 void set_ui_item_from_option(
GncOption& option) noexcept
override 1689 auto widget{GNC_DATE_FORMAT(get_widget())};
1690 auto [format, months, years, custom] = option.get_value<GncOptionDateFormat>();
1691 gnc_date_format_set_format(widget, format);
1692 gnc_date_format_set_months(widget, months);
1693 gnc_date_format_set_years(widget, years);
1694 gnc_date_format_set_custom(widget, custom.c_str());
1696 void set_option_from_ui_item(
GncOption& option) noexcept
override 1698 auto widget{GNC_DATE_FORMAT(get_widget())};
1699 GncOptionDateFormat format{
1700 gnc_date_format_get_format(widget),
1701 gnc_date_format_get_months(widget),
1702 gnc_date_format_get_years(widget),
1703 gnc_date_format_get_custom(widget)};
1704 option.set_value(format);
1710 create_option_widget<GncOptionUIType::DATE_FORMAT> (
GncOption& option,
1711 GtkGrid *page_box,
int row)
1713 auto enclosing = gnc_date_format_new_without_label ();
1714 set_name_label(option, page_box, row,
true);
1715 set_tool_tip(option, enclosing);
1716 option.set_ui_item(std::make_unique<GncGtkDateFormatUIItem>(enclosing));
1717 option.set_ui_item_from_option();
1719 g_signal_connect(G_OBJECT(enclosing),
"format_changed",
1720 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1721 gtk_widget_show_all(enclosing);
1722 grid_attach_widget(page_box, enclosing, row);
1726 static void plot_size_set_pixels(GtkWidget*,
PlotSize*);
1727 static void plot_size_set_percent(GtkWidget*,
PlotSize*);
1731 GtkWidget *m_widget;
1732 GtkWidget *m_pixel_button;
1733 GtkWidget *m_percent_button;
1734 GtkWidget *m_range_spinner;
1735 GtkAdjustment *m_adj_pct;
1736 GtkAdjustment *m_adj_px;
1737 unsigned long m_percent_handler;
1738 unsigned long m_pixel_handler;
1742 void set_entry_from_option(
GncOption& option);
1743 void set_option_from_entry(
GncOption& option);
1744 GtkWidget* get_widget() {
return m_widget; }
1745 GtkWidget* get_spinner() {
return m_range_spinner; }
1746 void set_pixels() { gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(m_range_spinner), m_adj_px); }
1747 void set_percent() { gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(m_range_spinner), m_adj_pct); }
1751 m_widget{gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)}, m_pixel_button{gtk_radio_button_new_with_label(
nullptr, _(
"Pixels"))},
1752 m_percent_button{gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(m_pixel_button), _(
"Percent"))},
1753 m_range_spinner{GTK_WIDGET(create_range_spinner(option))},
1754 m_adj_pct{GTK_ADJUSTMENT(g_object_ref(gtk_adjustment_new(100.0, 10.0, 100.0, 1.0, 5.0, 0.0)))},
1755 m_adj_px{GTK_ADJUSTMENT(g_object_ref(gtk_adjustment_new(1000.0, 110.0, 10000.0, 10.0, 250.0, 0.0)))}
1757 gtk_box_set_homogeneous(GTK_BOX(m_widget), FALSE);
1758 g_object_set (G_OBJECT(m_widget),
"margin", 3, NULL);
1759 set_tool_tip(option, m_widget);
1760 gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_pixel_button), FALSE, FALSE, 0);
1761 gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_percent_button), FALSE, FALSE, 0);
1762 gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_range_spinner),
1765 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_pixel_button), FALSE);
1766 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_percent_button), TRUE);
1768 m_pixel_handler = g_signal_connect(m_pixel_button,
"toggled", G_CALLBACK(plot_size_set_pixels),
this);
1769 m_percent_handler = g_signal_connect(m_percent_button,
"toggled", G_CALLBACK(plot_size_set_percent),
this);
1772 PlotSize::~PlotSize()
1774 g_signal_handler_disconnect(m_pixel_button, m_pixel_handler);
1775 g_signal_handler_disconnect(m_percent_button, m_percent_handler);
1776 g_object_unref(m_adj_pct);
1777 g_object_unref(m_adj_px);
1781 PlotSize::set_option_from_entry(
GncOption& option)
1783 auto value{gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_range_spinner))};
1784 if (option.is_alternate())
1785 option.set_value<
int>(static_cast<int>(value));
1787 option.set_value<
double>(value);
1791 PlotSize::set_entry_from_option(
GncOption& option)
1794 if (option.is_alternate())
1796 auto int_value{option.get_value<
int>()};
1797 value =
static_cast<double>(int_value);
1801 value = option.get_value<
double>();
1805 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pixel_button), TRUE);
1807 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_percent_button), TRUE);
1809 gtk_spin_button_set_value(GTK_SPIN_BUTTON(m_range_spinner), value);
1813 plot_size_set_pixels(GtkWidget *widget,
PlotSize *ps)
1819 plot_size_set_percent(GtkWidget *widget,
PlotSize *ps)
1824 using PlotSizePtr = std::unique_ptr<PlotSize>;
1831 m_plot_size{std::move(plot_size)} {}
1832 void set_ui_item_from_option(
GncOption& option) noexcept
override 1834 m_plot_size->set_entry_from_option(option);
1836 void set_option_from_ui_item(
GncOption& option) noexcept
override 1838 m_plot_size->set_option_from_entry(option);
1840 PlotSize* get_plot_size() {
return m_plot_size.get(); }
1842 PlotSizePtr m_plot_size;
1846 create_option_widget<GncOptionUIType::PLOT_SIZE> (
GncOption& option,
1847 GtkGrid *page_box,
int row)
1850 auto enclosing = gtk_frame_new(NULL);
1851 gtk_widget_set_halign (GTK_WIDGET(enclosing), GTK_ALIGN_START);
1852 set_name_label(option, page_box, row,
false);
1854 option.set_ui_item(std::make_unique<GncGtkPlotSizeUIItem>(std::make_unique<PlotSize>(option)));
1855 option.set_ui_item_from_option();
1857 auto widget{option_get_gtk_widget(&option)};
1858 gtk_container_add(GTK_CONTAINER(enclosing), widget);
1860 gtk_widget_show_all(enclosing);
1861 grid_attach_widget(page_box, enclosing, row);
1865 g_signal_connect(G_OBJECT(ui_item->get_plot_size()->get_spinner()),
"changed",
1866 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1874 GtkCellRenderer *cr;
1876 tm = gnc_tree_model_budget_new(gnc_get_current_book());
1877 cb = GTK_COMBO_BOX(gtk_combo_box_new_with_model(tm));
1879 cr = gtk_cell_renderer_text_new();
1880 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cb), cr, TRUE);
1882 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cb), cr,
"text",
1883 BUDGET_NAME_COLUMN, NULL);
1884 return GTK_WIDGET(cb);
1892 void set_ui_item_from_option(
GncOption& option) noexcept
override 1895 auto widget{GTK_COMBO_BOX(get_widget())};
1896 auto instance{option.get_value<
const QofInstance*>()};
1899 auto tree_model{gtk_combo_box_get_model(widget)};
1900 if (gnc_tree_model_budget_get_iter_for_budget(tree_model, &iter,
1901 GNC_BUDGET(instance)))
1902 gtk_combo_box_set_active_iter(widget, &iter);
1905 void set_option_from_ui_item(
GncOption& option) noexcept
override 1908 auto widget{GTK_COMBO_BOX(get_widget())};
1909 if (gtk_combo_box_get_active_iter(widget, &iter))
1911 auto tree_model{gtk_combo_box_get_model(widget)};
1912 auto budget{gnc_tree_model_budget_get_budget(tree_model, &iter)};
1913 option.set_value(qof_instance_cast(budget));
1919 create_option_widget<GncOptionUIType::BUDGET> (
GncOption& option,
1920 GtkGrid *page_box,
int row)
1922 auto widget{create_budget_widget(option)};
1924 option.set_ui_item(std::make_unique<GncGtkBudgetUIItem>(widget));
1925 option.set_ui_item_from_option();
1928 g_signal_connect(G_OBJECT(widget),
"changed",
1929 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1931 wrap_widget(option, widget, page_box, row);
1935 gnc_options_ui_factory_initialize(
void)
1938 create_option_widget<GncOptionUIType::BOOLEAN>);
1940 create_option_widget<GncOptionUIType::STRING>);
1942 create_option_widget<GncOptionUIType::TEXT>);
1944 create_option_widget<GncOptionUIType::CURRENCY>);
1946 create_option_widget<GncOptionUIType::COMMODITY>);
1948 create_option_widget<GncOptionUIType::MULTICHOICE>);
1950 create_option_widget<GncOptionUIType::DATE_ABSOLUTE>);
1952 create_option_widget<GncOptionUIType::DATE_RELATIVE>);
1954 create_option_widget<GncOptionUIType::DATE_BOTH>);
1956 create_option_widget<GncOptionUIType::ACCOUNT_LIST>);
1958 create_option_widget<GncOptionUIType::ACCOUNT_SEL>);
1960 create_option_widget<GncOptionUIType::LIST>);
1962 create_option_widget<GncOptionUIType::NUMBER_RANGE>);
1964 create_option_widget<GncOptionUIType::COLOR>);
1966 create_option_widget<GncOptionUIType::FONT>);
1968 create_option_widget<GncOptionUIType::PLOT_SIZE>);
1970 create_option_widget<GncOptionUIType::BUDGET>);
1972 create_option_widget<GncOptionUIType::PIXMAP>);
1974 create_option_widget<GncOptionUIType::RADIOBUTTON>);
1976 create_option_widget<GncOptionUIType::DATE_FORMAT>);
void gnc_tree_view_account_get_view_info(GncTreeViewAccount *view, AccountViewInfo *avi)
Given pointers to an account tree and old style filter block, this function will copy the current con...
static void set_func(GncOptionUIType type, WidgetCreateFunc func)
Register a WidgetCreateFunc.
bool is_multiselect() const noexcept
void gnc_currency_edit_set_currency(GNCCurrencyEdit *gce, const gnc_commodity *currency)
Set the widget to display a certain currency name.
GList * gnc_tree_view_account_get_selected_accounts(GncTreeViewAccount *view)
This function returns a list of the accounts associated with the selected items in the account tree v...
#define DEBUG(format, args...)
Print a debugging message.
stop here; the following types just aren't ready for prime time
void gnc_tree_view_account_set_view_info(GncTreeViewAccount *view, AccountViewInfo *avi)
Given pointers to an account tree and old style filter block, this function will applies the settings...
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
void gnc_tree_view_account_set_selected_accounts(GncTreeViewAccount *view, GList *account_list, gboolean show_last)
This function selects a set of accounts in the account tree view.
Represents the public interface for an option.
C++ Public interface for individual options.
Currency selection widget.
void gnc_tree_view_account_select_subaccounts(GncTreeViewAccount *view, Account *account)
This function selects all sub-accounts of an account in the account tree view.
uint16_t num_permissible_values() const
Implemented only for GncOptionMultiselectValue.
GtkTreeView implementation for gnucash account tree.
RelativeDatePeriod
Reporting periods relative to the current date.
GtkTreeView * gnc_tree_view_account_new(gboolean show_root)
Create a new account tree view.
gnc_commodity * gnc_currency_edit_get_currency(GNCCurrencyEdit *gce)
Retrieve the displayed currency of the widget.
Implementation templates and specializtions for GncOption values.
virtual void set_selectable(bool) const noexcept override
Control wether the widget is sensitive.
All type declarations for the whole Gnucash engine.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
void clear_ui_item() override
Clear the data from the widget.
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Holds a pointer to the UI item which will control the option and an enum representing the type of the...
GtkWidget * gnc_currency_edit_new(void)
Create a new GNCCurrencyEdit widget which can be used to provide an easy way to enter ISO currency co...
const char * permissible_value(uint16_t index) const
Implemented only for GncOptionMultiselectValue.
static void create(GncOption &option, GtkGrid *page, int row)
Create a widget.
#define LEAVE(format, args...)
Print a function exit debugging message.
class GncOptionGtkUIItem Gtk-specific Interface class for Option Widget
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
void get_limits(ValueType &, ValueType &, ValueType &) const noexcept
Implemented only for GncOptionNumericRange.
const char * permissible_value_name(uint16_t index) const
Implemented only for GncOptionMultiselectValue.
provides some utilities for working with the list of budgets in a book.
GncOptionUIType
Used by GncOptionClassifier to indicate to dialog-options what control should be displayed for the op...
Commodity handling public routines.
GList * account_type_list() const noexcept
Implemented only for GncOptionAccountListValue.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...