1#!/usr/local/bin/python3.8 2 3import math 4import gi 5gi.require_version('Gtk', '3.0') 6gi.require_version('XApp', '1.0') 7from gi.repository import Gio, Gtk, GObject, Gdk, GLib, XApp 8 9settings_objects = {} 10 11class EditableEntry (Gtk.Stack): 12 13 __gsignals__ = { 14 'changed': (GObject.SignalFlags.RUN_FIRST, None, 15 (str,)) 16 } 17 18 def __init__ (self): 19 super(EditableEntry, self).__init__() 20 21 self.set_transition_type(Gtk.StackTransitionType.CROSSFADE) 22 self.set_transition_duration(150) 23 24 self.label = Gtk.Label() 25 self.entry = Gtk.Entry() 26 self.button = Gtk.Button() 27 28 self.button.set_alignment(1.0, 0.5) 29 self.button.set_relief(Gtk.ReliefStyle.NONE) 30 self.add_named(self.button, "button"); 31 self.add_named(self.entry, "entry"); 32 self.set_visible_child_name("button") 33 self.editable = False 34 self.current_text = None 35 self.show_all() 36 37 self.button.connect("released", self._on_button_clicked) 38 self.button.connect("activate", self._on_button_clicked) 39 self.entry.connect("activate", self._on_entry_validated) 40 self.entry.connect("changed", self._on_entry_changed) 41 self.entry.connect("focus-out-event", self._on_focus_lost) 42 43 def set_text(self, text): 44 self.button.set_label(text) 45 self.entry.set_text(text) 46 self.current_text = text 47 48 def _on_focus_lost(self, widget, event): 49 self.button.set_label(self.current_text) 50 self.entry.set_text(self.current_text) 51 52 self.set_editable(False) 53 54 def _on_button_clicked(self, button): 55 self.set_editable(True) 56 self.entry.grab_focus() 57 58 def _on_entry_validated(self, entry): 59 self.set_editable(False) 60 self.emit("changed", entry.get_text()) 61 self.current_text = entry.get_text() 62 63 def _on_entry_changed(self, entry): 64 self.button.set_label(entry.get_text()) 65 66 def set_editable(self, editable): 67 if (editable): 68 self.set_visible_child_name("entry") 69 else: 70 self.set_visible_child_name("button") 71 self.editable = editable 72 73 def set_tooltip_text(self, tooltip): 74 self.button.set_tooltip_text(tooltip) 75 76 def get_editable(self): 77 return self.editable 78 79 def get_text(self): 80 return self.entry.get_text() 81 82class SettingsStack(Gtk.Stack): 83 def __init__(self): 84 Gtk.Stack.__init__(self) 85 self.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) 86 self.set_transition_duration(150) 87 self.expand = True 88 89class SettingsRevealer(Gtk.Revealer): 90 def __init__(self, schema=None, key=None, values=None, check_func=None): 91 Gtk.Revealer.__init__(self) 92 93 self.check_func = check_func 94 95 self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15) 96 Gtk.Revealer.add(self, self.box) 97 98 self.set_transition_type(Gtk.RevealerTransitionType.SLIDE_DOWN) 99 self.set_transition_duration(150) 100 101 if schema: 102 self.settings = Gio.Settings.new(schema) 103 # if there aren't values or a function provided to determine visibility we can do a simple bind 104 if values is None and check_func is None: 105 self.settings.bind(key, self, "reveal-child", Gio.SettingsBindFlags.GET) 106 else: 107 self.values = values 108 self.settings.connect("changed::" + key, self.on_settings_changed) 109 self.on_settings_changed(self.settings, key) 110 111 def add(self, widget): 112 self.box.pack_start(widget, False, True, 0) 113 114 #only used when checking values 115 def on_settings_changed(self, settings, key): 116 value = settings.get_value(key).unpack() 117 if self.check_func is None: 118 self.set_reveal_child(value in self.values) 119 else: 120 self.set_reveal_child(self.check_func(value, self.values)) 121 122class SettingsPage(Gtk.Box): 123 def __init__(self): 124 Gtk.Box.__init__(self) 125 self.set_orientation(Gtk.Orientation.VERTICAL) 126 self.set_spacing(30) 127 self.set_margin_left(80) 128 self.set_margin_right(80) 129 self.set_margin_top(15) 130 self.set_margin_bottom(15) 131 132 def add_section(self, title=None, subtitle=None): 133 section = SettingsSection(title, subtitle) 134 self.pack_start(section, False, False, 0) 135 136 return section 137 138 def add_reveal_section(self, title, schema=None, key=None, values=None, revealer=None): 139 section = SettingsSection(title) 140 if revealer is None: 141 revealer = SettingsRevealer(schema, key, values) 142 revealer.add(section) 143 section._revealer = revealer 144 self.pack_start(revealer, False, False, 0) 145 146 return section 147 148class SettingsSection(Gtk.Box): 149 def __init__(self, title=None, subtitle=None): 150 Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) 151 self.set_spacing(10) 152 153 self.always_show = False 154 self.revealers = [] 155 156 if title or subtitle: 157 header_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 158 header_box.set_spacing(5) 159 self.add(header_box) 160 161 if title: 162 label = Gtk.Label() 163 label.set_markup("<b>%s</b>" % title) 164 label.set_alignment(0, 0.5) 165 header_box.add(label) 166 167 if subtitle: 168 sub = Gtk.Label() 169 sub.set_text(subtitle) 170 sub.get_style_context().add_class("dim-label") 171 sub.set_alignment(0, 0.5) 172 header_box.add(sub) 173 174 self.frame = Gtk.Frame() 175 self.frame.set_no_show_all(True) 176 self.frame.set_shadow_type(Gtk.ShadowType.IN) 177 frame_style = self.frame.get_style_context() 178 frame_style.add_class("view") 179 self.size_group = Gtk.SizeGroup() 180 self.size_group.set_mode(Gtk.SizeGroupMode.VERTICAL) 181 182 self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 183 self.frame.add(self.box) 184 self.add(self.frame) 185 186 self.need_separator = False 187 188 def add_row(self, widget): 189 vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 190 if self.need_separator: 191 vbox.add(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)) 192 list_box = Gtk.ListBox() 193 list_box.set_selection_mode(Gtk.SelectionMode.NONE) 194 row = Gtk.ListBoxRow(can_focus=False) 195 row.add(widget) 196 if isinstance(widget, Switch): 197 list_box.connect("row-activated", widget.clicked) 198 list_box.add(row) 199 vbox.add(list_box) 200 self.box.add(vbox) 201 202 self.update_always_show_state() 203 204 self.need_separator = True 205 206 def add_reveal_row(self, widget, schema=None, key=None, values=None, check_func=None, revealer=None): 207 vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) 208 if self.need_separator: 209 vbox.add(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)) 210 list_box = Gtk.ListBox() 211 list_box.set_selection_mode(Gtk.SelectionMode.NONE) 212 row = Gtk.ListBoxRow(can_focus=False) 213 row.add(widget) 214 if isinstance(widget, Switch): 215 list_box.connect("row-activated", widget.clicked) 216 list_box.add(row) 217 vbox.add(list_box) 218 if revealer is None: 219 revealer = SettingsRevealer(schema, key, values, check_func) 220 widget.revealer = revealer 221 revealer.add(vbox) 222 self.box.add(revealer) 223 224 self.need_separator = True 225 226 self.revealers.append(revealer) 227 if not self.always_show: 228 revealer.notify_id = revealer.connect('notify::child-revealed', self.check_reveal_state) 229 self.check_reveal_state() 230 231 return revealer 232 233 def add_note(self, text): 234 label = Gtk.Label() 235 label.set_alignment(0, 0.5) 236 label.set_markup(text) 237 label.set_line_wrap(True) 238 self.add(label) 239 return label 240 241 def update_always_show_state(self): 242 if self.always_show: 243 return 244 245 self.frame.set_no_show_all(False) 246 self.frame.show_all() 247 self.always_show = True 248 249 for revealer in self.revealers: 250 revealer.disconnect(revealer.notify_id) 251 252 def check_reveal_state(self, *args): 253 for revealer in self.revealers: 254 if revealer.props.child_revealed: 255 self.box.show_all() 256 self.frame.show() 257 return 258 259 self.frame.hide() 260 261class SettingsWidget(Gtk.Box): 262 def __init__(self, dep_key=None): 263 Gtk.Box.__init__(self) 264 self.set_orientation(Gtk.Orientation.HORIZONTAL) 265 self.set_spacing(20) 266 self.set_border_width(5) 267 self.set_margin_left(20) 268 self.set_margin_right(20) 269 270 if dep_key: 271 self.set_dep_key(dep_key) 272 273 def set_dep_key(self, dep_key): 274 flag = Gio.SettingsBindFlags.GET 275 if dep_key[0] == "!": 276 dep_key = dep_key[1:] 277 flag |= Gio.Settings.BindFlags.INVERT_BOOLEAN 278 279 split = dep_key.split("/") 280 dep_settings = Gio.Settings.new(split[0]) 281 dep_settings.bind(split[1], self, "sensitive", flag) 282 283 def add_to_size_group(self, group): 284 group.add_widget(self.content_widget) 285 286 def fill_row(self): 287 self.set_border_width(0) 288 self.set_margin_left(0) 289 self.set_margin_right(0) 290 291 def get_settings(self, schema): 292 global settings_objects 293 try: 294 return settings_objects[schema] 295 except: 296 settings_objects[schema] = Gio.Settings.new(schema) 297 return settings_objects[schema] 298 299class SettingsLabel(Gtk.Label): 300 def __init__(self, text=None): 301 Gtk.Label.__init__(self) 302 if text: 303 self.set_label(text) 304 305 self.set_alignment(0.0, 0.5) 306 self.set_line_wrap(True) 307 308 def set_label_text(self, text): 309 self.set_label(text) 310 311class Switch(SettingsWidget): 312 bind_prop = "active" 313 bind_dir = Gio.SettingsBindFlags.DEFAULT 314 315 def __init__(self, label, dep_key=None, tooltip=""): 316 super(Switch, self).__init__(dep_key=dep_key) 317 318 self.content_widget = Gtk.Switch(valign=Gtk.Align.CENTER) 319 self.label = SettingsLabel(label) 320 self.pack_start(self.label, False, False, 0) 321 self.pack_end(self.content_widget, False, False, 0) 322 323 self.set_tooltip_text(tooltip) 324 325 def clicked(self, *args): 326 if self.is_sensitive(): 327 self.content_widget.set_active(not self.content_widget.get_active()) 328 329class SpinButton(SettingsWidget): 330 bind_prop = "value" 331 bind_dir = Gio.SettingsBindFlags.GET 332 333 def __init__(self, label, units="", mini=None, maxi=None, step=1, page=None, size_group=None, dep_key=None, tooltip=""): 334 super(SpinButton, self).__init__(dep_key=dep_key) 335 336 self.timer = None 337 338 if units: 339 label += " (%s)" % units 340 self.label = SettingsLabel(label) 341 self.content_widget = Gtk.SpinButton() 342 343 self.pack_start(self.label, False, False, 0) 344 self.pack_end(self.content_widget, False, False, 0) 345 346 range = self.get_range() 347 if mini == None or maxi == None: 348 mini = range[0] 349 maxi = range[1] 350 elif range is not None: 351 mini = max(mini, range[0]) 352 maxi = min(maxi, range[1]) 353 354 if not page: 355 page = step 356 357 self.content_widget.set_range(mini, maxi) 358 self.content_widget.set_increments(step, page) 359 360 digits = 0 361 if (step and '.' in str(step)): 362 digits = len(str(step).split('.')[1]) 363 self.content_widget.set_digits(digits) 364 365 self.content_widget.connect("value-changed", self.apply_later) 366 367 self.set_tooltip_text(tooltip) 368 369 if size_group: 370 self.add_to_size_group(size_group) 371 372 def apply_later(self, *args): 373 def apply(self): 374 self.set_value(self.content_widget.get_value()) 375 self.timer = None 376 377 if self.timer: 378 GLib.source_remove(self.timer) 379 self.timer = GLib.timeout_add(300, apply, self) 380 381class Entry(SettingsWidget): 382 bind_prop = "text" 383 bind_dir = Gio.SettingsBindFlags.DEFAULT 384 385 def __init__(self, label, expand_width=False, size_group=None, dep_key=None, tooltip=""): 386 super(Entry, self).__init__(dep_key=dep_key) 387 388 self.label = SettingsLabel(label) 389 self.content_widget = Gtk.Entry() 390 self.content_widget.set_valign(Gtk.Align.CENTER) 391 392 self.pack_start(self.label, False, False, 0) 393 self.pack_end(self.content_widget, expand_width, expand_width, 0) 394 395 self.set_tooltip_text(tooltip) 396 397 if size_group: 398 self.add_to_size_group(size_group) 399 400class TextView(SettingsWidget): 401 bind_prop = "text" 402 bind_dir = Gio.SettingsBindFlags.DEFAULT 403 404 def __init__(self, label, height=200, dep_key=None, tooltip=""): 405 super(TextView, self).__init__(dep_key=dep_key) 406 407 self.set_orientation(Gtk.Orientation.VERTICAL) 408 self.set_spacing(8) 409 410 self.label = Gtk.Label.new(label) 411 self.label.set_halign(Gtk.Align.CENTER) 412 413 self.scrolledwindow = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) 414 self.scrolledwindow.set_size_request(width=-1, height=height) 415 self.scrolledwindow.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC, 416 vscrollbar_policy=Gtk.PolicyType.AUTOMATIC) 417 self.scrolledwindow.set_shadow_type(type=Gtk.ShadowType.ETCHED_IN) 418 self.content_widget = Gtk.TextView() 419 self.content_widget.set_border_width(3) 420 self.content_widget.set_wrap_mode(wrap_mode=Gtk.WrapMode.NONE) 421 self.bind_object = self.content_widget.get_buffer() 422 423 self.pack_start(self.label, False, False, 0) 424 self.add(self.scrolledwindow) 425 self.scrolledwindow.add(self.content_widget) 426 self._value_changed_timer = None 427 428class FontButton(SettingsWidget): 429 bind_prop = "font-name" 430 bind_dir = Gio.SettingsBindFlags.DEFAULT 431 432 def __init__(self, label, size_group=None, dep_key=None, tooltip=""): 433 super(FontButton, self).__init__(dep_key=dep_key) 434 435 self.label = SettingsLabel(label) 436 437 self.content_widget = Gtk.FontButton() 438 self.content_widget.set_valign(Gtk.Align.CENTER) 439 440 self.pack_start(self.label, False, False, 0) 441 self.pack_end(self.content_widget, False, False, 0) 442 443 self.set_tooltip_text(tooltip) 444 445 if size_group: 446 self.add_to_size_group(size_group) 447 448class Range(SettingsWidget): 449 bind_prop = "value" 450 bind_dir = Gio.SettingsBindFlags.GET | Gio.SettingsBindFlags.NO_SENSITIVITY 451 452 def __init__(self, label, min_label="", max_label="", mini=None, maxi=None, step=None, invert=False, log=False, show_value=True, dep_key=None, tooltip="", flipped=False, units=""): 453 super(Range, self).__init__(dep_key=dep_key) 454 455 self.set_orientation(Gtk.Orientation.VERTICAL) 456 self.set_spacing(0) 457 458 self.log = log 459 self.invert = invert 460 self.flipped = flipped 461 self.timer = None 462 self.value = 0 463 464 hbox = Gtk.Box() 465 466 if units: 467 label += " ({})".format(units) 468 469 self.label = Gtk.Label.new(label) 470 self.label.set_halign(Gtk.Align.CENTER) 471 472 self.min_label= Gtk.Label() 473 self.max_label = Gtk.Label() 474 self.min_label.set_alignment(1.0, 0.75) 475 self.max_label.set_alignment(1.0, 0.75) 476 self.min_label.set_margin_right(6) 477 self.max_label.set_margin_left(6) 478 self.min_label.set_markup("<i><small>%s</small></i>" % min_label) 479 self.max_label.set_markup("<i><small>%s</small></i>" % max_label) 480 481 range = self.get_range() 482 if mini == None or maxi == None: 483 mini = range[0] 484 maxi = range[1] 485 elif range is not None: 486 mini = max(mini, range[0]) 487 maxi = min(maxi, range[1]) 488 489 if log: 490 mini = math.log(mini) 491 maxi = math.log(maxi) 492 if self.flipped: 493 self.map_get = lambda x: -1 * (math.log(x)) 494 self.map_set = lambda x: math.exp(x) 495 else: 496 self.map_get = lambda x: math.log(x) 497 self.map_set = lambda x: math.exp(x) 498 elif self.flipped: 499 self.map_get = lambda x: x * -1 500 self.map_set = lambda x: x * -1 501 502 if self.flipped: 503 tmp_mini = mini 504 mini = maxi * -1 505 maxi = tmp_mini * -1 506 507 if step is None: 508 self.step = (maxi - mini) * 0.02 509 else: 510 self.step = math.log(step) if log else step 511 512 self.content_widget = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, mini, maxi, self.step) 513 self.content_widget.set_inverted(invert) 514 self.content_widget.set_draw_value(show_value and not self.flipped) 515 self.bind_object = self.content_widget.get_adjustment() 516 517 if invert: 518 self.step *= -1 # Gtk.Scale.new_with_range want a positive value, but our custom scroll handler wants a negative value 519 520 hbox.pack_start(self.min_label, False, False, 0) 521 hbox.pack_start(self.content_widget, True, True, 0) 522 hbox.pack_start(self.max_label, False, False, 0) 523 524 self.pack_start(self.label, False, False, 0) 525 self.pack_start(hbox, True, True, 6) 526 527 self.content_widget.connect("scroll-event", self.on_scroll_event) 528 self.content_widget.connect("value-changed", self.apply_later) 529 530 self.set_tooltip_text(tooltip) 531 532 def apply_later(self, *args): 533 def apply(self): 534 if self.log: 535 self.set_value(math.exp(abs(self.content_widget.get_value()))) 536 else: 537 if self.flipped: 538 self.set_value(self.content_widget.get_value() * -1) 539 else: 540 self.set_value(self.content_widget.get_value()) 541 self.timer = None 542 543 if self.timer: 544 GLib.source_remove(self.timer) 545 self.timer = GLib.timeout_add(300, apply, self) 546 547 def on_scroll_event(self, widget, event): 548 found, delta_x, delta_y = event.get_scroll_deltas() 549 550 # If you scroll up, delta_y < 0. This is a weird world 551 widget.set_value(widget.get_value() - delta_y * self.step) 552 553 return True 554 555 def add_mark(self, value, position, markup): 556 if self.log: 557 self.content_widget.add_mark(math.log(value), position, markup) 558 else: 559 self.content_widget.add_mark(value, position, markup) 560 561 def set_rounding(self, digits): 562 if not self.log: 563 self.content_widget.set_round_digits(digits) 564 self.content_widget.set_digits(digits) 565 566class ComboBox(SettingsWidget): 567 bind_dir = None 568 569 def __init__(self, label, options=[], valtype=None, separator=None, size_group=None, dep_key=None, tooltip=""): 570 super(ComboBox, self).__init__(dep_key=dep_key) 571 572 self.valtype = valtype 573 self.separator = separator 574 self.option_map = {} 575 576 self.label = SettingsLabel(label) 577 578 self.content_widget = Gtk.ComboBox() 579 renderer_text = Gtk.CellRendererText() 580 self.content_widget.pack_start(renderer_text, True) 581 self.content_widget.add_attribute(renderer_text, "text", 1) 582 583 self.pack_start(self.label, False, False, 0) 584 self.pack_end(self.content_widget, False, False, 0) 585 self.content_widget.set_valign(Gtk.Align.CENTER) 586 587 self.set_options(options) 588 589 if separator: 590 self.content_widget.set_row_separator_func(self.is_separator_row) 591 592 self.set_tooltip_text(tooltip) 593 594 if size_group: 595 self.add_to_size_group(size_group) 596 597 def on_my_value_changed(self, widget): 598 tree_iter = widget.get_active_iter() 599 if tree_iter != None: 600 self.value = self.model[tree_iter][0] 601 self.set_value(self.value) 602 603 def on_setting_changed(self, *args): 604 self.value = self.get_value() 605 try: 606 self.content_widget.set_active_iter(self.option_map[self.value]) 607 except: 608 self.content_widget.set_active_iter(None) 609 610 def connect_widget_handlers(self, *args): 611 self.content_widget.connect('changed', self.on_my_value_changed) 612 613 def set_options(self, options): 614 if self.valtype is not None: 615 var_type = self.valtype 616 else: 617 # assume all keys are the same type (mixing types is going to cause an error somewhere) 618 var_type = type(options[0][0]) 619 self.model = Gtk.ListStore(var_type, str) 620 621 for option in options: 622 self.option_map[option[0]] = self.model.append([option[0], option[1]]) 623 624 self.content_widget.set_model(self.model) 625 self.content_widget.set_id_column(0) 626 627 def is_separator_row(self, model, tree_iter): 628 if model[tree_iter][0] == self.separator: 629 return True 630 else: 631 return False 632 633class ColorChooser(SettingsWidget): 634 bind_dir = None 635 636 def __init__(self, label, legacy_string=False, size_group=None, dep_key=None, tooltip=""): 637 super(ColorChooser, self).__init__(dep_key=dep_key) 638 # note: Gdk.Color is deprecated in favor of Gdk.RGBA, but as the hex format is still used 639 # in some places (most notably the desktop background handling in cinnamon-desktop) we 640 # still support it for now by adding the legacy_string argument 641 self.legacy_string = legacy_string 642 643 self.label = SettingsLabel(label) 644 self.content_widget = Gtk.ColorButton() 645 self.content_widget.set_use_alpha(True) 646 self.pack_start(self.label, False, False, 0) 647 self.pack_end(self.content_widget, False, False, 0) 648 649 self.set_tooltip_text(tooltip) 650 651 if size_group: 652 self.add_to_size_group(size_group) 653 654 def on_setting_changed(self, *args): 655 color_string = self.get_value() 656 rgba = Gdk.RGBA() 657 rgba.parse(color_string) 658 self.content_widget.set_rgba(rgba) 659 660 def connect_widget_handlers(self, *args): 661 self.content_widget.connect('color-set', self.on_my_value_changed) 662 663 def on_my_value_changed(self, widget): 664 if self.legacy_string: 665 color_string = self.content_widget.get_color().to_string() 666 else: 667 color_string = self.content_widget.get_rgba().to_string() 668 self.set_value(color_string) 669 670class FileChooser(SettingsWidget): 671 bind_dir = None 672 673 def __init__(self, label, dir_select=False, size_group=None, dep_key=None, tooltip=""): 674 super(FileChooser, self).__init__(dep_key=dep_key) 675 if dir_select: 676 action = Gtk.FileChooserAction.SELECT_FOLDER 677 else: 678 action = Gtk.FileChooserAction.OPEN 679 680 self.label = SettingsLabel(label) 681 self.content_widget = Gtk.FileChooserButton(action=action) 682 self.pack_start(self.label, False, False, 0) 683 self.pack_end(self.content_widget, False, False, 0) 684 685 self.set_tooltip_text(tooltip) 686 687 if size_group: 688 self.add_to_size_group(size_group) 689 690 def on_file_selected(self, *args): 691 self.set_value(self.content_widget.get_uri()) 692 693 def on_setting_changed(self, *args): 694 self.content_widget.set_uri(self.get_value()) 695 696 def connect_widget_handlers(self, *args): 697 self.content_widget.connect("file-set", self.on_file_selected) 698 699class IconChooser(SettingsWidget): 700 bind_prop = "icon" 701 bind_dir = Gio.SettingsBindFlags.DEFAULT 702 703 def __init__(self, label, default_icon=None, icon_categories=[], default_category=None, expand_width=False, size_group=None, dep_key=None, tooltip=""): 704 super(IconChooser, self).__init__(dep_key=dep_key) 705 706 self.label = SettingsLabel(label) 707 708 self.content_widget = XApp.IconChooserButton() 709 self.content_widget.set_icon_size(Gtk.IconSize.BUTTON) 710 711 dialog = self.content_widget.get_dialog() 712 if default_icon: 713 dialog.set_default_icon(default_icon) 714 715 for category in icon_categories: 716 dialog.add_custom_category(category['name'], category['icons']) 717 718 if default_category is not None: 719 self.content_widget.set_default_category(default_category) 720 721 self.pack_start(self.label, False, False, 0) 722 self.pack_end(self.content_widget, expand_width, expand_width, 0) 723 724 self.set_tooltip_text(tooltip) 725 726 if size_group: 727 self.add_to_size_group(size_group) 728 729class Button(SettingsWidget): 730 def __init__(self, label, callback=None): 731 super(Button, self).__init__() 732 self.label = label 733 self.callback = callback 734 735 self.content_widget = Gtk.Button(label=label) 736 self.pack_start(self.content_widget, True, True, 0) 737 self.content_widget.connect("clicked", self._on_button_clicked) 738 739 def _on_button_clicked(self, *args): 740 if self.callback is not None: 741 self.callback(self) 742 elif hasattr(self, "on_activated"): 743 self.on_activated() 744 else: 745 print("warning: button '%s' does nothing" % self.label) 746 747 def set_label(self, label): 748 self.label = label 749 self.content_widget.set_label(label) 750 751class Text(SettingsWidget): 752 def __init__(self, label, align=Gtk.Align.START): 753 super(Text, self).__init__() 754 self.label = label 755 756 if align == Gtk.Align.END: 757 xalign = 1.0 758 justification = Gtk.Justification.RIGHT 759 elif align == Gtk.Align.CENTER: 760 xalign = 0.5 761 justification = Gtk.Justification.CENTER 762 else: # START and FILL align left 763 xalign = 0 764 justification = Gtk.Justification.LEFT 765 766 self.content_widget = Gtk.Label(label, halign=align, xalign=xalign, justify=justification) 767 self.content_widget.set_line_wrap(True) 768 self.pack_start(self.content_widget, True, True, 0) 769