5 from pprint
import pprint
6 from debug_print_statements
import *
9 # These are functions that work on widgets in order to do 'magic'
12 def get_widget_by_name(container
, widget_name
):
13 if 'get_children' not in dir(container
):
14 # no get_children() method => this is not a container
17 containers
= [container
]
19 while len(containers
) != 0:
20 container
= containers
.pop(0)
21 for child
in container
.get_children():
22 if child
.get_name() == widget_name
:
24 if 'get_children' in dir(child
):
25 containers
.extend(child
.get_children())
27 # haven't returned by now => not found
30 def set_properties(widget
, properties_dict
, ignore_errors
=False):
31 for property_name
, property_value
in properties_dict
.iteritems():
34 widget
.set_property(property_name
, property_value
)
38 widget
.set_property(property_name
, property_value
)
40 class PythonicWidget():
42 def __init__(self
, *args
, **kwargs
):
43 self
.set_packing_vars(*args
, **kwargs
)
44 self
.attach_signal_handlers(**kwargs
)
45 self
.set_name_param(**kwargs
)
47 def set_packing_vars(self
, *args
, **kwargs
):
48 expand
= kwargs
.get("expand", True)
49 fill
= kwargs
.get("fill", True)
52 def set_packing(widget
=None, old_parent
=None):
53 parent
= self
.get_parent()
54 if parent
is not None and 'query_child_packing' in dir(parent
):
55 old_values
= list(parent
.query_child_packing(self
))
56 # we just want to change the expand and fill
57 old_values
[0] = expand
59 parent
.set_child_packing(self
, expand
, fill
, old_values
[2], old_values
[3])
62 self
.connect("parent-set", set_packing
)
64 def attach_signal_handlers(self
, **cb_dict
):
65 events_to_signals
= { 'on_click': 'clicked' }
67 for event
, func
in cb_dict
.items():
68 if event
in events_to_signals
:
69 self
.connect(events_to_signals
[event
], func
)
71 def set_name_param(self
, **kwargs
):
73 self
.set_name(kwargs
['name'])
76 def parent_window(self
):
77 if 'container' not in dir(self
):
80 parent
= self
.container
82 if isinstance(parent
, Window
):
84 if 'container' not in dir(parent
):
86 parent
= parent
.container
88 assert False, "Widget %r has no parent window" % self
91 def child_widgets(self
):
92 if 'get_children' not in dir(self
):
98 # When being called with self as a window, it is not returning widgets
100 while len(widgets
) != 0:
101 widget
= widgets
.pop(0)
102 if not isinstance( widget
, gtk
.Container
):
107 for child
in widget
.get_children():
109 if isinstance( child
, gtk
.Container
):
110 widgets
.extend(child
.get_children())
113 class Button(gtk
.Button
, PythonicWidget
):
114 def __init__(self
, label
=None, stock
=None, *args
, **kwargs
):
115 gtk
.Button
.__init
__(self
)
116 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
117 assert len(args
) == 0
120 self
.set_label(label
)
122 self
.set_use_stock(True)
123 self
.set_label(stock
)
126 class VBox(gtk
.VBox
, PythonicWidget
):
127 def __init__(self
, *args
, **kwargs
):
128 gtk
.VBox
.__init
__(self
)
129 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
131 widget
.container
= self
132 self
.pack_start(widget
)
134 class HBox(gtk
.HBox
, PythonicWidget
):
135 def __init__(self
, *args
, **kwargs
):
136 gtk
.HBox
.__init
__(self
)
137 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
139 widget
.container
= self
140 self
.pack_start(widget
)
142 class Label(gtk
.Label
, PythonicWidget
):
143 def __init__(self
, text
, *args
, **kwargs
):
144 gtk
.Label
.__init
__(self
)
145 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
148 class TextEntry(gtk
.Entry
, PythonicWidget
):
149 def __init__(self
, *args
, **kwargs
):
150 gtk
.Entry
.__init
__(self
)
151 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
154 self
.set_text(kwargs
['text'])
158 return self
.get_text()
162 return self
.get_text()
164 class TextView(gtk
.TextView
, PythonicWidget
):
165 def __init__(self
, *args
, **kwargs
):
166 gtk
.TextView
.__init
__(self
)
167 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
171 return self
.get_text()
173 def Labeled( label
, widget
, **kwargs
):
174 return HBox( Label(label
), widget
, **kwargs
)
176 class ScrolledWindow(gtk
.ScrolledWindow
, PythonicWidget
):
177 def __init__(self
, inside_widget
, horizontal
=None, vertical
=None, **kwargs
):
178 gtk
.ScrolledWindow
.__init
__(self
)
179 PythonicWidget
.__init
__(self
, **kwargs
)
180 # FIXME should this be add_with_viewport? Or should it check
181 # inside_widget to see if it should add_with_viewport
182 if isinstance(inside_widget
, gtk
.Viewport
):
183 self
.add(inside_widget
)
185 self
.add_with_viewport(inside_widget
)
186 exiting_horizontal
, existing_vertical
= self
.get_policy()
187 if horizontal
== 'always':
188 self
.set_policy(gtk
.POLICY_ALWAYS
, existing_vertical
)
189 elif horizontal
== 'never':
190 self
.set_policy(gtk
.POLICY_NEVER
, existing_vertical
)
191 elif horizontal
== 'auto' or horizontal
== 'automatic':
192 self
.set_policy(gtk
.POLICY_AUTOMATIC
, existing_vertical
)
193 exiting_horizontal
, existing_vertical
= self
.get_policy()
194 if vertical
== 'always':
195 self
.set_policy(exiting_horizontal
, gtk
.POLICY_ALWAYS
)
196 elif vertical
== 'never':
197 self
.set_policy(exiting_horizontal
, gtk
.POLICY_NEVER
)
198 elif vertical
== 'auto' or vertical
== 'automatic':
199 self
.set_policy(exiting_horizontal
, gtk
.POLICY_AUTOMATIC
)
203 class IconView(gtk
.IconView
, PythonicWidget
):
204 def __init__(self
, elements
, *args
, **kwargs
):
205 gtk
.IconView
.__init
__(self
)
206 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
207 set_properties(self
, kwargs
, ignore_errors
=True)
208 # FIXME check the format of args
209 self
.__init
_from
_icon
_set
(elements
)
211 def __init_from_icon_set(self
, elements
):
212 # elements should be a list. Each element should be the same.
214 # string - each 'icon' is a text
215 # (string, pixbuf) - standard icon and text
217 if type(elements
[0]) == type(""):
218 list = gtk
.ListStore(str)
219 for string
in elements
:
220 list.append([string
])
222 self
.set_text_column(0)
223 elif type(elements
[0]) == type(()):
229 class Toolbar(gtk
.Toolbar
, PythonicWidget
):
230 def __init__(self
, *child_widgets
, **kwargs
):
231 gtk
.Toolbar
.__init
__(self
)
232 PythonicWidget
.__init
__(self
, **kwargs
)
233 for child_widget
in child_widgets
:
234 # insert it at the end
235 #toolitem = gtk.ToolItem()
236 #toolitem.pack_start(child_widget)
237 self
.insert( child_widget
, -1 )
239 class NewButton(Button
, PythonicWidget
):
240 def __init__(self
, *args
, **kwargs
):
241 Button
.__init
__(self
, stock
="gtk-new")
242 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
244 class AddButton(Button
, PythonicWidget
):
245 def __init__(self
, *args
, **kwargs
):
246 Button
.__init
__(self
, stock
="gtk-add")
247 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
249 class RemoveButton(Button
, PythonicWidget
):
250 def __init__(self
, *args
, **kwargs
):
251 Button
.__init
__(self
, stock
="gtk-remove")
252 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
254 class SaveButton(Button
, PythonicWidget
):
255 def __init__(self
, *args
, **kwargs
):
256 Button
.__init
__(self
, stock
="gtk-save")
257 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
259 class NewToolbarButton(gtk
.ToolButton
, PythonicWidget
):
260 def __init__(self
, *args
, **kwargs
):
261 gtk
.ToolButton
.__init
__(self
, 'gtk-new')
262 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
264 class PropertiesButton(Button
, PythonicWidget
):
265 def __init__(self
, *args
, **kwargs
):
266 Button
.__init
__(self
, stock
="gtk-properties")
267 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
269 class PropertiesToolbarButton(gtk
.ToolButton
, PythonicWidget
):
270 def __init__(self
, *args
, **kwargs
):
271 gtk
.ToolButton
.__init
__(self
, "gtk-properties")
272 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
274 class ComboBox(gtk
.ComboBox
, PythonicWidget
):
275 def __init__(self
, *rows
, **kwargs
):
276 gtk
.ComboBox
.__init
__(self
)
277 PythonicWidget
.__init
__(self
, **kwargs
)
279 liststore
= gtk
.ListStore(str)
280 self
.set_model( liststore
)
282 cell
= gtk
.CellRendererText()
283 self
.pack_start( cell
, True )
284 self
.add_attribute( cell
, 'text', 0 )
288 for index
, row
in enumerate( rows
):
289 if isinstance( row
, basestring
):
294 if options
['selected']:
296 self
.append_text( text
)
298 if active
is not None:
299 self
.set_active( active
)
302 class Notebook(gtk
.Notebook
, PythonicWidget
):
303 def __init__(self
, *pages
, **kwargs
):
304 gtk
.Notebook
.__init
__(self
)
305 PythonicWidget
.__init
__(self
, **kwargs
)
307 for page_name
, page_contents
in pages
:
308 if isinstance(page_name
, basestring
):
309 page_name
= Label( page_name
)
310 self
.append_page( child
=page_contents
, tab_label
=page_name
)
312 class RadioButton(gtk
.RadioButton
, PythonicWidget
):
313 def __init__(self
, group
=None, label
=None, *args
, **kwargs
):
314 gtk
.RadioButton
.__init
__(self
, group
=None, label
=label
)
315 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
318 if 'value' in kwargs
:
319 self
.value
= kwargs
['value']
322 def update_all_radiobutton_groups(widget
, new_child
):
323 if 'get_children' not in dir( widget
):
326 child_radiobuttons
= [child
for child
in widget
.child_widgets
if isinstance( child
, RadioButton
) ]
329 for radiobutton
in child_radiobuttons
:
330 group_name
= radiobutton
.group
331 if group_name
not in groups
:
332 groups
[group_name
] = []
333 groups
[group_name
].append(radiobutton
)
335 for group_name
in groups
:
336 inital_group
= groups
[group_name
][0]
337 if len(groups
[group_name
]) <= 1:
339 for radiobutton
in groups
[group_name
][1:]:
340 radiobutton
.set_group(None)
341 radiobutton
.set_group(inital_group
)
344 def add_updater_callback(widget
, old_parent
):
345 #print "Adding the add_updater_callback to "+repr(widget)
346 # when the parent is set we need to tell the parent to update_all_radiobutton_groups
348 if "get_children" in dir( widget
):
349 #print repr(widget)+" is a container"
350 update_all_radiobutton_groups(widget
, None)
351 widget
.connect( "add", update_all_radiobutton_groups
)
353 if 'container' in dir( widget
) and widget
.container
:
354 widget
.container
.connect( "parent-set", add_updater_callback
)
356 self
.connect("parent-set", add_updater_callback
)
357 update_all_radiobutton_groups(self
, None)
361 class ListBox(gtk
.TreeView
, PythonicWidget
):
362 def __init__(self
, *rows
, **kwargs
):
364 columns
= kwargs
['columns']
366 # Turn our key error into a type error
367 raise TypeError, "ListBox constructor requires the 'columns' argument"
368 gtk
.TreeView
.__init
__(self
)
369 PythonicWidget
.__init
__(self
, **kwargs
)
371 # We assume they are all text columns for now
372 # TODO allow the caller to change this.
373 for index
, col
in enumerate(columns
):
374 if isinstance( col
, basestring
):
378 column
= gtk
.TreeViewColumn(col
, gtk
.CellRendererText(), text
=index
)
379 column
.set_resizable(True)
380 column
.set_sort_column_id(index
)
381 self
.append_column(column
)
383 #view_entries_list.connect("row-activated", show_single_entry)
386 #column_types.extend([x['type'] for x in view_def['columns']])
387 #column_types.extend([gobject.TYPE_PYOBJECT])
389 column_types
= [str] * len(columns
)
390 column_data
= gtk
.ListStore(*column_types
)
392 self
.set_model(column_data
)
395 if len(row
) != len(columns
):
396 raise TypeError, "Row %r has %d entries but there are %d columns definied (%r)" % ( row
, len(row
), len(columns
), columns
)
397 column_data
.append(row
)
403 class Window(gtk
.Window
, PythonicWidget
):
404 def __init__(self
, child_widget
, *args
, **kwargs
):
405 gtk
.Window
.__init
__(self
)
406 PythonicWidget
.__init
__(self
, **kwargs
)
408 self
.add(child_widget
)
409 child_widget
.container
= self
411 if 'title' in kwargs
:
412 self
.set_title(kwargs
['title'])
414 if 'quit_on_close' in kwargs
:
415 if kwargs
['quit_on_close'] == True:
416 self
.connect("destroy", gtk
.main_quit
)
418 def get_value(self
, value_name
):
419 # Either the widget is a text box (eg) that we can read the value off,
420 # or it's some kind of multi-selection thing, like a set of radio
422 widget_by_name
= get_widget_by_name(self
, value_name
)
424 return widget_by_name
.value
426 widget_by_group
= [widget
for widget
in self
.child_widgets
if isinstance( widget
, RadioButton
) and widget
.group
== value_name
]
427 if len(widget_by_group
) == 0:
428 # no radio buttons have value_name as a group name
430 for widget
in widget_by_group
:
431 if widget
.get_active():
432 if 'value' in dir(widget
):
439 class Dialog(gtk
.Dialog
, Window
, PythonicWidget
):
440 def __init__(self
, central_area
, button_area
, *args
, **kwargs
):
442 if 'title' in kwargs
:
443 title
= kwargs
['title']
445 gtk
.Dialog
.__init
__(self
, title
=title
, buttons
=button_area
)
446 PythonicWidget
.__init
__(self
)
448 self
.vbox
.pack_start(central_area
)
449 self
.central_area
= central_area
451 def wait_for_response(self
):
453 response
= self
.run()
457 def get_children(self
):
458 # if we don't have this get_widget_by_name won't work. We'll just skip
459 # the vbox in the middle. We (probably) don't care about the buttons at
461 return [self
.central_area
]
463 def FileChooser(filetypes
=None):
464 chooser
= gtk
.FileChooserDialog(buttons
=(gtk
.STOCK_CANCEL
,gtk
.RESPONSE_CANCEL
,gtk
.STOCK_OPEN
,gtk
.RESPONSE_OK
))
465 if filetypes
is not None:
466 for filetype
in filetypes
:
467 # TODO allow the user to change the name of the filter
468 filter = gtk
.FileFilter()
469 filter.add_pattern(filetype
)
470 chooser
.add_filter(filter)
473 response
= chooser
.run()
474 if response
== gtk
.RESPONSE_OK
:
475 result
= chooser
.get_filename()
476 elif response
== gtk
.RESPONSE_CANCEL
: