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

« back to all changes in this revision

Viewing changes to platform/osx/plat/frontends/widgets/customcontrol.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.plat.frontends.widgets.customcontrol -- CustomControl handlers.  """
30
 
 
31
 
from AppKit import *
32
 
from Foundation import *
33
 
from objc import YES, NO, nil
34
 
 
35
 
from miro.plat.frontends.widgets import wrappermap
36
 
from miro.plat.frontends.widgets.base import Widget, SimpleBin, FlippedView
37
 
from miro.plat.frontends.widgets import drawing
38
 
from miro.plat.frontends.widgets.layoutmanager import LayoutManager
39
 
 
40
 
class DrawableButtonCell(NSButtonCell):
41
 
    def startTrackingAt_inView_(self, point, view):
42
 
        view.setState_(NSOnState)
43
 
        return YES
44
 
 
45
 
    def continueTracking_at_inView_(self, lastPoint, at, view):
46
 
        view.setState_(NSOnState)
47
 
        return YES
48
 
 
49
 
    def stopTracking_at_inView_mouseIsUp_(self, lastPoint, at, view, mouseIsUp):
50
 
        if not mouseIsUp:
51
 
            view.setState_(NSOffState)
52
 
 
53
 
class DrawableButton(NSButton):
54
 
    def init(self):
55
 
        self = super(DrawableButton, self).init()
56
 
        self.layout_manager = LayoutManager()
57
 
        self.tracking_rect = None
58
 
        self.mouse_inside = False
59
 
        return self
60
 
 
61
 
    def remove_tracking_rect(self):
62
 
        if self.tracking_rect is not None:
63
 
            self.removeTrackingRect_(self.tracking_rect)
64
 
            self.tracking_rect = None
65
 
 
66
 
    def viewDidMoveToWindow(self):
67
 
        self.reset_tracking_rect()
68
 
 
69
 
    def setFrame_(self, rect):
70
 
        NSButton.setFrame_(self, rect)
71
 
        self.reset_tracking_rect()
72
 
 
73
 
    def setBounds_(self, rect):
74
 
        NSButton.setBounds_(self, rect)
75
 
        self.reset_tracking_rect()
76
 
 
77
 
    def reset_tracking_rect(self):
78
 
        self.remove_tracking_rect()
79
 
        if self.window() is not None:
80
 
            self.tracking_rect = self.addTrackingRect_owner_userData_assumeInside_(
81
 
                    self.bounds(), self, 0, NO)
82
 
 
83
 
    def mouseEntered_(self, event):
84
 
        window = self.window()
85
 
        if window is not nil and window.isMainWindow():
86
 
            self.mouse_inside = True
87
 
            self.setNeedsDisplay_(YES)
88
 
 
89
 
    def mouseExited_(self, event):
90
 
        window = self.window()
91
 
        if window is not nil and window.isMainWindow():
92
 
            self.mouse_inside = False
93
 
            self.setNeedsDisplay_(YES)
94
 
 
95
 
    def isOpaque(self):
96
 
        return wrappermap.wrapper(self).is_opaque()
97
 
 
98
 
    def drawRect_(self, rect):
99
 
        context = drawing.DrawingContext(self, self.bounds(), rect)
100
 
        context.style = drawing.DrawingStyle()
101
 
        wrapper = wrappermap.wrapper(self)
102
 
        if self.state() == NSOnState:
103
 
            wrapper.state = 'pressed'
104
 
        elif self.mouse_inside:
105
 
            wrapper.state = 'hover'
106
 
        else:
107
 
            wrapper.state = 'normal'
108
 
 
109
 
        wrappermap.wrapper(self).draw(context, self.layout_manager)
110
 
        self.layout_manager.reset()
111
 
 
112
 
    def sendAction_to_(self, action, to):
113
 
        # We override the Cocoa machinery here and just send it to our wrapper
114
 
        # widget.
115
 
        wrappermap.wrapper(self).emit('clicked')
116
 
        return YES
117
 
DrawableButton.setCellClass_(DrawableButtonCell)
118
 
 
119
 
class ContinousButtonCell(DrawableButtonCell):
120
 
    def stopTracking_at_inView_mouseIsUp_(self, lastPoint, at, view, mouseIsUp):
121
 
        view.onStopTracking(at)
122
 
        NSButtonCell.stopTracking_at_inView_mouseIsUp_(self, lastPoint, at,
123
 
                view, mouseIsUp)
124
 
 
125
 
class ContinuousDrawableButton(DrawableButton):
126
 
    def init(self):
127
 
        self = super(ContinuousDrawableButton, self).init()
128
 
        self.setContinuous_(YES)
129
 
        return self
130
 
 
131
 
    def mouseDown_(self, event):
132
 
        self.releaseInbounds = self.stopTracking = self.firedOnce = False
133
 
        self.cell().trackMouse_inRect_ofView_untilMouseUp_(event,
134
 
                self.bounds(), self, YES)
135
 
        if self.releaseInbounds:
136
 
            if self.firedOnce:
137
 
                wrappermap.wrapper(self).emit('released')
138
 
            else:
139
 
                wrappermap.wrapper(self).emit('clicked')
140
 
 
141
 
    def sendAction_to_(self, action, to):
142
 
        if self.stopTracking:
143
 
            return NO
144
 
        self.firedOnce = True
145
 
        wrappermap.wrapper(self).emit('held-down')
146
 
        return YES
147
 
 
148
 
    def onStopTracking(self, mouseLocation):
149
 
        self.releaseInbounds = NSPointInRect(mouseLocation, self.bounds())
150
 
        self.stopTracking = True
151
 
ContinuousDrawableButton.setCellClass_(ContinousButtonCell)
152
 
 
153
 
class CustomSliderCell(NSSliderCell):
154
 
    def calc_slider_amount(self, view, pos, size):
155
 
        slider_size = wrappermap.wrapper(view).slider_size()
156
 
        pos -= slider_size / 2
157
 
        size -= slider_size
158
 
        return max(0, min(1, float(pos) / size))
159
 
 
160
 
    def startTrackingAt_inView_(self, at, view):
161
 
        wrappermap.wrapper(view).emit('pressed')
162
 
        return self.continueTracking_at_inView_(at, at, view)
163
 
 
164
 
    def continueTracking_at_inView_(self, lastPoint, at, view):
165
 
        if view.isVertical():
166
 
            pos = at.y
167
 
            size = view.bounds().size.height
168
 
        else:
169
 
            pos = at.x
170
 
            size = view.bounds().size.width
171
 
        slider_amount = self.calc_slider_amount(view, pos, size)
172
 
        value = (self.maxValue() - self.minValue()) * slider_amount
173
 
        self.setFloatValue_(value)
174
 
        wrappermap.wrapper(view).emit('moved', value)
175
 
        if self.isContinuous():
176
 
            wrappermap.wrapper(view).emit('changed', value)
177
 
        return YES
178
 
    
179
 
    def stopTracking_at_inView_mouseIsUp_(self, lastPoint, at, view, mouseUp):
180
 
        wrappermap.wrapper(view).emit('released')
181
 
 
182
 
class CustomSliderView(NSSlider):
183
 
    def init(self):
184
 
        self = super(CustomSliderView, self).init()
185
 
        self.layout_manager = LayoutManager()
186
 
        return self
187
 
 
188
 
    def isOpaque(self):
189
 
        return wrappermap.wrapper(self).is_opaque()
190
 
 
191
 
    def knobThickness(self):
192
 
        return wrappermap.wrapper(self).slider_size()
193
 
 
194
 
    def isVertical(self):
195
 
        return not wrappermap.wrapper(self).is_horizontal()
196
 
 
197
 
    def drawRect_(self, rect):
198
 
        context = drawing.DrawingContext(self, self.bounds(), rect)
199
 
        context.style = drawing.DrawingStyle()
200
 
        wrappermap.wrapper(self).draw(context, self.layout_manager)
201
 
        self.layout_manager.reset()
202
 
 
203
 
    def sendAction_to_(self, action, to):
204
 
        # We override the Cocoa machinery here and just send it to our wrapper
205
 
        # widget.
206
 
        wrappermap.wrapper(self).emit('changed', self.floatValue())
207
 
        return YES
208
 
CustomSliderView.setCellClass_(CustomSliderCell)
209
 
 
210
 
class CustomButton(drawing.DrawingMixin, Widget):
211
 
    """See https://develop.participatoryculture.org/trac/democracy/wiki/WidgetAPI for a description of the API for this class."""
