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_widget_set_size_request(widget, 400, -1);
281 gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), TRUE);
282 gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW(widget), FALSE);
284 auto ui_item{std::make_unique<GncGtkTextUIItem>(widget)};
285 auto text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
286 option.set_ui_item(std::move(ui_item));
287 option.set_ui_item_from_option();
289 g_signal_connect(G_OBJECT(text_buffer),
"changed",
290 G_CALLBACK(gnc_option_changed_option_cb), &option);
291 gtk_container_add (GTK_CONTAINER (scroll), widget);
292 gtk_box_pack_start(GTK_BOX(enclosing), frame, TRUE, TRUE, 0);
293 set_name_label(option, page_box, row,
true);
294 set_tool_tip(option, enclosing);
295 gtk_widget_show_all(enclosing);
296 grid_attach_widget(GTK_GRID(page_box), enclosing, row);
304 void set_ui_item_from_option(
GncOption& option) noexcept
override 306 auto widget{GNC_CURRENCY_EDIT(get_widget())};
307 auto currency{option.get_value<gnc_commodity*>()};
312 void set_option_from_ui_item(
GncOption& option) noexcept
override 314 auto widget{GNC_CURRENCY_EDIT(get_widget())};
316 option.set_value<gnc_commodity*>(currency);
321 create_option_widget<GncOptionUIType::CURRENCY> (
GncOption& option, GtkGrid *page_box,
325 auto ui_item{std::make_unique<GncGtkCurrencyUIItem>(widget)};
326 option.set_ui_item(std::move(ui_item));
327 option.set_ui_item_from_option();
329 g_signal_connect(G_OBJECT(widget),
"changed",
330 G_CALLBACK(gnc_option_changed_widget_cb), &option);
331 wrap_widget(option, widget, page_box, row);
339 void set_ui_item_from_option(
GncOption& option) noexcept
override 341 auto widget{GNC_GENERAL_SELECT(get_widget())};
342 auto commodity{option.get_value<gnc_commodity*>()};
345 gnc_general_select_set_selected(widget, GNC_COMMODITY(commodity));
347 void set_option_from_ui_item(
GncOption& option) noexcept
override 349 auto widget{GNC_GENERAL_SELECT(get_widget())};
350 auto commodity{gnc_general_select_get_selected(widget)};
351 option.set_value<gnc_commodity*>(GNC_COMMODITY(commodity));
356 create_option_widget<GncOptionUIType::COMMODITY> (
GncOption& option, GtkGrid *page_box,
359 auto widget = gnc_general_select_new(GNC_GENERAL_SELECT_TYPE_SELECT,
360 gnc_commodity_edit_get_string,
361 gnc_commodity_edit_new_select,
364 auto ui_item{std::make_unique<GncGtkCommodityUIItem>(widget)};
365 option.set_ui_item(std::move(ui_item));
366 option.set_ui_item_from_option();
367 g_signal_connect(G_OBJECT(GNC_GENERAL_SELECT(widget)->entry),
"changed",
368 G_CALLBACK(gnc_option_changed_widget_cb), &option);
369 wrap_widget(option, widget, page_box, row);
373 create_multichoice_widget(
GncOption& option)
377 g_return_val_if_fail(num_values >= 0, NULL);
378 auto renderer = gtk_cell_renderer_text_new();
379 auto store = gtk_list_store_new(1, G_TYPE_STRING);
381 for (decltype(num_values) i = 0; i < num_values; i++)
385 gtk_list_store_append (store, &iter);
386 gtk_list_store_set(store, &iter, 0,
387 (itemstring && *itemstring) ? _(itemstring) :
"", -1);
390 auto widget{GTK_WIDGET(gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)))};
391 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(widget), renderer, TRUE);
392 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(widget),
393 renderer,
"text", 0);
394 g_object_unref(store);
404 void set_ui_item_from_option(
GncOption& option) noexcept
override 406 auto widget{GTK_COMBO_BOX(get_widget())};
407 gtk_combo_box_set_active(widget, option.get_value<uint16_t>());
409 void set_option_from_ui_item(
GncOption& option) noexcept
override 411 auto widget{GTK_COMBO_BOX(get_widget())};
412 option.set_value<uint16_t>(
static_cast<uint16_t
>(gtk_combo_box_get_active(widget)));
414 SCM get_widget_scm_value(
const GncOption& option)
const override 416 auto widget{GTK_COMBO_BOX(get_widget())};
417 auto id{gtk_combo_box_get_active(widget)};
419 return scm_from_utf8_symbol(value);
424 create_option_widget<GncOptionUIType::MULTICHOICE> (
GncOption& option, GtkGrid *page_box,
427 auto widget{create_multichoice_widget(option)};
428 auto ui_item{std::make_unique<GncGtkMultichoiceUIItem>(widget)};
429 option.set_ui_item(std::move(ui_item));
430 option.set_ui_item_from_option();
431 g_signal_connect(G_OBJECT(widget),
"changed",
432 G_CALLBACK(gnc_option_changed_widget_cb), &option);
433 wrap_widget(option, widget, page_box, row);
442 virtual void set_entry_from_option(
GncOption& option) = 0;
443 virtual void set_option_from_entry(
GncOption& option) = 0;
445 virtual GtkWidget* get_entry() = 0;
447 virtual GtkWidget* get_widget() = 0;
448 virtual void toggle_relative(
bool) {}
449 virtual void block_signals(
bool) = 0;
453 using GncDateEntryPtr = std::unique_ptr<GncDateEntry>;
460 void set_entry_from_option(
GncOption& option)
override;
461 void set_option_from_entry(
GncOption& option)
override;
462 GtkWidget* get_entry()
override {
return GTK_WIDGET(m_entry); }
463 GtkWidget* get_widget()
override {
return GTK_WIDGET(m_entry); }
464 void block_signals(
bool)
override;
467 unsigned long m_handler_id;
470 AbsoluteDateEntry::AbsoluteDateEntry(
GncOption& option) :
471 m_entry{GNC_DATE_EDIT(gnc_date_edit_new(time(NULL), FALSE, FALSE))}
473 auto entry = GNC_DATE_EDIT(m_entry)->date_entry;
474 m_handler_id = g_signal_connect(G_OBJECT(entry),
"changed",
475 G_CALLBACK(gnc_option_changed_option_cb),
480 AbsoluteDateEntry::block_signals(
bool block)
482 auto entry{G_OBJECT(GNC_DATE_EDIT(m_entry)->date_entry)};
484 g_signal_handler_block(entry, m_handler_id);
486 g_signal_handler_unblock(entry, m_handler_id);
490 AbsoluteDateEntry::set_entry_from_option(
GncOption& option)
492 gnc_date_edit_set_time(m_entry, option.get_value<
time64>());
496 AbsoluteDateEntry::set_option_from_entry(
GncOption& option)
498 option.set_value<
time64>(gnc_date_edit_get_date(m_entry));
506 void set_entry_from_option(
GncOption& option)
override;
507 void set_option_from_entry(
GncOption& option)
override;
508 GtkWidget* get_widget()
override {
return m_entry; }
509 GtkWidget* get_entry()
override {
return m_entry; }
510 void block_signals(
bool)
override;
513 unsigned long m_handler_id;
517 RelativeDateEntry::RelativeDateEntry(
GncOption& option)
520 auto renderer = gtk_cell_renderer_text_new();
521 auto store = gtk_list_store_new(1, G_TYPE_STRING);
524 for (decltype(num) index = 0; index < num; ++index)
527 gtk_list_store_append (store, &iter);
528 gtk_list_store_set (store, &iter, 0,
533 m_entry = GTK_WIDGET(gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)));
534 gtk_combo_box_set_active(GTK_COMBO_BOX(m_entry), 0);
535 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(m_entry), renderer, TRUE);
536 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(m_entry),
537 renderer,
"text", 0);
539 g_object_unref(store);
541 m_handler_id = g_signal_connect(G_OBJECT(m_entry),
"changed",
542 G_CALLBACK(gnc_option_changed_widget_cb),
547 RelativeDateEntry::set_entry_from_option(
GncOption& option)
549 gtk_combo_box_set_active(GTK_COMBO_BOX(m_entry), option.get_value<uint16_t>());
553 RelativeDateEntry::set_option_from_entry(
GncOption& option)
555 option.set_value<uint16_t>(gtk_combo_box_get_active(GTK_COMBO_BOX(m_entry)));
559 RelativeDateEntry::block_signals(
bool block)
562 g_signal_handler_block(m_entry, m_handler_id);
564 g_signal_handler_unblock(m_entry, m_handler_id);
567 using AbsoluteDateEntryPtr = std::unique_ptr<AbsoluteDateEntry>;
568 using RelativeDateEntryPtr = std::unique_ptr<RelativeDateEntry>;
575 void set_entry_from_option(
GncOption& option)
override;
576 void set_option_from_entry(
GncOption& option)
override;
577 GtkWidget* get_widget()
override {
return m_widget; }
578 GtkWidget* get_entry()
override;
579 void toggle_relative(
bool use_absolute)
override;
580 void block_signals(
bool)
override;
583 GtkWidget* m_abs_button;
584 AbsoluteDateEntryPtr m_abs_entry;
585 GtkWidget* m_rel_button;
586 RelativeDateEntryPtr m_rel_entry;
587 bool m_use_absolute =
true;
588 unsigned long m_abs_hdlr;
589 unsigned long m_rel_hdlr;
592 static void date_set_absolute_cb(GtkWidget *widget, gpointer data1);
593 static void date_set_relative_cb(GtkWidget *widget, gpointer data1);
595 BothDateEntry::BothDateEntry(
GncOption& option) :
596 m_widget{gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5)},
597 m_abs_button{gtk_radio_button_new(NULL)},
598 m_abs_entry{std::make_unique<AbsoluteDateEntry>(option)},
600 gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(m_abs_button))},
601 m_rel_entry{std::make_unique<RelativeDateEntry>(option)}
603 gtk_box_set_homogeneous (GTK_BOX(m_widget), FALSE);
604 m_abs_hdlr = g_signal_connect(G_OBJECT(m_abs_button),
"toggled",
605 G_CALLBACK(date_set_absolute_cb), &option);
606 m_rel_hdlr = g_signal_connect(G_OBJECT(m_rel_button),
"toggled",
607 G_CALLBACK(date_set_relative_cb), &option);
609 gtk_box_pack_start(GTK_BOX(m_widget),
610 m_abs_button, FALSE, FALSE, 0);
611 gtk_box_pack_start(GTK_BOX(m_widget),
612 m_abs_entry->get_entry(), FALSE, FALSE, 0);
613 gtk_box_pack_start(GTK_BOX(m_widget),
614 m_rel_button, FALSE, FALSE, 0);
615 gtk_box_pack_start(GTK_BOX(m_widget),
616 m_rel_entry->get_entry(), FALSE, FALSE, 0);
621 BothDateEntry::get_entry()
623 return m_use_absolute ? m_abs_entry->get_entry() : m_rel_entry->get_entry();
627 BothDateEntry::toggle_relative(
bool use_absolute)
629 m_use_absolute = use_absolute;
631 gtk_widget_set_sensitive(GTK_WIDGET(m_abs_entry->get_widget()),
633 gtk_widget_set_sensitive(GTK_WIDGET(m_rel_entry->get_widget()),
638 BothDateEntry::set_entry_from_option(
GncOption& option)
643 m_abs_entry->set_entry_from_option(option);
645 m_rel_entry->set_entry_from_option(option);
646 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_rel_button),
648 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_abs_button),
651 toggle_relative(m_use_absolute);
655 BothDateEntry::set_option_from_entry(
GncOption& option)
658 m_abs_entry->set_option_from_entry(option);
660 m_rel_entry->set_option_from_entry(option);
664 BothDateEntry::block_signals(
bool block)
668 g_signal_handler_block(m_abs_button, m_abs_hdlr);
669 g_signal_handler_block(m_rel_button, m_rel_hdlr);
673 g_signal_handler_unblock(m_abs_button, m_abs_hdlr);
674 g_signal_handler_unblock(m_rel_button, m_rel_hdlr);
676 m_abs_entry->block_signals(block);
677 m_rel_entry->block_signals(block);
686 void clear_ui_item()
override { m_entry =
nullptr; }
687 void set_ui_item_from_option(
GncOption& option) noexcept
override 690 m_entry->set_entry_from_option(option);
692 void set_option_from_ui_item(
GncOption& option) noexcept
override 695 m_entry->set_option_from_entry(option);
697 GtkWidget* get_widget()
const override 699 return m_entry->get_widget();
703 GncDateEntryPtr m_entry;
707 date_set_absolute_cb(GtkWidget *widget, gpointer data1)
709 GncOption* option =
static_cast<decltype(option)
>(data1);
710 auto ui_item = option->get_ui_item();
711 if (
auto date_ui = dynamic_cast<const GncOptionDateUIItem* const>(ui_item))
714 gnc_option_changed_option_cb(widget, option);
719 date_set_relative_cb(GtkWidget *widget, gpointer data1)
721 GncOption* option =
static_cast<decltype(option)
>(data1);
722 auto ui_item = option->get_ui_item();
723 if (
auto date_ui = dynamic_cast<const GncOptionDateUIItem* const>(ui_item))
726 gnc_option_changed_option_cb(widget, option);
731 create_date_option_widget(
GncOption& option, GtkGrid *page_box,
int row)
733 GtkWidget *enclosing{
nullptr};
734 auto type = option.get_ui_type();
737 case GncOptionUIType::DATE_ABSOLUTE:
738 option.set_ui_item(std::make_unique<GncOptionDateUIItem>(std::make_unique<AbsoluteDateEntry>(option), type));
740 case GncOptionUIType::DATE_RELATIVE:
741 option.set_ui_item(std::make_unique<GncOptionDateUIItem>(std::make_unique<RelativeDateEntry>(option), type));
743 case GncOptionUIType::DATE_BOTH:
744 option.set_ui_item(std::make_unique<GncOptionDateUIItem>(std::make_unique<BothDateEntry>(option), type));
747 PERR(
"Attempted to create date option widget with wrong UI type %d",
748 static_cast<int>(type));
752 auto widget{option_get_gtk_widget(&option)};
753 if (type == GncOptionUIType::DATE_RELATIVE)
755 enclosing = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
756 gtk_box_set_homogeneous(GTK_BOX (enclosing), FALSE);
758 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
762 enclosing = gtk_frame_new(
nullptr);
763 g_object_set(G_OBJECT(widget),
"margin", 3, NULL);
765 gtk_container_add (GTK_CONTAINER(enclosing), widget);
768 gtk_widget_set_halign (GTK_WIDGET(enclosing), GTK_ALIGN_START);
769 set_name_label(option, page_box, row,
false);
770 set_tool_tip(option, enclosing);
771 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
774 if (
auto date_ui{ui_item ? ui_item->get_entry() :
nullptr})
776 date_ui->block_signals(
true);
777 date_ui->set_entry_from_option(option);
778 date_ui->block_signals(
false);
781 gtk_widget_show_all(enclosing);
785 create_option_widget<GncOptionUIType::DATE_ABSOLUTE>(
GncOption& option,
786 GtkGrid *page_box,
int row)
788 create_date_option_widget(option, page_box, row);
792 create_option_widget<GncOptionUIType::DATE_RELATIVE>(
GncOption& option,
793 GtkGrid *page_box,
int row)
795 create_date_option_widget(option, page_box, row);
799 create_option_widget<GncOptionUIType::DATE_BOTH>(
GncOption& option,
800 GtkGrid *page_box,
int row)
802 create_date_option_widget(option, page_box, row);
805 using GncOptionAccountList = std::vector<GncGUID>;
808 account_select_all_cb(GtkWidget *widget, gpointer data)
810 GncOption* option =
static_cast<decltype(option)
>(data);
811 GncTreeViewAccount *tree_view;
812 GtkTreeSelection *selection;
814 tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget (option));
815 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
816 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
817 gtk_tree_selection_select_all(selection);
818 gnc_option_changed_widget_cb(widget, option);
822 account_clear_all_cb(GtkWidget *widget, gpointer data)
824 GncOption* option =
static_cast<decltype(option)
>(data);
825 GncTreeViewAccount *tree_view;
826 GtkTreeSelection *selection;
828 tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget (option));
829 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
830 gtk_tree_selection_unselect_all(selection);
831 gnc_option_changed_widget_cb(widget, option);
835 account_select_children_cb(GtkWidget *widget, gpointer data)
837 GncOption* option =
static_cast<decltype(option)
>(data);
838 GncTreeViewAccount *tree_view;
839 GList *acct_list = NULL, *acct_iter = NULL;
841 tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget (option));
844 for (acct_iter = acct_list; acct_iter; acct_iter = acct_iter->next)
847 g_list_free (acct_list);
851 account_set_default_cb(GtkWidget* widget, gpointer data)
853 GncOption* option =
static_cast<decltype(option)
>(data);
854 account_clear_all_cb(widget, data);
855 option->set_value(option->get_default_value<GncOptionAccountList>());
856 option->set_ui_item_from_option();
860 show_hidden_toggled_cb(GtkWidget *widget,
GncOption* option)
862 if (option->get_ui_type() != GncOptionUIType::ACCOUNT_LIST &&
863 option->get_ui_type() != GncOptionUIType::ACCOUNT_SEL)
866 auto tree_view = GNC_TREE_VIEW_ACCOUNT(option_get_gtk_widget(option));
869 avi.show_hidden = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
871 gnc_option_changed_widget_cb(widget, option);
879 void set_ui_item_from_option(
GncOption& option) noexcept
override 881 auto widget{GNC_TREE_VIEW_ACCOUNT(get_widget())};
882 GList *acc_list =
nullptr;
883 const GncOptionAccountList& accounts =
884 option.get_value<GncOptionAccountList>();
885 auto book{gnc_get_current_book()};
886 for (
auto guid : accounts)
889 acc_list = g_list_prepend(acc_list, account);
891 acc_list = g_list_reverse(acc_list);
893 g_list_free(acc_list);
895 void set_option_from_ui_item(
GncOption& option) noexcept
override 897 auto widget{GNC_TREE_VIEW_ACCOUNT(get_widget())};
899 GncOptionAccountList acc_vec;
900 acc_vec.reserve(g_list_length(acc_list));
901 for (
auto node = acc_list; node; node = g_list_next(node))
904 acc_vec.push_back(*guid);
906 g_list_free(acc_list);
907 option.set_value(acc_vec);
912 create_account_widget(
GncOption& option,
char *name)
914 bool multiple_selection;
915 GtkWidget *scroll_win;
921 GList *acct_type_list;
922 GtkTreeSelection *selection;
927 frame = gtk_frame_new(name);
929 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
930 gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE);
932 gtk_container_add(GTK_CONTAINER(frame), vbox);
935 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), FALSE);
936 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
937 if (multiple_selection)
938 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
940 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
951 avi.include_type[i] = FALSE;
952 avi.show_hidden = TRUE;
954 for (node = acct_type_list; node; node = node->next)
956 GNCAccountType type =
static_cast<decltype(type)
>(GPOINTER_TO_INT (node->data));
958 avi.include_type[type] = TRUE;
962 g_list_free (acct_type_list);
972 avi.include_type[i] = TRUE;
973 avi.show_hidden = TRUE;
977 scroll_win = gtk_scrolled_window_new(NULL, NULL);
978 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win),
979 GTK_POLICY_AUTOMATIC,
980 GTK_POLICY_AUTOMATIC);
982 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
983 gtk_container_set_border_width(GTK_CONTAINER(scroll_win), 5);
985 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
986 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
987 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 10);
989 option.set_ui_item(std::make_unique<GncGtkAccountListUIItem>(tree));
990 option.set_ui_item_from_option();
992 if (multiple_selection)
994 button = gtk_button_new_with_label(_(
"Select All"));
995 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
996 gtk_widget_set_tooltip_text(button, _(
"Select all accounts."));
998 g_signal_connect(G_OBJECT(button),
"clicked",
999 G_CALLBACK(account_select_all_cb), &option);
1001 button = gtk_button_new_with_label(_(
"Clear All"));
1002 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1003 gtk_widget_set_tooltip_text(button, _(
"Clear the selection and unselect all accounts."));
1005 g_signal_connect(G_OBJECT(button),
"clicked",
1006 G_CALLBACK(account_clear_all_cb), &option);
1008 button = gtk_button_new_with_label(_(
"Select Children"));
1009 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1010 gtk_widget_set_tooltip_text(button, _(
"Select all descendents of selected account."));
1012 g_signal_connect(G_OBJECT(button),
"clicked",
1013 G_CALLBACK(account_select_children_cb), &option);
1016 button = gtk_button_new_with_label(_(
"Select Default"));
1017 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1018 gtk_widget_set_tooltip_text(button, _(
"Select the default account selection."));
1020 g_signal_connect(G_OBJECT(button),
"clicked",
1021 G_CALLBACK(account_set_default_cb), &option);
1023 gtk_widget_set_margin_start (GTK_WIDGET(bbox), 6);
1024 gtk_widget_set_margin_end (GTK_WIDGET(bbox), 6);
1026 if (multiple_selection)
1030 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1031 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
1032 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1035 button = gtk_check_button_new_with_label(_(
"Show Hidden Accounts"));
1036 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1037 gtk_widget_set_tooltip_text(button, _(
"Show accounts that have been marked hidden."));
1038 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
1039 g_signal_connect(G_OBJECT(button),
"toggled",
1040 G_CALLBACK(show_hidden_toggled_cb), &option);
1042 gtk_container_add(GTK_CONTAINER(scroll_win), tree);
1047 option_account_sel_changed_cb(GtkTreeSelection *sel, gpointer data)
1049 auto tree_view{gtk_tree_selection_get_tree_view(sel)};
1050 gnc_option_changed_widget_cb(GTK_WIDGET(tree_view),
1051 static_cast<GncOption*>(data));
1055 create_option_widget<GncOptionUIType::ACCOUNT_LIST>(
GncOption& option,
1056 GtkGrid *page_box,
int row)
1058 auto enclosing{create_account_widget(option,
nullptr)};
1059 gtk_widget_set_vexpand (GTK_WIDGET(enclosing), TRUE);
1060 gtk_widget_set_hexpand (GTK_WIDGET(enclosing), TRUE);
1061 set_name_label(option, page_box, row,
true);
1062 set_tool_tip(option, enclosing);
1063 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
1065 auto widget{option_get_gtk_widget(&option)};
1066 auto selection{gtk_tree_view_get_selection(GTK_TREE_VIEW(widget))};
1067 g_signal_connect(G_OBJECT(selection),
"changed",
1068 G_CALLBACK(option_account_sel_changed_cb), &option);
1069 gtk_widget_show_all(enclosing);
1077 void set_ui_item_from_option(
GncOption& option) noexcept
override 1079 auto widget{GNC_ACCOUNT_SEL(get_widget())};
1080 auto instance{option.get_value<
const Account*>()};
1082 gnc_account_sel_set_account(widget, const_cast<Account*>(instance), FALSE);
1084 void set_option_from_ui_item(
GncOption& option) noexcept
override 1086 auto widget{GNC_ACCOUNT_SEL(get_widget())};
1088 option.set_value(static_cast<const Account*>(gnc_account_sel_get_account(widget)));
1093 create_option_widget<GncOptionUIType::ACCOUNT_SEL> (
GncOption& option,
1094 GtkGrid *page_box,
int row)
1096 auto acct_type_list{option.account_type_list()};
1097 auto widget{gnc_account_sel_new()};
1098 gnc_account_sel_set_acct_filters(GNC_ACCOUNT_SEL(widget),
1099 acct_type_list, NULL);
1100 g_list_free(acct_type_list);
1103 option.set_ui_item(std::make_unique<GncGtkAccountSelUIItem>(widget));
1104 option.set_ui_item_from_option();
1106 g_signal_connect(widget,
"account_sel_changed",
1107 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1108 wrap_widget(option, widget, page_box, row);
1110 gtk_container_child_set(GTK_CONTAINER(gtk_widget_get_parent(widget)),
1111 widget,
"fill", TRUE,
"expand", TRUE,
1116 list_changed_cb(GtkTreeSelection *selection,
GncOption* option)
1118 GtkTreeView *view = GTK_TREE_VIEW(option_get_gtk_widget (option));
1119 gnc_option_changed_widget_cb(GTK_WIDGET(view), option);
1123 list_select_all_cb(GtkWidget *widget, gpointer data)
1125 GncOption* option =
static_cast<decltype(option)
>(data);
1127 GtkTreeSelection *selection;
1129 view = GTK_TREE_VIEW(option_get_gtk_widget(option));
1130 selection = gtk_tree_view_get_selection(view);
1131 gtk_tree_selection_select_all(selection);
1132 gnc_option_changed_widget_cb(GTK_WIDGET(view), option);
1136 list_clear_all_cb(GtkWidget *widget, gpointer data)
1138 GncOption* option =
static_cast<decltype(option)
>(data);
1140 GtkTreeSelection *selection;
1142 view = GTK_TREE_VIEW(option_get_gtk_widget(option));
1143 selection = gtk_tree_view_get_selection(view);
1144 gtk_tree_selection_unselect_all(selection);
1145 gnc_option_changed_widget_cb(GTK_WIDGET(view), option);
1149 list_set_default_cb(GtkWidget *widget, gpointer data)
1151 GncOption* option =
static_cast<decltype(option)
>(data);
1152 list_clear_all_cb(widget, data);
1153 option->set_value(option->get_default_value<GncMultichoiceOptionIndexVec>());
1154 option->set_ui_item_from_option();
1163 void set_ui_item_from_option(
GncOption& option) noexcept
override 1165 auto widget{GTK_TREE_VIEW(get_widget())};
1166 auto selection{gtk_tree_view_get_selection(widget)};
1167 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1168 g_signal_handlers_block_by_func(selection, (gpointer)list_changed_cb, &option);
1169 gtk_tree_selection_unselect_all(selection);
1170 for (
auto index : option.get_value<GncMultichoiceOptionIndexVec>())
1172 auto path{gtk_tree_path_new_from_indices(index, -1)};
1173 gtk_tree_selection_select_path(selection, path);
1174 gtk_tree_path_free(path);
1176 g_signal_handlers_unblock_by_func(selection, (gpointer)list_changed_cb, &option);
1179 void set_option_from_ui_item(
GncOption& option) noexcept
override 1181 auto widget{GTK_TREE_VIEW(get_widget())};
1182 auto selection{gtk_tree_view_get_selection(widget)};
1183 auto selected_rows{gtk_tree_selection_get_selected_rows(selection,
nullptr)};
1184 GncMultichoiceOptionIndexVec vec;
1185 for (
auto row = selected_rows; row; row = g_list_next(row))
1187 auto path{
static_cast<GtkTreePath*
>(row->data)};
1188 auto indices{gtk_tree_path_get_indices(path)};
1189 vec.push_back(*indices);
1191 g_list_free_full(selected_rows, (GDestroyNotify)gtk_tree_path_free);
1192 option.set_value(vec);
1197 create_list_widget(
GncOption& option,
char *name)
1199 auto frame = gtk_frame_new(name);
1200 auto hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1201 gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
1202 gtk_container_add(GTK_CONTAINER(frame), hbox);
1204 auto store = gtk_list_store_new(1, G_TYPE_STRING);
1205 auto view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
1206 g_object_unref(store);
1207 auto renderer = gtk_cell_renderer_text_new();
1208 auto column = gtk_tree_view_column_new_with_attributes(
"", renderer,
1211 gtk_tree_view_append_column(view, column);
1212 gtk_tree_view_set_headers_visible(view, FALSE);
1215 for (decltype(num_values) i = 0; i < num_values; i++)
1219 auto string = (raw_string && *raw_string) ? _(raw_string) :
"";
1220 gtk_list_store_append(store, &iter);
1221 gtk_list_store_set(store, &iter, 0,
string ?
string :
"", -1);
1224 option.set_ui_item(std::make_unique<GncGtkListUIItem>(GTK_WIDGET(view)));
1225 option.set_ui_item_from_option();
1227 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(view), FALSE, FALSE, 0);
1229 auto selection = gtk_tree_view_get_selection(view);
1230 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1231 g_signal_connect(selection,
"changed",
1232 G_CALLBACK(list_changed_cb), &option);
1234 auto bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1235 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
1236 gtk_box_pack_end(GTK_BOX(hbox), bbox, FALSE, FALSE, 0);
1238 auto button = gtk_button_new_with_label(_(
"Select All"));
1239 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1240 gtk_widget_set_tooltip_text(button, _(
"Select all entries."));
1242 g_signal_connect(G_OBJECT(button),
"clicked",
1243 G_CALLBACK(list_select_all_cb), &option);
1245 button = gtk_button_new_with_label(_(
"Clear All"));
1246 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1247 gtk_widget_set_tooltip_text(button, _(
"Clear the selection and unselect all entries."));
1249 g_signal_connect(G_OBJECT(button),
"clicked",
1250 G_CALLBACK(list_clear_all_cb), &option);
1252 button = gtk_button_new_with_label(_(
"Select Default"));
1253 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1254 gtk_widget_set_tooltip_text(button, _(
"Select the default selection."));
1256 g_signal_connect(G_OBJECT(button),
"clicked",
1257 G_CALLBACK(list_set_default_cb), &option);
1259 g_object_set (G_OBJECT(hbox),
"margin", 3, NULL);
1265 create_option_widget<GncOptionUIType::LIST> (
GncOption& option,
1266 GtkGrid *page_box,
int row)
1269 auto enclosing{create_list_widget(option,
nullptr)};
1270 set_name_label(option, page_box, row,
true);
1271 set_tool_tip(option, enclosing);
1272 grid_attach_widget (GTK_GRID(page_box), enclosing, row);
1273 gtk_widget_show(enclosing);
1281 void set_ui_item_from_option(
GncOption& option) noexcept
override 1284 if (option.is_alternate())
1285 value = static_cast<double>(option.get_value<
int>());
1287 value = option.get_value<
double>();
1289 gtk_spin_button_set_value(GTK_SPIN_BUTTON(get_widget()), value);
1291 void set_option_from_ui_item(
GncOption& option) noexcept
override 1293 auto value{gtk_spin_button_get_value(GTK_SPIN_BUTTON(get_widget()))};
1294 if (option.is_alternate())
1295 option.set_value<
int>(static_cast<int>(value));
1297 option.set_value<
double>(value);
1306 static GtkSpinButton*
1309 gdouble lower_bound = G_MINDOUBLE;
1310 gdouble upper_bound = G_MAXDOUBLE;
1311 gdouble step_size = 1.0;
1313 if (option.is_alternate())
1315 int tmp_lower_bound = G_MININT;
1316 int tmp_upper_bound = G_MAXINT;
1317 int tmp_step_size = 1.0;
1318 option.
get_limits<
int>(tmp_upper_bound, tmp_lower_bound, tmp_step_size);
1319 lower_bound =(double)tmp_lower_bound;
1320 upper_bound = (double)tmp_upper_bound;
1321 step_size = (double)tmp_step_size;
1324 option.
get_limits<
double>(upper_bound, lower_bound, step_size);
1326 auto adj = GTK_ADJUSTMENT(gtk_adjustment_new(lower_bound, lower_bound,
1327 upper_bound, step_size,
1331 size_t num_decimals = 0;
1332 for (
auto steps = step_size; steps < 1; steps *= 10)
1334 auto widget = gtk_spin_button_new(adj, step_size, num_decimals);
1335 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
1337 size_t num_digits = 0;
1338 for (
auto bigger = MAX(ABS(lower_bound), ABS(upper_bound));
1339 bigger >= 1; bigger /= 10.0)
1341 num_digits += num_decimals;
1342 gtk_entry_set_width_chars(GTK_ENTRY(widget), num_digits);
1343 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
1345 return GTK_SPIN_BUTTON(widget);
1349 create_option_widget<GncOptionUIType::NUMBER_RANGE> (
GncOption& option,
1350 GtkGrid *page_box,
int row)
1352 auto widget{create_range_spinner(option)};
1353 option.set_ui_item(std::make_unique<GncGtkNumberRangeUIItem>(GTK_WIDGET(widget)));
1354 option.set_ui_item_from_option();
1356 g_signal_connect(G_OBJECT(widget),
"changed",
1357 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1358 wrap_widget(option, GTK_WIDGET(widget), page_box, row);
1366 void set_ui_item_from_option(
GncOption& option) noexcept
override 1373 auto value{option.get_value<std::string>().substr(0,6)};
1374 auto rgba_str{g_strdup_printf(
"#%s", value.c_str())};
1375 if (gdk_rgba_parse(&color, rgba_str))
1377 auto color_button = GTK_COLOR_CHOOSER(get_widget());
1378 gtk_color_chooser_set_rgba(color_button, &color);
1382 void set_option_from_ui_item(
GncOption& option) noexcept
override 1385 auto color_button = GTK_COLOR_CHOOSER(get_widget());
1386 gtk_color_chooser_get_rgba(color_button, &color);
1387 auto rgba_str = g_strdup_printf(
"%2x%2x%2x%2x",
1388 (uint8_t)(color.red * 255),
1389 (uint8_t)(color.green * 255),
1390 (uint8_t)(color.blue * 255),
1391 (uint8_t)(color.alpha * 255));
1392 auto rgb_str = g_strdup_printf(
"%2x%2x%2x",
1393 (uint8_t)(color.red * 255),
1394 (uint8_t)(color.green * 255),
1395 (uint8_t)(color.blue * 255));
1397 option.set_value(std::string{rgb_str});
1404 create_option_widget<GncOptionUIType::COLOR> (
GncOption& option, GtkGrid *page_box,
int row)
1406 auto widget = gtk_color_button_new();
1407 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(widget), TRUE);
1409 option.set_ui_item(std::make_unique<GncGtkColorUIItem>(widget));
1410 option.set_ui_item_from_option();
1412 g_signal_connect(G_OBJECT(widget),
"color-set",
1413 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1414 wrap_widget(option, widget, page_box, row);
1422 void set_ui_item_from_option(
GncOption& option) noexcept
override 1424 GtkFontChooser *font_chooser = GTK_FONT_CHOOSER(get_widget());
1425 gtk_font_chooser_set_font(font_chooser,
1426 option.get_value<std::string>().c_str());
1429 void set_option_from_ui_item(
GncOption& option) noexcept
override 1431 GtkFontChooser *font_chooser = GTK_FONT_CHOOSER(get_widget());
1432 option.set_value(std::string{gtk_font_chooser_get_font(font_chooser)});
1437 create_option_widget<GncOptionUIType::FONT> (
GncOption& option, GtkGrid *page_box,
int row)
1439 auto widget{gtk_font_button_new()};
1440 g_object_set(G_OBJECT(widget),
1446 option.set_ui_item(std::make_unique<GncGtkFontUIItem>(widget));
1447 option.set_ui_item_from_option();
1448 g_signal_connect(G_OBJECT(widget),
"font-set",
1449 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1450 wrap_widget(option, widget, page_box, row);
1453 #define LAST_SELECTION "last-selection" 1456 update_preview_cb (GtkFileChooser *chooser,
void* data)
1458 g_return_if_fail(chooser != NULL);
1460 ENTER(
"chooser %p", chooser);
1461 auto filename = gtk_file_chooser_get_preview_filename(chooser);
1462 DEBUG(
"chooser preview name is %s.", filename ? filename :
"(null)");
1463 if (filename == NULL)
1465 filename = g_strdup(static_cast<const char*>(g_object_get_data(G_OBJECT(chooser), LAST_SELECTION)));
1466 DEBUG(
"using last selection of %s", filename ? filename :
"(null)");
1467 if (filename == NULL)
1469 LEAVE(
"no usable name");
1474 auto image = GTK_IMAGE(gtk_file_chooser_get_preview_widget(chooser));
1475 auto pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL);
1477 auto have_preview = (pixbuf != NULL);
1479 gtk_image_set_from_pixbuf(image, pixbuf);
1481 g_object_unref(pixbuf);
1483 gtk_file_chooser_set_preview_widget_active(chooser, have_preview);
1484 LEAVE(
"preview visible is %d", have_preview);
1488 change_image_cb (GtkFileChooser *chooser,
void* data)
1490 auto filename{gtk_file_chooser_get_preview_filename(chooser)};
1493 g_object_set_data_full(G_OBJECT(chooser), LAST_SELECTION, filename, g_free);
1501 void set_ui_item_from_option(
GncOption& option) noexcept
override 1503 auto string{option.get_value<std::string>()};
1504 if (!
string.empty())
1506 DEBUG(
"string = %s",
string.c_str());
1507 auto chooser{GTK_FILE_CHOOSER(get_widget())};
1508 gtk_file_chooser_select_filename(chooser,
string.c_str());
1509 auto filename{gtk_file_chooser_get_filename(chooser)};
1510 g_object_set_data_full(G_OBJECT(chooser), LAST_SELECTION,
1511 g_strdup(
string.c_str()), g_free);
1512 DEBUG(
"Set %s, retrieved %s",
string.c_str(),
1513 filename ? filename :
"(null)");
1514 update_preview_cb(chooser, &option);
1517 void set_option_from_ui_item(
GncOption& option) noexcept
override 1519 auto string = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(get_widget()));
1520 DEBUG(
"filename %s",
string ?
string :
"(null)");
1523 option.set_value(std::string{
string});
1530 create_option_widget<GncOptionUIType::PIXMAP> (
GncOption& option,
1531 GtkGrid *page_box,
int row)
1533 auto enclosing{gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5)};
1534 gtk_box_set_homogeneous(GTK_BOX(enclosing), FALSE);
1535 auto button{gtk_button_new_with_label(_(
"Clear"))};
1536 gtk_widget_set_tooltip_text(button, _(
"Clear any selected image file."));
1537 auto widget{ gtk_file_chooser_button_new(_(
"Select image"),
1538 GTK_FILE_CHOOSER_ACTION_OPEN)};
1539 gtk_widget_set_tooltip_text(widget, _(
"Select an image file."));
1540 g_object_set(G_OBJECT(widget),
1542 "preview-widget", gtk_image_new(),
1544 option.set_ui_item(std::make_unique<GncGtkPixmapUIItem>(widget));
1545 option.set_ui_item_from_option();
1547 g_signal_connect(G_OBJECT (widget),
"selection-changed",
1548 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1549 g_signal_connect(G_OBJECT (widget),
"selection-changed",
1550 G_CALLBACK(change_image_cb), &option);
1551 g_signal_connect(G_OBJECT (widget),
"update-preview",
1552 G_CALLBACK(update_preview_cb), &option);
1553 g_signal_connect_swapped(G_OBJECT (button),
"clicked",
1554 G_CALLBACK(gtk_file_chooser_unselect_all), widget);
1556 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
1557 gtk_box_pack_start(GTK_BOX(enclosing), button, FALSE, FALSE, 0);
1559 gtk_widget_show(widget);
1560 set_name_label(option, page_box, row,
false);
1561 set_tool_tip(option, enclosing);
1562 gtk_widget_show(enclosing);
1563 grid_attach_widget(page_box, enclosing, row);
1567 radiobutton_set_cb(GtkWidget *w, gpointer data)
1569 GncOption* option =
static_cast<decltype(option)
>(data);
1570 gpointer _current, _new_value;
1571 gint current, new_value;
1573 auto widget = option_get_gtk_widget(option);
1575 _current = g_object_get_data(G_OBJECT(widget),
"gnc_radiobutton_index");
1576 current = GPOINTER_TO_INT (_current);
1578 _new_value = g_object_get_data (G_OBJECT(w),
"gnc_radiobutton_index");
1579 new_value = GPOINTER_TO_INT (_new_value);
1581 if (current == new_value)
1584 g_object_set_data (G_OBJECT(widget),
"gnc_radiobutton_index",
1585 GINT_TO_POINTER(new_value));
1586 gnc_option_changed_widget_cb(widget, option);
1594 void set_ui_item_from_option(
GncOption& option) noexcept
override 1596 auto index{option.get_value<uint16_t>()};
1597 auto list{gtk_container_get_children(GTK_CONTAINER(get_widget()))};
1598 auto box{GTK_WIDGET(list->data)};
1601 list = gtk_container_get_children(GTK_CONTAINER(box));
1602 auto node{g_list_nth(list, index)};
1603 GtkButton* button{};
1606 button = GTK_BUTTON(node->data);
1610 PERR(
"Invalid Radio Button Selection %hu", index);
1615 auto val{g_object_get_data (G_OBJECT (button),
1616 "gnc_radiobutton_index")};
1617 g_return_if_fail (GPOINTER_TO_UINT (val) == index);
1619 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
1621 void set_option_from_ui_item(
GncOption& option) noexcept
override 1623 auto index{g_object_get_data(G_OBJECT(get_widget()),
1624 "gnc_radiobutton_index")};
1625 option.set_value<uint16_t>(GPOINTER_TO_INT(index));
1630 create_radiobutton_widget(
char *name,
GncOption& option)
1632 GtkWidget *frame, *box;
1633 GtkWidget *widget = NULL;
1637 g_return_val_if_fail(num_values >= 0, NULL);
1640 frame = gtk_frame_new (name);
1643 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
1644 gtk_box_set_homogeneous (GTK_BOX (box), FALSE);
1645 gtk_container_add (GTK_CONTAINER (frame), box);
1647 option.set_ui_item(std::make_unique<GncGtkPixmapUIItem>(frame));
1648 option.set_ui_item_from_option();
1651 for (decltype(num_values) i = 0; i < num_values; i++)
1656 gtk_radio_button_new_with_label_from_widget (widget ?
1657 GTK_RADIO_BUTTON (widget) :
1659 label && *label ? _(label) :
"");
1660 g_object_set_data (G_OBJECT (widget),
"gnc_radiobutton_index",
1661 GINT_TO_POINTER (i));
1662 g_signal_connect(G_OBJECT(widget),
"toggled",
1663 G_CALLBACK(radiobutton_set_cb), &option);
1664 gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
1671 create_option_widget<GncOptionUIType::RADIOBUTTON> (
GncOption& option, GtkGrid *page_box,
int row)
1673 auto enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
1674 gtk_box_set_homogeneous (GTK_BOX (enclosing), FALSE);
1675 set_name_label(option, page_box, row,
true);
1676 set_tool_tip(option, enclosing);
1677 auto widget = create_radiobutton_widget(NULL, option);
1678 gtk_box_pack_start(GTK_BOX(enclosing), widget, FALSE, FALSE, 0);
1679 gtk_widget_show_all(enclosing);
1680 grid_attach_widget(page_box, enclosing, row);
1688 void set_ui_item_from_option(
GncOption& option) noexcept
override 1690 auto widget{GNC_DATE_FORMAT(get_widget())};
1691 auto [format, months, years, custom] = option.get_value<GncOptionDateFormat>();
1692 gnc_date_format_set_format(widget, format);
1693 gnc_date_format_set_months(widget, months);
1694 gnc_date_format_set_years(widget, years);
1695 gnc_date_format_set_custom(widget, custom.c_str());
1697 void set_option_from_ui_item(
GncOption& option) noexcept
override 1699 auto widget{GNC_DATE_FORMAT(get_widget())};
1700 GncOptionDateFormat format{
1701 gnc_date_format_get_format(widget),
1702 gnc_date_format_get_months(widget),
1703 gnc_date_format_get_years(widget),
1704 gnc_date_format_get_custom(widget)};
1705 option.set_value(format);
1711 create_option_widget<GncOptionUIType::DATE_FORMAT> (
GncOption& option,
1712 GtkGrid *page_box,
int row)
1714 auto enclosing = gnc_date_format_new_without_label ();
1715 set_name_label(option, page_box, row,
true);
1716 set_tool_tip(option, enclosing);
1717 option.set_ui_item(std::make_unique<GncGtkDateFormatUIItem>(enclosing));
1718 option.set_ui_item_from_option();
1720 g_signal_connect(G_OBJECT(enclosing),
"format_changed",
1721 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1722 gtk_widget_show_all(enclosing);
1723 grid_attach_widget(page_box, enclosing, row);
1727 static void plot_size_set_pixels(GtkWidget*,
PlotSize*);
1728 static void plot_size_set_percent(GtkWidget*,
PlotSize*);
1732 GtkWidget *m_widget;
1733 GtkWidget *m_pixel_button;
1734 GtkWidget *m_percent_button;
1735 GtkWidget *m_range_spinner;
1736 GtkAdjustment *m_adj_pct;
1737 GtkAdjustment *m_adj_px;
1738 unsigned long m_percent_handler;
1739 unsigned long m_pixel_handler;
1743 void set_entry_from_option(
GncOption& option);
1744 void set_option_from_entry(
GncOption& option);
1745 GtkWidget* get_widget() {
return m_widget; }
1746 GtkWidget* get_spinner() {
return m_range_spinner; }
1747 void set_pixels() { gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(m_range_spinner), m_adj_px); }
1748 void set_percent() { gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(m_range_spinner), m_adj_pct); }
1752 m_widget{gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)}, m_pixel_button{gtk_radio_button_new_with_label(
nullptr, _(
"Pixels"))},
1753 m_percent_button{gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(m_pixel_button), _(
"Percent"))},
1754 m_range_spinner{GTK_WIDGET(create_range_spinner(option))},
1755 m_adj_pct{GTK_ADJUSTMENT(g_object_ref(gtk_adjustment_new(100.0, 10.0, 100.0, 1.0, 5.0, 0.0)))},
1756 m_adj_px{GTK_ADJUSTMENT(g_object_ref(gtk_adjustment_new(1000.0, 110.0, 10000.0, 10.0, 250.0, 0.0)))}
1758 gtk_box_set_homogeneous(GTK_BOX(m_widget), FALSE);
1759 g_object_set (G_OBJECT(m_widget),
"margin", 3, NULL);
1760 set_tool_tip(option, m_widget);
1761 gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_pixel_button), FALSE, FALSE, 0);
1762 gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_percent_button), FALSE, FALSE, 0);
1763 gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_range_spinner),
1766 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_pixel_button), FALSE);
1767 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_percent_button), TRUE);
1769 m_pixel_handler = g_signal_connect(m_pixel_button,
"toggled", G_CALLBACK(plot_size_set_pixels),
this);
1770 m_percent_handler = g_signal_connect(m_percent_button,
"toggled", G_CALLBACK(plot_size_set_percent),
this);
1773 PlotSize::~PlotSize()
1775 g_signal_handler_disconnect(m_pixel_button, m_pixel_handler);
1776 g_signal_handler_disconnect(m_percent_button, m_percent_handler);
1777 g_object_unref(m_adj_pct);
1778 g_object_unref(m_adj_px);
1782 PlotSize::set_option_from_entry(
GncOption& option)
1784 auto value{gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_range_spinner))};
1785 if (option.is_alternate())
1786 option.set_value<
int>(static_cast<int>(value));
1788 option.set_value<
double>(value);
1792 PlotSize::set_entry_from_option(
GncOption& option)
1795 if (option.is_alternate())
1797 auto int_value{option.get_value<
int>()};
1798 value =
static_cast<double>(int_value);
1802 value = option.get_value<
double>();
1806 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pixel_button), TRUE);
1808 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_percent_button), TRUE);
1810 gtk_spin_button_set_value(GTK_SPIN_BUTTON(m_range_spinner), value);
1814 plot_size_set_pixels(GtkWidget *widget,
PlotSize *ps)
1820 plot_size_set_percent(GtkWidget *widget,
PlotSize *ps)
1825 using PlotSizePtr = std::unique_ptr<PlotSize>;
1832 m_plot_size{std::move(plot_size)} {}
1833 void set_ui_item_from_option(
GncOption& option) noexcept
override 1835 m_plot_size->set_entry_from_option(option);
1837 void set_option_from_ui_item(
GncOption& option) noexcept
override 1839 m_plot_size->set_option_from_entry(option);
1841 PlotSize* get_plot_size() {
return m_plot_size.get(); }
1843 PlotSizePtr m_plot_size;
1847 create_option_widget<GncOptionUIType::PLOT_SIZE> (
GncOption& option,
1848 GtkGrid *page_box,
int row)
1851 auto enclosing = gtk_frame_new(NULL);
1852 gtk_widget_set_halign (GTK_WIDGET(enclosing), GTK_ALIGN_START);
1853 set_name_label(option, page_box, row,
false);
1855 option.set_ui_item(std::make_unique<GncGtkPlotSizeUIItem>(std::make_unique<PlotSize>(option)));
1856 option.set_ui_item_from_option();
1858 auto widget{option_get_gtk_widget(&option)};
1859 gtk_container_add(GTK_CONTAINER(enclosing), widget);
1861 gtk_widget_show_all(enclosing);
1862 grid_attach_widget(page_box, enclosing, row);
1866 g_signal_connect(G_OBJECT(ui_item->get_plot_size()->get_spinner()),
"changed",
1867 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1875 GtkCellRenderer *cr;
1877 tm = gnc_tree_model_budget_new(gnc_get_current_book());
1878 cb = GTK_COMBO_BOX(gtk_combo_box_new_with_model(tm));
1880 cr = gtk_cell_renderer_text_new();
1881 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cb), cr, TRUE);
1883 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cb), cr,
"text",
1884 BUDGET_NAME_COLUMN, NULL);
1885 return GTK_WIDGET(cb);
1893 void set_ui_item_from_option(
GncOption& option) noexcept
override 1896 auto widget{GTK_COMBO_BOX(get_widget())};
1897 auto instance{option.get_value<
const QofInstance*>()};
1900 auto tree_model{gtk_combo_box_get_model(widget)};
1901 if (gnc_tree_model_budget_get_iter_for_budget(tree_model, &iter,
1902 GNC_BUDGET(instance)))
1903 gtk_combo_box_set_active_iter(widget, &iter);
1906 void set_option_from_ui_item(
GncOption& option) noexcept
override 1909 auto widget{GTK_COMBO_BOX(get_widget())};
1910 if (gtk_combo_box_get_active_iter(widget, &iter))
1912 auto tree_model{gtk_combo_box_get_model(widget)};
1913 auto budget{gnc_tree_model_budget_get_budget(tree_model, &iter)};
1914 option.set_value(qof_instance_cast(budget));
1920 create_option_widget<GncOptionUIType::BUDGET> (
GncOption& option,
1921 GtkGrid *page_box,
int row)
1923 auto widget{create_budget_widget(option)};
1925 option.set_ui_item(std::make_unique<GncGtkBudgetUIItem>(widget));
1926 option.set_ui_item_from_option();
1929 g_signal_connect(G_OBJECT(widget),
"changed",
1930 G_CALLBACK(gnc_option_changed_widget_cb), &option);
1932 wrap_widget(option, widget, page_box, row);
1936 gnc_options_ui_factory_initialize(
void)
1939 create_option_widget<GncOptionUIType::BOOLEAN>);
1941 create_option_widget<GncOptionUIType::STRING>);
1943 create_option_widget<GncOptionUIType::TEXT>);
1945 create_option_widget<GncOptionUIType::CURRENCY>);
1947 create_option_widget<GncOptionUIType::COMMODITY>);
1949 create_option_widget<GncOptionUIType::MULTICHOICE>);
1951 create_option_widget<GncOptionUIType::DATE_ABSOLUTE>);
1953 create_option_widget<GncOptionUIType::DATE_RELATIVE>);
1955 create_option_widget<GncOptionUIType::DATE_BOTH>);
1957 create_option_widget<GncOptionUIType::ACCOUNT_LIST>);
1959 create_option_widget<GncOptionUIType::ACCOUNT_SEL>);
1961 create_option_widget<GncOptionUIType::LIST>);
1963 create_option_widget<GncOptionUIType::NUMBER_RANGE>);
1965 create_option_widget<GncOptionUIType::COLOR>);
1967 create_option_widget<GncOptionUIType::FONT>);
1969 create_option_widget<GncOptionUIType::PLOT_SIZE>);
1971 create_option_widget<GncOptionUIType::BUDGET>);
1973 create_option_widget<GncOptionUIType::PIXMAP>);
1975 create_option_widget<GncOptionUIType::RADIOBUTTON>);
1977 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...