widgets.py 22.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# This file is part of gnome-tweak-tool.
#
# Copyright (c) 2011 John Stowers
#
# gnome-tweak-tool 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.
#
# gnome-tweak-tool 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 gnome-tweak-tool.  If not, see <http://www.gnu.org/licenses/>.

18
import logging
19
import os.path
20

21
from gi.repository import GLib, Gtk, Gdk, Gio, Pango
John Stowers's avatar
John Stowers committed
22

23
from gtweak.tweakmodel import Tweak, TweakGroup
24
from gtweak.gsettings import GSettingsSetting, GSettingsFakeSetting, GSettingsMissingError
25
from gtweak.gtksettings import GtkSettingsManager
26
from gtweak.gshellwrapper import GnomeShellFactory
27

28
UI_BOX_SPACING = 4
29
_shell = GnomeShellFactory().get_shell()
30

31 32 33 34 35 36 37 38 39
def build_label_beside_widget(txt, *widget, **kwargs):
    """
    Builds a HBox containing widgets.

    Optional Kwargs:
        hbox: Use an existing HBox, not a new one
        info: Informational text to be shown after the label
        warning: Warning text to be shown after the label
    """
40 41 42 43 44
    def make_image(icon, tip):
        image = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU)
        image.set_tooltip_text(tip)
        return image

45 46 47 48 49 50 51 52
    def show_tooltip_when_ellipsized(label, x, y, keyboard_mode, tooltip):
        layout = label.get_layout()
        if layout.is_ellipsized():
            tooltip.set_text(label.get_text())
            return True
        else:
            return False

53 54 55
    if kwargs.get("hbox"):
        hbox = kwargs.get("hbox")
    else:
56
        hbox = Gtk.Box()
57

58
    hbox.props.spacing = UI_BOX_SPACING
59
    lbl = Gtk.Label(label=txt)
John Stowers's avatar
John Stowers committed
60
    lbl.props.ellipsize = Pango.EllipsizeMode.END
John Stowers's avatar
John Stowers committed
61
    lbl.props.xalign = 0.0
62 63
    lbl.set_has_tooltip(True)
    lbl.connect("query-tooltip", show_tooltip_when_ellipsized)
Alex Muñoz's avatar
Alex Muñoz committed
64
    hbox.pack_start(lbl, True, True, 0)
65 66

    if kwargs.get("info"):
67 68 69 70 71 72 73
        hbox.pack_start(
                make_image("dialog-information-symbolic", kwargs.get("info")),
                False, False, 0)
    if kwargs.get("warning"):
        hbox.pack_start(
                make_image("dialog-warning-symbolic", kwargs.get("warning")),
                False, False, 0)
74 75 76 77

    for w in widget:
        hbox.pack_start(w, False, False, 0)

78 79 80 81
    #For Atk, indicate that the rightmost widget, usually the switch relates to the
    #label. By convention this is true in the great majority of cases. Settings that
    #construct their own widgets will need to set this themselves
    lbl.set_mnemonic_widget(widget[-1])
82

Alex Muñoz's avatar
Alex Muñoz committed
83
    return hbox
John Stowers's avatar
John Stowers committed
84 85

def build_combo_box_text(selected, *values):
86 87 88 89
    """
    builds a GtkComboBox and model containing the supplied values.
    @values: a list of 2-tuples (value, name)
    """
John Stowers's avatar
John Stowers committed
90
    store = Gtk.ListStore(str, str)
91
    store.set_sort_column_id(0, Gtk.SortType.ASCENDING)
John Stowers's avatar
John Stowers committed
92 93 94 95 96 97 98 99 100 101

    selected_iter = None
    for (val, name) in values:
        _iter = store.append( (val, name) )
        if val == selected:
            selected_iter = _iter

    combo = Gtk.ComboBox(model=store)
    renderer = Gtk.CellRendererText()
    combo.pack_start(renderer, True)
102
    combo.add_attribute(renderer, 'markup', 1)
John Stowers's avatar
John Stowers committed
103 104 105 106 107
    if selected_iter:
        combo.set_active_iter(selected_iter)

    return combo

