"""The OptionsBox widget is used to edit an OptionGroup.
For simple applications, rox.edit_options() provides an
easy way to edit the options.
You can add new types of option by appending to widget_registry (new
in ROX-Lib 1.9.13). Return a list of widgets (which are packed into either an
HBox or a VBox). For example, to add a button widget:
def build_button(box, node, label):
button = g.Button(label)
box.may_add_tip(button, node)
button.connect('clicked', my_button_handler)
return [button]
OptionsBox.widget_registry['button'] = build_button
You can then create such a button in Options.xml with:
Any element may have a 'size-group' attribute. Certain widgets (labels in
particular) in the same size group all have the same size.
For widgets that have options, your build function will be called with
the option as a third parameter. You should register get and set methods,
and arrange for box.check_widget to be called when the user changes the
value:
def build_toggle(box, node, label, option):
toggle = g.CheckButton(label)
box.may_add_tip(toggle, node)
box.handlers[option] = (
lambda: str(toggle.get_active()),
lambda: toggle.set_active(option.int_value))
toggle.connect('toggled', lambda w: box.check_widget(option))
return [toggle]
OptionsBox.widget_registry['mytoggle'] = build_toggle
"""
from rox import g, options, _
import rox
from xml.dom import Node, minidom
import gobject
REVERT = 1
# Functions for extracting data from XML nodes
def data(node):
"""Return all the text directly inside this DOM Node."""
return ''.join([text.nodeValue for text in node.childNodes
if text.nodeType == Node.TEXT_NODE])
def bool_attr(node, name, val=False):
"""Interpret node attribute as a boolean value"""
try:
v=node.getAttribute(name)
if v=='yes':
return True
else:
return False
except:
pass
return val
def str_attr(node, name, val=''):
"""Get string value of node attribute"""
try:
val=node.getAttribute(name)
except:
pass
return val
class OptionsBox(g.Dialog):
"""A dialog box which lets the user edit the options. The file
Options.xml specifies the layout of this box."""
tips = None # GtkTooltips
options = None # The OptionGroup we are editing
revert = None # Option -> old value
handlers = None # Option -> (get, set)
trans = None # Translation function (application's, not ROX-Lib's)
def __init__(self, options_group, options_xml, translation = None):
"""options_xml is an XML file, usually /Options.xml,
which defines the layout of the OptionsBox.
It contains an root element containing (nested)
elements. Each contains a number of widgets,
some of which correspond to options. The build_* functions are
used to create them.
Example:
When saving an untitled file, use this name as the default.
...
"""
assert isinstance(options_group, options.OptionGroup)
if translation is None:
import __main__
if hasattr(__main__.__builtins__, '_'):
translation = __main__.__builtins__._
else:
translation = lambda x: x
self.trans = translation
g.Dialog.__init__(self)
self.tips = g.Tooltips()
self.set_has_separator(False)
self.options = options_group
self.set_title((_('%s options')) % options_group.program)
self.set_position(g.WIN_POS_CENTER)
button = rox.ButtonMixed(g.STOCK_UNDO, _('_Revert'))
self.add_action_widget(button, REVERT)
self.tips.set_tip(button, _('Restore all options to how they were '
'when the window was opened'))
self.add_button(g.STOCK_OK, g.RESPONSE_OK)
self.set_default_response(g.RESPONSE_OK)
doc = minidom.parse(options_xml)
assert doc.documentElement.localName == 'options'
self.handlers = {} # Option -> (get, set)
self.revert = {} # Option -> old value
self.size_groups = {} # Name -> GtkSizeGroup
self.current_size_group = None
sections = []
for section in doc.documentElement.childNodes:
if section.nodeType != Node.ELEMENT_NODE:
continue
if section.localName != 'section':
print "Unknown section", section
continue
sections.append(section)
self.build_window_frame(add_frame = len(sections) > 1)
# Add each section
for section in sections:
self.build_section(section, None)
if len(sections) > 1:
self.tree_view.expand_all()
else:
self.sections_swin.hide()
self.updating = 0
def destroyed(widget):
rox.toplevel_unref()
if self.changed():
try:
self.options.save()
except:
rox.report_exception()
self.connect('destroy', destroyed)
def got_response(widget, response):
if response == int(g.RESPONSE_OK):
self.destroy()
elif response == REVERT:
for o in self.options:
o._set(self.revert[o])
self.update_widgets()
self.options.notify()
self.update_revert()
self.connect('response', got_response)
def open(self):
"""Show the window, updating all the widgets at the same
time. Use this instead of show()."""
rox.toplevel_ref()
for option in self.options:
self.revert[option] = option.value
self.update_widgets()
self.update_revert()
self.show()
def update_revert(self):
"Shade/unshade the Revert button. Internal."
self.set_response_sensitive(REVERT, self.changed())
def changed(self):
"""Check whether any options have different values (ie, whether Revert
will do anything)."""
for option in self.options:
if option.value != self.revert[option]:
return True
return False
def update_widgets(self):
"Make widgets show current values. Internal."
assert not self.updating
self.updating = 1
try:
for option in self.options:
try:
handler = self.handlers[option][1]
except KeyError:
print "No widget for option '%s'!" % option
else:
handler()
finally:
self.updating = 0
def build_window_frame(self, add_frame = True):
"Create the main structure of the window."
hbox = g.HBox(False, 4)
self.vbox.pack_start(hbox, True, True, 0)
# scrolled window for the tree view
sw = g.ScrolledWindow()
sw.set_shadow_type(g.SHADOW_IN)
sw.set_policy(g.POLICY_NEVER, g.POLICY_AUTOMATIC)
hbox.pack_start(sw, False, True, 0)
self.sections_swin = sw # Used to hide it...
# tree view
model = g.TreeStore(gobject.TYPE_STRING, gobject.TYPE_INT)
tv = g.TreeView(model)
sel = tv.get_selection()
sel.set_mode(g.SELECTION_BROWSE)
tv.set_headers_visible(False)
self.sections = model
self.tree_view = tv
tv.unset_flags(g.CAN_FOCUS) # Stop irritating highlight
# Add a column to display column 0 of the store...
cell = g.CellRendererText()
column = g.TreeViewColumn('Section', cell, text = 0)
tv.append_column(column)
sw.add(tv)
# main options area
notebook = g.Notebook()
notebook.set_show_tabs(False)
notebook.set_show_border(False)
self.notebook = notebook
if add_frame:
frame = g.Frame()
frame.set_shadow_type(g.SHADOW_IN)
hbox.pack_start(frame, True, True, 0)
frame.add(notebook)
else:
hbox.pack_start(notebook, True, True, 0)
# Flip pages
def change_page(sel, notebook):
selected = sel.get_selected()
if not selected:
return
model, titer = selected
page = model.get_value(titer, 1)
notebook.set_current_page(page)
sel.connect('changed', change_page, notebook)
self.vbox.show_all()
def check_widget(self, option):
"A widgets call this when the user changes its value."
if self.updating:
return
assert isinstance(option, options.Option)
new = self.handlers[option][0]()
if new == option.value:
return
option._set(new)
self.options.notify()
self.update_revert()
def build_section(self, section, parent):
"""Create a new page for the notebook and a new entry in the
sections tree, and build all the widgets inside the page."""
page = g.VBox(False, 4)
page.set_border_width(4)
self.notebook.append_page(page, g.Label('unused'))
titer = self.sections.append(parent)
self.sections.set(titer,
0, self.trans(section.getAttribute('title')),
1, self.notebook.page_num(page))
for node in section.childNodes:
if node.nodeType != Node.ELEMENT_NODE:
continue
name = node.localName
if name == 'section':
self.build_section(node, titer)
else:
self.build_widget(node, page)
page.show_all()
def build_widget(self, node, box):
"""Dispatches the job of dealing with a DOM Node to the
appropriate build_* function."""
label = node.getAttribute('label')
name = node.getAttribute('name')
if label:
label = self.trans(label)
old_size_group = self.current_size_group
sg = node.getAttributeNode('size-group')
if sg is not None:
self.current_size_group = sg.value or None
option = None
if name:
try:
option = self.options.options[name]
except KeyError:
raise Exception("Unknown option '%s'" % name)
# Check for a new-style function in the registry...
new_fn = widget_registry.get(node.localName, None)
if new_fn:
# Wrap it up so it appears old-style
fn = lambda *args: new_fn(self, *args)
else:
# Not in the registry... look in the class instead
try:
name = node.localName.replace('-', '_')
fn = getattr(self, 'build_' + name)
except AttributeError:
fn = self.build_unknown
if option:
widgets = fn(node, label, option)
else:
widgets = fn(node, label)
for w in widgets:
if hasattr(w, '_rox_lib_expand'):
expand=w._rox_lib_expand
else:
expand=False
box.pack_start(w, expand, True, 0)
self.current_size_group = old_size_group
def may_add_tip(self, widget, node):
"""If 'node' contains any text, use that as the tip for 'widget'."""
if node.childNodes:
data = ''.join([n.nodeValue for n in node.childNodes if n.nodeType == Node.TEXT_NODE]).strip()
else:
data = None
if data:
self.tips.set_tip(widget, self.trans(data))
def get_size_group(self, name):
"""Return the GtkSizeGroup for this name, creating one
if it doesn't currently exist."""
try:
return self.size_groups[name]
except KeyError:
group = g.SizeGroup(g.SIZE_GROUP_HORIZONTAL)
self.size_groups[name] = group
return group
def make_sized_label(self, label, suffix = ""):
"""Create a GtkLabel and add it to the current size-group, if any"""
widget = g.Label(label)
if self.current_size_group:
widget.set_alignment(1.0, 0.5)
group = self.get_size_group(self.current_size_group + suffix)
group.add_widget(widget)
return widget
# Each type of widget has a method called 'build_NAME' where name is
# the XML element name. This method is called as method(node, label,
# option) if it corresponds to an Option, or method(node, label)
# otherwise. It should return a list of widgets to add to the window
# and, if it's for an Option, set self.handlers[option] = (get, set).
def build_unknown(self, node, label, option = None):
return [g.Label("Unknown widget type <%s>" % node.localName)]
def build_label(self, node, label):
help_flag = int(node.getAttribute('help') or '0')
widget = self.make_sized_label(self.trans(data(node)))
if help_flag:
widget.set_alignment(0, 0.5)
else:
widget.set_alignment(0, 1)
widget.set_justify(g.JUSTIFY_LEFT)
widget.set_line_wrap(True)
if help_flag:
hbox = g.HBox(False, 4)
image = g.Image()
image.set_from_stock(g.STOCK_DIALOG_INFO,
g.ICON_SIZE_BUTTON)
align = g.Alignment(0, 0, 0, 0)
align.add(image)
hbox.pack_start(align, False, True, 0)
hbox.pack_start(widget, False, True, 0)
spacer = g.EventBox()
spacer.set_size_request(6, 6)
return [hbox, spacer]
return [widget]
def build_spacer(self, node, label):
""""""
eb = g.EventBox()
eb.set_size_request(8, 8)
return [eb]
def build_hbox(self, node, label):
"""... to layout child widgets horizontally."""
return self.do_box(node, label, g.HBox(False, 4))
def build_vbox(self, node, label):
"""... to layout child widgets vertically."""
return self.do_box(node, label, g.VBox(False, 0))
def do_box(self, node, label, widget):
"Helper function for building hbox, vbox and frame widgets."
if label:
widget.pack_start(self.make_sized_label(label),
False, True, 4)
for child in node.childNodes:
if child.nodeType == Node.ELEMENT_NODE:
self.build_widget(child, widget)
return [widget]
def build_frame(self, node, label):
"""... to group options under a heading."""
frame = g.Frame(label)
frame.set_shadow_type(g.SHADOW_NONE)
# Make the label bold...
# (bug in pygtk => use set_markup)
label_widget = frame.get_label_widget()
label_widget.set_markup('' + label + '')
#attr = pango.AttrWeight(pango.WEIGHT_BOLD)
#attr.start_index = 0
#attr.end_index = -1
#list = pango.AttrList()
#list.insert(attr)
#label_widget.set_attributes(list)
vbox = g.VBox(False, 4)
vbox.set_border_width(12)
frame.add(vbox)
self.do_box(node, None, vbox)
return [frame]
def do_entry(self, node, label, option):
"Helper function for entry and secretentry widgets"
box = g.HBox(False, 4)
entry = g.Entry()
if label:
label_wid = self.make_sized_label(label)
label_wid.set_alignment(1.0, 0.5)
box.pack_start(label_wid, False, True, 0)
box.pack_start(entry, True, True, 0)
else:
box = None
self.may_add_tip(entry, node)
entry.connect('changed', lambda e: self.check_widget(option))
def get():
return entry.get_chars(0, -1)
def set():
entry.set_text(option.value)
self.handlers[option] = (get, set)
return (entry, [box or entry])
def build_entry(self, node, label, option):
"Tooltip"
entry, result=self.do_entry(node, label, option)
return result
def build_secretentry(self, node, label, option):
"Tooltip"
entry, result=self.do_entry(node, label, option)
try:
ch=node.getAttribute('char')
if len(ch)>=1:
ch=ch[0]
else:
ch=u'\0'
except:
ch='*'
entry.set_visibility(False)
entry.set_invisible_char(ch)
return result
def build_font(self, node, label, option):
"Tooltip"
button = FontButton(self, option, label)
self.may_add_tip(button, node)
hbox = g.HBox(False, 4)
hbox.pack_start(self.make_sized_label(label), False, True, 0)
hbox.pack_start(button, False, True, 0)
self.handlers[option] = (button.get, button.set)
return [hbox]
def build_colour(self, node, label, option):
"Tooltip"
button = ColourButton(self, option, label)
self.may_add_tip(button, node)
hbox = g.HBox(False, 4)
hbox.pack_start(self.make_sized_label(label), False, True, 0)
hbox.pack_start(button, False, True, 0)
self.handlers[option] = (button.get, button.set)
return [hbox]
def build_numentry(self, node, label, option):
"""Tooltip.
Lets the user choose a number from min to max."""
minv = int(node.getAttribute('min'))
maxv = int(node.getAttribute('max'))
step = node.getAttribute('step')
unit = node.getAttribute('unit')
if step:
step = int(step)
else:
step = 1
if unit:
unit = self.trans(unit)
hbox = g.HBox(False, 4)
if label:
widget = self.make_sized_label(label)
widget.set_alignment(1.0, 0.5)
hbox.pack_start(widget, False, True, 0)
spin = g.SpinButton(g.Adjustment(minv, minv, maxv, step))
spin.set_width_chars(max(len(str(minv)), len(str(maxv))))
hbox.pack_start(spin, False, True, 0)
self.may_add_tip(spin, node)
if unit:
hbox.pack_start(g.Label(unit), False, True, 0)
self.handlers[option] = (
lambda: str(spin.get_value()),
lambda: spin.set_value(option.int_value))
spin.connect('value-changed', lambda w: self.check_widget(option))
return [hbox]
def build_filechooser(self, node, label, option):
"""Tooltip.
Lets the user choose a file (using a GtkFileChooser or by drag-and-drop).
Note: requires GTK >= 2.6
"""
filebutton = g.FileChooserButton(label)
eb = g.EventBox()
eb.add(filebutton)
self.may_add_tip(eb, node)
clearbutton = g.Button(stock = g.STOCK_CLEAR)
hbox = g.HBox(False, 4)
if label:
hbox.pack_start(g.Label(label + ":"), False, True, 0)
hbox.pack_start(eb, True, True, 0)
hbox.pack_start(clearbutton, False, True, 0)
self.handlers[option] = (
lambda: filebutton.get_filename(),
lambda: filebutton.set_filename(option.value))
filebutton.connect('selection-changed', lambda w: self.check_widget(option))
def clear(w):
filebutton.set_filename("")
self.check_widget(option)
clearbutton.connect('clicked', clear)
return [hbox or eb]
def build_menu(self, node, label, option):
"""Build an OptionMenu widget, only one item of which may be selected.
"""
values = []
has_combo = hasattr(g, 'combo_box_new_text')
if has_combo:
option_menu = g.combo_box_new_text()
option_menu.get_history = option_menu.get_active
option_menu.set_history = option_menu.set_active
else:
option_menu = g.OptionMenu()
menu = g.Menu()
if label:
box = g.HBox(False, 4)
label_wid = self.make_sized_label(label)
label_wid.set_alignment(1.0, 0.5)
box.pack_start(label_wid, False, True, 0)
box.pack_start(option_menu, True, True, 0)
else:
box = None
#self.may_add_tip(option_menu, node)
for item in node.getElementsByTagName('item'):
assert item.hasAttribute('value')
value = item.getAttribute('value')
label_item = self.trans(item.getAttribute('label')) or value
if has_combo:
option_menu.append_text(label_item)
else:
menu.append(g.MenuItem(label_item))
values.append(value)
if not has_combo:
menu.show_all()
option_menu.set_menu(menu)
option_menu.connect('changed', lambda e: self.check_widget(option))
def get():
return values[option_menu.get_history()]
def set():
try:
option_menu.set_history(values.index(option.value))
except ValueError:
print "Value '%s' not in combo list" % option.value
self.handlers[option] = (get, set)
return [box or option_menu]
def build_radio_group(self, node, label, option):
"""Build a list of radio buttons, only one of which may be selected.
TooltipTooltip"""
radios = []
values = []
button = None
for radio in node.getElementsByTagName('radio'):
label = self.trans(radio.getAttribute('label'))
button = g.RadioButton(button, label)
self.may_add_tip(button, radio)
radios.append(button)
values.append(radio.getAttribute('value'))
button.connect('toggled', lambda b: self.check_widget(option))
def set():
try:
i = values.index(option.value)
except:
print "Value '%s' not in radio group!" % option.value
i = 0
radios[i].set_active(True)
def get():
for r, v in zip(radios, values):
if r.get_active():
return v
raise Exception('Nothing selected!')
self.handlers[option] = (get, set)
return radios
def build_toggle(self, node, label, option):
"Tooltip"
toggle = g.CheckButton(label)
self.may_add_tip(toggle, node)
self.handlers[option] = (
lambda: str(toggle.get_active()),
lambda: toggle.set_active(option.int_value))
toggle.connect('toggled', lambda w: self.check_widget(option))
return [toggle]
def build_slider(self, node, label, option):
minv = int(node.getAttribute('min'))
maxv = int(node.getAttribute('max'))
fixed = int(node.getAttribute('fixed') or "0")
showvalue = int(node.getAttribute('showvalue') or "0")
end = node.getAttribute('end')
hbox = g.HBox(False, 4)
if label:
widget = self.make_sized_label(label)
hbox.pack_start(widget, False, True, 0)
if end:
hbox.pack_end(self.make_sized_label(self.trans(end),
suffix = '-unit'),
False, True, 0)
adj = g.Adjustment(minv, minv, maxv, 1, 10, 0)
slide = g.HScale(adj)
if fixed:
slide.set_size_request(adj.upper, 24)
else:
slide.set_size_request(120, -1)
if showvalue:
slide.set_draw_value(True)
slide.set_value_pos(g.POS_LEFT)
slide.set_digits(0)
else:
slide.set_draw_value(False)
self.may_add_tip(slide, node)
hbox.pack_start(slide, not fixed, True, 0)
self.handlers[option] = (
lambda: str(adj.get_value()),
lambda: adj.set_value(option.int_value))
slide.connect('value-changed',
lambda w: self.check_widget(option))
return [hbox]
def build_fixedlist(self, node, label, option):
"""Tooltip"""
select=str_attr(node, 'selection', 'single')
cont=g.VBox(False, 4)
cont._rox_lib_expand=True
if label:
label_wid = g.Label(label)
cont.pack_start(label_wid, False, True, 0)
label_wid.show()
swin = g.ScrolledWindow()
swin.set_border_width(4)
swin.set_policy(g.POLICY_NEVER, g.POLICY_ALWAYS)
swin.set_shadow_type(g.SHADOW_IN)
#swin.set_size_request(-1, 128)
cont.pack_start(swin, True, True, 0)
model = g.ListStore(str)
view = g.TreeView(model)
swin.add(view)
selection=view.get_selection()
if select=='none':
selection.set_mode(g.SELECTION_NONE)
elif select=='multiple':
selection.set_mode(g.SELECTION_MULTIPLE)
else:
selection.set_mode(g.SELECTION_SINGLE)
select='single'
def sel_changed(sel, box):
box.check_widget(option)
selection.connect('changed', sel_changed, self)
cell = g.CellRendererText()
column = g.TreeViewColumn('', cell, text = 0)
view.append_column(column)
for item in node.getElementsByTagName('listitem'):
label=item.getAttribute('label')
iter=model.append()
model.set(iter, 0, label)
self.may_add_tip(swin, node)
def make_sel(model, path, iter, l):
l.append(str(model.get_value(iter, 0)))
def get():
mode=view.get_selection().get_mode()
if mode==int(g.SELECTION_NONE):
return []
elif mode==int(g.SELECTION_SINGLE):
model, iter=view.get_selection().get_selected()
return [str(model.get_value(iter, 0))]
v=[]
view.get_selection().selected_foreach(make_sel, v)
return v
def set():
sel=view.get_selection()
mode=sel.get_mode()
sel.unselect_all()
for v in option.list_value:
iter=model.get_iter_first()
while iter:
if v==model.get_value(iter, 0):
sel.select_iter(iter)
break
iter=model.iter_next(iter)
self.handlers[option]=(get, set)
return [cont]
def build_varlist(self, node, label, option):
"""Tooltip"""
edit=bool_attr(node, 'edit')
reorder=bool_attr(node, 'reorder')
extend=bool_attr(node, 'extend')
select=str_attr(node, 'selection', 'single')
cont=rox.g.VBox(False, 4)
cont._rox_lib_expand=True
if label:
label_wid = rox.g.Label(label)
cont.pack_start(label_wid, False, True, 0)
label_wid.show()
swin = g.ScrolledWindow()
swin.set_border_width(4)
swin.set_policy(g.POLICY_NEVER, g.POLICY_ALWAYS)
swin.set_shadow_type(g.SHADOW_IN)
#swin.set_size_request(-1, 128)
cont.pack_start(swin, True, True, 0)
model = g.ListStore(str, str)
view = g.TreeView(model)
swin.add(view)
selection=view.get_selection()
if select=='none':
selection.set_mode(g.SELECTION_NONE)
elif select=='multiple':
selection.set_mode(g.SELECTION_MULTIPLE)
else:
selection.set_mode(g.SELECTION_SINGLE)
select='single'
if reorder:
view.set_reorderable(True)
def cell_edited(ell, path, new_text, col):
if col==0 and new_text.find('=')>=0:
return
iter=model.get_iter_from_string(path)
model.set(iter, col, new_text)
self.check_widget(option)
cell = g.CellRendererText()
column = g.TreeViewColumn('Variable', cell, text = 0)
view.append_column(column)
if edit:
cell.set_property('editable', True)
cell.connect('edited', cell_edited, 0)
cell = g.CellRendererText()
column = g.TreeViewColumn('Value', cell, text = 1)
view.append_column(column)
if edit:
cell.set_property('editable', True)
cell.connect('edited', cell_edited, 1)
def add(widget, box):
iter=model.append()
model.set(iter, 0, 'newvar', 1, 'new value')
if select=='single':
view.get_selection().select_iter(iter)
box.check_widget(option)
if extend:
hbox=g.HBox(False, 2)
cont.pack_start(hbox, False)
but=g.Button(stock=g.STOCK_ADD)
but.connect('clicked', add, self)
hbox.pack_start(but, False)
self.may_add_tip(swin, node)
def get():
v=[]
iter=model.get_iter_first()
while iter:
var=model.get_value(iter, 0)
val=model.get_value(iter, 1)
v.append(var+'='+val)
iter=model.iter_next(iter)
return v
def set():
model.clear()
for v in option.list_value:
var, val=v.split('=', 1)
iter=model.append()
model.set(iter, 0, var, 1, val)
self.handlers[option]=(get, set)
return [cont]
class FontButton(g.Button):
"""A button that opens a GtkFontSelectionDialog"""
def __init__(self, option_box, option, title):
g.Button.__init__(self)
self.option_box = option_box
self.option = option
self.title = title
self.label = g.Label('')
self.add(self.label)
self.dialog = None
self.connect('clicked', self.clicked)
def set(self):
self.label.set_text(self.option.value)
if self.dialog:
self.dialog.destroy()
def get(self):
return self.label.get()
def clicked(self, button):
if self.dialog:
self.dialog.destroy()
def closed(dialog):
self.dialog = None
def response(dialog, resp):
if resp != int(g.RESPONSE_OK):
dialog.destroy()
return
self.label.set_text(dialog.get_font_name())
dialog.destroy()
self.option_box.check_widget(self.option)
self.dialog = g.FontSelectionDialog(self.title)
self.dialog.set_position(g.WIN_POS_MOUSE)
self.dialog.connect('destroy', closed)
self.dialog.connect('response', response)
self.dialog.set_font_name(self.get())
self.dialog.show()
class ColourButton(g.Button):
"""A button that opens a GtkColorSelectionDialog"""
def __init__(self, option_box, option, title):
g.Button.__init__(self)
self.c_box = g.EventBox()
self.add(self.c_box)
self.option_box = option_box
self.option = option
self.title = title
self.set_size_request(64, 14)
self.dialog = None
self.connect('clicked', self.clicked)
self.connect('expose-event', self.expose)
def expose(self, widget, event):
# Some themes draw images and stuff here, so we have to
# override it manually.
self.c_box.window.draw_rectangle(
self.c_box.style.bg_gc[g.STATE_NORMAL], True,
0, 0,
self.c_box.allocation.width,
self.c_box.allocation.height)
def set(self, c = None):
if c is None:
c = g.gdk.color_parse(self.option.value)
self.c_box.modify_bg(g.STATE_NORMAL, c)
def get(self):
c = self.c_box.get_style().bg[g.STATE_NORMAL]
return '#%04x%04x%04x' % (c.red, c.green, c.blue)
def clicked(self, button):
if self.dialog:
self.dialog.destroy()
def closed(dialog):
self.dialog = None
def response(dialog, resp):
if resp != int(g.RESPONSE_OK):
dialog.destroy()
return
self.set(dialog.colorsel.get_current_color())
dialog.destroy()
self.option_box.check_widget(self.option)
self.dialog = g.ColorSelectionDialog(self.title)
self.dialog.set_position(g.WIN_POS_MOUSE)
self.dialog.connect('destroy', closed)
self.dialog.connect('response', response)
c = self.c_box.get_style().bg[g.STATE_NORMAL]
self.dialog.colorsel.set_current_color(c)
self.dialog.show()
# Add your own options here... (maps element localName to build function)
widget_registry = {
}