~mvo/software-center/qml

« back to all changes in this revision

Viewing changes to softwarecenter/ui/gtk/widgets/backforward.py

  • Committer: Michael Vogt
  • Date: 2011-10-05 13:08:09 UTC
  • mfrom: (1887.1.603 software-center)
  • Revision ID: michael.vogt@ubuntu.com-20111005130809-0tin9nr00f0uw65b
mergedĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010 Matthew McGowan
2
 
#
3
 
# Authors:
4
 
#   Matthew McGowan
5
 
#
6
 
# This program is free software: you can redistribute it and/or modify
7
 
# it under the terms of the GNU General Public License as published by
8
 
# the Free Software Foundation, either version 3 of the License, or
9
 
# (at your option) any later version.
10
 
#
11
 
# This program is distributed in the hope that it will be useful,
12
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
# GNU General Public License for more details.
15
 
#
16
 
# You should have received a copy of the GNU General Public License
17
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
 
19
 
 
20
 
import atk
21
 
import gtk
22
 
import gobject
23
 
import mkit
24
 
 
25
 
from gettext import gettext as _
26
 
 
27
 
 
28
 
DEFAULT_PART_SIZE = (29, -1)
29
 
DEFAULT_ARROW_SIZE = (12, 12)
30
 
 
31
 
 
32
 
class BackForwardButton(gtk.HBox):
33
 
 
34
 
    __gsignals__ = {'left-clicked':(gobject.SIGNAL_RUN_LAST,
35
 
                                    gobject.TYPE_NONE,
36
 
                                    (gtk.gdk.Event,)),
37
 
 
38
 
                    'right-clicked':(gobject.SIGNAL_RUN_LAST,
39
 
                                    gobject.TYPE_NONE,
40
 
                                    (gtk.gdk.Event,))}
41
 
 
42
 
    def __init__(self, part_size=None):
43
 
        gtk.HBox.__init__(self)
44
 
        self.theme = mkit.get_mkit_theme()
45
 
        self.separator = SeparatorPart()
46
 
        self.use_hand = False
47
 
 
48
 
        part_size = part_size or DEFAULT_PART_SIZE
49
 
 
50
 
        if self.get_direction() != gtk.TEXT_DIR_RTL:
51
 
            # ltr
52
 
            self.left = ButtonPartLeft('left-clicked', part_size)
53
 
            self.right = ButtonPartRight('right-clicked', part_size)
54
 
            self.set_button_atk_info_ltr()
55
 
        else:
56
 
            # rtl
57
 
            self.left = ButtonPartRight('left-clicked', part_size, gtk.ARROW_LEFT)
58
 
            self.right = ButtonPartLeft('right-clicked', part_size, gtk.ARROW_RIGHT)
59
 
            self.set_button_atk_info_rtl()
60
 
 
61
 
        atk_obj = self.get_accessible()
62
 
        atk_obj.set_name(_('History Navigation'))
63
 
        atk_obj.set_description(_('Navigate forwards and backwards.'))
64
 
        atk_obj.set_role(atk.ROLE_PANEL)
65
 
 
66
 
        self.pack_start(self.left)
67
 
        self.pack_start(self.separator, False)
68
 
        self.pack_end(self.right)
69
 
 
70
 
        self.separator.connect_after("style-set", self._on_style_set)
71
 
        self.connect_after('size-allocate', self._on_size_allocate)
72
 
        return
73
 
 
74
 
    def set_button_atk_info_ltr(self):
75
 
        # left button
76
 
        atk_obj = self.left.get_accessible()
77
 
        atk_obj.set_name(_('Back Button'))
78
 
        atk_obj.set_description(_('Navigates back.'))
79
 
        atk_obj.set_role(atk.ROLE_PUSH_BUTTON)
80
 
 
81
 
        # right button
82
 
        atk_obj = self.right.get_accessible()
83
 
        atk_obj.set_name(_('Forward Button'))
84
 
        atk_obj.set_description(_('Navigates forward.'))
85
 
        atk_obj.set_role(atk.ROLE_PUSH_BUTTON)
86
 
        return
87
 
 
88
 
    def set_button_atk_info_rtl(self):
89
 
        # right button
90
 
        atk_obj = self.right.get_accessible()
91
 
        atk_obj.set_name(_('Back Button'))
92
 
        atk_obj.set_description(_('Navigates back.'))
93
 
        atk_obj.set_role(atk.ROLE_PUSH_BUTTON)
94
 
 
95
 
        # left button
96
 
        atk_obj = self.left.get_accessible()
97
 
        atk_obj.set_name(_('Forward Button'))
98
 
        atk_obj.set_description(_('Navigates forward.'))
99
 
        atk_obj.set_role(atk.ROLE_PUSH_BUTTON)
100
 
        return
101
 
 
102
 
    def set_use_hand_cursor(self, use_hand):
103
 
        self.use_hand = use_hand
104
 
        return
105
 
 
106
 
    def _on_style_set(self, widget, oldstyle):
107
 
        # when alloc.width == 1, this is typical of an unallocated widget,
108
 
        # lets not break a sweat for nothing...
