source: trunk/src/testing/dim/device.py @ 4

Revision 4, 7.7 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1############################################################################
2#
3# DIM - A Direct Interaction Manager for SAGE
4# Copyright (C) 2007 Electronic Visualization Laboratory,
5# University of Illinois at Chicago
6#
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions are met:
11#
12#  * Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14#  * Redistributions in binary form must reproduce the above
15#    copyright notice, this list of conditions and the following disclaimer
16#    in the documentation and/or other materials provided with the distribution.
17#  * Neither the name of the University of Illinois at Chicago nor
18#    the names of its contributors may be used to endorse or promote
19#    products derived from this software without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32#
33# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
34#
35# Author: Ratko Jagodic
36#       
37############################################################################
38
39
40
41
42import events
43from globals import *
44
45
46# for smoothing of input data
47SMOOTHING_BUFFER_SIZE = 10   # how many previous values do we take into account?
48SMOOTHING_MODIFIER    = 0.2  # the amount of smoothing, and delay (0=none, 1=tons)
49
50
51
52class Device:
53    """ events is a list of eventIds that this device can generate """
54
55    def __init__(self, deviceType, deviceId, needPointer, displayId=0):
56        self.deviceType = deviceType
57        self.deviceId = deviceId
58        self.displayId = displayId
59        self.__smoothingBuffer = []  # history of previous values (tuples of (x,y))
60       
61        # set the bounds
62        di = getSageData().getDisplayInfo(self.displayId)
63        self.bounds = Bounds(0, di.sageW, di.sageH, 0)
64        self.displayBounds = self.bounds   # first bounds are always equal to the display size
65        #self.globalMode = True  # False if in appMode... ie the events are forwarded to the app
66        self.toEvtHandler = None  # all our the events should go to this handler (ie device captured by the evtHandler)
67        self.lastMoveCallback = None  # this is used for generating EVT_LEFT_WINDOW and EVT_ENTERED_WINDOW
68        self.dragMode = False     # an overlay can request this device to produce drag event for a bit
69
70        # this is for app specific stuff such as magic carpet lenses
71        # these devices send special events
72        self.specialDevice = False   
73        self.specialId = 0       
74       
75        self.evtMgr = getEvtMgr()  # from globals
76        self.overlayMgr = getOverlayMgr()  # from globals
77
78        # we create a pointer if needed
79        self.pointer = None   
80        if needPointer:
81            self.overlayMgr.addOverlay(OVERLAY_POINTER, self.onPointerAdded, displayId=self.displayId)
82
83
84    def destroy(self):
85        if self.pointer:
86            self.overlayMgr.removeOverlay(self.pointer.overlayId)
87
88
89    def onPointerAdded(self, pointerOverlay):
90        self.pointer = pointerOverlay
91
92
93    ## def changeMode(self, toGlobal, newBounds):
94##         """ Changes the current mode for this device.
95##             toGlobal=False for appMode, True for globalMode
96##             You need to pass the new bounds in as well. If changing
97##             to appMode, pass in the appBounds in SAGE coords, otherwise
98##             pass in the SAGE display bounds.
99##         """
100   
101##         self.bounds = newBounds
102##         self.globalMode = toGlobal
103
104##         # now convert the position to those new bounds
105##         self.x = float(self.x - newBounds.left) / newBounds.getWidth()
106##         self.y = float(self.y - newBounds.bottom) / newBounds.getHeight()
107
108       
109       
110    def onMessage(self, data, firstMsg=False):
111        """ This method gets called when a message arrives from the HWCapture
112            for this device. In here you should provide the conversion from
113            HW events to the SAGE App Events. FirstMsg just signifies
114            that this is the very first message right after the device creation.
115           
116            Must be implemented by the subclass.
117        """
118       
119        raise NotImplementedError
120
121
122    def setSpecialId(self, newId):
123        self.specialId = newId
124
125
126    def getSpecialId(self):
127        """ When using special devices you need to specify which deviceId will be reported """
128        return self.specialId
129   
130
131    ### these are the methods to call when an event occurs
132    ### this will pass the event on to the system to be handled
133   
134    def postEvtMove(self, newX, newY, dX, dY):
135        evt = events.MoveEvent(self, newX, newY, dX, dY, self.toEvtHandler)
136        self.evtMgr.postEvent( evt )
137           
138
139    def postEvtAnalog1(self, x, y, dX, dY, dZ):
140        evt = events.Analog1Event(self, x, y, dX, dY, dZ, self.toEvtHandler)
141        self.evtMgr.postEvent( evt )
142
143
144    def postEvtAnalog2(self, x, y, dX, dY, dZ, angle = 0):
145        evt = events.Analog2Event(self, x, y, dX, dY, dZ, angle, self.toEvtHandler)
146        self.evtMgr.postEvent( evt )
147
148
149    def postEvtAnalog3(self, x, y, dX, dY, dZ):
150        evt = events.Analog3Event(self, x, y, dX, dY, dZ, self.toEvtHandler)
151        self.evtMgr.postEvent( evt )
152
153   
154    def postEvtClick(self, x, y, btnId, isDown, forEvt):
155        evt = events.ClickEvent(self, x, y, btnId, isDown, forEvt, self.toEvtHandler)
156        self.evtMgr.postEvent( evt )
157        if not isDown:
158            self.toEvtHandler = None  # not captured anymore
159
160
161    def postEvtArrow(self, arrow, x, y):
162        evt = events.ArrowEvent(self, arrow, x, y, self.toEvtHandler)
163        self.evtMgr.postEvent( evt )
164
165
166    def postEvtKey(self, key, x, y):
167        evt = events.KeyEvent(self, key, x, y, self.toEvtHandler)
168        self.evtMgr.postEvent( evt )
169
170
171    def postEvtCustom(self, data):
172        evt = events.CustomEvent(self, data, self.toEvtHandler)
173        self.evtMgr.postEvent( evt )
174       
175
176
177
178    ### should be called by the subclass if smoothing is desired for every frame (new input)
179    ### takes in two new values for x and y and returns smoothed values for x and y
180    def smooth(self, newX, newY, bufSize=SMOOTHING_BUFFER_SIZE, smoothAmount=SMOOTHING_MODIFIER):
181        self.__smoothingBuffer.insert(0, (newX, newY))   # insert the newest
182
183        if len(self.__smoothingBuffer) > bufSize:
184            del self.__smoothingBuffer[ len(self.__smoothingBuffer)-1 ]  # delete the oldest
185
186        # do the non-linear averaging
187        totX, totY, totMod = 0.0, 0.0, 0.0
188        mod = 1.0
189        for i in range(0, len(self.__smoothingBuffer)):
190            totX += self.__smoothingBuffer[i][0]*mod
191            totY += self.__smoothingBuffer[i][1]*mod
192            totMod += mod
193            mod = mod*smoothAmount
194
195        smoothX = int(round(totX / totMod))
196        smoothY = int(round(totY / totMod))
197
198        # record the new value
199        self.__smoothingBuffer[0] = (smoothX, smoothY)
200               
201        return smoothX, smoothY
202       
Note: See TracBrowser for help on using the repository browser.