108 109 110 111 112
def build_horizontal_sizegroup():
    sg = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
    sg.props.ignore_hidden = True
    return sg

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
def build_tight_button(stock_id):
    button = Gtk.Button()
    button.set_relief(Gtk.ReliefStyle.NONE)
    button.set_focus_on_click(False)
    button.add(Gtk.Image.new_from_stock(stock_id, Gtk.IconSize.MENU))
    data =  ".button {\n" \
            "-GtkButton-default-border : 0px;\n" \
            "-GtkButton-default-outside-border : 0px;\n" \
            "-GtkButton-inner-border: 0px;\n" \
            "-GtkWidget-focus-line-width : 0px;\n" \
            "-GtkWidget-focus-padding : 0px;\n" \
            "padding: 0px;\n" \
            "}"
    provider = Gtk.CssProvider()
    provider.load_from_data(data)
    # 600 = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
129
    button.get_style_context().add_provider(provider, 600)
130 131
    return button

132 133 134 135
def adjust_schema_for_overrides(originalSchema, key, options):
    if (_shell is None):
        return originalSchema

136 137 138 139
    if (_shell.mode == 'user'):
        overridesSchema = "org.gnome.shell.overrides"
        overridesFile = "org.gnome.shell.gschema.xml"
    elif (_shell.mode == 'classic'):
140 141 142
        overridesSchema = "org.gnome.shell.extensions.classic-overrides"
        overridesFile = None
    else:
143
        return originalSchema
144

145 146 147 148
    try:
        if (key in GSettingsSetting(overridesSchema, schema_filename=overridesFile).list_keys()):
            options['schema_filename'] = overridesFile
            return overridesSchema
149
    except GSettingsMissingError as e:
150 151
        logging.info("GSetting missing %s" % (e.message))

152 153 154
    return originalSchema


John Stowers's avatar
John Stowers committed
155
class _GSettingsTweak(Tweak):
Alex Muñoz's avatar
Alex Muñoz committed
156
    def __init__(self, name, schema_name, key_name, **options):
157
        schema_name = adjust_schema_for_overrides(schema_name, key_name, options)
John Stowers's avatar
John Stowers committed
158 159
        self.schema_name = schema_name
        self.key_name = key_name
Alex Muñoz's avatar
Alex Muñoz committed
160
        self._extra_info = None
161 162
        if 'uid' not in options:
            options['uid'] = key_name
163 164 165
        try:
            self.settings = GSettingsSetting(schema_name, **options)
            Tweak.__init__(self,
Alex Muñoz's avatar
Alex Muñoz committed
166
                name,
167 168
                options.get("description",self.settings.schema_get_description(key_name)),
                **options)
169
        except GSettingsMissingError as e:
170 171 172
            self.settings = GSettingsFakeSetting()
            Tweak.__init__(self,"","")
            self.loaded = False
John Stowers's avatar
John Stowers committed
173
            logging.info("GSetting missing %s" % (e.message))
174 175 176 177
        except KeyError:
            self.settings = GSettingsFakeSetting()
            Tweak.__init__(self,"","")
            self.loaded = False
John Stowers's avatar
John Stowers committed
178
            logging.info("GSettings missing key %s (key %s)" % (schema_name, key_name))
179

180 181 182 183
        if options.get("logout_required") and self.loaded:
            self.settings.connect("changed::%s" % key_name, self._on_changed_notify_logout)

    def _on_changed_notify_logout(self, settings, key_name):
184
        self.notify_logout()
185

Alex Muñoz's avatar
Alex Muñoz committed
186 187 188 189 190 191
    @property
    def extra_info(self):
        if self._extra_info is None:
            self._extra_info = self.settings.schema_get_summary(self.key_name)
        return self._extra_info

192
class _DependableMixin(object):
John Stowers's avatar
John Stowers committed
193

194 195 196 197 198 199 200 201 202 203 204
    def add_dependency_on_tweak(self, depends, depends_how):
        if isinstance(depends, Tweak):
            self._depends = depends
            if depends_how is None:
                depends_how = lambda x,kn: x.get_boolean(kn)
            self._depends_how = depends_how

            sensitive = self._depends_how(
                                depends.settings,
                                depends.key_name,
            )
205
            self.set_sensitive(sensitive)
206 207 208 209 210

            depends.settings.connect("changed::%s" % depends.key_name, self._on_changed_depend)

    def _on_changed_depend(self, settings, key_name):
        sensitive = self._depends_how(settings,key_name)
211
        self.set_sensitive(sensitive)
212

213
class ListBoxTweakGroup(Gtk.ListBox, TweakGroup):
214 215 216
    def __init__(self, name, *tweaks, **options):
        if 'uid' not in options:
            options['uid'] = self.__class__.__name__
217
        Gtk.ListBox.__init__(self,
218 219
                        selection_mode=Gtk.SelectionMode.NONE,
                        name=options['uid'])
220 221
        self.get_style_context().add_class(
                        options.get('css_class','tweak-group'))
222
        self.props.margin = 20
223 224 225 226
        self.props.vexpand = False
        self.props.valign = Gtk.Align.START

        self._sg = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
227 228
        self._sg.props.ignore_hidden = True

229 230 231 232 233 234 235 236 237 238
        TweakGroup.__init__(self, name, **options)

        for t in tweaks:
            self.add_tweak_row(t)

    #FIXME: need to add remove_tweak_row and remove_tweak (which clears
    #the search cache etc)

    def add_tweak_row(self, t, position=None):
        if self.add_tweak(t):
239 240 241 242 243 244 245 246
            if isinstance(t, Gtk.ListBoxRow):
                row = t
            else:
                row = Gtk.ListBoxRow(name=t.uid)
                row.get_style_context().add_class("tweak")
                if isinstance(t, Title):
                    row.get_style_context().add_class("title")
                row.add(t)
247 248 249 250
            if position is None:
                self.add(row)
            else:
                self.insert(row, position)
251 252
            if t.widget_for_size_group:
                self._sg.add_widget(t.widget_for_size_group)
253
            return row
254

255
class GSettingsCheckTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
John Stowers's avatar
John Stowers committed
256
    def __init__(self, name, schema_name, key_name, **options):
257
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
258
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
John Stowers's avatar
John Stowers committed
259

260
        widget = Gtk.CheckButton.new_with_label(name)
John Stowers's avatar
John Stowers committed
261 262
        self.settings.bind(
                key_name,
263
                widget,
John Stowers's avatar
John Stowers committed
264
                "active", Gio.SettingsBindFlags.DEFAULT)
265
        self.add(widget)
John Stowers's avatar
John Stowers committed
266 267 268 269 270 271 272
        self.widget_for_size_group = None

        self.add_dependency_on_tweak(
                options.get("depends_on"),
                options.get("depends_how")
        )

273
class GSettingsSwitchTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
274
    def __init__(self, name, schema_name, key_name, **options):
275
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
276
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
John Stowers's avatar
John Stowers committed
277

John Stowers's avatar
John Stowers committed
278 279
        w = Gtk.Switch()
        self.settings.bind(key_name, w, "active", Gio.SettingsBindFlags.DEFAULT)
280

281 282 283 284 285
        self.add_dependency_on_tweak(
                options.get("depends_on"),
                options.get("depends_how")
        )

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
        vbox1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox1.props.spacing = UI_BOX_SPACING
        lbl = Gtk.Label(label=name)
        lbl.props.ellipsize = Pango.EllipsizeMode.END
        lbl.props.xalign = 0.0
        vbox1.pack_start(lbl, True, True, 0)

        if options.get("desc"):
            description = options.get("desc")
            lbl_desc = Gtk.Label()
            lbl_desc.props.xalign = 0.0
            lbl_desc.set_line_wrap(True)
            lbl_desc.get_style_context().add_class("dim-label")
            lbl_desc.set_markup("<span size='small'>"+GLib.markup_escape_text(description)+"</span>")
            vbox1.pack_start(lbl_desc, True, True, 0)

        vbox2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox2_upper = Gtk.Box()
        vbox2_lower = Gtk.Box()
        vbox2.pack_start(vbox2_upper, True, True, 0)
        vbox2.pack_start(w, False, False, 0)
        vbox2.pack_start(vbox2_lower, True, True, 0)

        self.pack_start(vbox1, True, True, 0)
        self.pack_start(vbox2, False, False, 0)
        self.widget_for_size_group = None

313
class GSettingsFontButtonTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
314
    def __init__(self, name, schema_name, key_name, **options):
