~ubuntu-branches/ubuntu/natty/miro/natty

« back to all changes in this revision

Viewing changes to portable/frontends/widgets/gtk/controls.py

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2011-01-22 02:46:33 UTC
  • mfrom: (1.4.10 upstream) (1.7.5 experimental)
  • Revision ID: james.westby@ubuntu.com-20110122024633-kjme8u93y2il5nmf
Tags: 3.5.1-1ubuntu1
* Merge from debian.  Remaining ubuntu changes:
  - Use python 2.7 instead of python 2.6
  - Relax dependency on python-dbus to >= 0.83.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Miro - an RSS based video player application
2
 
# Copyright (C) 2005-2010 Participatory Culture Foundation
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17
 
#
18
 
# In addition, as a special exception, the copyright holders give
19
 
# permission to link the code of portions of this program with the OpenSSL
20
 
# library.
21
 
#
22
 
# You must obey the GNU General Public License in all respects for all of
23
 
# the code used other than OpenSSL. If you modify file(s) with this
24
 
# exception, you may extend this exception to your version of the file(s),
25
 
# but you are not obligated to do so. If you do not wish to do so, delete
26
 
# this exception statement from your version. If you delete this exception
27
 
# statement from all source files in the program, then also delete it here.
28
 
 
29
 
"""miro.frontends.widgets.gtk.controls -- Control Widgets."""
30
 
 
31
 
import weakref
32
 
 
33
 
import gtk
34
 
import gobject
35
 
import pango
36
 
 
37
 
from miro import searchengines
38
 
from miro.frontends.widgets import widgetconst
39
 
from miro.frontends.widgets.gtk.base import Widget
40
 
from miro.frontends.widgets.gtk.simple import Label
41
 
 
42
 
class BinBaselineCalculator(object):
43
 
    """Mixin class that defines the baseline method for gtk.Bin subclasses,
44
 
    where the child is the label that we are trying to get the baseline for.
45
 
    """
46
 
 
47
 
    def baseline(self):
48
 
        my_size = self._widget.size_request()
49
 
        child_size = self._widget.child.size_request()
50
 
        ypad = (my_size[1] - child_size[1]) / 2
51
 
 
52
 
        pango_context = self._widget.get_pango_context()
53
 
        metrics = pango_context.get_metrics(self._widget.style.font_desc)
54
 
        return pango.PIXELS(metrics.get_descent()) + ypad
55
 
 
56
 
class TextEntry(Widget):
57
 
    entry_class = gtk.Entry
58
 
    def __init__(self, initial_text=None):
59
 
        Widget.__init__(self)
60
 
        self.create_signal('activate')
61
 
        self.create_signal('changed')
62
 
        self.create_signal('validate')
63
 
        self.set_widget(self.entry_class())
64
 
        self.forward_signal('activate')
65
 
        self.forward_signal('changed')
66
 
        if initial_text is not None:
67
 
            self.set_text(initial_text)
68
 
 
69
 
    def focus(self):
70
 
        self._widget.grab_focus()
71
 
 
72
 
    def set_text(self, text):
73
 
        self._widget.set_text(text)
74
 
 
75
 
    def get_text(self):
76
 
        return self._widget.get_text().decode('utf-8')
77
 
 
78
 
    def set_width(self, chars):
79
 
        self._widget.set_width_chars(chars)
80
 
 
81
 
    def set_invisible(self, setting):
82
 
        self._widget.props.visibility = not setting
83
 
 
84
 
    def set_activates_default(self, setting):
85
 
        self._widget.set_activates_default(setting)
86
 
 
87
 
    def baseline(self):
88
 
        layout_height = pango.PIXELS(self._widget.get_layout().get_size()[1])
89
 
        ypad = (self._widget.size_request()[1] - layout_height) / 2
90
 
        pango_context = self._widget.get_pango_context()
91
 
        metrics = pango_context.get_metrics(self._widget.style.font_desc)
92
 
        return pango.PIXELS(metrics.get_descent()) + ypad
93
 
 
94
 
class SecureTextEntry(TextEntry):
95
 
    def __init__(self, initial_text=None):
96
 
        TextEntry.__init__(self, initial_text)
97
 
        self.set_invisible(True)
98
 
 
99
 
class MultilineTextEntry(Widget):
100
 
    entry_class = gtk.TextView
101
 
    def __init__(self, initial_text=None):
102
 
        Widget.__init__(self)
103
 
        self.set_widget(self.entry_class())
104
 
        if initial_text is not None:
105
 
            self.set_text(initial_text)
106
 
        self._widget.set_wrap_mode(gtk.WRAP_WORD)
107
 
 
108
 
    def focus(self):
109
 
        self._widget.grab_focus()
110
 
 
111
 
    def set_text(self, text):
112
 
        self._widget.get_buffer().set_text(text)
113
 
 
114
 
    def get_text(self):
115
 
        buffer_ = self._widget.get_buffer()
116
 
        return buffer_.get_text(*(buffer_.get_bounds())).decode('utf-8')
117
 
 
118
 
    def baseline(self):
119
 
        # FIXME
120
 
        layout_height = pango.PIXELS(self._widget.get_layout().get_size()[1])
121
 
        ypad = (self._widget.size_request()[1] - layout_height) / 2
122
 
        pango_context = self._widget.get_pango_context()
123
 
        metrics = pango_context.get_metrics(self._widget.style.font_desc)
124
 
        return pango.PIXELS(metrics.get_descent()) + ypad
125
 
 
126
 
class Checkbox(Widget, BinBaselineCalculator):
127
 
    """Widget that the user can toggle on or off."""