109
 
        if self.allocation.width == 1:
110
 
            return
111
 
 
112
 
        old_xthickness = self.theme['xthickness']
113
 
        self.theme = mkit.get_mkit_theme()
114
 
        if old_xthickness > self.theme['xthickness']:
115
 
            a = self.allocation
116
 
            self.queue_draw_area(a.x, a.y,
117
 
                                 a.width+self.theme['xthickness'], a.height)
118
 
        else:
119
 
            self.queue_draw()
120
 
        return
121
 
 
122
 
    def _on_size_allocate(self, widget, allocation):
123
 
        self.queue_draw()
124
 
        return
125
 
 
126
 
    def draw(self, cr, expose_area, left_alpha=1.0, right_alpha=1.0):
127
 
        self.separator.alpha = max(left_alpha, right_alpha)
128
 
        self.separator.queue_draw()
129
 
        self.left.draw(cr, expose_area, left_alpha)
130
 
        self.right.draw(cr, expose_area, right_alpha)
131
 
        return
132
 
 
133
 
 
134
 
class SeparatorPart(gtk.DrawingArea):
135
 
 
136
 
    def __init__(self):
137
 
        gtk.DrawingArea.__init__(self)
138
 
        self.alpha = 1.0
139
 
        self.theme = mkit.get_mkit_theme()
140
 
        self.set_size_request(self.theme['xthickness'], -1)
141
 
 
142
 
        atk_obj = self.get_accessible()
143
 
        atk_obj.set_role(atk.ROLE_SEPARATOR)
144
 
 
145
 
        self.connect("expose-event", self._on_expose)
146
 
        self.connect("style-set", self._on_style_set)
147
 
        return
148
 
 
149
 
    def _on_expose(self, widget, event):
150
 
        parent = self.get_parent()
151
 
        if not parent: return
152
 
        cr = widget.window.cairo_create()
153
 
        cr.rectangle(event.area)
154
 
        if self.alpha == 1.0:
155
 
            cr.set_source_rgb(*self.theme.dark_line[self.state].floats())
156
 
        else:
157
 
            r, g, b = self.theme.dark_line[self.state].floats()
158
 
            cr.set_source_rgba(r, g, b, self.alpha)
159
 
 
160
 
        cr.fill()
161
 
        del cr
162
 
        return
163
 
 
164
 
    def _on_style_set(self, widget, old_style):
165
 
        self.theme = mkit.get_mkit_theme()
166
 
        self.set_size_request(self.theme['xthickness'], -1)
167
 
        return
168
 
 
169
 
 
170
 
class ButtonPart(gtk.EventBox):
171
 
 
172
 
    def __init__(self, arrow_type, signal_name, part_size):
173
 
        gtk.EventBox.__init__(self)
174
 
 
175
 
        self.is_active = False
176
 
 
177
 
        self.set_redraw_on_allocate(False)
178
 
        self.set_visible_window(False)
179
 
 
180
 
        self.set_size_request(*part_size)
181
 
        self.shape = mkit.SHAPE_RECTANGLE
182
 
        self.button_down = False
183
 
        self.add(gtk.Arrow(arrow_type, gtk.SHADOW_OUT))
184
 
 
185
 
        self.set_flags(gtk.CAN_FOCUS)
186
 
        self.set_events(gtk.gdk.ENTER_NOTIFY_MASK|
187
 
                        gtk.gdk.LEAVE_NOTIFY_MASK|
188
 
                        gtk.gdk.BUTTON_PRESS_MASK|
189
 
                        gtk.gdk.BUTTON_RELEASE_MASK)
190
 
 
191
 
        self.connect("enter-notify-event", self._on_enter)
192
 
        self.connect("leave-notify-event", self._on_leave)
193
 
        self.connect("button-press-event", self._on_press)
194
 
        self.connect("button-release-event", self._on_release, signal_name)
195
 
        self.connect("key-press-event", self._on_key_press)
196
 
        self.connect("key-release-event", self._on_key_release, signal_name)
197
 
        return
198
 
 
199
 
    def set_sensitive(self, is_sensitive):
200
 
        if is_sensitive:
201
 
            self.set_state(gtk.STATE_NORMAL)
202
 
        super(ButtonPart, self).set_sensitive(is_sensitive)
203
 
        return
204
 
 
205
 
    def set_active(self, is_active):
206
 
        if is_active:
207
 
            self.shadow_type = gtk.SHADOW_IN
208
 
            self.set_state(gtk.STATE_ACTIVE)
209
 
        else:
210
 
            self.shadow_type = gtk.SHADOW_OUT
211
 
            self.set_state(gtk.STATE_NORMAL)
212
 
        return
213
 
 
214
 
    def _on_enter(self, widget, event):
215
 
        if self.state == gtk.STATE_INSENSITIVE: return
216
 
        if not self.button_down:
217
 
            self.set_state(gtk.STATE_PRELIGHT)
218
 
        else:
219
 
            self.set_active(True)
220
 
        if self.parent.use_hand:
221
 
            self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
222
 
        return
223
 
 
224
 
    def _on_key_press(self, widget, event):