315
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
316
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
John Stowers's avatar
John Stowers committed
317 318

        w = Gtk.FontButton()
319
        w.set_use_font(True)
John Stowers's avatar
John Stowers committed
320
        self.settings.bind(key_name, w, "font-name", Gio.SettingsBindFlags.DEFAULT)
321
        build_label_beside_widget(name, w, hbox=self)
322
        self.widget_for_size_group = w
John Stowers's avatar
John Stowers committed
323

324
class GSettingsRangeTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
Alex Muñoz's avatar
Alex Muñoz committed
325
    def __init__(self, name, schema_name, key_name, **options):
326
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
327
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
328 329 330 331 332 333

        #returned variant is range:(min, max)
        _min, _max = self.settings.get_range(key_name)[1]

        w = Gtk.HScale.new_with_range(_min, _max, options.get('adjustment_step', 1))
        self.settings.bind(key_name, w.get_adjustment(), "value", Gio.SettingsBindFlags.DEFAULT)
334 335

        build_label_beside_widget(self.name, w, hbox=self)
336 337
        self.widget_for_size_group = w

338
class GSettingsSpinButtonTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
339
    def __init__(self, name, schema_name, key_name, **options):
340
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
341
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
342 343 344 345

        #returned variant is range:(min, max)
        _min, _max = self.settings.get_range(key_name)[1]

346
        adjustment = Gtk.Adjustment(value=0, lower=_min, upper=_max, step_increment=options.get('adjustment_step', 1))
347 348 349 350
        w = Gtk.SpinButton()
        w.set_adjustment(adjustment)
        w.set_digits(options.get('digits', 0))
        self.settings.bind(key_name, adjustment, "value", Gio.SettingsBindFlags.DEFAULT)
351

352
        build_label_beside_widget(name, w, hbox=self)
353
        self.widget_for_size_group = w
354

Alex Muñoz's avatar
Alex Muñoz committed
355 356 357 358
        self.add_dependency_on_tweak(
                options.get("depends_on"),
                options.get("depends_how")
        )
359

360
class GSettingsComboEnumTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
361
    def __init__(self, name, schema_name, key_name, **options):
362
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
363
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
John Stowers's avatar
John Stowers committed
364 365 366 367 368

        _type, values = self.settings.get_range(key_name)
        value = self.settings.get_string(key_name)
        self.settings.connect('changed::'+self.key_name, self._on_setting_changed)

369
        w = build_combo_box_text(value, *[(v,v.replace("-"," ").title()) for v in values])
John Stowers's avatar
John Stowers committed
370 371 372
        w.connect('changed', self._on_combo_changed)
        self.combo = w

373
        build_label_beside_widget(name, w, hbox=self)
John Stowers's avatar
John Stowers committed
374 375
        self.widget_for_size_group = w

376 377 378
    def _values_are_different(self):
        #to stop bouncing back and forth between changed signals. I suspect there must be a nicer
        #Gio.settings_bind way to fix this
John Stowers's avatar
John Stowers committed
379
        return self.settings.get_string(self.key_name) != \
380
               self.combo.get_model().get_value(self.combo.get_active_iter(), 0)
John Stowers's avatar
John Stowers committed
381 382

    def _on_setting_changed(self, setting, key):
383 384 385 386 387
        assert key == self.key_name
        val = self.settings.get_string(key)
        model = self.combo.get_model()
        for row in model:
            if val == row[0]:
388
                self.combo.set_active_iter(row.iter)
389
                break
John Stowers's avatar
John Stowers committed
390 391

    def _on_combo_changed(self, combo):
392 393
        val = self.combo.get_model().get_value(self.combo.get_active_iter(), 0)
        if self._values_are_different():
394
            self.settings.set_string(self.key_name, val)
John Stowers's avatar
John Stowers committed
395

396
class GSettingsComboTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
397
    def __init__(self, name, schema_name, key_name, key_options, **options):
398
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
399
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
400

401 402 403 404 405
        #check key_options is iterable
        #and if supplied, check it is a list of 2-tuples
        assert len(key_options) >= 0
        if len(key_options):
            assert len(key_options[0]) == 2
Alex Muñoz's avatar
Alex Muñoz committed
406
        self._key_options = key_options