128
 
 
129
 
    def __init__(self, label):
130
 
        Widget.__init__(self)
131
 
        self.set_widget(gtk.CheckButton(label))
132
 
        self.create_signal('toggled')
133
 
        self.forward_signal('toggled')
134
 
 
135
 
    def get_checked(self):
136
 
        return self._widget.get_active()
137
 
 
138
 
    def set_checked(self, value):
139
 
        self._widget.set_active(value)
140
 
 
141
 
class RadioButtonGroup:
142
 
    """RadioButtonGroup.
143
 
 
144
 
    Create the group, then create a bunch of RadioButtons passing in the group.
145
 
    """
146
 
    def __init__(self):
147
 
        self._buttons = []
148
 
 
149
 
    def add_button(self, button):
150
 
        self._buttons.append(button)
151
 
 
152
 
    def get_buttons(self):
153
 
        return self._buttons
154
 
 
155
 
    def get_selected(self):
156
 
        for mem in self._buttons:
157
 
            if mem.get_selected():
158
 
                return mem
159
 
 
160
 
    def set_selected(self, button):
161
 
        for mem in self._buttons:
162
 
            if mem is button:
163
 
                mem._widget.set_active(True)
164
 
            else:
165
 
                mem._widget.set_active(False)
166
 
 
167
 
 
168
 
# use a weakref so that we're not creating circular references between
169
 
# RadioButtons and RadioButtonGroups
170
 
radio_button_to_group_mapping = weakref.WeakValueDictionary()
171
 
 
172
 
class RadioButton(Widget, BinBaselineCalculator):
173
 
    """RadioButton."""
174
 
    def __init__(self, label, group=None):
175
 
        Widget.__init__(self)
176
 
        self.set_widget(gtk.RadioButton(label=label))
177
 
        self.create_signal('clicked')
178
 
        self.forward_signal('clicked')
179
 
 
180
 
        if group:
181
 
            buttons = group.get_buttons()
182
 
            if buttons:
183
 
                self._widget.set_group(buttons[0]._widget)
184
 
        else:
185
 
            group = RadioButtonGroup()
186
 
 
187
 
        group.add_button(self)
188
 
        oid = id(self)
189
 
        radio_button_to_group_mapping[oid] = group
190
 
 
191
 
    def get_group(self):
192
 
        return radio_button_to_group_mapping[id(self)]
193
 
 
194
 
    def get_selected(self):
195
 
        return self._widget.get_active()
196
 
 
197
 
    def set_selected(self):
198
 
        radio_button_to_group_mapping[id(self)].set_selected(self)
199
 
 
200
 
class Button(Widget, BinBaselineCalculator):
201
 
    def __init__(self, text, style='normal'):
202
 
        Widget.__init__(self)
203
 
        # We just ignore style here, GTK users expect their own buttons.
204
 
        self.set_widget(gtk.Button())
205
 
        self.create_signal('clicked')
206
 
        self.forward_signal('clicked')
207
 
        self.label = Label(text)
208
 
        self._widget.add(self.label._widget)
209
 
        self.label._widget.show()
210
 
 
211
 
    def set_text(self, title):
212
 
        self.label.set_text(title)
213
 
 
214
 
    def set_bold(self, bold):
215
 
        self.label.set_bold(bold)
216
 
 
217
 
    def set_size(self, scale_factor):
218
 
        self.label.set_size(scale_factor)
219
 
 
220
 
    def set_color(self, color):
221
 
        self.label.set_color(color)
222
 
 
223
 
class OptionMenu(Widget):
224
 
    def __init__(self, options):
225
 
        Widget.__init__(self)
226
 
        self.create_signal('changed')
227
 
 
228
 
        self.set_widget(gtk.ComboBox(gtk.ListStore(str, str)))
229
 
        self.cell = gtk.CellRendererText()
230
 
        self._widget.pack_start(self.cell, True)
231
 
        self._widget.add_attribute(self.cell, 'text', 0)
232
 
        if options:
233
 
            for option in options:
234
 
                self._widget.get_model().append((option, 'booya'))
235
 
            self._widget.set_active(0)
236
 
        self.options = options
237
 
        self.wrapped_widget_connect('changed', self.on_changed)
238
 
 
239
 
    def baseline(self):
240
 
        my_size = self._widget.size_request()
241
 
        child_size = self._widget.child.size_request()
242
 
        ypad = self.cell.props.ypad + (my_size[1] - child_size[1]) / 2
243
 
 
244
 
        pango_context = self._widget.get_pango_context()
245
 
        metrics = pango_context.get_metrics(self._widget.style.font_desc)
246
 
        return pango.PIXELS(metrics.get_descent()) + ypad 
247
 
 
248
 
    def set_bold(self, bold):
249
 
        if bold:
250
 
            self.cell.props.weight = pango.WEIGHT_BOLD
251
 
        else:
252
 
            self.cell.props.weight = pango.WEIGHT_NORMAL
253
 
 
254
 
    def set_size(self, size):
255
 
        if size == widgetconst.SIZE_NORMAL:
256
 
            self.cell.props.scale = 1
257
 
        else:
258
 
            self.cell.props.scale = 0.85
259
 
 
260
 
    def set_color(self, color):
261
 
        self.cell.props.foreground_gdk = self.make_color(color)
262
 
 
263
 
    def set_selected(self, index):
264
 
        self._widget.set_active(index)
265
 
 
266
 
    def get_selected(self):
267
 
        return self._widget.get_active()
268
 
 
269
 
    def on_changed(self, widget):
270
 
        index = widget.get_active()
271
 
        self.emit('changed', index)