225
 
        # react to spacebar, enter, numpad-enter
226
 
        if event.keyval in (32, 65293, 65421):
227
 
            self.set_state(gtk.STATE_ACTIVE)
228
 
        return
229
 
 
230
 
    def _on_key_release(self, widget, event, signal_name):
231
 
        # react to spacebar, enter, numpad-enter
232
 
        if event.keyval in (32, 65293, 65421):
233
 
            self.set_state(gtk.STATE_SELECTED)
234
 
            self.get_parent().emit(signal_name, event)
235
 
        return
236
 
 
237
 
    def _on_leave(self, widget, event):
238
 
        if self.state == gtk.STATE_INSENSITIVE: return
239
 
        self.set_active(False)
240
 
        if self.parent.use_hand:
241
 
            self.window.set_cursor(None)
242
 
        return
243
 
 
244
 
    def _on_press(self, widget, event):
245
 
        if self.state == gtk.STATE_INSENSITIVE: return
246
 
        self.button_down = True
247
 
        self.set_active(True)
248
 
        return
249
 
 
250
 
    def _on_release(self, widget, event, signal_name):
251
 
        if self.state == gtk.STATE_INSENSITIVE: return
252
 
        self.button_down = False
253
 
        self.shadow_type = gtk.SHADOW_OUT
254
 
        p = gtk.gdk.device_get_core_pointer()
255
 
        x, y = p.get_state(widget.window)[0]
256
 
        rr = gtk.gdk.region_rectangle(widget.allocation)
257
 
        if rr.point_in(int(x), int(y)):
258
 
            self.set_state(gtk.STATE_PRELIGHT)
259
 
            self.get_parent().emit(signal_name, event)
260
 
        else:
261
 
            self.set_state(gtk.STATE_NORMAL)
262
 
        return
263
 
 
264
 
    def do_draw(self, cr, a, expose_area, xo, wo, alpha):
265
 
        if gtk.gdk.region_rectangle(expose_area).rect_in(a) == gtk.gdk.OVERLAP_RECTANGLE_OUT:
266
 
            return
267
 
        if not self.parent.get_property('visible'): return
268
 
 
269
 
        cr.save()
270
 
        cr.rectangle(a)
271
 
        cr.clip()
272
 
 
273
 
        self.parent.theme.paint_bg(cr,
274
 
                                   self,
275
 
                                   a.x+xo, a.y,
276
 
                                   a.width+wo, a.height,
277
 
                                   alpha=alpha)
278
 
 
279
 
        if self.has_focus():
280
 
            self.style.paint_focus(self.window,
281
 
                                   self.state,
282
 
                                   (a.x+4, a.y+4, a.width-8, a.height-8),
283
 
                                   self,
284
 
                                   'button',
285
 
                                   a.x+4, a.y+4,
286
 
                                   a.width-8, a.height-8)
287
 
        cr.restore()
288
 
        return
289
 
 
290
 
 
291
 
class ButtonPartLeft(ButtonPart):
292
 
 
293
 
    def __init__(self, sig_name, part_size, arrow_type=gtk.ARROW_LEFT):
294
 
        ButtonPart.__init__(self,
295
 
                            arrow_type,
296
 
                            sig_name,
297
 
                            part_size)
298
 
        self.connect("expose-event", self._on_expose)
299
 
        return
300
 
 
301
 
    def _on_expose(self, widget, event):
302
 
        cr = self.window.cairo_create()
303
 
        self.draw(cr, event.area, alpha=1.0)
304
 
        return
305
 
 
306
 
    def draw(self, cr, expose_area, alpha):
307
 
        r = int(self.parent.theme['curvature'])
308
 
        self.do_draw(cr,
309
 
                     self.allocation,
310
 
                     expose_area,
311
 
                     xo=0,
312
 
                     wo=r,
313
 
                     alpha=alpha)
314
 
        return
315
 
 
316
 
 
317
 
class ButtonPartRight(ButtonPart):
318
 
 
319
 
    def __init__(self, sig_name, part_size, arrow_type=gtk.ARROW_RIGHT):
320
 
        ButtonPart.__init__(self,
321
 
                            arrow_type,
322
 
                            sig_name,
323
 
                            part_size)
324
 
        self.connect("expose-event", self._on_expose)
325
 
        return
326
 
 
327
 
    def _on_expose(self, widget, event):
328
 
        cr = self.window.cairo_create()
329
 
        self.draw(cr, event.area, alpha=1.0)
330
 
        return
331
 
 
332
 
    def draw(self, cr, expose_area, alpha):
333
 
        r = int(self.parent.theme['curvature'])
334
 
        self.do_draw(cr,
335
 
                     self.allocation,
336
 
                     expose_area,
337
 
                     xo=-r,
338
 
                     wo=r,
339
 
                     alpha=alpha)
340
 
        return
341
 
 
342
 
if __name__ == "__main__":
343
 
    win = gtk.Window()
344
 
    win.set_default_size(300,100)
345
 
    backforward = BackForwardButton()
346
 
    win.add(backforward)
347
 
    win.show_all()
348
 
 
349
 
    gtk.main()