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 if 'expand' not in kwargs
and 'fill' not in kwargs
:
49 # if we're creating a widget that has no parent, then we should get
50 # of this now or there'll be errors later
53 expand
= kwargs
.get("expand", True)
54 fill
= kwargs
.get("fill", True)
57 def set_packing(widget
=None, old_parent
=None):
58 parent
= self
.get_parent()
59 if parent
is not None and 'query_child_packing' in dir(parent
):
60 old_values
= list(parent
.query_child_packing(self
))
61 # we just want to change the expand and fill
62 old_values
[0] = expand
64 parent
.set_child_packing(self
, expand
, fill
, old_values
[2], old_values
[3])
67 self
.connect("parent-set", set_packing
)
69 def attach_signal_handlers(self
, **cb_dict
):
70 events_to_signals
= { 'on_click': 'clicked' }
72 for event
, func
in cb_dict
.items():
73 if event
in events_to_signals
:
74 self
.connect(events_to_signals
[event
], func
)
76 def set_name_param(self
, **kwargs
):
78 self
.set_name(kwargs
['name'])
81 def parent_window(self
):
82 if 'container' not in dir(self
):
85 parent
= self
.container
87 if isinstance(parent
, Window
):
89 if 'container' not in dir(parent
):
91 parent
= parent
.container
93 assert False, "Widget %r has no parent window" % self
96 def child_widgets(self
):
97 if 'get_children' not in dir(self
):
103 # When being called with self as a window, it is not returning widgets
105 while len(widgets
) != 0:
106 widget
= widgets
.pop(0)
107 if not isinstance( widget
, gtk
.Container
):
112 for child
in widget
.get_children():
114 if isinstance( child
, gtk
.Container
):
115 widgets
.extend(child
.get_children())
118 class Button(gtk
.Button
, PythonicWidget
):
119 def __init__(self
, label
=None, stock
=None, *args
, **kwargs
):
120 gtk
.Button
.__init
__(self
)
121 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
122 assert len(args
) == 0
125 self
.set_label(label
)
127 self
.set_use_stock(True)
128 self
.set_label(stock
)
131 class VBox(gtk
.VBox
, PythonicWidget
):
132 def __init__(self
, *args
, **kwargs
):
133 gtk
.VBox
.__init
__(self
)
134 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
136 widget
.container
= self
137 self
.pack_start(widget
)
139 class HBox(gtk
.HBox
, PythonicWidget
):
140 def __init__(self
, *args
, **kwargs
):
141 gtk
.HBox
.__init
__(self
)
142 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
144 widget
.container
= self
145 self
.pack_start(widget
)
147 class Label(gtk
.Label
, PythonicWidget
):
148 def __init__(self
, text
, *args
, **kwargs
):
149 gtk
.Label
.__init
__(self
)
150 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
153 class TextEntry(gtk
.Entry
, PythonicWidget
):
154 def __init__(self
, *args
, **kwargs
):
155 gtk
.Entry
.__init
__(self
)
156 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
159 self
.set_text(kwargs
['text'])
163 return self
.get_text()
167 return self
.get_text()
169 class TextView(gtk
.TextView
, PythonicWidget
):
170 def __init__(self
, *args
, **kwargs
):
171 gtk
.TextView
.__init
__(self
)
172 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
176 return self
.get_text()
178 def Labeled( label
, widget
, **kwargs
):
179 return HBox( Label(label
), widget
, **kwargs
)
181 class ScrolledWindow(gtk
.ScrolledWindow
, PythonicWidget
):
182 def __init__(self
, inside_widget
, horizontal
=None, vertical
=None, **kwargs
):
183 gtk
.ScrolledWindow
.__init
__(self
)
184 PythonicWidget
.__init
__(self
, **kwargs
)
185 # FIXME should this be add_with_viewport? Or should it check
186 # inside_widget to see if it should add_with_viewport
187 if isinstance(inside_widget
, gtk
.Viewport
):
188 self
.add(inside_widget
)
190 self
.add_with_viewport(inside_widget
)
191 exiting_horizontal
, existing_vertical
= self
.get_policy()
192 if horizontal
== 'always':
193 self
.set_policy(gtk
.POLICY_ALWAYS
, existing_vertical
)
194 elif horizontal
== 'never':
195 self
.set_policy(gtk
.POLICY_NEVER
, existing_vertical
)
196 elif horizontal
== 'auto' or horizontal
== 'automatic':
197 self
.set_policy(gtk
.POLICY_AUTOMATIC
, existing_vertical
)
198 exiting_horizontal
, existing_vertical
= self
.get_policy()
199 if vertical
== 'always':
200 self
.set_policy(exiting_horizontal
, gtk
.POLICY_ALWAYS
)
201 elif vertical
== 'never':
202 self
.set_policy(exiting_horizontal
, gtk
.POLICY_NEVER
)
203 elif vertical
== 'auto' or vertical
== 'automatic':
204 self
.set_policy(exiting_horizontal
, gtk
.POLICY_AUTOMATIC
)
208 class IconView(gtk
.IconView
, PythonicWidget
):
209 def __init__(self
, elements
, *args
, **kwargs
):
210 gtk
.IconView
.__init
__(self
)
211 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
212 set_properties(self
, kwargs
, ignore_errors
=True)
213 # FIXME check the format of args
214 self
.__init
_from
_icon
_set
(elements
)
216 def __init_from_icon_set(self
, elements
):
217 # elements should be a list. Each element should be the same.
219 # string - each 'icon' is a text
220 # (string, pixbuf) - standard icon and text
222 if type(elements
[0]) == type(""):
223 list = gtk
.ListStore(str)
224 for string
in elements
:
225 list.append([string
])
227 self
.set_text_column(0)
228 elif type(elements
[0]) == type(()):
234 class Toolbar(gtk
.Toolbar
, PythonicWidget
):
235 def __init__(self
, *child_widgets
, **kwargs
):
236 gtk
.Toolbar
.__init
__(self
)
237 PythonicWidget
.__init
__(self
, **kwargs
)
238 for child_widget
in child_widgets
:
239 # insert it at the end
240 #toolitem = gtk.ToolItem()
241 #toolitem.pack_start(child_widget)
242 self
.insert( child_widget
, -1 )
244 class NewButton(Button
, PythonicWidget
):
245 def __init__(self
, *args
, **kwargs
):
246 Button
.__init
__(self
, stock
="gtk-new")
247 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
249 class AddButton(Button
, PythonicWidget
):
250 def __init__(self
, *args
, **kwargs
):
251 Button
.__init
__(self
, stock
="gtk-add")
252 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
254 class RemoveButton(Button
, PythonicWidget
):
255 def __init__(self
, *args
, **kwargs
):
256 Button
.__init
__(self
, stock
="gtk-remove")
257 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
259 class SaveButton(Button
, PythonicWidget
):
260 def __init__(self
, *args
, **kwargs
):
261 Button
.__init
__(self
, stock
="gtk-save")
262 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
264 class NewToolbarButton(gtk
.ToolButton
, PythonicWidget
):
265 def __init__(self
, *args
, **kwargs
):
266 gtk
.ToolButton
.__init
__(self
, 'gtk-new')
267 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
269 class PropertiesButton(Button
, PythonicWidget
):
270 def __init__(self
, *args
, **kwargs
):
271 Button
.__init
__(self
, stock
="gtk-properties")
272 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
274 class PropertiesToolbarButton(gtk
.ToolButton
, PythonicWidget
):
275 def __init__(self
, *args
, **kwargs
):
276 gtk
.ToolButton
.__init
__(self
, "gtk-properties")
277 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
279 class ComboBox(gtk
.ComboBox
, PythonicWidget
):
280 def __init__(self
, *rows
, **kwargs
):
281 gtk
.ComboBox
.__init
__(self
)
282 PythonicWidget
.__init
__(self
, **kwargs
)
284 liststore
= gtk
.ListStore(str)
285 self
.set_model( liststore
)
287 cell
= gtk
.CellRendererText()
288 self
.pack_start( cell
, True )
289 self
.add_attribute( cell
, 'text', 0 )
293 for index
, row
in enumerate( rows
):
294 if isinstance( row
, basestring
):
299 if options
['selected']:
301 self
.append_text( text
)
303 if active
is not None:
304 self
.set_active( active
)
307 class Notebook(gtk
.Notebook
, PythonicWidget
):
308 def __init__(self
, *pages
, **kwargs
):
309 gtk
.Notebook
.__init
__(self
)
310 PythonicWidget
.__init
__(self
, **kwargs
)
312 for page_name
, page_contents
in pages
:
313 if isinstance(page_name
, basestring
):
314 page_name
= Label( page_name
)
315 self
.append_page( child
=page_contents
, tab_label
=page_name
)
317 class RadioButton(gtk
.RadioButton
, PythonicWidget
):
318 def __init__(self
, group
=None, label
=None, *args
, **kwargs
):
319 gtk
.RadioButton
.__init
__(self
, group
=None, label
=label
)
320 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
323 if 'value' in kwargs
:
324 self
.value
= kwargs
['value']
327 def update_all_radiobutton_groups(widget
, new_child
):
328 if 'get_children' not in dir( widget
):
331 child_radiobuttons
= [child
for child
in widget
.child_widgets
if isinstance( child
, RadioButton
) ]
334 for radiobutton
in child_radiobuttons
:
335 group_name
= radiobutton
.group
336 if group_name
not in groups
:
337 groups
[group_name
] = []
338 groups
[group_name
].append(radiobutton
)
340 for group_name
in groups
:
341 inital_group
= groups
[group_name
][0]
342 if len(groups
[group_name
]) <= 1:
344 for radiobutton
in groups
[group_name
][1:]:
345 radiobutton
.set_group(None)
346 radiobutton
.set_group(inital_group
)
349 def add_updater_callback(widget
, old_parent
):
350 #print "Adding the add_updater_callback to "+repr(widget)
351 # when the parent is set we need to tell the parent to update_all_radiobutton_groups
353 if "get_children" in dir( widget
):
354 #print repr(widget)+" is a container"
355 update_all_radiobutton_groups(widget
, None)
356 widget
.connect( "add", update_all_radiobutton_groups
)
358 if 'container' in dir( widget
) and widget
.container
:
359 widget
.container
.connect( "parent-set", add_updater_callback
)
361 self
.connect("parent-set", add_updater_callback
)
362 update_all_radiobutton_groups(self
, None)
366 class ListBox(gtk
.TreeView
, PythonicWidget
):
367 def __init__(self
, *rows
, **kwargs
):
369 columns
= kwargs
['columns']
371 # Turn our key error into a type error
372 raise TypeError, "ListBox constructor requires the 'columns' argument"
373 gtk
.TreeView
.__init
__(self
)
374 PythonicWidget
.__init
__(self
, **kwargs
)
376 # We assume they are all text columns for now
377 # TODO allow the caller to change this.
378 for index
, col
in enumerate(columns
):
379 if isinstance( col
, basestring
):
383 column
= gtk
.TreeViewColumn(col
, gtk
.CellRendererText(), text
=index
)
384 column
.set_resizable(True)
385 column
.set_sort_column_id(index
)
386 self
.append_column(column
)
388 #view_entries_list.connect("row-activated", show_single_entry)
391 #column_types.extend([x['type'] for x in view_def['columns']])
392 #column_types.extend([gobject.TYPE_PYOBJECT])
394 column_types
= [str] * len(columns
)
395 self
.rows
= ListStore(column_types
=column_types
, rows
=rows
)
397 self
.set_model(self
.rows
)
399 class ListStore(gtk
.ListStore
, PythonicWidget
):
400 def __init__(self
, column_types
, rows
=None, *args
, **kwargs
):
401 gtk
.ListStore
.__init
__(self
, *column_types
)
402 PythonicWidget
.__init
__(self
, *args
, **kwargs
)
403 self
.column_types
= column_types
405 if len(row
) != len(column_types
):
406 raise TypeError, "Row %r has %d entries but there are %d columns definied (%r)" % ( row
, len(row
), len(columns
), columns
)
407 gtk
.ListStore
.append(self
, row
)
410 class Window(gtk
.Window
, PythonicWidget
):
411 def __init__(self
, child_widget
, *args
, **kwargs
):
412 gtk
.Window
.__init
__(self
)
413 PythonicWidget
.__init
__(self
, **kwargs
)
415 self
.add(child_widget
)
416 child_widget
.container
= self
418 if 'title' in kwargs
:
419 self
.set_title(kwargs
['title'])
421 if 'quit_on_close' in kwargs
:
422 if kwargs
['quit_on_close'] == True:
423 self
.connect("destroy", gtk
.main_quit
)
425 def get_value(self
, value_name
):
426 # Either the widget is a text box (eg) that we can read the value off,
427 # or it's some kind of multi-selection thing, like a set of radio
429 widget_by_name
= get_widget_by_name(self
, value_name
)
431 return widget_by_name
.value
433 widget_by_group
= [widget
for widget
in self
.child_widgets
if isinstance( widget
, RadioButton
) and widget
.group
== value_name
]
434 if len(widget_by_group
) == 0:
435 # no radio buttons have value_name as a group name
437 for widget
in widget_by_group
:
438 if widget
.get_active():
439 if 'value' in dir(widget
):
446 class Dialog(gtk
.Dialog
, Window
, PythonicWidget
):
447 def __init__(self
, central_area
, button_area
, *args
, **kwargs
):
449 if 'title' in kwargs
:
450 title
= kwargs
['title']
452 gtk
.Dialog
.__init
__(self
, title
=title
, buttons
=button_area
)
453 PythonicWidget
.__init
__(self
)
455 self
.vbox
.pack_start(central_area
)
456 self
.central_area
= central_area
458 def wait_for_response(self
):
460 response
= self
.run()
464 def get_children(self
):
465 # if we don't have this get_widget_by_name won't work. We'll just skip
466 # the vbox in the middle. We (probably) don't care about the buttons at
468 return [self
.central_area
]
470 def FileChooser(filetypes
=None):
471 chooser
= gtk
.FileChooserDialog(buttons
=(gtk
.STOCK_CANCEL
,gtk
.RESPONSE_CANCEL
,gtk
.STOCK_OPEN
,gtk
.RESPONSE_OK
))
472 if filetypes
is not None:
473 for filetype
in filetypes
:
474 # TODO allow the user to change the name of the filter
475 filter = gtk
.FileFilter()
476 filter.add_pattern(filetype
)
477 chooser
.add_filter(filter)
480 response
= chooser
.run()
481 if response
== gtk
.RESPONSE_OK
:
482 result
= chooser
.get_filename()
483 elif response
== gtk
.RESPONSE_CANCEL
: