Skip to content

Commit

Permalink
[c++options] Restore the ability to set plot sizes in pixels.
Browse files Browse the repository at this point in the history
Enable and fix the previously untested GtkOptionGtkUIItem::PLOTSIZE.

This has the potentially unfortunate side effect that integer range
options are assumed to be plot sizes. That's correct for now, but
if some report comes along that needs an integer range option for
something else it will have to be differentiated.
  • Loading branch information
jralls committed Feb 26, 2023
1 parent 408b5ec commit 6ab7b16
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 81 deletions.
191 changes: 113 additions & 78 deletions gnucash/gnome-utils/gnc-option-gtk-ui.cpp
Expand Up @@ -24,6 +24,7 @@
#include <gnc-option-impl.hpp>
#include "gnc-option-gtk-ui.hpp"
#include <config.h> // for scanf format string
#include <memory>
#include <qof.h>
#include <gnc-engine.h> // for GNC_MOD_GUI
#include <gnc-commodity.h> // for GNC_COMMODITY
Expand All @@ -33,6 +34,7 @@
#include "gnc-date-edit.h" // for gnc_date_edit
#include "gnc-date-format.h" //for GNC_DATE_FORMAT
#include "gnc-general-select.h" // for GNC_GENERAL_SELECT
#include "gnc-option-uitype.hpp"
#include "gnc-tree-view-account.h" // for GNC_TREE_VIEW_ACCOUNT
#include "gnc-tree-model-budget.h" // for gnc_tree_model_budget
#include "misc-gnome-utils.h" // for xxxgtk_textview_set_text
Expand Down Expand Up @@ -1699,115 +1701,148 @@ create_option_widget<GncOptionUIType::DATE_FORMAT> (GncOption& option,
grid_attach_widget(page_box, enclosing, row);
}

static void
gnc_rd_option_px_set_cb(GtkWidget *widget, GncOption* option)
class PlotSize;
static void plot_size_set_pixels(GtkWidget*, PlotSize*);
static void plot_size_set_percent(GtkWidget*, PlotSize*);

class PlotSize
{
option->set_alternate(true);
gnc_option_changed_option_cb(widget, option);
GtkWidget *m_widget;
GtkWidget *m_pixel_button;
GtkWidget *m_percent_button;
GtkWidget *m_range_spinner;
GtkAdjustment *m_adj_pct;
GtkAdjustment *m_adj_px;
unsigned long m_percent_handler;
unsigned long m_pixel_handler;
public:
PlotSize(GncOption& option);
~PlotSize();
void set_entry_from_option(GncOption& option);
void set_option_from_entry(GncOption& option);
GtkWidget* get_widget() { return m_widget; }
GtkWidget* get_spinner() { return m_range_spinner; }
void set_pixels() { gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(m_range_spinner), m_adj_px); }
void set_percent() { gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(m_range_spinner), m_adj_pct); }
};

PlotSize::PlotSize(GncOption& option) :
m_widget{gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)}, m_pixel_button{gtk_radio_button_new_with_label(nullptr, _("Pixels"))},
m_percent_button{gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(m_pixel_button), _("Percent"))},
m_range_spinner{GTK_WIDGET(create_range_spinner(option))},
m_adj_pct{GTK_ADJUSTMENT(g_object_ref(gtk_adjustment_new(100.0, 10.0, 100.0, 1.0, 5.0, 0.0)))},
m_adj_px{GTK_ADJUSTMENT(g_object_ref(gtk_adjustment_new(1000.0, 110.0, 10000.0, 10.0, 250.0, 0.0)))}
{
gtk_box_set_homogeneous(GTK_BOX(m_widget), FALSE);
g_object_set (G_OBJECT(m_widget), "margin", 3, NULL);
set_tool_tip(option, m_widget);
gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_pixel_button), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_percent_button), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(m_widget), GTK_WIDGET(m_range_spinner),
FALSE, FALSE, 0);

gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_pixel_button), FALSE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(m_percent_button), TRUE);

m_pixel_handler = g_signal_connect(m_pixel_button, "toggled", G_CALLBACK(plot_size_set_pixels), this);
m_percent_handler = g_signal_connect(m_percent_button, "toggled", G_CALLBACK(plot_size_set_percent), this);
}

static void
gnc_rd_option_p_set_cb(GtkWidget *widget, GncOption* option)
PlotSize::~PlotSize()
{
option->set_alternate(false);
gnc_option_changed_option_cb(widget, option);
g_signal_handler_disconnect(m_pixel_button, m_pixel_handler);
g_signal_handler_disconnect(m_percent_button, m_percent_handler);
g_object_unref(m_adj_pct);
g_object_unref(m_adj_px);
}

void
PlotSize::set_option_from_entry(GncOption& option)
{
auto value{gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_range_spinner))};
if (option.is_alternate())
option.set_value<int>(static_cast<int>(value));
else
option.set_value<double>(value);
}

void
PlotSize::set_entry_from_option(GncOption& option)
{
double value;
if (option.is_alternate())
{
auto int_value{option.get_value<int>()};
value = static_cast<double>(int_value);
}
else
{
value = option.get_value<double>();
}

if (value > 100.0)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pixel_button), TRUE);
else
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_percent_button), TRUE);

gtk_spin_button_set_value(GTK_SPIN_BUTTON(m_range_spinner), value);
}

void
plot_size_set_pixels(GtkWidget *widget, PlotSize *ps)
{
ps->set_pixels();
}

void
plot_size_set_percent(GtkWidget *widget, PlotSize *ps)
{
ps->set_percent();
}

using PlotSizePtr = std::unique_ptr<PlotSize>;

class GncGtkPlotSizeUIItem : public GncOptionGtkUIItem
{
public:
GncGtkPlotSizeUIItem(GtkWidget* widget) :
GncOptionGtkUIItem{widget, GncOptionUIType::PLOT_SIZE} {}
GncGtkPlotSizeUIItem(PlotSizePtr&& plot_size) :
GncOptionGtkUIItem{plot_size->get_widget(), GncOptionUIType::PLOT_SIZE},
m_plot_size{std::move(plot_size)} {}
void set_ui_item_from_option(GncOption& option) noexcept override
{
auto widgets{gtk_container_get_children(GTK_CONTAINER(get_widget()))};
GtkWidget *button{}, *spin{};
if (option.is_alternate())
{
button = GTK_WIDGET(g_list_nth_data(widgets, 2));
spin = GTK_WIDGET(g_list_nth_data(widgets, 3));
}
else
{
button = GTK_WIDGET(g_list_nth_data(widgets, 2));
spin = GTK_WIDGET(g_list_nth_data(widgets, 3));
}
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
option.get_value<double>());
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
m_plot_size->set_entry_from_option(option);
}
void set_option_from_ui_item(GncOption& option) noexcept override
{
auto widgets{gtk_container_get_children(GTK_CONTAINER(get_widget()))};
auto px_button{GTK_BUTTON(g_list_nth_data(widgets, 0))};
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(px_button)))
{
option.set_alternate(false);
option.set_value(gtk_spin_button_get_value(GTK_SPIN_BUTTON(get_widget())));
}
else
{
option.set_alternate(true);
option.set_value(gtk_spin_button_get_value(GTK_SPIN_BUTTON(get_widget())));
}
m_plot_size->set_option_from_entry(option);
}
PlotSize* get_plot_size() { return m_plot_size.get(); }
private:
PlotSizePtr m_plot_size;
};


template<> void
create_option_widget<GncOptionUIType::PLOT_SIZE> (GncOption& option,
GtkGrid *page_box, int row)
{
GtkWidget *value_percent;
GtkWidget *px_butt, *p_butt;
GtkWidget *hbox;
GtkAdjustment *adj_percent;

auto enclosing = gtk_frame_new(NULL);
gtk_widget_set_halign (GTK_WIDGET(enclosing), GTK_ALIGN_START);
set_name_label(option, page_box, row, false);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
g_object_set (G_OBJECT(hbox), "margin", 3, NULL);
set_tool_tip(option, hbox);

auto value_px = create_range_spinner(option);

adj_percent = GTK_ADJUSTMENT(gtk_adjustment_new(1, 10, 100, 1, 5.0, 0));
value_percent = gtk_spin_button_new(adj_percent, 1, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(value_percent), TRUE);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(value_percent), 100); //default
gtk_entry_set_width_chars(GTK_ENTRY(value_percent), 3);
gtk_widget_set_sensitive(value_percent, FALSE);