212
 
    def __init__(self):
213
 
        Widget.__init__(self)
214
 
        self.create_signal('clicked')
215
 
        self.view = DrawableButton.alloc().init()
216
 
        self.view.setRefusesFirstResponder_(NO)
217
 
    
218
 
    def enable(self):
219
 
        Widget.enable(self)
220
 
        self.view.setEnabled_(True)
221
 
 
222
 
    def disable(self):
223
 
        Widget.disable(self)
224
 
        self.view.setEnabled_(False)
225
 
 
226
 
    def remove_viewport(self):
227
 
        self.view.remove_tracking_rect()
228
 
        Widget.remove_viewport(self)
229
 
 
230
 
class ContinuousCustomButton(CustomButton):
231
 
    """See https://develop.participatoryculture.org/trac/democracy/wiki/WidgetAPI for a description of the API for this class."""
232
 
    def __init__(self):
233
 
        CustomButton.__init__(self)
234
 
        self.create_signal('held-down')
235
 
        self.create_signal('released')
236
 
        self.view = ContinuousDrawableButton.alloc().init()
237
 
        self.view.setRefusesFirstResponder_(NO)
238
 
 
239
 
    def set_delays(self, initial, repeat):
240
 
        self.view.cell().setPeriodicDelay_interval_(initial, repeat)
241
 
 
242
 
class CustomSlider(drawing.DrawingMixin, Widget):
243
 
    """See https://develop.participatoryculture.org/trac/democracy/wiki/WidgetAPI for a description of the API for this class."""
244
 
    def __init__(self):
245
 
        Widget.__init__(self)
246
 
        self.create_signal('pressed')
247
 
        self.create_signal('released')
248
 
        self.create_signal('changed')
249
 
        self.create_signal('moved')
250
 
        self.view = CustomSliderView.alloc().init()
251
 
        self.view.setRefusesFirstResponder_(NO)
252
 
        if self.is_continuous():
253
 
            self.view.setContinuous_(YES)
254
 
        else:
255
 
            self.view.setContinuous_(NO)
256
 
 
257
 
    def viewport_created(self):
258
 
        self.view.cell().setKnobThickness_(self.slider_size())
259
 
 
260
 
    def get_value(self):
261
 
        return self.view.floatValue()
262
 
 
263
 
    def set_value(self, value):
264
 
        self.view.setFloatValue_(value)
265
 
 
266
 
    def get_range(self):
267
 
        return self.view.minValue(), self.view.maxValue()
268
 
 
269
 
    def set_range(self, min_value, max_value):
270
 
        self.view.setMinValue_(min_value)
271
 
        self.view.setMaxValue_(max_value)
272
 
 
273
 
    def set_increments(self, increment, big_increment):
274
 
        pass
275
 
 
276
 
    def enable(self):
277
 
        Widget.enable(self)
278
 
        self.view.setEnabled_(True)
279
 
 
280
 
    def disable(self):
281
 
        Widget.disable(self)
282
 
        self.view.setEnabled_(False)