Moved DialogResponse, ButtonClickedBlocker and MixedButton to gtkutils
[zeroinstall.git] / zeroinstall / gtkui / gtkutils.py
blob97af3adefb5aaa5b8e134ff3990947873f466965
1 """Useful utility methods for GTK."""
3 # Copyright (C) 2009, Thomas Leonard
4 # See the README file for details, or visit http://0install.net.
6 import gtk
7 from zeroinstall.support import tasks
9 class Template:
10 """Wrapper for GtkBuilder widget tree that throws a sensible exception if the widget isn't found."""
11 def __init__(self, builderfile, root):
12 """Constructor.
13 @param builderfile: pathname of the .ui file to load
14 @param root: the name of the top-level widget inside the file"""
15 self.builder = gtk.Builder()
16 self.builder.set_translation_domain('zero-install')
17 self.builder.add_from_file(builderfile)
18 self.builderfile = builderfile
19 self.root = root
21 def get_widget(self, name = None):
22 """Look up a widget by name."""
23 if not name:
24 name = self.root
25 widget = self.builder.get_object(name)
26 assert widget, "Widget '%s' not found in GtkBuilder file '%s'" % (name, self.builderfile)
27 return widget
29 def show_message_box(parent, message, type = gtk.MESSAGE_ERROR):
30 """Display a non-modal message box with an OK button.
31 @param parent: the parent window
32 @param message: the message to be displayed
33 @param type: the type of box (used for the icon)"""
34 box = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT,
35 type, gtk.BUTTONS_OK,
36 str(message))
37 box.set_position(gtk.WIN_POS_CENTER)
38 def resp(b, r):
39 b.destroy()
40 box.connect('response', resp)
41 box.show()
43 _busy_pointer = None
44 def get_busy_pointer():
45 """Get a GDK background-activity cursor.
46 Use this when something is happening, but the GUI is still responsive.
47 @return: the busy cursor (a singleton)
48 @rtype: gdk.Cursor
49 """
50 global _busy_pointer
51 if _busy_pointer is not None:
52 return _busy_pointer
54 # This is crazy. We build a cursor that looks like the old
55 # Netscape busy-with-a-pointer cursor and set that, then the
56 # X server replaces it with a decent-looking one!!
57 # See http://mail.gnome.org/archives/gtk-list/2007-May/msg00100.html
59 bit_data = "\
60 \x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\
61 \x0c\x00\x00\x00\x1c\x00\x00\x00\x3c\x00\x00\x00\
62 \x7c\x00\x00\x00\xfc\x00\x00\x00\xfc\x01\x00\x00\
63 \xfc\x3b\x00\x00\x7c\x38\x00\x00\x6c\x54\x00\x00\
64 \xc4\xdc\x00\x00\xc0\x44\x00\x00\x80\x39\x00\x00\
65 \x80\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
66 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
67 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
68 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
69 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
70 \x00\x00\x00\x00\x00\x00\x00\x00"
72 try:
73 pix = gtk.gdk.bitmap_create_from_data(None, bit_data, 32, 32)
74 color = gtk.gdk.Color()
75 _busy_pointer = gtk.gdk.Cursor(pix, pix, color, color, 2, 2)
76 except:
77 #old bug http://bugzilla.gnome.org/show_bug.cgi?id=103616
78 _busy_pointer = gtk.gdk.Cursor(gtk.gdk.WATCH)
79 return _busy_pointer
81 class DialogResponse(tasks.Blocker):
82 """Triggers when the GtkDialog gets a response.
83 @since: 1.5"""
84 response = None
85 def __init__(self, dialog):
86 tasks.Blocker.__init__(self, dialog.get_title())
87 a = None
88 def response(d, resp):
89 self.response = resp
90 d.disconnect(a)
91 self.trigger()
92 a = dialog.connect('response', response)
94 class ButtonClickedBlocker(tasks.Blocker):
95 """Triggers when the GtkButton is activated.
96 @since: 1.5"""
97 def __init__(self, button):
98 tasks.Blocker.__init__(self, "Button click")
99 a = None
100 def clicked(b):
101 b.disconnect(a)
102 self.trigger()
103 a = button.connect('clicked', lambda b: self.trigger())
105 def MixedButton(message, stock, x_align = 0.5, button = None):
106 """A GtkButton with a stock icon.
107 @since: 1.5"""
108 if button is None:
109 button = gtk.Button()
111 label = gtk.Label('')
112 label.set_text_with_mnemonic(message)
113 label.set_mnemonic_widget(button)
115 image = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_BUTTON)
116 box = gtk.HBox(False, 2)
117 align = gtk.Alignment(x_align, 0.5, 0.0, 0.0)
119 box.pack_start(image, False, False, 0)
120 box.pack_end(label, False, False, 0)
122 button.add(align)
123 align.add(box)
124 return button