px_butt = gtk_radio_button_new_with_label(NULL, _("Pixels"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(px_butt), TRUE);


p_butt = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(px_butt), _("Percent"));

gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(px_butt), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(value_px), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(p_butt), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(value_percent),
FALSE, FALSE, 0);

option.set_ui_item(std::make_unique<GncGtkPlotSizeUIItem>(static_cast<GtkWidget*>(hbox)));
option.set_ui_item(std::make_unique<GncGtkPlotSizeUIItem>(std::make_unique<PlotSize>(option)));
option.set_ui_item_from_option();

g_signal_connect(G_OBJECT(value_px), "changed",
G_CALLBACK(gnc_option_changed_widget_cb), &option);
g_signal_connect(G_OBJECT(value_percent), "changed",
G_CALLBACK(gnc_option_changed_widget_cb), &option);
g_signal_connect(G_OBJECT(px_butt), "toggled",
G_CALLBACK(gnc_rd_option_px_set_cb), &option);
g_signal_connect(G_OBJECT(p_butt), "toggled",
G_CALLBACK(gnc_rd_option_p_set_cb), &option);
auto widget{option_get_gtk_widget(&option)};
gtk_container_add(GTK_CONTAINER(enclosing), widget);

gtk_container_add(GTK_CONTAINER(enclosing), hbox);
gtk_widget_show_all(enclosing);
grid_attach_widget(page_box, enclosing, row);

auto ui_item{dynamic_cast<GncGtkPlotSizeUIItem*>(option.get_ui_item())};
if (ui_item)
g_signal_connect(G_OBJECT(ui_item->get_plot_size()->get_spinner()), "changed",
G_CALLBACK(gnc_option_changed_widget_cb), &option);
}

static GtkWidget *
Expand Down
8 changes: 7 additions & 1 deletion libgnucash/engine/gnc-option-impl.hpp
Expand Up @@ -332,7 +332,13 @@ class GncOptionRangeValue : public OptionClassifier
const char* key, const char* doc_string,
ValueType value, ValueType min,
ValueType max, ValueType step) :
OptionClassifier{section, name, key, doc_string},
GncOptionRangeValue<ValueType>{section, name, key, doc_string, value, min,
max, step, GncOptionUIType::NUMBER_RANGE} {}
GncOptionRangeValue<ValueType>(const char* section, const char* name,
const char* key, const char* doc_string,
ValueType value, ValueType min,
ValueType max, ValueType step, GncOptionUIType ui) :
OptionClassifier{section, name, key, doc_string}, m_ui_type{ui},
m_value{value >= min && value <= max ? value : min},
m_default_value{value >= min && value <= max ? value : min},
m_min{min}, m_max{max}, m_step{step} {
Expand Down
6 changes: 4 additions & 2 deletions libgnucash/engine/gnc-optiondb.cpp
Expand Up @@ -21,10 +21,12 @@
* *
\********************************************************************/

#include <cstdint>
#include <functional>
#include <string>
#include <limits>
#include <sstream>
#include "gnc-option-uitype.hpp"
#include "kvp-value.hpp"
#include "qofbookslots.h"
#include "guid.hpp"
Expand Down Expand Up @@ -768,9 +770,9 @@ gnc_register_number_plot_size_option(GncOptionDB* db,
const char* key, const char* doc_string,
int value)
{
// Pixel values don't make much sense so always use percent.
//65K is 10x reasonable, but it's a convenient constant.
GncOption option{GncOptionRangeValue<int>{section, name, key, doc_string,
value, 10, 100, 1}};
value, 10, UINT16_MAX, 1, GncOptionUIType::PLOT_SIZE}};
db->register_option(section, std::move(option));
}

Expand Down

0 comments on commit 6ab7b16

Please sign in to comment.