def activateSWCursor(self, x=None, y=None, type=None, drawToo=True): gw = self.__theGwidget hideTkCursor(gw) # from Ptkplot # ignore type for now since only one type of software cursor # is implemented gw.update_idletasks() if not self.__isSWCursorActive: if not self.__SWCursor: self.__SWCursor = FullWindowCursor(0.5, 0.5, gw) self.__isSWCursorActive = 1 gw.bind("<Motion>",self.moveCursor) if drawToo and not self.__SWCursor.isVisible(): self.__SWCursor.draw()
class MplCanvasAdapter(tkagg.FigureCanvasTkAgg): """ Is a FigureCanvasTkAgg, with extra methods to look like Canvas """ def __init__(self, gkikernel, figure, master=None): tkagg.FigureCanvasTkAgg.__init__(self, figure, master, self.resize_event) # members self.__theGwidget = self.get_tk_widget() # THE gwidget self.__gkiKernel = gkikernel self.__doIdleRedraw = 0 self.__doIdleSWCursor = 0 self.ignoreNextRedraw = 0 # used externally to this class ... # Add a placeholder software cursor attribute. If it is None, # that means no software cursor is in effect. If it is not None, # then it will be used to render the cursor. self.__isSWCursorActive = 0 self.__SWCursor = None # Basic bindings for the virtual trackball. # ! Do NOT set these without undergoing a major GkiMpl design # check ! Binding Expose to tkExpose forces tkRedraw to be # called WAY too many times during a window resize. This uses the # draw buffer, which is slow and unnecessary for resizes. # self.__theGwidget.bind('<Expose>', self.tkExpose) # self.__theGwidget.bind('<Configure>', self.tkExpose) # init draw issue def pack(self, **kw): """ delegate to the gwidget """ self.__theGwidget.pack(kw) def winfo_id(self): """ delegate to the gwidget """ self.__theGwidget.winfo_id() def gwidgetize(self, width, height): """ This is a one-stop shopping spot to add all the extra attributes to the gwidget object it needs to be seen as a "gwidget" in the GKI sense. See requirements in GkiInteractiveTkBase. """ gw = self.__theGwidget # Add attributes to the gwidget gw.lastX = None gw.lastY = None gw.width = width gw.height = height # Add our functions to the gwidget gw.activateSWCursor = self.activateSWCursor gw.deactivateSWCursor = self.deactivateSWCursor gw.isSWCursorActive = self.isSWCursorActive gw.getSWCursor = self.getSWCursor gw.moveCursorTo = self.moveCursorTo gw.tkRedraw = self.tkRedraw def resize_event(self, evt=None): # See also get/set_size_inches, figure.get_window_extent(). The latter # is Bbox, use .width/.height() # # before rsz: w = self.figure.get_window_extent().width # not func .98 # before rsz: h = self.figure.get_window_extent().height() # is in .91 # Note that the 'evt' arg was always part of the signature for # versions before MPL v 0.98.5.2, when it became optional. # So see if it is there. Always use it if present, it is accurate. if evt != None: curW = evt.width curH = evt.height else: dpi = self.figure.get_dpi() curW = self.figure.get_figwidth() * dpi curH = self.figure.get_figheight() * dpi # Need to deactivate cursor before resizing, then re-act. after self.wrappedRedrawOrResize(w=curW, h=curH) # also update the widget's w/h attrs; we will need this for the cursor self.__theGwidget.width = curW self.__theGwidget.height = curH def flush(self): self.__doIdleRedraw = 0 # show and draw could be defined to catch events before passing through # def show(self): tkagg.FigureCanvasTkAgg.show(self) # def draw(self): tkagg.FigureCanvasTkAgg.draw(self) def wrappedRedrawOrResize(self, w=None, h=None): """Wrap the redraw (or resize) with a deactivate and then re-activate of the cursor. If w or h are provided then we are only resizing.""" # need to indicate cursor is not visible before this, since # cursor sleeps are now issued by redraw. The presumption is that # redraw/resize will affect cursor visibility, so we set it first resizing = w != None cursorActivate = 0 if self.__isSWCursorActive: # deactivate cursor for duration of redraw # otherwise it slows the redraw to a glacial pace cursorActivate = 1 x = self.__SWCursor.lastx y = self.__SWCursor.lasty self.deactivateSWCursor() if resizing: self.__gkiKernel.resizeGraphics(w, h) else: # should document how this line gets to GkiMplKernel.redraw() self.__theGwidget.redraw(self.__theGwidget) if cursorActivate: # Need to activate it, but don't draw it if only resizing, there is # a bug where the previous crosshair cursor is drawn too. self.activateSWCursor(x, y, drawToo=(not resizing)) # tkRedraw() is used as if it belonged to the gwidget's class def tkRedraw(self, *dummy): """ delegate to the gwidget """ gw = self.__theGwidget self.__doIdleRedraw = 1 gw.after_idle(self.idleRedraw) def idleRedraw(self): """Do a redraw, then set buffer so no more happen on this idle cycle""" if self.__doIdleRedraw: self.__doIdleRedraw = 0 self.wrappedRedrawOrResize() # isSWCursorActive() is used as if it belonged to the gwidget's class def isSWCursorActive(self): """ getter """ return self.__isSWCursorActive # activateSWCursor() is used as if it belonged to the gwidget's class def activateSWCursor(self, x=None, y=None, type=None, drawToo=True): gw = self.__theGwidget hideTkCursor(gw) # from Ptkplot # ignore type for now since only one type of software cursor # is implemented gw.update_idletasks() if not self.__isSWCursorActive: if not self.__SWCursor: self.__SWCursor = FullWindowCursor(0.5, 0.5, gw) self.__isSWCursorActive = 1 gw.bind("<Motion>",self.moveCursor) if drawToo and not self.__SWCursor.isVisible(): self.__SWCursor.draw() # deactivateSWCursor() is used as if it belonged to the gwidget's class def deactivateSWCursor(self): gw = self.__theGwidget gw.update_idletasks() if self.__isSWCursorActive: self.__SWCursor.erase() gw.unbind("<Motion>") self.__SWCursor.isLastSWmove = 1 self.__isSWCursorActive = 0 gw['cursor'] = 'arrow' # set back to normal # getSWCursor() is used as if it belonged to the gwidget's class def getSWCursor(self): """ getter """ return self.__SWCursor def SWCursorWake(self): """ Wake cursor only after idle """ self.__doIdleSWCursor = 1 self.after_idle(self.idleSWCursorWake) def idleSWCursorWake(self): """Do cursor redraw, then reset so no more happen on this idle cycle""" if self.__doIdleSWCursor: self.__doIdleSWCursor = 0 self.SWCursorImmediateWake() def SWCursorImmediateWake(self): if self.__isSWCursorActive: self.__SWCursor.draw() def moveCursor(self, event): """Call back for mouse motion events""" # Kludge to handle the fact that MacOS X (X11) doesn't remember # software driven moves, the first move will just move nothing # but will properly update the coordinates. Do not do this under Aqua. gw = self.__theGwidget if WUTIL_USING_X and self.__SWCursor.isLastSWmove: x = self.__SWCursor.lastx y = self.__SWCursor.lasty # call the wutil version moveCursorTo(gw.winfo_id(), gw.winfo_rootx(), gw.winfo_rooty(), int(x*gw.winfo_width()), int((1.-y)*gw.winfo_height())) else: x = (event.x+0.5)/gw.winfo_width() y = 1.-(event.y+0.5)/gw.winfo_height() self.__SWCursor.moveTo(x,y,SWmove=0) # moveCursorTo() is used as if it belonged to the gwidget's class def moveCursorTo(self, x, y, SWmove=0): self.__SWCursor.moveTo(float(x)/self.__theGwidget.width, float(y)/self.__theGwidget.height, SWmove) def activate(self): """Not really needed for Tkplot widgets""" pass def tkExpose(self, *dummy): """Redraw the widget upon the tkExpose event. Make it active, update tk events, call redraw procedure.""" if self.ignoreNextRedraw: self.ignoreNextRedraw = 0 else: self.tkRedraw()