From 8eac0214d20a6114fd07e1585c45c7a2a04c8bf0 Mon Sep 17 00:00:00 2001 From: Justin Haygood Date: Sat, 4 Sep 2021 19:49:14 -0400 Subject: [PATCH 1/3] Add support for antialias and related subpixel order settings --- src/Views/Appearance.vala | 164 +++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 3 deletions(-) diff --git a/src/Views/Appearance.vala b/src/Views/Appearance.vala index adad65ad5..7b79f3209 100644 --- a/src/Views/Appearance.vala +++ b/src/Views/Appearance.vala @@ -20,9 +20,12 @@ public class PantheonShell.Appearance : Gtk.Grid { private const string INTERFACE_SCHEMA = "org.gnome.desktop.interface"; + private const string XSETTINGS_SCHEMA = "org.gnome.settings-daemon.plugins.xsettings"; private const string STYLESHEET_KEY = "gtk-theme"; private const string STYLESHEET_PREFIX = "io.elementary.stylesheet."; private const string TEXT_SIZE_KEY = "text-scaling-factor"; + private const string ANTIALIAS_KEY = "antialiasing"; + private const string SUBPIXELORDER_KEY = "rgba-order"; private const string DYSLEXIA_KEY = "dyslexia-friendly-support"; private const string FONT_KEY = "font-name"; @@ -36,6 +39,12 @@ public class PantheonShell.Appearance : Gtk.Grid { private const double[] TEXT_SCALE = {0.75, 1, 1.25, 1.5}; private Granite.Widgets.ModeButton text_size_modebutton; + + private Granite.Widgets.ModeButton text_antialias_modebutton; + + private Granite.Widgets.ModeButton text_subpixelorder_modebutton; + private Gtk.Label text_subpixelorder_label; + private Gtk.Label text_subpixelorder_description_label; private enum AccentColor { NO_PREFERENCE, @@ -190,6 +199,90 @@ public class PantheonShell.Appearance : Gtk.Grid { text_size_modebutton.append_text (_("Default")); text_size_modebutton.append_text (_("Large")); text_size_modebutton.append_text (_("Larger")); + + var text_antialias_label = new Gtk.Label(_("Text anti-aliasing:")) { + halign = Gtk.Align.END, + }; + + text_antialias_modebutton = new Granite.Widgets.ModeButton (); + + text_antialias_modebutton.mode_added.connect ((mode_ix,mode_widget) => { + + var font_options = new Cairo.FontOptions(); + + switch (mode_ix) { + case 0: + font_options.set_antialias(Cairo.Antialias.NONE); + break; + case 1: + font_options.set_antialias(Cairo.Antialias.GRAY); + break; + case 2: + font_options.set_antialias(Cairo.Antialias.SUBPIXEL); + break; + } + + mode_widget.set_font_options (font_options); + }); + + text_antialias_modebutton.append_text (_("None")); + text_antialias_modebutton.append_text (_("Grayscale")); + text_antialias_modebutton.append_text (_("Subpixel")); + + var text_antialias_description_label = new Gtk.Label ( + _("Text anti-aliasing can improve text appearance and legibility, depending on display hardware. Choose the mode that looks best on your display. Apps have to be re-opened for changes to take effect") + ) { + max_width_chars = 60, + wrap = true, + xalign = 0 + }; + + text_antialias_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + + text_subpixelorder_label = new Gtk.Label(_("Text subpixel order:")) { + halign = Gtk.Align.END, + }; + + text_subpixelorder_modebutton = new Granite.Widgets.ModeButton (); + + text_subpixelorder_modebutton.mode_added.connect ((mode_ix,mode_widget) => { + + var font_options = new Cairo.FontOptions(); + font_options.set_antialias (Cairo.Antialias.SUBPIXEL); + + switch (mode_ix) { + case 0: + font_options.set_subpixel_order (Cairo.SubpixelOrder.RGB); + break; + case 1: + font_options.set_subpixel_order (Cairo.SubpixelOrder.BGR); + break; + case 2: + font_options.set_subpixel_order (Cairo.SubpixelOrder.VRGB); + break; + case 3: + font_options.set_subpixel_order (Cairo.SubpixelOrder.VBGR); + break; + } + + mode_widget.set_font_options (font_options); + }); + + text_subpixelorder_modebutton.append_text (_("Red On Left (RGB)")); + text_subpixelorder_modebutton.append_text (_("Blue On Left (BGR)")); + text_subpixelorder_modebutton.append_text (_("Red On Top (VRGB)")); + text_subpixelorder_modebutton.append_text (_("Blue On Top (VBGR)")); + + text_subpixelorder_description_label = new Gtk.Label ( + _("Different displays have different positions of the red, green, and blue subpixels. Select the mode that looks the best on your display. Apps have to be re-opened for changes to take effect") + ) { + max_width_chars = 60, + wrap = true, + xalign = 0 + }; + + text_subpixelorder_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + var dyslexia_font_label = new Gtk.Label (_("Dyslexia-friendly text:")) { halign = Gtk.Align.END @@ -216,9 +309,18 @@ public class PantheonShell.Appearance : Gtk.Grid { */ attach (text_size_label, 0, 8); attach (text_size_modebutton, 1, 8, 2); - attach (dyslexia_font_label, 0, 9); - attach (dyslexia_font_switch, 1, 9); - attach (dyslexia_font_description_label, 1, 10, 2); + + attach (text_antialias_label, 0, 9); + attach (text_antialias_modebutton, 1, 9, 2); + attach (text_antialias_description_label, 1, 10, 2); + + attach (text_subpixelorder_label, 0, 11); + attach (text_subpixelorder_modebutton, 1, 11, 2); + attach (text_subpixelorder_description_label, 1, 12, 2); + + attach (dyslexia_font_label, 0, 13); + attach (dyslexia_font_switch, 1, 13); + attach (dyslexia_font_description_label, 1, 14, 2); Pantheon.AccountsService? pantheon_act = null; @@ -428,6 +530,25 @@ public class PantheonShell.Appearance : Gtk.Grid { dyslexia_font_switch.state_set.connect (() => { toggle_dyslexia_support (interface_settings, dyslexia_font_switch.get_active () ); }); + + var xsettings_settings = new GLib.Settings (XSETTINGS_SCHEMA); + + update_text_antialias_modebutton (xsettings_settings); + + xsettings_settings.changed.connect (() => { + update_text_antialias_modebutton (xsettings_settings); + update_text_subpixelorder_modebutton (xsettings_settings); + }); + + text_antialias_modebutton.mode_changed.connect (() => { + set_text_antialias (xsettings_settings, text_antialias_modebutton.selected); + }); + + update_text_subpixelorder_modebutton (xsettings_settings); + + text_subpixelorder_modebutton.mode_changed.connect (() => { + set_text_subpixelorder (xsettings_settings, text_subpixelorder_modebutton.selected); + }); } private class PrefersAccentColorButton : Gtk.RadioButton { @@ -522,6 +643,43 @@ public class PantheonShell.Appearance : Gtk.Grid { private void update_text_size_modebutton (GLib.Settings interface_settings) { text_size_modebutton.set_active (get_text_scale (interface_settings)); } + + private int get_text_antialias (GLib.Settings xsettings_settings) { + return xsettings_settings.get_enum (ANTIALIAS_KEY); + } + + private void set_text_antialias (GLib.Settings xsettings_settings, int option) { + xsettings_settings.set_enum (ANTIALIAS_KEY, option); + } + + private void update_text_antialias_modebutton (GLib.Settings xsettings_settings) { + text_antialias_modebutton.set_active (get_text_antialias (xsettings_settings)); + } + + private int get_text_subpixelorder (GLib.Settings xsettings_settings) { + return xsettings_settings.get_enum (SUBPIXELORDER_KEY) - 1; + } + + private void set_text_subpixelorder (GLib.Settings xsettings_settings, int option) { + xsettings_settings.set_enum (SUBPIXELORDER_KEY, option + 1); + } + + private void update_text_subpixelorder_modebutton (GLib.Settings xsettings_settings) { + + var antialias = get_text_antialias (xsettings_settings); + + if (antialias != 2) { + text_subpixelorder_label.visible = false; + text_subpixelorder_modebutton.visible = false; + text_subpixelorder_description_label.visible = false; + } else { + text_subpixelorder_label.visible = true; + text_subpixelorder_modebutton.visible = true; + text_subpixelorder_description_label.visible = true; + } + + text_subpixelorder_modebutton.set_active (get_text_subpixelorder (xsettings_settings)); + } private static DateTime double_date_time (double dbl) { var hours = (int) dbl; From a184881d37fea8e977ff65589ca039bbf70f7d68 Mon Sep 17 00:00:00 2001 From: Justin Haygood Date: Sun, 5 Sep 2021 19:10:18 -0400 Subject: [PATCH 2/3] Adjust margins between settings --- src/Views/Appearance.vala | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Views/Appearance.vala b/src/Views/Appearance.vala index 7b79f3209..5c7ff189f 100644 --- a/src/Views/Appearance.vala +++ b/src/Views/Appearance.vala @@ -202,9 +202,12 @@ public class PantheonShell.Appearance : Gtk.Grid { var text_antialias_label = new Gtk.Label(_("Text anti-aliasing:")) { halign = Gtk.Align.END, + margin_top = 18 }; - text_antialias_modebutton = new Granite.Widgets.ModeButton (); + text_antialias_modebutton = new Granite.Widgets.ModeButton () { + margin_top = 18 + }; text_antialias_modebutton.mode_added.connect ((mode_ix,mode_widget) => { @@ -241,9 +244,12 @@ public class PantheonShell.Appearance : Gtk.Grid { text_subpixelorder_label = new Gtk.Label(_("Text subpixel order:")) { halign = Gtk.Align.END, + margin_top = 18 }; - text_subpixelorder_modebutton = new Granite.Widgets.ModeButton (); + text_subpixelorder_modebutton = new Granite.Widgets.ModeButton () { + margin_top = 18 + }; text_subpixelorder_modebutton.mode_added.connect ((mode_ix,mode_widget) => { @@ -285,11 +291,13 @@ public class PantheonShell.Appearance : Gtk.Grid { var dyslexia_font_label = new Gtk.Label (_("Dyslexia-friendly text:")) { - halign = Gtk.Align.END + halign = Gtk.Align.END, + margin_top = 18 }; var dyslexia_font_switch = new Gtk.Switch () { - halign = Gtk.Align.START + halign = Gtk.Align.START, + margin_top = 18 }; var dyslexia_font_description_label = new Gtk.Label ( From fdee019f7ef435ba4627a80a216d152a8045de95 Mon Sep 17 00:00:00 2001 From: Justin Haygood Date: Thu, 9 Sep 2021 08:13:55 -0400 Subject: [PATCH 3/3] Create new tab for Text settings --- src/Plug.vala | 4 + src/Views/Appearance.vala | 287 --------------------- src/Views/Text.vala | 299 ++++++++++++++++++++++ src/Widgets/TextFontOptionRadioGroup.vala | 83 ++++++ src/meson.build | 2 + 5 files changed, 388 insertions(+), 287 deletions(-) create mode 100644 src/Views/Text.vala create mode 100644 src/Widgets/TextFontOptionRadioGroup.vala diff --git a/src/Plug.vala b/src/Plug.vala index ce776b766..4456bf2bb 100644 --- a/src/Plug.vala +++ b/src/Plug.vala @@ -34,6 +34,7 @@ public class PantheonShell.Plug : Switchboard.Plug { settings.set ("desktop/appearance", "appearance"); settings.set ("desktop/dock", "dock"); settings.set ("desktop/multitasking", "multitasking"); + settings.set ("desktop/text", "text"); // DEPRECATED settings.set ("desktop/wallpaper", "wallpaper"); @@ -60,6 +61,9 @@ public class PantheonShell.Plug : Switchboard.Plug { var appearance = new Appearance (); stack.add_titled (appearance, "appearance", _("Appearance")); + + var text = new Text (); + stack.add_titled (text, "text", _("Text")); if (GLib.Environment.find_program_in_path ("plank") != null) { var dock = new Dock (); diff --git a/src/Views/Appearance.vala b/src/Views/Appearance.vala index 5c7ff189f..bc422e1af 100644 --- a/src/Views/Appearance.vala +++ b/src/Views/Appearance.vala @@ -20,31 +20,8 @@ public class PantheonShell.Appearance : Gtk.Grid { private const string INTERFACE_SCHEMA = "org.gnome.desktop.interface"; - private const string XSETTINGS_SCHEMA = "org.gnome.settings-daemon.plugins.xsettings"; private const string STYLESHEET_KEY = "gtk-theme"; private const string STYLESHEET_PREFIX = "io.elementary.stylesheet."; - private const string TEXT_SIZE_KEY = "text-scaling-factor"; - private const string ANTIALIAS_KEY = "antialiasing"; - private const string SUBPIXELORDER_KEY = "rgba-order"; - - private const string DYSLEXIA_KEY = "dyslexia-friendly-support"; - private const string FONT_KEY = "font-name"; - private const string DOCUMENT_FONT_KEY = "document-font-name"; - private const string MONOSPACE_FONT_KEY = "monospace-font-name"; - - private const string OD_REG_FONT = "OpenDyslexic Regular 9"; - private const string OD_DOC_FONT = "OpenDyslexic Regular 10"; - private const string OD_MON_FONT = "OpenDyslexicMono Regular 10"; - - private const double[] TEXT_SCALE = {0.75, 1, 1.25, 1.5}; - - private Granite.Widgets.ModeButton text_size_modebutton; - - private Granite.Widgets.ModeButton text_antialias_modebutton; - - private Granite.Widgets.ModeButton text_subpixelorder_modebutton; - private Gtk.Label text_subpixelorder_label; - private Gtk.Label text_subpixelorder_description_label; private enum AccentColor { NO_PREFERENCE, @@ -187,149 +164,6 @@ public class PantheonShell.Appearance : Gtk.Grid { schedule_grid.add (to_label); schedule_grid.add (to_time); - var text_size_label = new Gtk.Label (_("Text size:")) { - halign = Gtk.Align.END, - margin_top = 24 - }; - - text_size_modebutton = new Granite.Widgets.ModeButton () { - margin_top = 24 - }; - text_size_modebutton.append_text (_("Small")); - text_size_modebutton.append_text (_("Default")); - text_size_modebutton.append_text (_("Large")); - text_size_modebutton.append_text (_("Larger")); - - var text_antialias_label = new Gtk.Label(_("Text anti-aliasing:")) { - halign = Gtk.Align.END, - margin_top = 18 - }; - - text_antialias_modebutton = new Granite.Widgets.ModeButton () { - margin_top = 18 - }; - - text_antialias_modebutton.mode_added.connect ((mode_ix,mode_widget) => { - - var font_options = new Cairo.FontOptions(); - - switch (mode_ix) { - case 0: - font_options.set_antialias(Cairo.Antialias.NONE); - break; - case 1: - font_options.set_antialias(Cairo.Antialias.GRAY); - break; - case 2: - font_options.set_antialias(Cairo.Antialias.SUBPIXEL); - break; - } - - mode_widget.set_font_options (font_options); - }); - - text_antialias_modebutton.append_text (_("None")); - text_antialias_modebutton.append_text (_("Grayscale")); - text_antialias_modebutton.append_text (_("Subpixel")); - - var text_antialias_description_label = new Gtk.Label ( - _("Text anti-aliasing can improve text appearance and legibility, depending on display hardware. Choose the mode that looks best on your display. Apps have to be re-opened for changes to take effect") - ) { - max_width_chars = 60, - wrap = true, - xalign = 0 - }; - - text_antialias_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - - text_subpixelorder_label = new Gtk.Label(_("Text subpixel order:")) { - halign = Gtk.Align.END, - margin_top = 18 - }; - - text_subpixelorder_modebutton = new Granite.Widgets.ModeButton () { - margin_top = 18 - }; - - text_subpixelorder_modebutton.mode_added.connect ((mode_ix,mode_widget) => { - - var font_options = new Cairo.FontOptions(); - font_options.set_antialias (Cairo.Antialias.SUBPIXEL); - - switch (mode_ix) { - case 0: - font_options.set_subpixel_order (Cairo.SubpixelOrder.RGB); - break; - case 1: - font_options.set_subpixel_order (Cairo.SubpixelOrder.BGR); - break; - case 2: - font_options.set_subpixel_order (Cairo.SubpixelOrder.VRGB); - break; - case 3: - font_options.set_subpixel_order (Cairo.SubpixelOrder.VBGR); - break; - } - - mode_widget.set_font_options (font_options); - }); - - text_subpixelorder_modebutton.append_text (_("Red On Left (RGB)")); - text_subpixelorder_modebutton.append_text (_("Blue On Left (BGR)")); - text_subpixelorder_modebutton.append_text (_("Red On Top (VRGB)")); - text_subpixelorder_modebutton.append_text (_("Blue On Top (VBGR)")); - - text_subpixelorder_description_label = new Gtk.Label ( - _("Different displays have different positions of the red, green, and blue subpixels. Select the mode that looks the best on your display. Apps have to be re-opened for changes to take effect") - ) { - max_width_chars = 60, - wrap = true, - xalign = 0 - }; - - text_subpixelorder_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - - - var dyslexia_font_label = new Gtk.Label (_("Dyslexia-friendly text:")) { - halign = Gtk.Align.END, - margin_top = 18 - }; - - var dyslexia_font_switch = new Gtk.Switch () { - halign = Gtk.Align.START, - margin_top = 18 - }; - - var dyslexia_font_description_label = new Gtk.Label ( - _("Bottom-heavy shapes and increased character spacing can help improve legibility and reading speed.") - ) { - max_width_chars = 60, - wrap = true, - xalign = 0 - }; - dyslexia_font_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - - /* Rows 0 to 3 are for the dark style UI that gets attached only if we - * can connect to the DBus API - * - * Row 4 and 5 are for accent color UI that gets constructed only if the - * current stylesheet is supported (begins with the STYLESHEET_PREFIX) - */ - attach (text_size_label, 0, 8); - attach (text_size_modebutton, 1, 8, 2); - - attach (text_antialias_label, 0, 9); - attach (text_antialias_modebutton, 1, 9, 2); - attach (text_antialias_description_label, 1, 10, 2); - - attach (text_subpixelorder_label, 0, 11); - attach (text_subpixelorder_modebutton, 1, 11, 2); - attach (text_subpixelorder_description_label, 1, 12, 2); - - attach (dyslexia_font_label, 0, 13); - attach (dyslexia_font_switch, 1, 13); - attach (dyslexia_font_description_label, 1, 14, 2); - Pantheon.AccountsService? pantheon_act = null; string? user_path = null; @@ -522,41 +356,6 @@ public class PantheonShell.Appearance : Gtk.Grid { attach (accent_grid, 1, 4, 2); attach (accent_info, 1, 5, 2); } - - update_text_size_modebutton (interface_settings); - - interface_settings.changed.connect (() => { - update_text_size_modebutton (interface_settings); - }); - - text_size_modebutton.mode_changed.connect (() => { - set_text_scale (interface_settings, text_size_modebutton.selected); - }); - - dyslexia_font_switch.set_active (update_dyslexia_font_switch (interface_settings)); - - dyslexia_font_switch.state_set.connect (() => { - toggle_dyslexia_support (interface_settings, dyslexia_font_switch.get_active () ); - }); - - var xsettings_settings = new GLib.Settings (XSETTINGS_SCHEMA); - - update_text_antialias_modebutton (xsettings_settings); - - xsettings_settings.changed.connect (() => { - update_text_antialias_modebutton (xsettings_settings); - update_text_subpixelorder_modebutton (xsettings_settings); - }); - - text_antialias_modebutton.mode_changed.connect (() => { - set_text_antialias (xsettings_settings, text_antialias_modebutton.selected); - }); - - update_text_subpixelorder_modebutton (xsettings_settings); - - text_subpixelorder_modebutton.mode_changed.connect (() => { - set_text_subpixelorder (xsettings_settings, text_subpixelorder_modebutton.selected); - }); } private class PrefersAccentColorButton : Gtk.RadioButton { @@ -603,92 +402,6 @@ public class PantheonShell.Appearance : Gtk.Grid { } } - private void toggle_dyslexia_support (GLib.Settings interface_settings, bool state) { - if (state == true) { - interface_settings.set_string (FONT_KEY, OD_REG_FONT); - interface_settings.set_string (DOCUMENT_FONT_KEY, OD_DOC_FONT); - interface_settings.set_string (MONOSPACE_FONT_KEY, OD_MON_FONT); - } - else { - interface_settings.reset (FONT_KEY); - interface_settings.reset (DOCUMENT_FONT_KEY); - interface_settings.reset (MONOSPACE_FONT_KEY); - } - } - - private bool update_dyslexia_font_switch (GLib.Settings interface_settings) { - var interface_font = interface_settings.get_string (FONT_KEY); - var document_font = interface_settings.get_string (DOCUMENT_FONT_KEY); - var monospace_font = interface_settings.get_string (MONOSPACE_FONT_KEY); - - if (interface_font == OD_REG_FONT || document_font == OD_DOC_FONT || monospace_font == OD_MON_FONT ) { - return true; - } - - else { - return false; - } - } - - private int get_text_scale (GLib.Settings interface_settings) { - double text_scaling_factor = interface_settings.get_double (TEXT_SIZE_KEY); - - if (text_scaling_factor <= TEXT_SCALE[0]) { - return 0; - } else if (text_scaling_factor <= TEXT_SCALE[1]) { - return 1; - } else if (text_scaling_factor <= TEXT_SCALE[2]) { - return 2; - } else { - return 3; - } - } - - private void set_text_scale (GLib.Settings interface_settings, int option) { - interface_settings.set_double (TEXT_SIZE_KEY, TEXT_SCALE[option]); - } - - private void update_text_size_modebutton (GLib.Settings interface_settings) { - text_size_modebutton.set_active (get_text_scale (interface_settings)); - } - - private int get_text_antialias (GLib.Settings xsettings_settings) { - return xsettings_settings.get_enum (ANTIALIAS_KEY); - } - - private void set_text_antialias (GLib.Settings xsettings_settings, int option) { - xsettings_settings.set_enum (ANTIALIAS_KEY, option); - } - - private void update_text_antialias_modebutton (GLib.Settings xsettings_settings) { - text_antialias_modebutton.set_active (get_text_antialias (xsettings_settings)); - } - - private int get_text_subpixelorder (GLib.Settings xsettings_settings) { - return xsettings_settings.get_enum (SUBPIXELORDER_KEY) - 1; - } - - private void set_text_subpixelorder (GLib.Settings xsettings_settings, int option) { - xsettings_settings.set_enum (SUBPIXELORDER_KEY, option + 1); - } - - private void update_text_subpixelorder_modebutton (GLib.Settings xsettings_settings) { - - var antialias = get_text_antialias (xsettings_settings); - - if (antialias != 2) { - text_subpixelorder_label.visible = false; - text_subpixelorder_modebutton.visible = false; - text_subpixelorder_description_label.visible = false; - } else { - text_subpixelorder_label.visible = true; - text_subpixelorder_modebutton.visible = true; - text_subpixelorder_description_label.visible = true; - } - - text_subpixelorder_modebutton.set_active (get_text_subpixelorder (xsettings_settings)); - } - private static DateTime double_date_time (double dbl) { var hours = (int) dbl; var minutes = (int) Math.round ((dbl - hours) * 60); diff --git a/src/Views/Text.vala b/src/Views/Text.vala new file mode 100644 index 000000000..ce4004ebb --- /dev/null +++ b/src/Views/Text.vala @@ -0,0 +1,299 @@ +/* +* Copyright 2018–2021 elementary, Inc. (https://elementary.io) +* Copyright 2021 Justin Haygood (jhaygood86@gmail.com) +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation; either +* version 3 of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301 USA +* +*/ + +public class PantheonShell.Text : Gtk.Grid { + + private const string INTERFACE_SCHEMA = "org.gnome.desktop.interface"; + private const string XSETTINGS_SCHEMA = "org.gnome.settings-daemon.plugins.xsettings"; + private const string TEXT_SIZE_KEY = "text-scaling-factor"; + private const string ANTIALIAS_KEY = "antialiasing"; + private const string SUBPIXELORDER_KEY = "rgba-order"; + + private const string DYSLEXIA_KEY = "dyslexia-friendly-support"; + private const string FONT_KEY = "font-name"; + private const string DOCUMENT_FONT_KEY = "document-font-name"; + private const string MONOSPACE_FONT_KEY = "monospace-font-name"; + + private const string OD_REG_FONT = "OpenDyslexic Regular 9"; + private const string OD_DOC_FONT = "OpenDyslexic Regular 10"; + private const string OD_MON_FONT = "OpenDyslexicMono Regular 10"; + + private const double[] TEXT_SCALE = {0.75, 1, 1.25, 1.5}; + + private Granite.Widgets.ModeButton text_size_modebutton; + private TextFontOptionRadioGroup text_antialias_group; + private TextFontOptionRadioGroup text_subpixelorder_group; + private Gtk.Label text_subpixelorder_label; + private Gtk.Label text_subpixelorder_description_label; + + construct { + column_spacing = 12; + halign = Gtk.Align.CENTER; + row_spacing = 6; + margin_start = margin_end = 12; + margin_bottom = 24; + + var text_size_label = new Gtk.Label (_("Text size:")) { + halign = Gtk.Align.END, + margin_top = 24 + }; + + text_size_modebutton = new Granite.Widgets.ModeButton () { + margin_top = 24 + }; + text_size_modebutton.append_text (_("Small")); + text_size_modebutton.append_text (_("Default")); + text_size_modebutton.append_text (_("Large")); + text_size_modebutton.append_text (_("Larger")); + + var text_antialias_label = new Gtk.Label(_("Text anti-aliasing:")) { + halign = Gtk.Align.END, + margin_top = 18 + }; + + text_antialias_group = new TextFontOptionRadioGroup () { + margin_top = 18 + }; + + text_antialias_group.append_option(_("None"), (font_options) => { + font_options.set_antialias(Cairo.Antialias.NONE); + }); + + text_antialias_group.append_option(_("Grayscale"), (font_options) => { + font_options.set_antialias(Cairo.Antialias.GRAY); + }); + + text_antialias_group.append_option(_("Subpixel"), (font_options) => { + font_options.set_antialias(Cairo.Antialias.SUBPIXEL); + }); + + + var text_antialias_description_label = new Gtk.Label ( + _("Text anti-aliasing can improve text appearance and legibility, depending on display hardware. Choose the mode that looks best on your display. Apps have to be re-opened for changes to take effect") + ) { + max_width_chars = 60, + wrap = true, + xalign = 0 + }; + + text_antialias_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + + text_subpixelorder_label = new Gtk.Label(_("Text subpixel order:")) { + halign = Gtk.Align.END, + margin_top = 18 + }; + + text_subpixelorder_group = new TextFontOptionRadioGroup () { + margin_top = 18 + }; + + text_subpixelorder_group.append_option(_("Red On Left (RGB)"), (font_options) => { + font_options.set_subpixel_order (Cairo.SubpixelOrder.RGB); + }); + + text_subpixelorder_group.append_option(_("Blue On Left (BGR)"), (font_options) => { + font_options.set_subpixel_order (Cairo.SubpixelOrder.BGR); + }); + + text_subpixelorder_group.append_option(_("Red On Top (VRGB)"), (font_options) => { + font_options.set_subpixel_order (Cairo.SubpixelOrder.VRGB); + }); + + text_subpixelorder_group.append_option(_("Blue On Top (VBGR)"), (font_options) => { + font_options.set_subpixel_order (Cairo.SubpixelOrder.VBGR); + }); + + text_subpixelorder_description_label = new Gtk.Label ( + _("Different displays have different positions of the red, green, and blue subpixels. Select the mode that looks the best on your display. Apps have to be re-opened for changes to take effect") + ) { + max_width_chars = 60, + wrap = true, + xalign = 0 + }; + + text_subpixelorder_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + + + var dyslexia_font_label = new Gtk.Label (_("Dyslexia-friendly text:")) { + halign = Gtk.Align.END, + margin_top = 18 + }; + + var dyslexia_font_switch = new Gtk.Switch () { + halign = Gtk.Align.START, + margin_top = 18 + }; + + var dyslexia_font_description_label = new Gtk.Label ( + _("Bottom-heavy shapes and increased character spacing can help improve legibility and reading speed.") + ) { + max_width_chars = 60, + wrap = true, + xalign = 0 + }; + dyslexia_font_description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + + /* Rows 0 to 3 are for the dark style UI that gets attached only if we + * can connect to the DBus API + * + * Row 4 and 5 are for accent color UI that gets constructed only if the + * current stylesheet is supported (begins with the STYLESHEET_PREFIX) + */ + attach (text_size_label, 0, 8); + attach (text_size_modebutton, 1, 8, 2); + + attach (text_antialias_label, 0, 9); + attach (text_antialias_group, 1, 9, 2); + attach (text_antialias_description_label, 1, 10, 2); + + attach (text_subpixelorder_label, 0, 11); + attach (text_subpixelorder_group, 1, 11, 2); + attach (text_subpixelorder_description_label, 1, 12, 2); + + attach (dyslexia_font_label, 0, 13); + attach (dyslexia_font_switch, 1, 13); + attach (dyslexia_font_description_label, 1, 14, 2); + + var interface_settings = new GLib.Settings (INTERFACE_SCHEMA); + + update_text_size_modebutton (interface_settings); + + interface_settings.changed.connect (() => { + update_text_size_modebutton (interface_settings); + }); + + text_size_modebutton.mode_changed.connect (() => { + set_text_scale (interface_settings, text_size_modebutton.selected); + }); + + dyslexia_font_switch.set_active (update_dyslexia_font_switch (interface_settings)); + + dyslexia_font_switch.state_set.connect (() => { + toggle_dyslexia_support (interface_settings, dyslexia_font_switch.get_active () ); + }); + + var xsettings_settings = new GLib.Settings (XSETTINGS_SCHEMA); + + update_text_antialias_modebutton (xsettings_settings); + + xsettings_settings.changed.connect (() => { + update_text_antialias_modebutton (xsettings_settings); + update_text_subpixelorder_modebutton (xsettings_settings); + }); + + text_antialias_group.changed.connect (() => { + set_text_antialias (xsettings_settings, text_antialias_group.selected); + }); + + update_text_subpixelorder_modebutton (xsettings_settings); + + text_subpixelorder_group.changed.connect (() => { + set_text_subpixelorder (xsettings_settings, text_subpixelorder_group.selected); + }); + } + + private void toggle_dyslexia_support (GLib.Settings interface_settings, bool state) { + if (state == true) { + interface_settings.set_string (FONT_KEY, OD_REG_FONT); + interface_settings.set_string (DOCUMENT_FONT_KEY, OD_DOC_FONT); + interface_settings.set_string (MONOSPACE_FONT_KEY, OD_MON_FONT); + } + else { + interface_settings.reset (FONT_KEY); + interface_settings.reset (DOCUMENT_FONT_KEY); + interface_settings.reset (MONOSPACE_FONT_KEY); + } + } + + private bool update_dyslexia_font_switch (GLib.Settings interface_settings) { + var interface_font = interface_settings.get_string (FONT_KEY); + var document_font = interface_settings.get_string (DOCUMENT_FONT_KEY); + var monospace_font = interface_settings.get_string (MONOSPACE_FONT_KEY); + + if (interface_font == OD_REG_FONT || document_font == OD_DOC_FONT || monospace_font == OD_MON_FONT ) { + return true; + } + + else { + return false; + } + } + + private int get_text_scale (GLib.Settings interface_settings) { + double text_scaling_factor = interface_settings.get_double (TEXT_SIZE_KEY); + + if (text_scaling_factor <= TEXT_SCALE[0]) { + return 0; + } else if (text_scaling_factor <= TEXT_SCALE[1]) { + return 1; + } else if (text_scaling_factor <= TEXT_SCALE[2]) { + return 2; + } else { + return 3; + } + } + + private void set_text_scale (GLib.Settings interface_settings, int option) { + interface_settings.set_double (TEXT_SIZE_KEY, TEXT_SCALE[option]); + } + + private void update_text_size_modebutton (GLib.Settings interface_settings) { + text_size_modebutton.set_active (get_text_scale (interface_settings)); + } + + private int get_text_antialias (GLib.Settings xsettings_settings) { + return xsettings_settings.get_enum (ANTIALIAS_KEY); + } + + private void set_text_antialias (GLib.Settings xsettings_settings, int option) { + xsettings_settings.set_enum (ANTIALIAS_KEY, option); + } + + private void update_text_antialias_modebutton (GLib.Settings xsettings_settings) { + text_antialias_group.set_active (get_text_antialias (xsettings_settings)); + } + + private int get_text_subpixelorder (GLib.Settings xsettings_settings) { + return xsettings_settings.get_enum (SUBPIXELORDER_KEY) - 1; + } + + private void set_text_subpixelorder (GLib.Settings xsettings_settings, int option) { + xsettings_settings.set_enum (SUBPIXELORDER_KEY, option + 1); + } + + private void update_text_subpixelorder_modebutton (GLib.Settings xsettings_settings) { + + var antialias = get_text_antialias (xsettings_settings); + + if (antialias != 2) { + text_subpixelorder_label.visible = false; + text_subpixelorder_group.visible = false; + text_subpixelorder_description_label.visible = false; + } else { + text_subpixelorder_label.visible = true; + text_subpixelorder_group.visible = true; + text_subpixelorder_description_label.visible = true; + } + + text_subpixelorder_group.set_active (get_text_subpixelorder (xsettings_settings)); + } + +} diff --git a/src/Widgets/TextFontOptionRadioGroup.vala b/src/Widgets/TextFontOptionRadioGroup.vala new file mode 100644 index 000000000..1a24f53ed --- /dev/null +++ b/src/Widgets/TextFontOptionRadioGroup.vala @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2021 Justin Haygood + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +public class PantheonShell.TextFontOptionRadioGroup : Gtk.Box { + + public delegate void FontOptionsCallback (Cairo.FontOptions font_options); + public signal void changed (); + + private Gee.List radio_buttons; + + public TextFontOptionRadioGroup () { + Object(orientation: Gtk.Orientation.VERTICAL, spacing: 5); + + radio_buttons = new Gee.ArrayList (); + } + + public void append_option(string label, FontOptionsCallback font_options_callback) { + + Gtk.RadioButton radio_button; + + if (radio_buttons.size == 0) { + radio_button = new Gtk.RadioButton (null) { + halign = Gtk.Align.START + }; + } else { + radio_button = new Gtk.RadioButton.from_widget (radio_buttons.first ()) { + halign = Gtk.Align.START + }; + } + + radio_buttons.add (radio_button); + + var radio_button_label = new Gtk.Label (label); + radio_button.add (radio_button_label); + + var label_font_options = new Cairo.FontOptions (); + + font_options_callback(label_font_options); + + radio_button_label.set_font_options (label_font_options); + + pack_start (radio_button); + + radio_button.toggled.connect(() => { + changed (); + }); + } + + public int selected { + get { + for (var i = 0; i < radio_buttons.size; i++) { + if (radio_buttons[i].active) { + return i; + } + } + + return -1; + } + + set { + set_active (value); + } + } + + public void set_active (int new_active_index) { + radio_buttons[new_active_index].active = true; + } +} diff --git a/src/meson.build b/src/meson.build index 259c0bf2c..ccfd55626 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,8 +6,10 @@ plug_files = files( 'Views/Appearance.vala', 'Views/Dock.vala', 'Views/Multitasking.vala', + 'Views/Text.vala', 'Views/Wallpaper.vala', 'Widgets/SolidColorContainer.vala', + 'Widgets/TextFontOptionRadioGroup.vala', 'Widgets/WallpaperContainer.vala', )