1 """The OptionsBox widget is used to edit an OptionGroup.
2 For simple applications, rox.edit_options() provides an
3 easy way to edit the options.
5 You can add new types of option by appending to widget_registry (new
6 in ROX-Lib 1.9.13). Return a list of widgets (which are packed into either an
7 HBox or a VBox). For example, to add a button widget:
9 def build_button(box, node, label):
10 button = g.Button(label)
11 box.may_add_tip(button, node)
12 button.connect('clicked', my_button_handler)
14 OptionsBox.widget_registry['button'] = build_button
16 You can then create such a button in Options.xml with:
18 <button label='...'>Tooltip</button>
20 For widgets that have options, your build function will be called with
21 the option as a third parameter. You should register get and set methods,
22 and arrange for box.check_widget to be called when the user changes the
25 def build_toggle(box, node, label, option):
26 toggle = g.CheckButton(label)
27 box.may_add_tip(toggle, node)
29 box.handlers[option] = (
30 lambda: str(toggle.get_active()),
31 lambda: toggle.set_active(option.int_value))
33 toggle.connect('toggled', lambda w: box.check_widget(option))
36 OptionsBox.widget_registry['mytoggle'] = build_toggle
39 from rox
import g
, options
, _
41 from xml
.dom
import Node
, minidom
46 # Functions for extracting data from XML nodes
48 """Return all the text directly inside this DOM Node."""
49 return ''.join([text
.nodeValue
for text
in node
.childNodes
50 if text
.nodeType
== Node
.TEXT_NODE
])
52 def bool_attr(node
, name
, val
=False):
53 """Interpret node attribute as a boolean value"""
55 v
=node
.getAttribute(name
)
64 def str_attr(node
, name
, val
=''):
65 """Get string value of node attribute"""
67 val
=node
.getAttribute(name
)
72 class OptionsBox(g
.Dialog
):
73 """A dialog box which lets the user edit the options. The file
74 Options.xml specifies the layout of this box."""
76 tips
= None # GtkTooltips
77 options
= None # The OptionGroup we are editing
78 revert
= None # Option -> old value
79 handlers
= None # Option -> (get, set)
80 trans
= None # Translation function (application's, not ROX-Lib's)
82 def __init__(self
, options_group
, options_xml
, translation
= None):
83 """options_xml is an XML file, usually <app_dir>/Options.xml,
84 which defines the layout of the OptionsBox.
86 It contains an <options> root element containing (nested)
87 <section> elements. Each <section> contains a number of widgets,
88 some of which correspond to options. The build_* functions are
95 <section title='First section'>
96 <label>Here are some options</label>
97 <entry name='default_name' label='Default file name'>
98 When saving an untitled file, use this name as the default.
100 <section title='Nested section'>
106 assert isinstance(options_group
, options
.OptionGroup
)
108 if translation
is None:
110 if hasattr(__main__
.__builtins
__, '_'):
111 translation
= __main__
.__builtins
__._
113 translation
= lambda x
: x
114 self
.trans
= translation
116 g
.Dialog
.__init
__(self
)
117 self
.tips
= g
.Tooltips()
118 self
.set_has_separator(False)
120 self
.options
= options_group
121 self
.set_title((_('%s options')) % options_group
.program
)
122 self
.set_position(g
.WIN_POS_CENTER
)
124 button
= rox
.ButtonMixed(g
.STOCK_UNDO
, _('_Revert'))
125 self
.add_action_widget(button
, REVERT
)
126 self
.tips
.set_tip(button
, _('Restore all options to how they were '
127 'when the window was opened'))
129 self
.add_button(g
.STOCK_OK
, g
.RESPONSE_OK
)
131 self
.set_default_response(g
.RESPONSE_OK
)
133 doc
= minidom
.parse(options_xml
)
134 assert doc
.documentElement
.localName
== 'options'
136 self
.handlers
= {} # Option -> (get, set)
137 self
.revert
= {} # Option -> old value
138 self
.size_groups
= {} # Name -> GtkSizeGroup
139 self
.current_size_group
= None
141 self
.build_window_frame()
145 for section
in doc
.documentElement
.childNodes
:
146 if section
.nodeType
!= Node
.ELEMENT_NODE
:
148 if section
.localName
!= 'section':
149 print "Unknown section", section
151 self
.build_section(section
, None)
154 self
.tree_view
.expand_all()
156 self
.sections_swin
.hide()
160 def destroyed(widget
):
166 rox
.report_exception()
167 self
.connect('destroy', destroyed
)
169 def got_response(widget
, response
):
170 if response
== g
.RESPONSE_OK
:
172 elif response
== REVERT
:
173 for o
in self
.options
:
174 o
._set
(self
.revert
[o
])
175 self
.update_widgets()
176 self
.options
.notify()
178 self
.connect('response', got_response
)
181 """Show the window, updating all the widgets at the same
182 time. Use this instead of show()."""
184 for option
in self
.options
:
185 self
.revert
[option
] = option
.value
186 self
.update_widgets()
190 def update_revert(self
):
191 "Shade/unshade the Revert button. Internal."
192 self
.set_response_sensitive(REVERT
, self
.changed())
195 """Check whether any options have different values (ie, whether Revert
196 will do anything)."""
197 for option
in self
.options
:
198 if option
.value
!= self
.revert
[option
]:
202 def update_widgets(self
):
203 "Make widgets show current values. Internal."
204 assert not self
.updating
208 for option
in self
.options
:
210 handler
= self
.handlers
[option
][1]
212 print "No widget for option '%s'!" % option
218 def build_window_frame(self
):
219 "Create the main structure of the window."
220 hbox
= g
.HBox(False, 4)
221 self
.vbox
.pack_start(hbox
, True, True, 0)
223 # scrolled window for the tree view
224 sw
= g
.ScrolledWindow()
225 sw
.set_shadow_type(g
.SHADOW_IN
)
226 sw
.set_policy(g
.POLICY_NEVER
, g
.POLICY_AUTOMATIC
)
227 hbox
.pack_start(sw
, False, True, 0)
228 self
.sections_swin
= sw
# Used to hide it...
231 model
= g
.TreeStore(gobject
.TYPE_STRING
, gobject
.TYPE_INT
)
232 tv
= g
.TreeView(model
)
233 sel
= tv
.get_selection()
234 sel
.set_mode(g
.SELECTION_BROWSE
)
235 tv
.set_headers_visible(False)
236 self
.sections
= model
238 tv
.unset_flags(g
.CAN_FOCUS
) # Stop irritating highlight
240 # Add a column to display column 0 of the store...
241 cell
= g
.CellRendererText()
242 column
= g
.TreeViewColumn('Section', cell
, text
= 0)
243 tv
.append_column(column
)
249 frame
.set_shadow_type(g
.SHADOW_IN
)
250 hbox
.pack_start(frame
, True, True, 0)
252 notebook
= g
.Notebook()
253 notebook
.set_show_tabs(False)
254 notebook
.set_show_border(False)
256 self
.notebook
= notebook
259 # (sel = sel; pygtk bug?)
260 def change_page(tv
, sel
= sel
, notebook
= notebook
):
261 selected
= sel
.get_selected()
264 model
, titer
= selected
265 page
= model
.get_value(titer
, 1)
267 notebook
.set_current_page(page
)
268 sel
.connect('changed', change_page
)
272 def check_widget(self
, option
):
273 "A widgets call this when the user changes its value."
277 assert isinstance(option
, options
.Option
)
279 new
= self
.handlers
[option
][0]()
281 if new
== option
.value
:
285 self
.options
.notify()
288 def build_section(self
, section
, parent
):
289 """Create a new page for the notebook and a new entry in the
290 sections tree, and build all the widgets inside the page."""
291 page
= g
.VBox(False, 4)
292 page
.set_border_width(4)
293 self
.notebook
.append_page(page
, g
.Label('unused'))
295 titer
= self
.sections
.append(parent
)
296 self
.sections
.set(titer
,
297 0, self
.trans(section
.getAttribute('title')),
298 1, self
.notebook
.page_num(page
))
299 for node
in section
.childNodes
:
300 if node
.nodeType
!= Node
.ELEMENT_NODE
:
302 name
= node
.localName
303 if name
== 'section':
304 self
.build_section(node
, titer
)
306 self
.build_widget(node
, page
)
309 def build_widget(self
, node
, box
):
310 """Dispatches the job of dealing with a DOM Node to the
311 appropriate build_* function."""
312 label
= node
.getAttribute('label')
313 name
= node
.getAttribute('name')
315 label
= self
.trans(label
)
317 old_size_group
= self
.current_size_group
318 sg
= node
.getAttributeNode('size-group')
320 self
.current_size_group
= sg
.value
or None
325 option
= self
.options
.options
[name
]
327 raise Exception("Unknown option '%s'" % name
)
329 # Check for a new-style function in the registry...
330 new_fn
= widget_registry
.get(node
.localName
, None)
332 # Wrap it up so it appears old-style
333 fn
= lambda *args
: new_fn(self
, *args
)
335 # Not in the registry... look in the class instead
337 name
= node
.localName
.replace('-', '_')
338 fn
= getattr(self
, 'build_' + name
)
339 except AttributeError:
340 fn
= self
.build_unknown
343 widgets
= fn(node
, label
, option
)
345 widgets
= fn(node
, label
)
347 box
.pack_start(w
, False, True, 0)
349 self
.current_size_group
= old_size_group
351 def may_add_tip(self
, widget
, node
):
352 """If 'node' contains any text, use that as the tip for 'widget'."""
354 data
= ''.join([n
.nodeValue
for n
in node
.childNodes
if n
.nodeType
== Node
.TEXT_NODE
]).strip()
358 self
.tips
.set_tip(widget
, self
.trans(data
))
360 def get_size_group(self
, name
):
361 """Return the GtkSizeGroup for this name, creating one
362 if it doesn't currently exist."""
364 return self
.size_groups
[name
]
366 group
= g
.SizeGroup(g
.SIZE_GROUP_HORIZONTAL
)
367 self
.size_groups
[name
] = group
370 def make_sized_label(self
, label
, suffix
= ""):
371 """Create a GtkLabel and add it to the current size-group, if any"""
372 widget
= g
.Label(label
)
373 if self
.current_size_group
:
374 widget
.set_alignment(1.0, 0.5)
375 group
= self
.get_size_group(self
.current_size_group
+ suffix
)
376 group
.add_widget(widget
)
379 # Each type of widget has a method called 'build_NAME' where name is
380 # the XML element name. This method is called as method(node, label,
381 # option) if it corresponds to an Option, or method(node, label)
382 # otherwise. It should return a list of widgets to add to the window
383 # and, if it's for an Option, set self.handlers[option] = (get, set).
385 def build_unknown(self
, node
, label
, option
= None):
386 return [g
.Label("Unknown widget type <%s>" % node
.localName
)]
388 def build_label(self
, node
, label
):
389 help_flag
= int(node
.getAttribute('help') or '0')
390 widget
= self
.make_sized_label(self
.trans(data(node
)))
392 widget
.set_alignment(0, 0.5)
394 widget
.set_alignment(0, 1)
395 widget
.set_justify(g
.JUSTIFY_LEFT
)
396 widget
.set_line_wrap(True)
399 hbox
= g
.HBox(False, 4)
401 image
.set_from_stock(g
.STOCK_DIALOG_INFO
,
403 align
= g
.Alignment(0, 0, 0, 0)
406 hbox
.pack_start(align
, False, True, 0)
407 hbox
.pack_start(widget
, False, True, 0)
409 spacer
= g
.EventBox()
410 spacer
.set_size_request(6, 6)
412 return [hbox
, spacer
]
415 def build_spacer(self
, node
, label
):
418 eb
.set_size_request(8, 8)
421 def build_hbox(self
, node
, label
):
422 """<hbox>...</hbox> to layout child widgets horizontally."""
423 return self
.do_box(node
, label
, g
.HBox(False, 4))
424 def build_vbox(self
, node
, label
):
425 """<vbox>...</vbox> to layout child widgets vertically."""
426 return self
.do_box(node
, label
, g
.VBox(False, 0))
428 def do_box(self
, node
, label
, widget
):
429 "Helper function for building hbox, vbox and frame widgets."
431 widget
.pack_start(self
.make_sized_label(label
),
434 for child
in node
.childNodes
:
435 if child
.nodeType
== Node
.ELEMENT_NODE
:
436 self
.build_widget(child
, widget
)
440 def build_frame(self
, node
, label
):
441 """<frame label='Title'>...</frame> to group options under a heading."""
442 frame
= g
.Frame(label
)
443 frame
.set_shadow_type(g
.SHADOW_NONE
)
445 # Make the label bold...
446 # (bug in pygtk => use set_markup)
447 label_widget
= frame
.get_label_widget()
448 label_widget
.set_markup('<b>' + label
+ '</b>')
449 #attr = pango.AttrWeight(pango.WEIGHT_BOLD)
450 #attr.start_index = 0
452 #list = pango.AttrList()
454 #label_widget.set_attributes(list)
456 vbox
= g
.VBox(False, 4)
457 vbox
.set_border_width(12)
460 self
.do_box(node
, None, vbox
)
464 def do_entry(self
, node
, label
, option
):
465 "Helper function for entry and secretentry widgets"
466 box
= g
.HBox(False, 4)
470 label_wid
= self
.make_sized_label(label
)
471 label_wid
.set_alignment(1.0, 0.5)
472 box
.pack_start(label_wid
, False, True, 0)
473 box
.pack_start(entry
, True, True, 0)
477 self
.may_add_tip(entry
, node
)
479 entry
.connect('changed', lambda e
: self
.check_widget(option
))
482 return entry
.get_chars(0, -1)
484 entry
.set_text(option
.value
)
485 self
.handlers
[option
] = (get
, set)
487 return (entry
, [box
or entry
])
489 def build_entry(self
, node
, label
, option
):
490 "<entry name='...' label='...'>Tooltip</entry>"
491 entry
, result
=self
.do_entry(node
, label
, option
)
494 def build_secretentry(self
, node
, label
, option
):
495 "<secretentry name='...' label='...' char='*'>Tooltip</secretentry>"
496 entry
, result
=self
.do_entry(node
, label
, option
)
498 ch
=node
.getAttribute('char')
506 entry
.set_visibility(False)
507 entry
.set_invisible_char(ch
)
511 def build_font(self
, node
, label
, option
):
512 "<font name='...' label='...'>Tooltip</font>"
513 button
= FontButton(self
, option
, label
)
515 self
.may_add_tip(button
, node
)
517 hbox
= g
.HBox(False, 4)
518 hbox
.pack_start(self
.make_sized_label(label
), False, True, 0)
519 hbox
.pack_start(button
, False, True, 0)
521 self
.handlers
[option
] = (button
.get
, button
.set)
525 def build_colour(self
, node
, label
, option
):
526 "<colour name='...' label='...'>Tooltip</colour>"
527 button
= ColourButton(self
, option
, label
)
529 self
.may_add_tip(button
, node
)
531 hbox
= g
.HBox(False, 4)
532 hbox
.pack_start(self
.make_sized_label(label
), False, True, 0)
533 hbox
.pack_start(button
, False, True, 0)
535 self
.handlers
[option
] = (button
.get
, button
.set)
539 def build_numentry(self
, node
, label
, option
):
540 """<numentry name='...' label='...' min='0' max='100' step='1'>Tooltip</numentry>.
541 Lets the user choose a number from min to max."""
542 minv
= int(node
.getAttribute('min'))
543 maxv
= int(node
.getAttribute('max'))
544 step
= node
.getAttribute('step')
545 unit
= node
.getAttribute('unit')
551 unit
= self
.trans(unit
)
553 hbox
= g
.HBox(False, 4)
555 widget
= self
.make_sized_label(label
)
556 widget
.set_alignment(1.0, 0.5)
557 hbox
.pack_start(widget
, False, True, 0)
559 spin
= g
.SpinButton(g
.Adjustment(minv
, minv
, maxv
, step
))
560 spin
.set_width_chars(max(len(str(minv
)), len(str(maxv
))))
561 hbox
.pack_start(spin
, False, True, 0)
562 self
.may_add_tip(spin
, node
)
565 hbox
.pack_start(g
.Label(unit
), False, True, 0)
567 self
.handlers
[option
] = (
568 lambda: str(spin
.get_value()),
569 lambda: spin
.set_value(option
.int_value
))
571 spin
.connect('value-changed', lambda w
: self
.check_widget(option
))
575 def build_menu(self
, node
, label
, option
):
576 """Build an OptionMenu widget, only one item of which may be selected.
577 <menu name='...' label='...'>
578 <item value='...' label='...'/>
579 <item value='...' label='...'/>
584 option_menu
= g
.OptionMenu()
586 option_menu
.set_menu(menu
)
589 box
= g
.HBox(False, 4)
590 label_wid
= self
.make_sized_label(label
)
591 label_wid
.set_alignment(1.0, 0.5)
592 box
.pack_start(label_wid
, False, True, 0)
593 box
.pack_start(option_menu
, True, True, 0)
597 #self.may_add_tip(option_menu, node)
599 for item
in node
.getElementsByTagName('item'):
600 assert item
.hasAttribute('value')
601 value
= item
.getAttribute('value')
602 label_item
= self
.trans(item
.getAttribute('label')) or value
604 menu
.append(g
.MenuItem(label_item
))
607 option_menu
.connect('changed', lambda e
: self
.check_widget(option
))
610 return values
[option_menu
.get_history()]
614 option_menu
.set_history(values
.index(option
.value
))
616 print "Value '%s' not in combo list" % option
.value
618 self
.handlers
[option
] = (get
, set)
620 return [box
or option_menu
]
623 def build_radio_group(self
, node
, label
, option
):
624 """Build a list of radio buttons, only one of which may be selected.
625 <radio-group name='...'>
626 <radio value='...' label='...'>Tooltip</radio>
627 <radio value='...' label='...'>Tooltip</radio>
632 for radio
in node
.getElementsByTagName('radio'):
633 label
= self
.trans(radio
.getAttribute('label'))
634 button
= g
.RadioButton(button
, label
)
635 self
.may_add_tip(button
, radio
)
636 radios
.append(button
)
637 values
.append(radio
.getAttribute('value'))
638 button
.connect('toggled', lambda b
: self
.check_widget(option
))
642 i
= values
.index(option
.value
)
644 print "Value '%s' not in radio group!" % option
.value
646 radios
[i
].set_active(True)
648 for r
, v
in zip(radios
, values
):
651 raise Exception('Nothing selected!')
653 self
.handlers
[option
] = (get
, set)
657 def build_toggle(self
, node
, label
, option
):
658 "<toggle name='...' label='...'>Tooltip</toggle>"
659 toggle
= g
.CheckButton(label
)
660 self
.may_add_tip(toggle
, node
)
662 self
.handlers
[option
] = (
663 lambda: str(toggle
.get_active()),
664 lambda: toggle
.set_active(option
.int_value
))
666 toggle
.connect('toggled', lambda w
: self
.check_widget(option
))
670 def build_slider(self
, node
, label
, option
):
671 minv
= int(node
.getAttribute('min'))
672 maxv
= int(node
.getAttribute('max'))
673 fixed
= int(node
.getAttribute('fixed') or "0")
674 showvalue
= int(node
.getAttribute('showvalue') or "0")
675 end
= node
.getAttribute('end')
677 hbox
= g
.HBox(False, 4)
679 widget
= self
.make_sized_label(label
)
680 hbox
.pack_start(widget
, False, True, 0)
683 hbox
.pack_end(self
.make_sized_label(self
.trans(end
),
687 adj
= g
.Adjustment(minv
, minv
, maxv
, 1, 10, 0)
688 slide
= g
.HScale(adj
)
691 slide
.set_size_request(adj
.upper
, 24)
693 slide
.set_size_request(120, -1)
695 slide
.set_draw_value(True)
696 slide
.set_value_pos(g
.POS_LEFT
)
699 slide
.set_draw_value(False)
701 self
.may_add_tip(slide
, node
)
702 hbox
.pack_start(slide
, not fixed
, True, 0)
704 self
.handlers
[option
] = (
705 lambda: str(adj
.get_value()),
706 lambda: adj
.set_value(option
.int_value
))
708 slide
.connect('value-changed',
709 lambda w
: self
.check_widget(option
))
713 def build_fixedlist(self
, node
, label
, option
):
714 """<fixedlist name='...' label='...' selection='single|none|multiple'>Tooltip<listitem label='...'/><listitem label='...'/></fixedlist>"""
715 select
=str_attr(node
, 'selection', 'single')
717 cont
=g
.VBox(False, 4)
720 label_wid
= g
.Label(label
)
721 cont
.pack_start(label_wid
, False, True, 0)
724 swin
= g
.ScrolledWindow()
725 swin
.set_border_width(4)
726 swin
.set_policy(g
.POLICY_NEVER
, g
.POLICY_ALWAYS
)
727 swin
.set_shadow_type(g
.SHADOW_IN
)
728 swin
.set_size_request(-1, 128)
729 cont
.pack_start(swin
, True, True, 0)
731 model
= g
.ListStore(str)
732 view
= g
.TreeView(model
)
735 selection
=view
.get_selection()
737 selection
.set_mode(g
.SELECTION_NONE
)
738 elif select
=='multiple':
739 selection
.set_mode(g
.SELECTION_MULTIPLE
)
741 selection
.set_mode(g
.SELECTION_SINGLE
)
744 def sel_changed(sel
, box
):
745 box
.check_widget(option
)
747 selection
.connect('changed', sel_changed
, self
)
749 cell
= g
.CellRendererText()
750 column
= g
.TreeViewColumn('', cell
, text
= 0)
751 view
.append_column(column
)
753 for item
in node
.getElementsByTagName('listitem'):
754 label
=item
.getAttribute('label')
756 model
.set(iter, 0, label
)
758 self
.may_add_tip(swin
, node
)
760 def make_sel(model
, path
, iter, l
):
761 l
.append(str(model
.get_value(iter, 0)))
764 mode
=view
.get_selection().get_mode()
765 if mode
==g
.SELECTION_NONE
:
767 elif mode
==g
.SELECTION_SINGLE
:
768 model
, iter=view
.get_selection().get_selected()
769 return [str(model
.get_value(iter, 0))]
772 view
.get_selection().selected_foreach(make_sel
, v
)
776 sel
=view
.get_selection()
779 for v
in option
.list_value
:
780 iter=model
.get_iter_first()
782 if v
==model
.get_value(iter, 0):
783 sel
.select_iter(iter)
786 iter=model
.iter_next(iter)
788 self
.handlers
[option
]=(get
, set)
792 def build_varlist(self
, node
, label
, option
):
793 """<varlist name='...' label='...' edit='yes|no' extend='yes|no' selection='single|none|multiple'>Tooltip</varlist>"""
794 edit
=bool_attr(node
, 'edit')
795 reorder
=bool_attr(node
, 'reorder')
796 extend
=bool_attr(node
, 'extend')
797 select
=str_attr(node
, 'selection', 'single')
799 cont
=rox
.g
.VBox(False, 4)
802 label_wid
= rox
.g
.Label(label
)
803 cont
.pack_start(label_wid
, False, True, 0)
806 swin
= g
.ScrolledWindow()
807 swin
.set_border_width(4)
808 swin
.set_policy(g
.POLICY_NEVER
, g
.POLICY_ALWAYS
)
809 swin
.set_shadow_type(g
.SHADOW_IN
)
810 swin
.set_size_request(-1, 128)
811 cont
.pack_start(swin
, True, True, 0)
813 model
= g
.ListStore(str, str)
814 view
= g
.TreeView(model
)
817 selection
=view
.get_selection()
819 selection
.set_mode(g
.SELECTION_NONE
)
820 elif select
=='multiple':
821 selection
.set_mode(g
.SELECTION_MULTIPLE
)
823 selection
.set_mode(g
.SELECTION_SINGLE
)
827 view
.set_reorderable(True)
829 def cell_edited(ell
, path
, new_text
, col
):
830 if col
==0 and new_text
.find('=')>=0:
832 iter=model
.get_iter_from_string(path
)
833 model
.set(iter, col
, new_text
)
834 self
.check_widget(option
)
836 cell
= g
.CellRendererText()
837 column
= g
.TreeViewColumn('Variable', cell
, text
= 0)
838 view
.append_column(column
)
840 cell
.set_property('editable', True)
841 cell
.connect('edited', cell_edited
, 0)
843 cell
= g
.CellRendererText()
844 column
= g
.TreeViewColumn('Value', cell
, text
= 1)
845 view
.append_column(column
)
847 cell
.set_property('editable', True)
848 cell
.connect('edited', cell_edited
, 1)
850 def add(widget
, box
):
852 model
.set(iter, 0, 'newvar', 1, 'new value')
854 view
.get_selection().select_iter(iter)
855 box
.check_widget(option
)
857 hbox
=g
.HBox(False, 2)
858 cont
.pack_start(hbox
, False)
860 but
=g
.Button(stock
=g
.STOCK_ADD
)
861 but
.connect('clicked', add
, self
)
862 hbox
.pack_start(but
, False)
864 self
.may_add_tip(swin
, node
)
868 iter=model
.get_iter_first()
870 var
=model
.get_value(iter, 0)
871 val
=model
.get_value(iter, 1)
872 v
.append(var
+'='+val
)
874 iter=model
.iter_next(iter)
879 for v
in option
.list_value
:
880 var
, val
=v
.split('=', 1)
882 model
.set(iter, 0, var
, 1, val
)
884 self
.handlers
[option
]=(get
, set)
889 class FontButton(g
.Button
):
890 """A button that opens a GtkFontSelectionDialog"""
891 def __init__(self
, option_box
, option
, title
):
892 g
.Button
.__init
__(self
)
893 self
.option_box
= option_box
896 self
.label
= g
.Label('<font>')
899 self
.connect('clicked', self
.clicked
)
902 self
.label
.set_text(self
.option
.value
)
904 self
.dialog
.destroy()
907 return self
.label
.get()
909 def clicked(self
, button
):
911 self
.dialog
.destroy()
916 def response(dialog
, resp
):
917 if resp
!= g
.RESPONSE_OK
:
920 self
.label
.set_text(dialog
.get_font_name())
922 self
.option_box
.check_widget(self
.option
)
924 self
.dialog
= g
.FontSelectionDialog(self
.title
)
925 self
.dialog
.set_position(g
.WIN_POS_MOUSE
)
926 self
.dialog
.connect('destroy', closed
)
927 self
.dialog
.connect('response', response
)
929 self
.dialog
.set_font_name(self
.get())
932 class ColourButton(g
.Button
):
933 """A button that opens a GtkColorSelectionDialog"""
934 def __init__(self
, option_box
, option
, title
):
935 g
.Button
.__init
__(self
)
936 self
.c_box
= g
.EventBox()
938 self
.option_box
= option_box
941 self
.set_size_request(64, 14)
943 self
.connect('clicked', self
.clicked
)
944 self
.connect('expose-event', self
.expose
)
946 def expose(self
, widget
, event
):
947 # Some themes draw images and stuff here, so we have to
948 # override it manually.
949 self
.c_box
.window
.draw_rectangle(
950 self
.c_box
.style
.bg_gc
[g
.STATE_NORMAL
], True,
952 self
.c_box
.allocation
.width
,
953 self
.c_box
.allocation
.height
)
955 def set(self
, c
= None):
957 c
= g
.gdk
.color_parse(self
.option
.value
)
958 self
.c_box
.modify_bg(g
.STATE_NORMAL
, c
)
961 c
= self
.c_box
.get_style().bg
[g
.STATE_NORMAL
]
962 return '#%04x%04x%04x' % (c
.red
, c
.green
, c
.blue
)
964 def clicked(self
, button
):
966 self
.dialog
.destroy()
971 def response(dialog
, resp
):
972 if resp
!= g
.RESPONSE_OK
:
975 self
.set(dialog
.colorsel
.get_current_color())
977 self
.option_box
.check_widget(self
.option
)
979 self
.dialog
= g
.ColorSelectionDialog(self
.title
)
980 self
.dialog
.set_position(g
.WIN_POS_MOUSE
)
981 self
.dialog
.connect('destroy', closed
)
982 self
.dialog
.connect('response', response
)
984 c
= self
.c_box
.get_style().bg
[g
.STATE_NORMAL
]
985 self
.dialog
.colorsel
.set_current_color(c
)
988 # Add your own options here... (maps element localName to build function)