summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormbkma <[email protected]>2025-08-14 21:25:45 +0200
committermbkma <[email protected]>2025-12-29 14:06:10 +0100
commit7c92b9685d14a59e8a26d4b0da656fb1ed1f0ab1 (patch)
treec034f9e2ccf56235f2315572b66ed92cfc80e896 /src
parent7ef327f6f269c7a49357e001cd41d7aaf5807749 (diff)
downloadmate-calc-fix/#34.tar.bz2
mate-calc-fix/#34.tar.xz
Configurable decimal separator support. Now mate-calc supports both period (.) and comma (,) as decimal separators.fix/#34
Diffstat (limited to 'src')
-rw-r--r--src/mate-calc.c3
-rw-r--r--src/math-equation.c70
-rw-r--r--src/math-equation.h8
-rw-r--r--src/math-preferences.c29
-rw-r--r--src/mp-convert.c23
-rw-r--r--src/mp-equation-lexer.l2
-rw-r--r--src/mp-equation.h3
-rw-r--r--src/mp.h5
-rw-r--r--src/preferences.ui44
9 files changed, 176 insertions, 11 deletions
diff --git a/src/mate-calc.c b/src/mate-calc.c
index da95462..91f27eb 100644
--- a/src/mate-calc.c
+++ b/src/mate-calc.c
@@ -21,6 +21,7 @@
#include "math-window.h"
#include "math-preferences.h"
+#include "math-equation.h"
#include "mp-equation.h"
#include "unit-manager.h"
#include "utility.h"
@@ -219,6 +220,7 @@ int main(int argc, char **argv)
show_hist = g_settings_get_boolean(g_settings_var, "show-history");
number_format = g_settings_get_enum(g_settings_var, "number-format");
angle_units = g_settings_get_enum(g_settings_var, "angle-units");
+ RadixChar radix_char = g_settings_get_enum(g_settings_var, "radix-char");
button_mode = g_settings_get_enum(g_settings_var, "button-mode");
source_currency = g_settings_get_string(g_settings_var, "source-currency");
target_currency = g_settings_get_string(g_settings_var, "target-currency");
@@ -232,6 +234,7 @@ int main(int argc, char **argv)
math_equation_set_show_trailing_zeroes(equation, show_zeroes);
math_equation_set_number_format(equation, number_format);
math_equation_set_angle_units(equation, angle_units);
+ math_equation_set_radix_char(equation, radix_char);
math_equation_set_source_currency(equation, source_currency);
math_equation_set_target_currency(equation, target_currency);
math_equation_set_source_units(equation, source_units);
diff --git a/src/math-equation.c b/src/math-equation.c
index 2ce3ab8..63947b7 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -40,6 +40,7 @@ enum {
PROP_BASE,
PROP_WORD_SIZE,
PROP_ANGLE_UNITS,
+ PROP_RADIX_CHAR,
PROP_SOURCE_CURRENCY,
PROP_TARGET_CURRENCY,
PROP_SOURCE_UNITS,
@@ -47,7 +48,7 @@ enum {
PROP_SERIALIZER
};
-static GType number_mode_type, number_format_type, angle_unit_type;
+static GType number_mode_type, number_format_type, angle_unit_type, radix_char_type;
/* Expression mode state */
typedef struct {
@@ -67,6 +68,7 @@ struct MathEquationPrivate
gint word_size; /* Word size in bits */
MPAngleUnit angle_units; /* Units for trigonometric functions */
+ RadixChar radix_char; /* Decimal separator character preference */
char *source_currency;
char *target_currency;
char *source_units;
@@ -274,13 +276,19 @@ reformat_separators(MathEquation *equation)
}
static void
+reformat_separators_cb(gpointer user_data)
+{
+ reformat_separators(MATH_EQUATION(user_data));
+}
+
+static void
reformat_display(MathEquation *equation)
{
/* Change ans */
reformat_ans(equation);
/* Add/remove thousands separators */
- reformat_separators(equation);
+ g_idle_add_once(reformat_separators_cb, equation);
g_signal_emit_by_name(equation, "display-changed");
}
@@ -630,6 +638,34 @@ math_equation_get_angle_units(MathEquation *equation)
}
void
+math_equation_set_radix_char(MathEquation *equation, RadixChar radix_char)
+{
+ g_return_if_fail(equation != NULL);
+ if (equation->priv->radix_char == radix_char)
+ return;
+ equation->priv->radix_char = radix_char;
+
+ /* Update the serializer radix character and thousands separator */
+ if (radix_char == RADIX_COMMA) {
+ mp_serializer_set_radix(equation->priv->serializer, ',');
+ mp_serializer_set_thousands_separator(equation->priv->serializer, '.');
+ }
+ else {
+ mp_serializer_set_radix(equation->priv->serializer, '.');
+ mp_serializer_set_thousands_separator(equation->priv->serializer, ',');
+ }
+
+ g_object_notify(G_OBJECT(equation), "radix-char");
+}
+
+RadixChar
+math_equation_get_radix_char(MathEquation *equation)
+{
+ g_return_val_if_fail(equation != NULL, RADIX_DOT);
+ return equation->priv->radix_char;
+}
+
+void
math_equation_set_source_currency(MathEquation *equation, const gchar *currency)
{
g_return_if_fail(equation != NULL);
@@ -816,8 +852,7 @@ math_equation_get_equation(MathEquation *equation)
}
g_free(text);
- text = eq_text->str;
- g_string_free(eq_text, FALSE);
+ text = g_string_free(eq_text, FALSE);
return text;
}
@@ -1136,6 +1171,7 @@ parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
options.base = mp_serializer_get_base(equation->priv->serializer);
options.wordlen = equation->priv->word_size;
options.angle_units = equation->priv->angle_units;
+ options.radix_char = (equation->priv->radix_char == RADIX_COMMA) ? ',' : '.';
options.variable_is_defined = variable_is_defined;
options.get_variable = get_variable;
options.set_variable = set_variable;
@@ -1523,6 +1559,9 @@ math_equation_set_property(GObject *object,
case PROP_ANGLE_UNITS:
math_equation_set_angle_units(self, g_value_get_int(value));
break;
+ case PROP_RADIX_CHAR:
+ math_equation_set_radix_char(self, g_value_get_int(value));
+ break;
case PROP_SOURCE_CURRENCY:
math_equation_set_source_currency(self, g_value_get_string(value));
break;
@@ -1590,6 +1629,9 @@ math_equation_get_property(GObject *object,
case PROP_ANGLE_UNITS:
g_value_set_enum(value, self->priv->angle_units);
break;
+ case PROP_RADIX_CHAR:
+ g_value_set_enum(value, self->priv->radix_char);
+ break;
case PROP_SOURCE_CURRENCY:
g_value_set_string(value, self->priv->source_currency);
break;
@@ -1639,6 +1681,12 @@ math_equation_class_init(MathEquationClass *klass)
{MP_GRADIANS, "gradians", "gradians"},
{0, NULL, NULL}
};
+ static GEnumValue radix_char_values[] =
+ {
+ {RADIX_DOT, "dot", "dot"},
+ {RADIX_COMMA, "comma", "comma"},
+ {0, NULL, NULL}
+ };
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->get_property = math_equation_get_property;
@@ -1648,6 +1696,7 @@ math_equation_class_init(MathEquationClass *klass)
number_mode_type = g_enum_register_static("NumberMode", number_mode_values);
number_format_type = math_mp_display_format_get_type();
angle_unit_type = g_enum_register_static("AngleUnit", angle_unit_values);
+ radix_char_type = g_enum_register_static("RadixChar", radix_char_values);
g_object_class_install_property(object_class,
PROP_STATUS,
@@ -1730,6 +1779,14 @@ math_equation_class_init(MathEquationClass *klass)
MP_DEGREES,
G_PARAM_READWRITE));
g_object_class_install_property(object_class,
+ PROP_RADIX_CHAR,
+ g_param_spec_enum("radix-char",
+ "radix-char",
+ "Radix character",
+ radix_char_type,
+ RADIX_DOT,
+ G_PARAM_READWRITE));
+ g_object_class_install_property(object_class,
PROP_SOURCE_CURRENCY,
g_param_spec_string("source-currency",
"source-currency",
@@ -1879,7 +1936,7 @@ insert_text_cb(MathEquation *equation,
equation->priv->state.entered_multiply = strcmp(text, "×") == 0;
/* Update thousands separators */
- reformat_separators(equation);
+ g_idle_add_once(reformat_separators_cb, equation);
g_object_notify(G_OBJECT(equation), "display");
}
@@ -1896,7 +1953,7 @@ delete_range_cb(MathEquation *equation,
equation->priv->state.entered_multiply = FALSE;
/* Update thousands separators */
- reformat_separators(equation);
+ g_idle_add_once(reformat_separators_cb, equation);
// FIXME: A replace will emit this both for delete-range and insert-text, can it be avoided?
g_object_notify(G_OBJECT(equation), "display");
@@ -1938,6 +1995,7 @@ math_equation_init(MathEquation *equation)
equation->priv->state.status = g_strdup("");
equation->priv->word_size = 32;
equation->priv->angle_units = MP_DEGREES;
+ equation->priv->radix_char = RADIX_DOT; /* Default to dot separator */
// FIXME: Pick based on locale
equation->priv->source_currency = g_strdup("");
equation->priv->target_currency = g_strdup("");
diff --git a/src/math-equation.h b/src/math-equation.h
index 954334c..af3b67b 100644
--- a/src/math-equation.h
+++ b/src/math-equation.h
@@ -44,6 +44,11 @@ typedef enum {
SUBSCRIPT
} NumberMode;
+typedef enum {
+ RADIX_DOT = 0,
+ RADIX_COMMA = 1
+} RadixChar;
+
GType math_equation_get_type(void);
MathEquation *math_equation_new(void);
@@ -84,6 +89,9 @@ gint math_equation_get_word_size(MathEquation *equation);
void math_equation_set_angle_units(MathEquation *equation, MPAngleUnit angle_unit);
MPAngleUnit math_equation_get_angle_units(MathEquation *equation);
+void math_equation_set_radix_char(MathEquation *equation, RadixChar radix_char);
+RadixChar math_equation_get_radix_char(MathEquation *equation);
+
void math_equation_set_source_currency(MathEquation *equation, const gchar *currency);
const gchar *math_equation_get_source_currency(MathEquation *equation);
diff --git a/src/math-preferences.c b/src/math-preferences.c
index 41e43a6..023080c 100644
--- a/src/math-preferences.c
+++ b/src/math-preferences.c
@@ -95,6 +95,21 @@ word_size_combobox_changed_cb(GtkWidget *combo, MathPreferencesDialog *dialog)
math_equation_set_word_size(dialog->priv->equation, value);
}
+void radix_char_combobox_changed_cb(GtkWidget *combo, MathPreferencesDialog *dialog);
+G_MODULE_EXPORT
+void
+radix_char_combobox_changed_cb(GtkWidget *combo, MathPreferencesDialog *dialog)
+{
+ RadixChar value;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+ gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+ gtk_tree_model_get(model, &iter, 1, &value, -1);
+ math_equation_set_radix_char(dialog->priv->equation, value);
+}
+
void decimal_places_spin_change_value_cb(GtkWidget *spin, MathPreferencesDialog *dialog);
G_MODULE_EXPORT
void
@@ -198,6 +213,13 @@ angle_unit_cb(MathEquation *equation, GParamSpec *spec, MathPreferencesDialog *d
}
static void
+radix_char_cb(MathEquation *equation, GParamSpec *spec, MathPreferencesDialog *dialog)
+{
+ set_combo_box_from_int(GET_WIDGET(dialog->priv->ui, "radix_char_combobox"), math_equation_get_radix_char(equation));
+ g_settings_set_enum(g_settings_var, "radix-char", math_equation_get_radix_char(equation));
+}
+
+static void
create_gui(MathPreferencesDialog *dialog)
{
GtkWidget *widget;
@@ -275,6 +297,11 @@ create_gui(MathPreferencesDialog *dialog)
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 0);
+ widget = GET_WIDGET(dialog->priv->ui, "radix_char_combobox");
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), renderer, TRUE);
+ gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(widget), renderer, "text", 0);
+
/* Label used in preferences dialog. The %d is replaced by a spinbutton */
string = _("Show %d decimal _places");
tokens = g_strsplit(string, "%d", 2);
@@ -308,6 +335,7 @@ create_gui(MathPreferencesDialog *dialog)
g_signal_connect(dialog->priv->equation, "notify::number-format", G_CALLBACK(number_format_cb), dialog);
g_signal_connect(dialog->priv->equation, "notify::word-size", G_CALLBACK(word_size_cb), dialog);
g_signal_connect(dialog->priv->equation, "notify::angle-units", G_CALLBACK(angle_unit_cb), dialog);
+ g_signal_connect(dialog->priv->equation, "notify::radix-char", G_CALLBACK(radix_char_cb), dialog);
accuracy_cb(dialog->priv->equation, NULL, dialog);
show_thousands_separators_cb(dialog->priv->equation, NULL, dialog);
@@ -315,6 +343,7 @@ create_gui(MathPreferencesDialog *dialog)
number_format_cb(dialog->priv->equation, NULL, dialog);
word_size_cb(dialog->priv->equation, NULL, dialog);
angle_unit_cb(dialog->priv->equation, NULL, dialog);
+ radix_char_cb(dialog->priv->equation, NULL, dialog);
}
static void
diff --git a/src/mp-convert.c b/src/mp-convert.c
index 5f097c8..97d4c07 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -15,6 +15,7 @@
#include <ctype.h>
#include <math.h>
#include <langinfo.h>
+#include <glib.h>
#include "mp.h"
@@ -217,8 +218,8 @@ set_from_sexagesimal(const char *str, int length, MPNumber *z)
return false;
}
-bool
-mp_set_from_string(const char *str, int default_base, MPNumber *z)
+static bool
+mp_set_from_string_internal(const char *str, int default_base, gunichar radix_char, MPNumber *z)
{
int i, base, negate = 0, multiplier = 0, base_multiplier = 1;
const char *c, *end;
@@ -287,9 +288,10 @@ mp_set_from_string(const char *str, int default_base, MPNumber *z)
mp_clear(&fraction);
}
- if (*c == '.') {
+ /* Check for the specified radix character */
+ if (g_utf8_get_char(c) == radix_char) {
has_fraction = TRUE;
- c++;
+ c = g_utf8_next_char(c);
}
/* Convert fractional part */
@@ -327,3 +329,16 @@ mp_set_from_string(const char *str, int default_base, MPNumber *z)
return false;
}
+
+bool
+mp_set_from_string_with_radix(const char *str, int default_base, gunichar radix_char, MPNumber *z)
+{
+ return mp_set_from_string_internal(str, default_base, radix_char, z);
+}
+
+bool
+mp_set_from_string(const char *str, int default_base, MPNumber *z)
+{
+ /* Default to period for backward compatibility */
+ return mp_set_from_string_internal(str, default_base, '.', z);
+}
diff --git a/src/mp-equation-lexer.l b/src/mp-equation-lexer.l
index 6899f8f..1cd93ea 100644
--- a/src/mp-equation-lexer.l
+++ b/src/mp-equation-lexer.l
@@ -103,7 +103,7 @@ IN [iI][nN]
{OR} {return tOR;}
{XOR} {return tXOR;}
{IN} {return tIN;}
-{NUMBER} {if (mp_set_from_string(yytext, _mp_equation_get_extra(yyscanner)->options->base, &yylval->int_t) != 0) REJECT; return tNUMBER;}
+{NUMBER} {if (mp_set_from_string_with_radix(yytext, _mp_equation_get_extra(yyscanner)->options->base, _mp_equation_get_extra(yyscanner)->options->radix_char, &yylval->int_t) != 0) REJECT; return tNUMBER;}
{SUP_NUM} {yylval->integer = super_atoi(yytext); return tSUPNUM;}
{NSUP_NUM} {yylval->integer = super_atoi(yytext); return tNSUPNUM;}
{SUB_NUM} {yylval->integer = sub_atoi(yytext); return tSUBNUM;}
diff --git a/src/mp-equation.h b/src/mp-equation.h
index d7eddd3..f5ff19f 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -36,6 +36,9 @@ typedef struct {
/* Units for angles (e.g. radians, degrees) */
MPAngleUnit angle_units;
+ /* Radix character to use for decimal separator */
+ gunichar radix_char;
+
// FIXME:
// int enable_builtins;
diff --git a/src/mp.h b/src/mp.h
index 437f6f7..abe2f59 100644
--- a/src/mp.h
+++ b/src/mp.h
@@ -255,6 +255,11 @@ void mp_set_from_random(MPNumber *z);
*/
bool mp_set_from_string(const char *text, int default_base, MPNumber *z);
+/* Sets z from a string representation in 'text' using the specified radix character.
+ * Returns true on success.
+ */
+bool mp_set_from_string_with_radix(const char *text, int default_base, gunichar radix_char, MPNumber *z);
+
/* Returns x as a native single-precision floating point number */
float mp_to_float(const MPNumber *x);
diff --git a/src/preferences.ui b/src/preferences.ui
index ca1e2da..e19ed33 100644
--- a/src/preferences.ui
+++ b/src/preferences.ui
@@ -54,6 +54,24 @@
</row>
</data>
</object>
+ <object class="GtkListStore" id="number_base_model">
+ <columns>
+ <!-- column-name label -->
+ <column type="gchararray"/>
+ <!-- column-name radix_char -->
+ <column type="gint"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes" comments="Radix character combo: use dot as decimal separator and comma as thousands separator">Dot (123,456.789)</col>
+ <col id="1">0</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes" comments="Radix character combo: use comma as decimal separator and dot as thousands separator">Comma (123.456,789)</col>
+ <col id="1">1</col>
+ </row>
+ </data>
+ </object>
<object class="GtkDialog" id="preferences_dialog">
<property name="can_focus">False</property>
<property name="border_width">8</property>
@@ -184,6 +202,32 @@
</packing>
</child>
<child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" comments="Preferences dialog: label for radix and thousands separator combo box">_Separators:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">radix_char_combobox</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="radix_char_combobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">number_base_model</property>
+ <signal name="changed" handler="radix_char_combobox_changed_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>