1'''
2Defines the preferences dialog.
3
4@author: Eitan Isaacson
5@organization: Mozilla Foundation
6@copyright: Copyright (c) 2006, 2007 Mozilla Foundation
7@license: BSD
8
9All rights reserved. This program and the accompanying materials are made
10available under the terms of the BSD which accompanies this distribution, and
11is available at U{http://www.opensource.org/licenses/bsd-license.php}
12'''
13
14import gi
15
16from gi.repository import Gtk as gtk
17from gi.repository import Gdk as gdk
18from gi.repository import Atk as atk
19from gi.repository.Gio import Settings as GSettings
20
21from .i18n import _
22from . import node
23from .tools import parseColorString
24
25class AccerciserPreferencesDialog(gtk.Dialog):
26  '''
27  Class that creates a preferences dialog.
28  '''
29  def __init__(self, plugins_view=None, hotkeys_view=None):
30    '''
31    Initialize a preferences dialog.
32
33    @param plugins_view: Treeview of plugins.
34    @type plugins_view: L{PluginManager._View}
35    @param hotkeys_view: Treeview of global hotkeys.
36    @type hotkeys_view: L{HotkeyTreeView}
37    '''
38    gtk.Dialog.__init__(self, title=_('accerciser Preferences'))
39    self.add_buttons(gtk.STOCK_CLOSE, gtk.ResponseType.CLOSE)
40    self.connect('response', self._onResponse)
41    self.set_default_size(500, 250)
42    notebook = gtk.Notebook()
43    vbox = self.get_children()[0]
44    vbox.pack_start(notebook, True, True, 2)
45    for view, section in [(plugins_view, _('Plugins')),
46                          (hotkeys_view, _('Global Hotkeys'))]:
47      if view is not None:
48        sw = gtk.ScrolledWindow()
49        sw.set_shadow_type(gtk.ShadowType.IN)
50        sw.set_policy(gtk.PolicyType.AUTOMATIC, gtk.PolicyType.AUTOMATIC)
51        sw.set_size_request(500, 150)
52        sw.add(view)
53        notebook.append_page(sw, gtk.Label.new(section))
54
55    notebook.append_page(_HighlighterView(), gtk.Label.new(_('Highlighting')))
56
57  def _onResponse(self, dialog, response_id):
58    '''
59    Callback for dialog responses, always destroy it.
60
61    @param dialog: This dialog.
62    @type dialog: L{AccerciserPreferencesDialog}
63    @param response_id: Response ID recieved.
64    @type response_id: integer
65    '''
66    dialog.destroy()
67
68class _HighlighterView(gtk.Alignment):
69  '''
70  A container widget with the settings for the highlighter.
71  '''
72  def __init__(self):
73    gtk.Alignment.__init__(self)
74    self.set_padding(12, 12, 18, 12)
75    self.gsettings = GSettings.new('org.a11y.Accerciser')
76    self._buildUI()
77
78  def _buildUI(self):
79    '''
80    Programatically build the UI.
81    '''
82    table = gtk.Table.new(3, 2, True)
83    table.set_col_spacings(6)
84    self.add(table)
85    labels = [None, None, None]
86    controls = [None, None, None]
87    labels[0] = gtk.Label.new(_('Highlight duration:'))
88    controls[0] = gtk.SpinButton()
89    controls[0].set_range(0.01, 5)
90    controls[0].set_digits(2)
91    controls[0].set_value(self.gsettings.get_double('highlight-duration'))
92    controls[0].set_increments(0.01, 0.1)
93    controls[0].connect('value-changed', self._onDurationChanged)
94    labels[1] = gtk.Label.new(_('Border color:'))
95    controls[1] = self._ColorButton(node.BORDER_COLOR, node.BORDER_ALPHA)
96    controls[1].connect('color-set', self._onColorSet, 'highlight-border')
97    controls[1].set_tooltip_text(_('The border color of the highlight box'))
98    labels[2] = gtk.Label.new(_('Fill color:'))
99    controls[2] = self._ColorButton(node.FILL_COLOR, node.FILL_ALPHA)
100    controls[2].connect('color-set', self._onColorSet, 'highlight-fill')
101    controls[2].set_tooltip_text(_('The fill color of the highlight box'))
102
103    for label, control, row in zip(labels, controls, range(3)):
104      label.set_alignment(0, 0.5)
105      table.attach(label, 0, 1, row, row + 1, gtk.AttachOptions.FILL)
106      table.attach(control, 1, 2, row, row + 1, gtk.AttachOptions.FILL)
107
108    for label, control in zip([x.get_accessible() for x in labels],
109                              [x.get_accessible() for x in controls]):
110      label.add_relationship(atk.RelationType.LABEL_FOR, control)
111      control.add_relationship(atk.RelationType.LABELLED_BY, label)
112
113  def _onDurationChanged(self, spin_button):
114    '''
115    Callback for the duration spin button. Update key and the global variable
116    in the L{node} module.
117
118    @param spin_button: The spin button that emitted the value-changed signal.
119    @type spin_button: gtk.SpinButton
120    '''
121    node.HL_DURATION = int(spin_button.get_value()*1000)
122    self.gsettings.set_double('highlight-duration',
123                            spin_button.get_value())
124
125
126  def _onColorSet(self, color_button, key):
127    '''
128    Callback for a color button. Update gsettings and the global variables
129    in the L{node} module.
130
131    @param color_button: The color button that emitted the color-set signal.
132    @type color_button: l{_HighlighterView._ColorButton}
133    @param key: the key name suffix for this color setting.
134    @type key: string
135    '''
136    if 'fill' in key:
137      node.FILL_COLOR = color_button.get_rgb_string()
138      node.FILL_ALPHA = color_button.get_alpha_float()
139    else:
140      node.BORDER_COLOR = color_button.get_rgb_string()
141      node.BORDER_ALPHA = color_button.get_alpha_float()
142
143    self.gsettings.set_string(key, color_button.get_rgba_string())
144
145  class _ColorButton(gtk.ColorButton):
146    '''
147    ColorButton derivative with useful methods for us.
148    '''
149    def __init__(self, color, alpha):
150      color = gdk.color_parse(color)
151      gtk.ColorButton.__init__(self)
152      self.set_use_alpha(True)
153      self.set_alpha(int(alpha*0xffff))
154      self.set_color(color)
155
156    def get_rgba_string(self):
157      '''
158      Get the current color and alpha in string format.
159
160      @return: String in the format of #rrggbbaa.
161      @rtype: string.
162      '''
163      color = self.get_color()
164      color_val = 0
165      color_val |= color.red >> 8 << 24
166      color_val |= color.green >> 8 << 16
167      color_val |= color.blue >> 8 << 8
168      color_val |= self.get_alpha() >> 8
169      return \
170          '#' + hex(color_val).replace('0x', '').replace('L', '').rjust(8, '0')
171
172    def get_rgb_string(self):
173      '''
174      Get the current color in string format.
175
176      @return: String in the format of #rrggbb.
177      @rtype: string.
178      '''
179      color = self.get_color()
180      color_val = 0
181      color_val |= color.red >> 8 << 16
182      color_val |= color.green >> 8 << 8
183      color_val |= color.blue >> 8
184      return \
185          '#' + hex(color_val).replace('0x', '').replace('L', '').rjust(6, '0')
186
187    def get_alpha_float(self):
188      '''
189      Get the current alpha as a value from 0.0 to 1.0.
190      '''
191      return self.get_alpha()/float(0xffff)
192