diff options
author | Colomban Wendling <[email protected]> | 2024-05-21 10:51:37 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2024-05-21 10:51:37 +0200 |
commit | a3def4737c267b649194fd8c2f37cc8fa0f2bc0d (patch) | |
tree | fb9741e3151e05b834afbb7d49b92e6d079255dd | |
parent | 72827148e15294308c20c06d3a5b9654d8b24a7f (diff) | |
download | mate-screensaver-master.tar.bz2 mate-screensaver-master.tar.xz |
Formatting the value of a GtkScale is actually pretty tricky, because
the lower and upper values representations are used to compute the size
required do draw *all* values. This means the representations for the
lower and upper bounds have to be at least as big as any other possible
value, failing that leads to wrapping and overflowing of the value
representation.
This was previously partially done in `time_to_string_text()`, but not
only wasn't it comprehensive (it only did so for whole minutes < 59),
but it also meant that if one of the bounds wasn't a whole minute it
didn't have the desired effect.
Fix this by extracting the code for padding the string outside of the
time formatting, and pad the resulting format string whatever it is.
Also improve the padding to try and be less visible, by padding to the
side where we don't want the value to align (e.g. pad on the right if
we want the value left-aligned).
This is still basically a sad hack, but there doesn't seem to be a
better way to do this when neither the lower nor upper bound is
necessarily the largest value.
-rw-r--r-- | src/mate-screensaver-preferences.c | 138 |
1 files changed, 62 insertions, 76 deletions
diff --git a/src/mate-screensaver-preferences.c b/src/mate-screensaver-preferences.c index d20c364..1bcdcaf 100644 --- a/src/mate-screensaver-preferences.c +++ b/src/mate-screensaver-preferences.c @@ -969,13 +969,7 @@ static char * time_to_string_text (long time) { char *secs, *mins, *hours, *string; - char *chk_hour_str, *chk_minute_str, *chk_hour_minute_str; - char *chk_ascii_str; int sec, min, hour; - size_t chk_ascii_len; - int len_minutes; - int n, inc_len; - int diff; sec = time % 60; time = time - sec; @@ -992,52 +986,6 @@ time_to_string_text (long time) secs = g_strdup_printf (ngettext ("%d second", "%d seconds", sec), sec); - /* inc_len = it's the lenght of the string "1 hour 59 minutes" */ - chk_hour_str = g_strdup_printf (ngettext ("%d hour", - "%d hours", 1), 1); - chk_minute_str = g_strdup_printf (ngettext ("%d minute", - "%d minutes", 59), 59); - chk_hour_minute_str = g_strdup_printf (_("%s %s"), - chk_hour_str, chk_minute_str); - inc_len = strlen (chk_hour_minute_str) - 1; - g_free (chk_hour_str); - g_free (chk_minute_str); - g_free (chk_hour_minute_str); - - len_minutes = 0; - for (n = 2; n < 60; n++) - { - char *minute_str = g_strdup_printf (ngettext ("%d minute", - "%d minutes", n), n); - char *ascii_str = g_str_to_ascii (minute_str, NULL); - size_t ascii_str_len = strlen (ascii_str); - size_t extra_length = (n < 10) ? 2 : 3; - - diff = (int) (ascii_str_len - extra_length); - if (diff > len_minutes) - len_minutes = diff; - - g_free (minute_str); - g_free (ascii_str); - } - - /* check the lenght of the string "1 minute" */ - chk_minute_str = g_strdup_printf (ngettext ("%d minute", - "%d minutes", 1), 1); - chk_ascii_str = g_str_to_ascii (chk_minute_str, NULL); - chk_ascii_len = strlen (chk_ascii_str); - diff = (int) (chk_ascii_len - 2); - - if (diff > len_minutes) - len_minutes = diff; - - g_free (chk_minute_str); - g_free (chk_ascii_str); - - /* len_minutes = MAX (1, len_minutes) */ - if (len_minutes < 1) - len_minutes = 1; - if (hour > 0) { if (sec > 0) @@ -1060,28 +1008,7 @@ time_to_string_text (long time) else { /* minutes */ - size_t max_len; - string = g_strdup_printf (_("%s"), mins); - if (min == 1) - max_len = (size_t) (len_minutes + inc_len + 3); - else if (min < 10) - max_len = (size_t) (len_minutes + inc_len); - else - max_len = (size_t) (len_minutes + inc_len - 1); - - while (strlen (string) != max_len) - { - char *string_aux; - - if (strlen (string) % 2 == 0) - string_aux = g_strconcat (string, " ", NULL); - else - string_aux = g_strconcat (" " , string, NULL); - - g_free (string); - string = string_aux; - } } } else @@ -1101,11 +1028,70 @@ static char * format_value_callback_time (GtkScale *scale, gdouble value) { - /*You need to make up for 27 characters in length, otherwise the display will split into different lines*/ + gchar *time_str, *big_time_str; + GtkAdjustment *adj; + gdouble lower, range, delta; + gint pad_size; + + /* get the value representation as a string */ if (value == 0) - return g_strdup_printf (_("Never ")); + time_str = g_strdup (_("Never")); + else + time_str = time_to_string_text ((long) (value * 60.0)); + + /* Now, adjust the string so the representation for the bounds are the + * longest ones, and try and adjust the length as smoothly as possible. + * The issue here is that GTK is using the lower and upper value + * representations to compute the largest expected value's bounding box, + * so those need to be bigger than anything else we might represent, + * otherwise layout gets messed up (wraps and overflows). To achieve this, + * we pad the values near each bound so its length is at least the same as + * the biggest actual value. We cannot really do anything perfect here + * because what matters is the pango layout size for the largest value, but + * we don't have access to enough information to create one matching what + * GTK will actually use, and even so it'd be trial-and-error until the + * layout is big enough. So the silly assumptions below are probably good + * enough. */ + adj = gtk_range_get_adjustment (GTK_RANGE (scale)); + lower = gtk_adjustment_get_lower (adj); + range = gtk_adjustment_get_upper (adj) - lower; + delta = range / 2 - (value - lower); + /* the largest (character-wise) time string we expect */ + big_time_str = time_to_string_text (7199 /* 1:59:59 */); + pad_size = ((g_utf8_strlen (big_time_str, -1) * (ABS (delta) / range)) - + g_utf8_strlen (time_str, -1)); + g_free (big_time_str); + if (pad_size > 0) + { + /* pad string with EM SPACE (U+2003) */ + GString *padded = g_string_new (NULL); + + /* adjust pad side in RTL locales that aren't actually translated, as + * a properly translated one would have text drawn RTL already */ + if (gtk_widget_get_direction (GTK_WIDGET (scale)) == GTK_TEXT_DIR_RTL) + { + const gchar *msg_plural = "%d minutes"; + if (ngettext ("%d minute", msg_plural, 2) == msg_plural) + delta *= -1; + } + + if (delta < 0) + { + for (gint i = 0; i < pad_size; i++) + g_string_append_unichar (padded, 0x2003); + g_string_append (padded, time_str); + } + else + { + g_string_append (padded, time_str); + for (gint i = 0; i < pad_size; i++) + g_string_append_unichar (padded, 0x2003); + } + g_free (time_str); + time_str = g_string_free (padded, FALSE); + } - return time_to_string_text ((long) (value * 60.0)); + return time_str; } static void |