Changeset 824e488 in sasview for src/sas/guiframe/local_perspectives/plotting/binder.py
- Timestamp:
- Mar 5, 2015 2:18:47 PM (10 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- b5de88e
- Parents:
- b9dbd6b
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/guiframe/local_perspectives/plotting/binder.py
r79492222 r824e488 2 2 Extension to MPL to support the binding of artists to key/mouse events. 3 3 """ 4 5 class Selection: 4 import logging 5 import sys 6 7 class Selection(object): 6 8 """ 7 9 Store and compare selections. … … 9 11 # TODO: We need some way to check in prop matches, preferably 10 12 # TODO: without imposing structure on prop. 11 13 12 14 artist = None 13 15 prop = {} 14 16 def __init__(self, artist=None, prop={}): 15 17 self.artist, self.prop = artist, self.prop 16 18 17 19 def __eq__(self, other): 18 20 return self.artist is other.artist 19 21 20 22 def __ne__(self, other): 21 23 return self.artist is not other.artist 22 24 23 25 def __nonzero__(self): 24 26 return self.artist is not None 25 27 26 class BindArtist: 27 28 # Track keyboard modifiers for events. 29 # TODO: Move keyboard modifier support into the backend. We cannot 30 # TODO: properly support it from outside the windowing system since there 31 # TODO: is no way to recognized whether shift is held down when the mouse 32 # TODO: first clicks on the the application window. 28 class BindArtist(object): 29 """ 30 Track keyboard modifiers for events. 31 TODO: Move keyboard modifier support into the backend. We cannot 32 TODO: properly support it from outside the windowing system since there 33 TODO: is no way to recognized whether shift is held down when the mouse 34 TODO: first clicks on the the application window. 35 """ 33 36 control, shift, alt, meta = False, False, False, False 34 37 … … 36 39 dclick_threshhold = 0.25 37 40 _last_button, _last_time = None, 0 38 41 39 42 # Mouse/keyboard events we can bind to 40 43 events = ['enter', 'leave', 'motion', 'click', 'dclick', 'drag', 'release', 41 'scroll', 'key', 'keyup']44 'scroll', 'key', 'keyup'] 42 45 # TODO: Need our own event structure 43 46 def __init__(self, figure): … … 54 57 ] 55 58 except: 56 # print "bypassing scroll_event: wrong matplotlib version"59 # print "bypassing scroll_event: wrong matplotlib version" 57 60 self._connections = [ 58 61 canvas.mpl_connect('motion_notify_event', self._onMotion), … … 66 69 canvas.mpl_disconnect(canvas.button_pick_id) 67 70 canvas.mpl_disconnect(canvas.scroll_pick_id) 68 except: 69 pass71 except: 72 logging.error(sys.exc_value) 70 73 self.canvas = canvas 71 74 self.figure = figure 72 75 self.clearall() 73 76 74 77 def clear(self, *artists): 75 78 """ 76 79 self.clear(h1,h2,...) 77 80 Remove connections for artists h1, h2, ... 78 81 79 82 Use clearall() to reset all connections. 80 83 81 84 """ 82 85 for h in artists: … … 92 95 if self._haskey.artist in artists: 93 96 self._haskey = Selection() 94 97 95 98 def clearall(self): 96 99 """ 97 100 Clear connections to all artists. 98 101 99 102 Use clear(h1,h2,...) to reset specific artists. 100 103 """ … … 113 116 In case we need to disconnect from the canvas... 114 117 """ 115 try: 118 try: 116 119 for cid in self._connections: 117 120 self.canvas.mpl_disconnect(cid) 118 except: 121 except: 119 122 pass 120 123 self._connections = [] … … 125 128 def __call__(self, trigger, artist, action): 126 129 """Register a callback for an artist to a particular trigger event. 127 130 128 131 usage: 129 132 self.connect(eventname,artist,action) 130 133 131 134 where: 132 135 eventname is a string … … 148 151 key: key pressed when mouse is on the artist 149 152 keyrelease: key released for the artist 150 153 151 154 The event received by action has a number of attributes: 152 155 name is the event name which was triggered … … 158 161 shift,control,alt,meta are flags which are true if the 159 162 corresponding key is pressed at the time of the event. 160 details is a dictionary of artist specific details, such as the 163 details is a dictionary of artist specific details, such as the 161 164 id(s) of the point that were clicked. 162 165 163 166 When receiving an event, first check the modifier state to be 164 167 sure it applies. E.g., the callback for 'press' might be: … … 175 178 :TODO: Attach multiple callbacks to the same event? 176 179 :TODO: Clean up interaction with toolbar modes 177 :TODO: push/pushclear/pop context so that binding changes 180 :TODO: push/pushclear/pop context so that binding changes 178 181 for the duration 179 182 :TODO: e.g., to support ? context sensitive help 180 183 181 184 """ 182 185 # Check that the trigger is valid … … 186 189 # Register the trigger callback 187 190 self._actions[trigger][artist] = action 188 # print "==> added",artist,[artist],"to",trigger,":",189 # self._actions[trigger].keys()191 # print "==> added",artist,[artist],"to",trigger,":", 192 # self._actions[trigger].keys() 190 193 # Maintain a list of all artists 191 if artist not in self._artists: 194 if artist not in self._artists: 192 195 self._artists.append(artist) 193 196 … … 231 234 # print "search"," ".join([str(h) for h in self._artists]) 232 235 found = Selection() 233 # print "searching in",self._artists236 # print "searching in",self._artists 234 237 for artist in self._artists: 235 238 # TODO: should contains() return false if invisible? 236 if not artist.get_visible(): 239 if not artist.get_visible(): 237 240 continue 238 241 # TODO: optimization - exclude artists not inaxes 239 242 try: 240 inside, prop = artist.contains(event)243 inside, prop = artist.contains(event) 241 244 except: 242 245 # Probably an old version of matplotlib … … 245 248 found.artist, found.prop = artist, prop 246 249 break 247 # print "found",found.artist248 250 # print "found",found.artist 251 249 252 # TODO: how to check if prop is equal? 250 253 if found != self._current: … … 253 256 self._current = found 254 257 return found 255 258 256 259 def _onMotion(self, event): 257 260 """ … … 259 262 other artists are invisible. 260 263 """ 261 # # Can't kill double-click on motion since Windows produces262 # # spurious motion events.263 # self._last_button = None264 264 # # Can't kill double-click on motion since Windows produces 265 # # spurious motion events. 266 # self._last_button = None 267 265 268 # Dibs on the motion event for the clicked artist 266 269 if self._hasclick: 267 270 # Make sure the x,y data use the coordinate system of the 268 271 # artist rather than the default axes coordinates. 269 272 270 273 transform = self._hasclick.artist.get_transform() 271 # x,y = event.xdata,event.ydata274 # x,y = event.xdata,event.ydata 272 275 x, y = event.x, event.y 273 276 try: … … 280 283 else: 281 284 found = self._find_current(event) 282 # print "found",found.artist285 # print "found",found.artist 283 286 self.trigger(found, 'motion', event) 284 287 … … 288 291 """ 289 292 import time 290 293 291 294 # Check for double-click 292 295 event_time = time.time() 293 # print event_time,self._last_time,self.dclick_threshhold294 # print (event_time > self._last_time + self.dclick_threshhold)295 # print event.button,self._last_button296 # print event_time,self._last_time,self.dclick_threshhold 297 # print (event_time > self._last_time + self.dclick_threshhold) 298 # print event.button,self._last_button 296 299 if (event.button != self._last_button) or \ 297 300 (event_time > self._last_time + self.dclick_threshhold): … … 301 304 self._last_button = event.button 302 305 self._last_time = event_time 303 306 304 307 # If an artist is already dragging, feed any additional button 305 308 # presses to that artist. … … 311 314 else: 312 315 found = self._find_current(event) 313 # print "button %d pressed"%event.button316 # print "button %d pressed"%event.button 314 317 # Note: it seems like if "click" returns False then hasclick should 315 318 # not be set. The problem is that there are two reasons it can … … 346 349 self.trigger(self._hasclick, 'release', event) 347 350 self._hasclick = Selection() 348 351 349 352 def _onKey(self, event): 350 353 """ … … 355 358 # TODO: Can we tab between items? 356 359 # TODO: How do unhandled events get propogated to axes, figure and 357 # TODO: finally to application? Do we need to implement a full tags 360 # TODO: finally to application? Do we need to implement a full tags 358 361 # TODO: architecture a la Tk? 359 362 # TODO: Do modifiers cause a grab? Does the artist see the modifiers? … … 368 371 self.trigger(found, 'key', event) 369 372 self._haskey = found 370 373 371 374 def _onKeyRelease(self, event): 372 375 """
Note: See TracChangeset
for help on using the changeset viewer.