407

408
        self.combo = build_combo_box_text(
409
                    self.settings.get_string(self.key_name),
410
                    *key_options)
411
        self.combo.connect('changed', self._on_combo_changed)
412 413 414
        self.settings.connect('changed::'+self.key_name, self._on_setting_changed)

        build_label_beside_widget(name, self.combo,hbox=self)
415 416 417 418 419 420 421 422 423 424 425 426
        self.widget_for_size_group = self.combo

    def _on_setting_changed(self, setting, key):
        assert key == self.key_name
        val = self.settings.get_string(key)
        model = self.combo.get_model()
        for row in model:
            if val == row[0]:
                self.combo.set_active_iter(row.iter)
                return

        self.combo.set_active(-1)
427 428 429 430 431

    def _on_combo_changed(self, combo):
        _iter = combo.get_active_iter()
        if _iter:
            value = combo.get_model().get_value(_iter, 0)
432
            self.settings.set_string(self.key_name, value)
433

Alex Muñoz's avatar
Alex Muñoz committed
434 435 436 437 438 439 440
    @property
    def extra_info(self):
        if self._extra_info is None:
           self._extra_info = self.settings.schema_get_summary(self.key_name)
           self._extra_info += " " + " ".join(op[0] for op in self._key_options)
        return self._extra_info

441 442
class FileChooserButton(Gtk.FileChooserButton):
    def __init__(self, title, local_only, mimetypes):
443 444
        Gtk.FileChooserButton.__init__(self, title=title)

445 446 447 448 449
        if mimetypes:
            f = Gtk.FileFilter()
            for m in mimetypes:
                f.add_mime_type(m)
            self.set_filter(f)
450 451

        #self.set_width_chars(15)
452
        self.set_local_only(local_only)
453 454
        self.set_action(Gtk.FileChooserAction.OPEN)

455
class GSettingsFileChooserButtonTweak(Gtk.Box, _GSettingsTweak, _DependableMixin):
456
    def __init__(self, name, schema_name, key_name, local_only, mimetypes, **options):
457
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
458
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
459 460 461

        self.settings.connect('changed::'+self.key_name, self._on_setting_changed)

462
        self.filechooser = FileChooserButton(name,local_only,mimetypes)
463 464 465
        self.filechooser.set_uri(self.settings.get_string(self.key_name))
        self.filechooser.connect("file-set", self._on_file_set)

466
        build_label_beside_widget(name, self.filechooser, hbox=self)
467 468 469 470 471 472 473 474 475 476 477 478
        self.widget_for_size_group = self.filechooser

    def _values_are_different(self):
        return self.settings.get_string(self.key_name) != self.filechooser.get_uri()

    def _on_setting_changed(self, setting, key):
        self.filechooser.set_uri(self.settings.get_string(key))

    def _on_file_set(self, chooser):
        uri = self.filechooser.get_uri()
        if uri and self._values_are_different():
            self.settings.set_string(self.key_name, uri)
479

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
class GetterSetterSwitchTweak(Gtk.Box, Tweak):
    def __init__(self, name, **options):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
        Tweak.__init__(self, name, options.get("description",""), **options)

        sw = Gtk.Switch()
        sw.set_active(self.get_active())
        sw.connect("notify::active", self._on_toggled)

        build_label_beside_widget(name, sw, hbox=self)

    def _on_toggled(self, sw, pspec):
        self.set_active(sw.get_active())

    def get_active(self):
        raise NotImplementedError()

    def set_active(self, v):
        raise NotImplementedError()

500
class DarkThemeSwitcher(Gtk.Box, Tweak):
501
    def __init__(self, **options):
Alex Muñoz's avatar
Alex Muñoz committed
502
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
503 504 505 506
        Tweak.__init__(self, _("Enable dark theme for all applications"),
                       _("Enable the dark theme hint for all the applications in the session"),
                       **options)

507 508
        self._gtksettings3 = GtkSettingsManager('3.0')
        self._gtksettings4 = GtkSettingsManager('4.0')
509 510

        w = Gtk.Switch()
511
        w.set_active(self._gtksettings3.get_integer("gtk-application-prefer-dark-theme"))
512

513
        title = _("Global Dark Theme")
