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 adad65ad5..bc422e1af 100644 --- a/src/Views/Appearance.vala +++ b/src/Views/Appearance.vala @@ -22,20 +22,6 @@ public class PantheonShell.Appearance : Gtk.Grid { private const string INTERFACE_SCHEMA = "org.gnome.desktop.interface"; 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 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 enum AccentColor { NO_PREFERENCE, @@ -178,48 +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 dyslexia_font_label = new Gtk.Label (_("Dyslexia-friendly text:")) { - halign = Gtk.Align.END - }; - - var dyslexia_font_switch = new Gtk.Switch () { - halign = Gtk.Align.START - }; - - 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 (dyslexia_font_label, 0, 9); - attach (dyslexia_font_switch, 1, 9); - attach (dyslexia_font_description_label, 1, 10, 2); - Pantheon.AccountsService? pantheon_act = null; string? user_path = null; @@ -412,22 +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 () ); - }); } private class PrefersAccentColorButton : Gtk.RadioButton { @@ -474,55 +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 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', )