514
        description = _("Applications need to be restarted for this change to take place.")
515
        w.connect("notify::active", self._on_switch_changed)
516

Alex Muñoz's avatar
Alex Muñoz committed
517 518
        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        hbox.props.spacing = UI_BOX_SPACING
519
        lbl = Gtk.Label(label=title)
Alex Muñoz's avatar
Alex Muñoz committed
520 521 522 523
        lbl.props.ellipsize = Pango.EllipsizeMode.END
        lbl.props.xalign = 0.0
        hbox.pack_start(lbl, True, True, 0)
        hbox.pack_start(w, False, False, 0)
524

Alex Muñoz's avatar
Alex Muñoz committed
525 526
        lbl_des = Gtk.Label()
        lbl_des.props.xalign = 0.0
527 528
        lbl_des.get_style_context().add_class("dim-label")
        lbl_des.set_markup("<span size='small'>"+GLib.markup_escape_text(description)+"</span>")
529

Alex Muñoz's avatar
Alex Muñoz committed
530 531
        self.pack_start(hbox, False, False, 0)
        self.pack_start(lbl_des, False, False,0)
532
        self.widget_for_size_group = None
533 534 535 536 537

    def _on_switch_changed(self, switch, param):
        active = switch.get_active()

        try:
538 539 540
            self._gtksettings3.set_integer("gtk-application-prefer-dark-theme",
                                          active)
            self._gtksettings4.set_integer("gtk-application-prefer-dark-theme",
541 542
                                          active)
        except:
543
            self.notify_information(_("Error writing setting"))
544

545
class Title(Gtk.Box, Tweak):
546
    def __init__(self, name, desc, **options):
547
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
548
        Tweak.__init__(self, name, desc, **options)
549
        widget = Gtk.Label()
550
        widget.set_markup("<b>"+GLib.markup_escape_text(name)+"</b>")
551
        widget.props.xalign = 0.0
552 553
        if not options.get("top"):
            widget.set_margin_top(10)
554
        self.add(widget)
555

Alex Muñoz's avatar
Alex Muñoz committed
556
class GSettingsSwitchTweakValue(Gtk.Box, _GSettingsTweak):
557

Alex Muñoz's avatar
Alex Muñoz committed
558 559
    def __init__(self, name, schema_name, key_name, **options):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
Alex Muñoz's avatar
Alex Muñoz committed
560
        _GSettingsTweak.__init__(self, name, schema_name, key_name, **options)
Alex Muñoz's avatar
Alex Muñoz committed
561 562 563 564

        sw = Gtk.Switch()
        sw.set_active(self.get_active())
        sw.connect("notify::active", self._on_toggled)
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591

        vbox1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox1.props.spacing = UI_BOX_SPACING
        lbl = Gtk.Label(label=name)
        lbl.props.ellipsize = Pango.EllipsizeMode.END
        lbl.props.xalign = 0.0
        vbox1.pack_start(lbl, True, True, 0)

        if options.get("desc"):
            description = options.get("desc")
            lbl_desc = Gtk.Label()
            lbl_desc.props.xalign = 0.0
            lbl_desc.set_line_wrap(True)
            lbl_desc.get_style_context().add_class("dim-label")
            lbl_desc.set_markup("<span size='small'>"+GLib.markup_escape_text(description)+"</span>")
            vbox1.pack_start(lbl_desc, True, True, 0)

        vbox2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox2_upper = Gtk.Box()
        vbox2_lower = Gtk.Box()
        vbox2.pack_start(vbox2_upper, True, True, 0)
        vbox2.pack_start(sw, False, False, 0)
        vbox2.pack_start(vbox2_lower, True, True, 0)

        self.pack_start(vbox1, True, True, 0)
        self.pack_start(vbox2, False, False, 0)
        self.widget_for_size_group = None
Alex Muñoz's avatar
Alex Muñoz committed
592 593 594

    def _on_toggled(self, sw, pspec):
        self.set_active(sw.get_active())
595

Alex Muñoz's avatar
Alex Muñoz committed
596 597
    def set_active(self, v):
        raise NotImplementedError()
598

Alex Muñoz's avatar
Alex Muñoz committed
599 600
    def get_active(self):
        raise NotImplementedError()