def delay(s): if STATMODE: return # NO TIME FOR SLEEP IN STATMODE if USING_PYGAME: from time import sleep sleep(s) else: from pyjamas.Timer import Timer timer = Timer(notify=update) timer.schedule(s * 1000)
def queuereduce(sender, maxlines=1000): showOutputMeta("Reducing...") outputPanel.add(HTML(" ")) outputPanel.add(HTML(" ")) outputPanel.add( HTML(""" <p>Takes too long? Try the <a href="https://bitbucket.org/bgeron </continuation-calculus-paper/">Python evaluator.</a>.</p> """.strip())) # Schedule reduceterm(maxlines) really soon. timer = Timer(notify=functools.partial(reduceterm, maxlines=maxlines)) timer.schedule(50) # after 50 milliseconds
def queuereduce(sender, maxlines=1000): showOutputMeta("Reducing...") outputPanel.add(HTML(" ")) outputPanel.add(HTML(" ")) outputPanel.add( HTML( """ <p>Takes too long? Try the <a href="https://bitbucket.org/bgeron </continuation-calculus-paper/">Python evaluator.</a>.</p> """.strip() ) ) # Schedule reduceterm(maxlines) really soon. timer = Timer(notify=functools.partial(reduceterm, maxlines=maxlines)) timer.schedule(50) # after 50 milliseconds
class Photos(Composite): def __init__(self): Composite.__init__(self) self.albums = [] self.photos = [] self.grid = Grid(4, 4, CellPadding=4, CellSpacing=4) self.grid.addTableListener(self) self.drill = 0 self.pos = 0 self.up = Button("Up", self) self.next = Button("Next", self) self.prev = Button("Prev", self) self.timer = Timer(notify=self) self.userid = "jameskhedley" self.album_url = "http://picasaweb.google.com/data/feed/base/user/" + self.userid + "?alt=json-in-script&kind=album&hl=en_US&callback=restCb" self.doRESTQuery(self.album_url, self.timer) self.vp = VerticalPanel() self.disclosure = DisclosurePanel( "Click for boring technical details.") self.disclosure.add( HTML( '''<p>OK so you want to write client JS to do a RESTful HTTP query from picasa right? Well you can't because of the Same Origin Policy. Basically this means that because the domain of the query and the domain of the hosted site are different, then that could well be a cross-site scripting (XSS) attack. So, the workaround is to do the call from a script tag so the JSON we get back is part of the document. But since we don't know what URL to hit yet, once we find out then we have to inject a new script tag dynamically which the browser will run as soon as we append it. To be honest I'm not 100% why Google use RESTful services and not JSON-RPC or somesuch, which would be easier. Well, easier for me.''')) self.IDPanel = HorizontalPanel() self.IDPanel.add(Label("Enter google account:")) self.IDButton = Button("Go", self) self.IDBox = TextBox() self.IDBox.setText(self.userid) self.IDPanel.add(self.IDBox) self.IDPanel.add(self.IDButton) self.vp.add(self.IDPanel) self.vp.add(self.disclosure) self.vp.add(self.grid) self.initWidget(self.vp) def doRESTQuery(self, url, timer): """this is a totally different from an RPC call in that we have to dynamically add script tags to the DOM when we want to query the REST API. These rely on callbacks in the DOM so we can either add them dynamically or pre-define them in public/Main.html. Once we've done that have to wait for the response. Which means we need to provide a listener for the timer""" new_script = DOM.createElement("script") DOM.setElemAttribute(new_script, "src", url) DOM.setElemAttribute(new_script, "type", "text/javascript") doc().body.appendChild(new_script) self.timer.schedule(100) def onCellClicked(self, sender, row, col): if self.drill == 0: self.drill += 1 self.vp.clear() self.grid.clear() self.vp.add(self.up) self.vp.add(self.grid) gridcols = self.grid.getColumnCount() album = self.albums[row + col + (row * (gridcols - 1))] url = "http://picasaweb.google.com/data/feed/base/user/" + self.userid + "/albumid/" + album[ "id"] + "?alt=json-in-script&kind=photo&hl=en_US&callback=restCb" self.doRESTQuery(url, self.timer) elif self.drill == 1: self.drill += 1 gridcols = self.grid.getColumnCount() self.pos = row + col + (row * (gridcols - 1)) photo = self.photos[self.pos] self.vp.clear() self.fullsize = HTML('<img src="' + photo["full"] + '"/>') hp = HorizontalPanel() hp.add(self.up) hp.add(self.prev) hp.add(self.next) hp.setSpacing(8) self.vp.add(hp) self.vp.add(self.fullsize) def onClick(self, sender): if sender == self.IDButton: self.userid = self.IDBox.getText() if self.userid == "" or self.userid.isdigit(): return self.drill = 0 self.album_url = "http://picasaweb.google.com/data/feed/base/user/" + self.userid + "?alt=json-in-script&kind=album&hl=en_US&callback=restCb" self.grid.clear() self.doRESTQuery(self.album_url, self.timer) else: if self.drill == 2: if sender == self.up: self.drill = 1 self.vp.clear() self.vp.add(self.up) self.vp.add(self.grid) self.fillGrid(self.photos, "photos") else: if sender == self.next: if self.pos >= len(self.photos): return self.pos += 1 elif sender == self.prev: if self.pos < 1: return self.pos -= 1 photo = self.photos[self.pos] self.fullsize.setHTML('<img src="' + photo["full"] + '"/>') elif self.drill == 1: self.drill = 0 self.vp.clear() self.vp.add(self.IDPanel) self.vp.add(self.disclosure) self.vp.add(self.grid) self.fillGrid(self.albums, "albums") def onTimer(self, timer): fd = doc().getElementById("__pygwt_hiddenData") receiver = fd.innerHTML if receiver == 'wait': self.timer.schedule(1000) return fd.innerHTML = 'wait' if self.drill == 0: self.parseAlbums(receiver) self.fillGrid(self.albums, "albums") elif self.drill == 1: self.parsePhotos(receiver) self.fillGrid(self.photos, "photos") def fillGrid(self, items, type): self.grid.clear() cols = self.grid.getColumnCount() self.grid.resizeRows((len(items) / cols) + 1) rows = self.grid.getRowCount() for i in range(len(items)): vp = VerticalPanel() if type == 'photos': vp.add(items[i]['thumb']) else: vp.add(items[i]['thumb']) vp.add(items[i]['title']) self.grid.setWidget(int(i / cols), i % cols, vp) def parsePhotos(self, items): photo_list = json.loads(items) self.photos = [] for ph in photo_list: aphoto = {} aphoto['thumb'] = HTML( '<img src="' + ph[u"media$group"][u"media$thumbnail"][1][u"url"] + '"/>') aphoto['full'] = ph[u"media$group"][u"media$content"][0][u"url"] self.photos.append(aphoto) def parseAlbums(self, items): album_list = json.loads(items) self.albums = [] for al in album_list: analbum = {} analbum['title'] = HTML(al[u"title"][u"$t"]) analbum['thumb'] = HTML( '<img src="' + al[u"media$group"][u"media$thumbnail"][0][u"url"] + '"/>') url = al[u"id"][u"$t"] analbum['id'] = url.split(u'albumid/')[1].split(u'?alt')[0] self.albums.append(analbum)
class RandomColor: __doc__ = '''This last example demonstrates what most pyjamas programmers currently do with timers: create a Timer instance specifying <code>notify</code> with an object that has an <code>onTimer</code> attribute that is callable. The slider on the left will adjust how often the middle panel changes color; it is either OFF or a value of seconds from 1 to 5. Changing the slider immediately cancels the current timer and starts a new timer to change the color in the newly specified time. Like the previous example, this timer reschedules itself (if it wasn't turned off) at the end of the call to <code>onTimer()</code>. ''' def __init__(self): # create the label and slider self.__label = Label('OFF') self.slider = slider = HorizontalSlider(0, 5, step=1, StyleName="slider") slider.setDragable(True) slider.addControlValueListener(self) # put them in a hpanel self.hpanel = hpanel = HorizontalPanel(Spacing=10) hpanel.add(slider) hpanel.add(self.__label) # create the color panel and give it color self.colorpanel = CaptionPanel('Color:', SimplePanel(StyleName='colorpanel')) self.randomcolor() # we're initially off self.value = 0 # create our timer self.timer = Timer(notify=self) def initialize(self): # this method solves an apparent bug with the slider: the # slider doesn't draw its handle if the position is set before # showing, so instead of doing this in __init__ (where I # originally had it), this method gets called after it is # shown on the root panel. See below when it gets called. self.slider.setValue(self.value) self.slider.setControlPos(self.value) def onTimer(self, timer): # when the timer fires we randomize the color and (maybe) # reschedule ourselves. self.randomcolor() v = self.value * 1000 if v: self.timer.schedule(v) def onControlValueChanged(self, sender, old, new): # event handler for when the slider is moved. if new == self.value: return self.value = new # is it being turned off? if new == 0: self.__label.setText('OFF') self.timer.cancel() else: # no it's being reset self.__label.setText(str(new) + ' sec') self.onTimer(self.timer) def randomcolor(self): # randomize the color and set the panel accordingly r = random()*256 g = random()*256 b = random()*256 e = self.colorpanel.getWidget().getElement() color = '#%02x%02x%02x' % (r, g, b) self.colorpanel.setCaption('Color: %s' % color) DOM.setStyleAttribute(e, "background", color)
class Photos(Composite): def __init__(self): Composite.__init__(self) self.albums = [] self.photos = [] self.grid = Grid(4, 4, CellPadding=4, CellSpacing=4) self.grid.addTableListener(self) self.drill = 0 self.pos = 0 self.up = Button("Up", self) self.next = Button("Next", self) self.prev = Button("Prev", self) self.timer = Timer(notify=self) self.userid = "jameskhedley" self.album_url = "http://picasaweb.google.com/data/feed/base/user/" + self.userid + "?alt=json-in-script&kind=album&hl=en_US&callback=restCb" self.doRESTQuery(self.album_url, self.timer) self.vp = VerticalPanel() self.disclosure = DisclosurePanel("Click for boring technical details.") self.disclosure.add(HTML('''<p>OK so you want to write client JS to do a RESTful HTTP query from picasa right? Well you can't because of the Same Origin Policy. Basically this means that because the domain of the query and the domain of the hosted site are different, then that could well be a cross-site scripting (XSS) attack. So, the workaround is to do the call from a script tag so the JSON we get back is part of the document. But since we don't know what URL to hit yet, once we find out then we have to inject a new script tag dynamically which the browser will run as soon as we append it. To be honest I'm not 100% why Google use RESTful services and not JSON-RPC or somesuch, which would be easier. Well, easier for me.''')) self.IDPanel = HorizontalPanel() self.IDPanel.add(Label("Enter google account:")) self.IDButton = Button("Go", self) self.IDBox = TextBox() self.IDBox.setText(self.userid) self.IDPanel.add(self.IDBox) self.IDPanel.add(self.IDButton) self.vp.add(self.IDPanel) self.vp.add(self.disclosure) self.vp.add(self.grid) self.initWidget(self.vp) def doRESTQuery(self, url, timer): """this is a totally different from an RPC call in that we have to dynamically add script tags to the DOM when we want to query the REST API. These rely on callbacks in the DOM so we can either add them dynamically or pre-define them in public/Main.html. Once we've done that have to wait for the response. Which means we need to provide a listener for the timer""" JS("$wnd.receiver = 'wait'") new_script = DOM.createElement("script") DOM.setElemAttribute(new_script, "src", url) DOM.setElemAttribute(new_script, "type","text/javascript") JS("$wnd.document.body.appendChild(@{{new_script}})") self.timer.schedule(100) def onCellClicked(self, sender, row, col): if self.drill==0: self.drill += 1 self.vp.clear() self.grid.clear() self.vp.add(self.up) self.vp.add(self.grid) gridcols = self.grid.getColumnCount() album = self.albums[row+col+(row*(gridcols-1))] url = "http://picasaweb.google.com/data/feed/base/user/" + self.userid + "/albumid/" + album["id"] + "?alt=json-in-script&kind=photo&hl=en_US&callback=restCb" self.doRESTQuery(url, self.timer) elif self.drill==1: self.drill += 1 gridcols = self.grid.getColumnCount() self.pos =row+col+(row*(gridcols-1)) photo = self.photos[self.pos] self.vp.clear() self.fullsize = HTML('<img src="' + photo["full"] + '"/>') hp = HorizontalPanel() hp.add(self.up) hp.add(self.prev) hp.add(self.next) hp.setSpacing(8) self.vp.add(hp) self.vp.add(self.fullsize) def onClick(self, sender): if sender == self.IDButton: self.userid = self.IDBox.getText() if self.userid == "" or self.userid.isdigit(): return self.drill = 0 self.album_url = "http://picasaweb.google.com/data/feed/base/user/" + self.userid + "?alt=json-in-script&kind=album&hl=en_US&callback=restCb" self.grid.clear() self.doRESTQuery(self.album_url, self.timer) else: if self.drill == 2: if sender == self.up: self.drill=1 self.vp.clear() self.vp.add(self.up) self.vp.add(self.grid) self.fillGrid(self.photos, "photos") else: if sender == self.next: if self.pos >= len(self.photos): return self.pos +=1 elif sender == self.prev: if self.pos < 1: return self.pos -=1 photo = self.photos[self.pos] self.fullsize.setHTML('<img src="' + photo["full"] + '"/>') elif self.drill == 1: self.drill=0 self.vp.clear() self.vp.add(self.IDPanel) self.vp.add(self.disclosure) self.vp.add(self.grid) self.fillGrid(self.albums, "albums") def onTimer(self, timer): receiver = JS("$wnd.receiver") if receiver == 'wait': self.timer.schedule(1000) return JS("$wnd.receiver = 'wait'") if self.drill == 0: self.parseAlbums(receiver) self.fillGrid(self.albums, "albums") elif self.drill == 1: self.parsePhotos(receiver) self.fillGrid(self.photos, "photos") def fillGrid(self, items, type): self.grid.clear() cols = self.grid.getColumnCount() self.grid.resizeRows((len(items)/cols)+1) rows = self.grid.getRowCount() for i in range(len(items)): vp = VerticalPanel() if type == 'photos': vp.add(items[i]['thumb']) else: vp.add(items[i]['thumb']) vp.add(items[i]['title']) self.grid.setWidget(int(i/cols), i%cols, vp) def parsePhotos(self, items): photo_list = JSONParser().jsObjectToPyObject(items) self.photos = [] for i in range(len(photo_list)): index = "%s" % i aphoto = {} aphoto['thumb'] = HTML('<img src="' + photo_list[index]["media$group"]["media$thumbnail"]["1"]["url"] + '"/>') aphoto['full'] = photo_list[index]["media$group"]["media$content"]["0"]["url"] self.photos.append(aphoto) def parseAlbums(self, items): album_list = JSONParser().jsObjectToPyObject(items) self.albums = [] for i in range(len(album_list)): index = "%s" % i analbum = {} analbum['title'] = HTML(album_list[index]["title"]["$t"]) analbum['thumb'] = HTML('<img src="' + album_list[index]["media$group"]["media$thumbnail"]["0"]["url"] + '"/>') url = album_list[index]["id"]["$t"] analbum['id'] = url.split('albumid/')[1].split('?alt')[0] self.albums.append(analbum)
class DNDHelper(object): """ DNDHelper is a singleton drag and drop agent. It acts as dragging/dropping agent for platforms that do not support html5 drag and drop. """ def __init__(self): self.dropTargets = [] self.dragging = NOT_DRAGGING self.dragBusy = False self._currentTargetElement = None self.previousDropTarget = None self.draggingImage = None self.origMouseX = 0 self.origMouseY = 0 self.currentDragOperation = 'none' self.data = None self.returnTimer = Timer(notify=self.onReturningWidget) self.mouseEvent = None self.dragDataStore = None def setCurrentTargetElement(self, element): if self._currentTargetElement is not None: if not DOM.compare(self._currentTargetElement, element): # leave_event = self.makeDragEvent(self.mouseEvent, 'dragleave', # self.currentTargetElement) self.fireDNDEvent('dragleave', self.currentTargetElement, self.currentDropWidget) # self.currentDropWidget.onDragLeave(leave_event) # self.finalize(leave_event) self._currentTargetElement = element def getCurrentTargetElement(self): return self._currentTargetElement currentTargetElement = property(getCurrentTargetElement, setCurrentTargetElement) def getElement(self): """ ie6 GlassWidget impl needs this """ return self.dragWidget.getElement() def updateDropEffect(self, dataTransfer, event_type): """ http://dev.w3.org/html5/spec/dnd.html#dragevent """ # default for dragstart, drag, dragleave dropEffect = 'none' if event_type in ['dragover', 'dragenter']: ea = dataTransfer.getEffectAllowed() if ea == 'none': dropEffect = 'none' elif ea.startswith('copy') or ea == 'all': dropEffect = 'copy' elif ea.startswith('link'): dropEffect = 'link' elif ea == 'move': dropEffect = 'move' else: dropEffect = 'copy' elif event_type in ['drop', 'dragend']: dropEffect = self.currentDragOperation dataTransfer.dropEffect = dropEffect def updateDragOperation(self, event): """ http://dev.w3.org/html5/spec/dnd.html """ dataTransfer = event.dataTransfer ea = dataTransfer.effectAllowed de = dataTransfer.dropEffect if (de == 'copy' and ea in ['uninitialized', 'copy', 'copyLink', 'copyMove', 'all']): self.currentDragOperation = 'copy' elif (de == 'link' and ea in ['uninitialized', 'link', 'copyLink', 'linkMove', 'all']): self.currentDragOperation = 'link' elif (de == 'move' and ea in ['uninitialized', 'move', 'copyMove', 'linkMove', 'all']): self.currentDragOperation = 'move' else: self.currentDragOperation = 'none' def updateAllowedEffects(self, drag_event): dt = drag_event.dataTransfer self.dragDataStore.allowed_effects_state = dt.effectAllowed def registerTarget(self, target): """ Rather than searching the entire document for drop target widgets and maybe drop targets within widgets, this implementation holds a list of widgets and searches only within this list for potential drop targets. """ if not target in self.dropTargets: self.dropTargets.append(target) def unregisterTarget(self, target): """ I dont know why, but a widget may no longer want to be registered as a drop target. """ while target in self.dropTargets: self.dropTargets.remove(target) def setDragImage(self, element, x, y): position_absolute = DOM.getStyleAttribute(element, 'position') == 'absolute' if position_absolute: self.dragLeftOffset = x + DOM.getAbsoluteLeft(element.offsetParent) self.dragTopOffset = y + DOM.getAbsoluteTop(element.offsetParent) else: self.dragLeftOffset = x self.dragTopOffset = y if element.tagName.lower().endswith('img'): src = DOM.getAttribute(element, 'src') element = DOM.createElement('img') DOM.setAttribute(element, 'src', src) if not self.draggingImage: self.createDraggingImage(element) else: self.draggingImage.setImage(element) def addFeedbackElement(self, element): """ This is called from DataTransfer """ if self.draggingImage: self.draggingImage.addElement(element) else: self.createDraggingImage(element) def createDraggingImage(self, element): self.draggingImage = DraggingWidget(element) return self.draggingImage def setDragImageLocation(self, x, y): """ Move the dragging image around. """ elt_top = y - self.dragTopOffset elt_left = x - self.dragLeftOffset # if self.absParent: # ap = self.absParent # elt_top -= int(self.absTop) # elt_left -= int(self.absLeft) self.draggingImage.setStyleAttribute('top', elt_top) self.draggingImage.setStyleAttribute('left', elt_left) def getAbsoluteLeft(self): """ GlassWidget wants this """ # return 0 # if self.absParent: # return self.absParent.getAbsoluteLeft() return self.dragWidget.getAbsoluteLeft() #return self.origLeft def getAbsoluteTop(self): """ GlassWidget wants this """ # return 0 # if self.absParent: # return self.absParent.getAbsoluteTop() return self.dragWidget.getAbsoluteTop() #return self.origTop def makeDragEvent(self, event, type, target=None): dt = DataTransfer(self.dragDataStore) self.updateDropEffect(dt, type) drag_event = DragEvent(event, type, dt, target) return drag_event def finalize(self, event): self.dragDataStore.allowed_effects_state = \ event.dataTransfer.effectAllowed if event.type in ['dragstart', 'drop']: self.dragDataStore.setMode(PROTECTED) event.dataTransfer.dataStore = None def fireDNDEvent(self, name, target, widget): if name == 'dragstart': self.dragDataStore.setMode(READ_WRITE) elif name == 'drop': self.dragDataStore.setMode(READ_ONLY) event = self.makeDragEvent(self.mouseEvent, name, target) widget.onBrowserEvent(event) self.finalize(event) return event def initFeedbackImage(self): ds = self.dragDataStore x = 0 y = 0 if ds.bitmap is not None: if ds.hotspot_coordinate is not None: offset = ds.hotspot_coordinate x = offset[0] y = offset[1] self.setDragImage(ds.bitmap, x, y) return if self.dragDataStore.elements: for element in self.dragDataStore.elements: self.addFeedbackElement(element) def onMouseMove(self, sender, x, y): event = DOM.eventGetCurrentEvent() self.mouseEvent = event button = DOM.eventGetButton(event) if not button == Event.BUTTON_LEFT: return ## The following commented code lets the native dnd happen in IE. sucks. ## But it may enable dragging our widgets out of IE into other apps. # else: # try: # self.dragWidget.getElement().dragDrop() # return # except: # pass # Adjust x and y to absolute coordinates. x, y = eventCoordinates(event) if self.dragging == DRAGGING_NO_MOVEMENT_YET: self.origMouseX = x self.origMouseY = y self.currentDragOperation = 'none' fromElement = self.dragWidget.getElement() # Is the widget itself draggable? try: draggable = fromElement.draggable except: draggable = False # if not, find the draggable element at (x, y) in the widget if not draggable: fromElement = findDraggable(sender.getElement(), self.origMouseX, self.origMouseY) # Nothing draggable found. return. if fromElement is None: self.dragging = NOT_DRAGGING return # Get the location for the dragging widget #self.absParent = None #self.absParent = self.dragWidget.getParent() #self.absLeft = DOM.getStyleAttribute(fromElement, 'left') #print self.absLeft #self.absTop = DOM.getStyleAttribute(fromElement, 'top') #print self.absTop #self.origTop = DOM.getAbsoluteTop(fromElement) + parent.getAbsoluteTop() #self.origLeft = DOM.getAbsoluteLeft(fromElement) + parent.getAbsoluteLeft() self.origTop = DOM.getAbsoluteTop(fromElement) self.origLeft = DOM.getAbsoluteLeft(fromElement) #self.glassTop = DOM.getAbsoluteTop(fromElement.offsetParent) #self.glassLeft = DOM.getAbsoluteTop(fromElement.offsetParent) position_absolute = DOM.getStyleAttribute(fromElement, 'position') == 'absolute' if position_absolute: self.dragLeftOffset = ( self.origMouseX - DOM.getAbsoluteLeft(fromElement.offsetParent)) self.dragTopOffset = ( self.origMouseY - DOM.getAbsoluteTop(fromElement.offsetParent)) else: self.dragLeftOffset = self.origMouseX - self.origLeft self.dragTopOffset = self.origMouseY - self.origTop # self.setDragImage(fromElement, # self.origMouseX - self.origLeft, # self.origMouseY - self.origTop) self.dragDataStore.elements = [fromElement] dragStartEvent = self.fireDNDEvent('dragstart', None, self.dragWidget) if not isCanceled(dragStartEvent): self.initFeedbackImage() RootPanel().add(self.draggingImage) self.setDragImageLocation(x, y) self.dragging = ACTIVELY_DRAGGING GlassWidget.show(self) elif self.dragging == ACTIVELY_DRAGGING: try: doc().selection.empty() except: wnd().getSelection().removeAllRanges() self.setDragImageLocation(x, y) # If we are still working on the previous iteration, or if we have # done this recently, we'll wait for the next event. if self.dragBusy or time.time() - self.drag_time < 0.25: return self.doDrag(event, x, y) self.drag_time = time.time() def doDrag(self, event, x, y): self.dragBusy = True #self.dragDataStore.dropEffect = 'none' drag_event = self.fireDNDEvent('drag', None, self.dragWidget) # drag event was not canceled if not isCanceled(drag_event): target = None widget = None # Find the most specific element under the cursor and the widget # with the drop listener for it. for widget in self.dropTargets: target = getElementUnderMouse(widget, x, y) if target is not None: break if target: drop_widget = widget drop_element = target if (not self.currentTargetElement or not DOM.compare( drop_element, self.currentTargetElement)): # enter_event = self.makeDragEvent(event,'dragenter', # drop_element) enter_event = self.fireDNDEvent('dragenter', drop_element, drop_widget) # drop_widget.onDragEnter(enter_event) # self.finalize(enter_event) if isCanceled(enter_event): self.currentTargetElement = drop_element self.currentDropWidget = drop_widget if self.currentTargetElement is not None: # disable dropping if over event is not canceled # over_event = self.makeDragEvent(event, 'dragover', # drop_element) over_event = self.fireDNDEvent('dragover', drop_element, self.currentDropWidget) # self.currentDropWidget.onDragOver(over_event) # self.finalize(over_event) if isCanceled(over_event): self.updateDragOperation(over_event) else: self.currentDragOperation = 'none' self.draggingImage.updateCursor(self.currentDragOperation) else: self.currentTargetElement = None else: self.currentDragOperation = 'none' self.dragBusy = False def onMouseDown(self, sender, x, y): self.dragWidget = sender event = DOM.eventGetCurrentEvent() self.mouseEvent = event button = DOM.eventGetButton(event) if button != Event.BUTTON_LEFT: return # x, y = eventCoordinates(event) # self.origMouseX = x # self.origMouseY = y self.dragging = DRAGGING_NO_MOVEMENT_YET self.drag_time = time.time() self.dragDataStore = DragDataStore() def onMouseUp(self, sender, x, y): # event = DOM.eventGetCurrentEvent() self.dragging = NOT_DRAGGING if self.draggingImage: GlassWidget.hide() if (self.currentDragOperation == 'none' or not self.currentTargetElement): if self.currentTargetElement: # leave_event = self.makeDragEvent(event, 'dragleave', # self.currentTargetElement) self.fireDNDEvent('dragleave', self.currentTargetElement, self.currentDropWidget) # self.currentDropWidget.onDragLeave(leave_event) # self.finalize(leave_event) else: self.currentDragOperation = 'none' self.returnDrag() else: # self.dragDataStore.mode = READ_ONLY # drop_event = self.makeDragEvent(event, 'drop', # self.currentTargetElement) drop_event = self.fireDNDEvent('drop', self.currentTargetElement, self.currentDropWidget) #self.dropEffect = self.currentDragOperation # self.currentDropWidget.onDrop(drop_event) # self.finalize(drop_event) if isCanceled(drop_event): self.currentDragOperation = drop_event.dataTransfer.dropEffect else: self.currentDragOperation = 'none' self.zapDragImage() #self.dropEffect = self.currentDragOperation self.fireDNDEvent('dragend', None, self.dragWidget) # dragEnd_event = self.makeDragEvent(event, 'dragend') # self.dragWidget.onDragEnd(dragEnd_event) # self.finalize(dragEnd_event) def zapDragImage(self): RootPanel().remove(self.draggingImage) self.draggingImage = None def returnDrag(self): self.moveItemTo(self.draggingImage, self.origLeft, self.origTop) def returnXY(self, start, destination, count): start_x, start_y = start destination_x, destination_y = destination diff_x = (start_x - destination_x) / count diff_y = (start_y - destination_y) / count while (abs(start_x - destination_x) > 10 or abs(start_y - destination_y) > 10): start_x -= diff_x start_y -= diff_y yield start_x, start_y raise StopIteration def onReturningWidget(self, timer): try: next_loc = self.return_iterator.next() except StopIteration: self.zapDragImage() return x, y = next_loc self.draggingImage.setStyleAttribute('top', str(y)) self.draggingImage.setStyleAttribute('left', str(x)) self.returnTimer.schedule(50) def moveItemTo(self, widget, x, y): self.returnWidget = widget returnWidgetDestination = x, y widgetStart = widget.getAbsoluteLeft(), widget.getAbsoluteTop() self.return_iterator = self.returnXY(widgetStart, returnWidgetDestination, 10) self.returnTimer.schedule(50) def onMouseEnter(self, sender): pass def onMouseLeave(self, sender): if self.dragging == DRAGGING_NO_MOVEMENT_YET: self.dragging = NOT_DRAGGING def onMouseGlassEnter(self, sender): pass def onMouseGlassLeave(self, sender): pass
class RandomColor: __doc__ = '''This last example demonstrates what most pyjamas programmers currently do with timers: create a Timer instance specifying <code>notify</code> with an object that has an <code>onTimer</code> attribute that is callable. The slider on the left will adjust how often the middle panel changes color; it is either OFF or a value of seconds from 1 to 5. Changing the slider immediately cancels the current timer and starts a new timer to change the color in the newly specified time. Like the previous example, this timer reschedules itself (if it wasn't turned off) at the end of the call to <code>onTimer()</code>. ''' def __init__(self): # create the label and slider self.__label = Label('OFF') self.slider = slider = HorizontalSlider(0, 5, step=1, StyleName="slider") slider.setDragable(True) slider.addControlValueListener(self) # put them in a hpanel self.hpanel = hpanel = HorizontalPanel(Spacing=10) hpanel.add(slider) hpanel.add(self.__label) # create the color panel and give it color self.colorpanel = CaptionPanel('Color:', SimplePanel(StyleName='colorpanel')) self.randomcolor() # we're initially off self.value = 0 # create our timer self.timer = Timer(notify=self) def initialize(self): # this method solves an apparent bug with the slider: the # slider doesn't draw its handle if the position is set before # showing, so instead of doing this in __init__ (where I # originally had it), this method gets called after it is # shown on the root panel. See below when it gets called. self.slider.setValue(self.value) self.slider.setControlPos(self.value) def onTimer(self, timer): # when the timer fires we randomize the color and (maybe) # reschedule ourselves. self.randomcolor() v = self.value * 1000 if v: self.timer.schedule(v) def onControlValueChanged(self, sender, old, new): # event handler for when the slider is moved. if new == self.value: return self.value = new # is it being turned off? if new == 0: self.__label.setText('OFF') self.timer.cancel() else: # no it's being reset self.__label.setText(str(new) + ' sec') self.onTimer(self.timer) def randomcolor(self): # randomize the color and set the panel accordingly r = random() * 256 g = random() * 256 b = random() * 256 e = self.colorpanel.getWidget().getElement() color = '#%02x%02x%02x' % (r, g, b) self.colorpanel.setCaption('Color: %s' % color) DOM.setStyleAttribute(e, "background", color)
class DataRunManager(object) : """ @brief Class to take care of all the data taking runs. Starts them and polls the RPC service to see when it's finished. Implemented as a singleton. Call the DataRunManager.instance() static method to get the only running instance. """ pollingTime=1000 idlePollingTime=4000 # Longer polling time when I don't think I'm taking data. _onlyInstance=None # The following members are used as an enum to describe what the event is DataTakingStartedEvent=0 DataTakingFinishedEvent=1 DataTakingStatusEvent=3 @staticmethod def instance() : # static method so no "self" parameter if DataRunManager._onlyInstance==None : DataRunManager._onlyInstance=DataRunManager() return DataRunManager._onlyInstance def __init__(self) : # Since this is a singleton, throw an exception if the constructor is called # explicitly. if DataRunManager._onlyInstance!=None : raise Exception( "DataRunManager is a singleton class. Call 'DataRunManager.instance()' to get the only running instance" ) self.rpcService=GlibRPCService.instance() self.pollingTimer=Timer( notify=self.pollRPCService ) self.eventHandlers = [] self.fractionComplete = 1 self.statusString = "Not taking data" self.firstRun = True # I'll poll once immediately on startup just in case the user is connecting to an # already running service. The code that handles the response to this starts the # timer running. self.pollRPCService() def onRemoteResponse(self, response, request_info): """ The method that gets called after a successful RPC call. """ #ErrorMessage( "Response to method '"+request_info.method+"'='"+str(response)+"'" ) if request_info.method=="getDataTakingStatus" : self._onGetDataTakingStatusResponse(response) elif request_info.method=="startSCurveRun" : self._startRunResponse(response,"S-curve run") elif request_info.method=="startOccupancyCheck" : self._startRunResponse(response,"Occupancy check") elif request_info.method=="startTrimCalibration" : self._startRunResponse(response,"Trim calibration") elif request_info.method=="stopTakingData" : pass else : ErrorMessage( "Received an unexpected response for method "+request_info.method ) def onRemoteError(self, code, message, request_info): """ The method that gets called after an unsuccessful RPC call. """ ErrorMessage( "Unable to contact server: "+str(message) ) def _onGetDataTakingStatusResponse( self, response ) : """ Handles the response to a getDataTakingStatus RPC call. Separate method for code layout only. """ newFraction=response["fractionComplete"] newStatus=response["statusString"] statusHasChanged=False if (self.fractionComplete!=newFraction) or (self.statusString!=newStatus) : statusHasChanged=True if self.firstRun : # If something is already running on initialisation, tell everything for handler in self.eventHandlers : handler.onDataTakingEvent( DataRunManager.DataTakingStartedEvent, None ) self.firstRun=False self.fractionComplete=newFraction self.statusString=newStatus # only want to inform the listening classes if there is a change in the status if statusHasChanged : if self.fractionComplete>=1 : eventCode=DataRunManager.DataTakingFinishedEvent details=None else : eventCode=DataRunManager.DataTakingStatusEvent details={"fractionComplete":self.fractionComplete,"statusString":self.statusString} # Inform all the registered handlers what is going on for handler in self.eventHandlers : handler.onDataTakingEvent( eventCode, details ) if self.fractionComplete<1 : # If data hasn't finished then set the timer to fire again. self.pollingTimer.schedule( DataRunManager.pollingTime ) else : # I'll constantly poll to make sure it's not taking data, in case something/someone # else connects and tells the RPC service to do something. I'll use a longer time # though. if self.idlePollingTime>0 : self.pollingTimer.schedule( DataRunManager.idlePollingTime ) def _startRunResponse( self, reponse, runType ) : """ Handles the response to a RPC call. Separate method for code layout only. """ self.statusString=runType+" started" # Start polling the RPC service to see how the run is going self.pollingTimer.schedule( DataRunManager.pollingTime ) # inform all registered handlers that data taking has started for handler in self.eventHandlers : handler.onDataTakingEvent( DataRunManager.DataTakingStartedEvent, None ) def pollRPCService( self ) : """ Method that polls the RPC service to see what the state of data taking is. This method is bound to a Timer so that it will periodically be called. """ self.rpcService.getDataTakingStatus( None, self ) def registerEventHandler( self, handler ) : """ Registers an event handler that will be notified when certain things happen, e.g. data taking started, data taking finished. """ self.eventHandlers.append( handler ) def startSCurveRun( self, thresholds ) : if self.fractionComplete!=1 : raise AlreadyTakingDataError() self.fractionComplete=0 self.statusString="Initiating s-curve run" self.rpcService.startSCurveRun( thresholds, self ) def startOccupancyCheck( self ) : if self.fractionComplete!=1 : raise AlreadyTakingDataError() self.fractionComplete=0 self.statusString="Initiating occupancy check" self.rpcService.startOccupancyCheck( None, self ) def startTrimCalibration( self, midPointTarget, maxLoops ) : if self.fractionComplete!=1 : raise AlreadyTakingDataError() self.fractionComplete=0 self.statusString="Initiating trim calibration" self.rpcService.startTrimCalibration( {'midPointTarget':midPointTarget,'maxLoops':maxLoops}, self ) def stopTakingData( self ) : self.rpcService.stopTakingData( None, self )
class IntroPage: DiceInstance = 0 VarTempScore = 0 #Temporary Score Variable VarTotScore = [] #Total Score Variable CountTurn = 1 #Count to display player number in Temporary Score Board def __init__(self): self.DPanel = DockPanel(HorizontalAlignment = HasAlignment.ALIGN_CENTER, Spacing=10) # Creates the Docker Panel Instance self.VPanel = VerticalPanel() # Creates the Vertical Panel Instance self.VPanel1 = VerticalPanel() # Creates the Vertical Panel Instance self.HPanel = HorizontalPanel() # Creates a Horizontal Panel Instance self.HPanel1 = HorizontalPanel()# Creates a Horizontal Panel Instance self.image=Image()#Creates the Image instance to embed the images of dice self.DummyUrl = self.image.getUrl() self.timer = Timer(notify=self.StillImage)#Timer for display of gif animation self.timerRButton = Timer(notify=self.OneAlert)#Timer for controlling states of Roll button #whenever the output of the dice is 1 self.RollButton = Button("Roll", getattr(self, "RollButtonPressed")) #Initially Disabled self.RollButton.setEnabled(False) self.BankButton = Button("Bank", getattr(self, "BankButtonPressed")) #Initially Disabled self.BankButton.setEnabled(False) #The start button controls both the number players as well the winning score self.StartButton = Button("Start", getattr(self, "StartButtonPressed")) #Intially Enabled self.StartButton.setEnabled(True) self.PlayerNum = TextBox() #Enter the Number of Players self.WinScore = TextBox() #Enter the Target Score self.PlayerNum.setText("0") self.WinScore.setText("0") # self.OK = Button("OK", getattr(self, "okButtonPressed")) self.NameScore = FlexTable() #main score board self.NameScore.setStyleName("NameScore") self.TempBoard = FlexTable() #Temporary score board self.TempBoard.setStyleName("TempBoard") self.TxtInstructions = HTML() def StartButtonPressed(self): self.CountTurn = 1 if int(self.PlayerNum.getText()) >= 2 and int(self.PlayerNum.getText()) <= 6 and int(self.WinScore.getText()) >= 10 and int(self.WinScore.getText()) <= 100: self.DPanel.remove(self.TxtInstructions, DockPanel.CENTER) self.BankButton.setVisible(True) self.RollButton.setVisible(True) # self.image.setVisible(True) self.TempBoard.setVisible(True) self.NameScore.setVisible(True) self.image = Image( self.DummyUrl + "images/0.png") self.image.setSize("200px", "300px") self.DPanel.add(self.image, DockPanel.CENTER) RootPanel().add(self.DPanel) self.StartButton.setEnabled(False) self.PlayerNum.setEnabled(False) self.WinScore.setEnabled(False) self.RollButton.setEnabled(True) self.TempBoard.setText(1,0,"Player"+str(1)) self.TempBoard.setText(1, 1, "0") self.NameScore.getRowFormatter().addStyleName(self.CountTurn,"Rows") else: Window.alert("Please Enter Correct Parameters " ) #Command for alert window return 0 VarPlayer = ["Player" + str(i) for i in xrange(1,int(self.PlayerNum.getText())+1)] i = 0 while i < int(self.PlayerNum.getText()): self.NameScore.setText(i+1, 0, VarPlayer[i]) self.NameScore.setText(i+1, 1, "0") self.VarTotScore.append(0) #m*1 vector of zeros indicating the initial scores i += 1 def OneAlert(self): AlrtTxt = " Sorry, your turn is over" Window.alert(AlrtTxt) self.timerRButton.cancel() self.RollButton.setEnabled(True) def StillImage(self): self.DPanel.remove(self.image, DockPanel.CENTER) self.image = Image( self.DummyUrl + "images/" +str(self.DiceInstance)+".png") self.image.setSize("300px", "300px") self.DPanel.add(self.image, DockPanel.CENTER) self.DPanel.setCellHeight(self.image, "300px") self.DPanel.setCellWidth(self.image, "600px") RootPanel().add(self.DPanel) self.timer.cancel() if self.DiceInstance != 1: self.TempBoard.setText(1, 1, self.DiceInstance + int(self.TempBoard.getText(1, 1))) self.BankButton.setEnabled(True) self.RollButton.setEnabled(True) else: self.NameScore.getRowFormatter().removeStyleName(self.CountTurn,"Rows") self.RollButton.setEnabled(False) self.timerRButton.schedule(1500) self.CountTurn += 1 if self.CountTurn % int(self.PlayerNum.getText()) == 1: self.CountTurn = 1 self.TempBoard.setText(1,0,"Player"+str(self.CountTurn)) self.TempBoard.setText(1, 1, "0") self.NameScore.getRowFormatter().addStyleName(self.CountTurn,"Rows"); else: self.TempBoard.setText(1,0,"Player"+str(self.CountTurn)) self.TempBoard.setText(1, 1, "0") self.NameScore.getRowFormatter().addStyleName(self.CountTurn,"Rows"); def RollButtonPressed(self): self.DiceInstance = random.randint(1, 6) # value turned after rolling the dice self.DPanel.remove(self.image, DockPanel.CENTER) self.image = Image("http://www.animatedimages.org/data/media/710/animated-dice-image-0064.gif") self.image.setSize("100px", "200px") self.DPanel.add(self.image, DockPanel.CENTER) self.DPanel.setCellHeight(self.image, "300px") self.DPanel.setCellWidth(self.image, "600px") RootPanel().add(self.DPanel) self.BankButton.setEnabled(False) self.RollButton.setEnabled(False) self.timer.schedule(3000) def BankButtonPressed(self): self.BankButton.setEnabled(False) self.NameScore.setText(self.CountTurn, 1, int(self.NameScore.getText(self.CountTurn, 1)) + int(self.TempBoard.getText(1,1))) if int(self.NameScore.getText(self.CountTurn, 1)) >= int(self.WinScore.getText()): AlrtTxt = "Congratulation!!! Player"+ str(self.CountTurn) + " wins !!!!" Window.alert(AlrtTxt) self.DPanel.remove(self.image, DockPanel.CENTER) self.DPanel.add(self.TxtInstructions, DockPanel.CENTER) self.BankButton.setVisible(False) self.RollButton.setVisible(False) # self.image.setVisible(False) self.TempBoard.setVisible(False) self.NameScore.setVisible(False) i = int(self.PlayerNum.getText()) while i > 0: self.NameScore. removeRow(i) i -= 1 self.TempBoard.setText(1,0,"X") self.TempBoard.setText(1, 1, "0") self.StartButton.setEnabled(True) # self.OK.setEnabled(True) self.PlayerNum.setEnabled(True) self.WinScore.setEnabled(True) self.RollButton.setEnabled(False) self.BankButton.setEnabled(False) self.NameScore.getRowFormatter().removeStyleName(self.CountTurn,"Rows"); self.DPanel.remove(self.image, DockPanel.CENTER) self.image = Image( self.DummyUrl + "images/0.png") self.image.setSize("200px", "300px") self.DPanel.add(self.image, DockPanel.CENTER) self.DPanel.setCellHeight(self.image, "200px") self.DPanel.setCellWidth(self.image, "400px") RootPanel().add(self.DPanel) else: self.NameScore.getRowFormatter().removeStyleName(self.CountTurn,"Rows"); self.CountTurn += 1 if self.CountTurn % int(self.PlayerNum.getText()) == 1: self.CountTurn = 1 self.TempBoard.setText(1,0,"Player"+str(self.CountTurn)) self.TempBoard.setText(1, 1, "0") self.NameScore.getRowFormatter().addStyleName(self.CountTurn,"Rows"); else: self.TempBoard.setText(1,0,"Player"+str(self.CountTurn)) self.TempBoard.setText(1, 1, "0") self.NameScore.getRowFormatter().addStyleName(self.CountTurn,"Rows"); def OnGameLoad(self): self.NameScore.setText(0, 0, "Player ID") self.NameScore.setText(0, 1, "Score") self.NameScore.setCellSpacing(10) self.NameScore.setCellPadding(10) self.NameScore.setBorderWidth(2) self.NameScore.setVisible(False) self.TempBoard.setText(0, 0, "Player's Turn") self.TempBoard.setText(0, 1, "Temporary Score") self.TempBoard.setText(1, 0, "X") self.TempBoard.setText(1, 1, "0") self.TempBoard.setCellSpacing(10) self.TempBoard.setCellPadding(10) self.TempBoard.setBorderWidth(2) self.TempBoard.setVisible(False) #Adding StartButton to Dock panel self.DPanel.add(self.StartButton, DockPanel.EAST) self.DPanel.setCellHeight(self.StartButton, "200px") self.DPanel.setCellWidth(self.StartButton, "20px") Txt = HTML("<center><b>Enter Number of Players (between 2 & 6)</b><center>")#Adding playernumber and winscore textbox to Horizontal Panel Txt1 = HTML("<left><b>Enter Target Score (between 10 & 100)</b><left>") self.HPanel1.add(Txt) self.HPanel1.add(self.PlayerNum) self.HPanel1.add(Txt1) self.HPanel1.add(self.WinScore) self.HPanel1.add(self.StartButton) self.HPanel1.setSpacing(20) #Adding Horizontal panel containing playernumber and winscore textbox to Dock Panel self.DPanel.add(self.HPanel1, DockPanel.NORTH) self.DPanel.setCellHeight(self.HPanel1, "30px") self.DPanel.setCellWidth(self.HPanel1, "2000px") self.TxtInstructions = HTML("<b><u><center>Instructions</center></u><ul><li>Pig is game for 2 to 6 Players.</li><li>Players take turns rolling a dice as many times as they like. </li><li>If a roll is 2, 3, 4, 5 or 6, the player adds that many points to their score for the turn. </li><li>A player may choose to end their turn at any time and 'bank' their points.</li><li>If a player rolls a 1, they lose all their unbanked points and their turn is over.</li><li>The first player to score the target or more wins.</li></ul></b>") self.TxtInstructions.setStyleName("TxtInstructions") self.DPanel.add(self.TxtInstructions, DockPanel.CENTER) self.DPanel.add(self.NameScore, DockPanel.WEST) #Adding main scoreboard to Dock Panel self.DPanel.setCellHeight(self.NameScore, "300px") self.DPanel.setCellWidth(self.NameScore, "100px") self.DPanel.setSpacing(10) self.DPanel.setPadding(2) #Adding Tempboard and BankButton to Horizontal Panel self.HPanel.add(self.TempBoard) #Adding BankButton and RollButton to vertical panel self.VPanel.add(self.RollButton) self.RollButton.setVisible(False) self.VPanel.add(self.BankButton) self.BankButton.setVisible(False) self.VPanel.setSpacing(10) #Adding Vertical panel containing BankButton and RollButton to Horizontal Panel self.HPanel.add(self.VPanel) self.HPanel.setSpacing(40) #Adding Horizontal panel containing Tempboard and vertical panel containing BankButton and RollButton to Dock Panel self.DPanel.add(self.HPanel, DockPanel.SOUTH) self.DPanel.setCellHeight(self.HPanel, "20px") self.DPanel.setCellWidth(self.HPanel, "2000px") RootPanel().add(self.DPanel)
class SeeMeNot(object): def __init__(self, symbol_shape, message_symbol_coder, symbol_signal_coder): self.timer = Timer(notify=self) self.setTimer(self.timer) self.symbol_shape = symbol_shape self.message_symbol_coder = message_symbol_coder self.symbol_signal_coder = symbol_signal_coder self.decoded = {} def setTimer(self, timer): self.timer.schedule(2000) def onTimer(self, timer): print 'onTimer Called.' JS(""" var myinfoobject = new Object(); myinfoobject['populate'] = true; chrome.windows.getCurrent(myinfoobject, mylocalfunction); function mylocalfunction(window) { @{{focused_window}} = window.id; tabs = window.tabs; if (!tabs) { return; } tabs_len = tabs.length; for (var i = 0; i < tabs_len; i++) { if (tabs[i].active) { @{{focused_tab}} = tabs[i].id console.log("Issuing getDom request to " + tabs[i].id); chrome.tabs.sendRequest(tabs[i].id, {action: "getDOM"}, function(response) { if (!response.process) { console.log('Nothing to process.'); return; } console.log("SeeMeNot Response from python " + response.dom.substr(0,8)); var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var img = new Image(); img.onload = function() { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); console.log('canvas ' + canvas.width + ' ' + canvas.height); @{{width}} = imageData.width; @{{height}} = imageData.height; var datalength = imageData.data.length; @{{imageDataArray}} = new Array(); for (var j = 0; j < datalength; j = j + 4) { @{{imageDataArray}}.push(imageData.data[j]); } } img.src = response.dom; @{{b64}} = response.dom; } ); } } }""") print 'Focused win:', focused_window print 'Focused tab:', focused_tab print "Target py'd:", str(b64)[:min(40, len(str(b64)))] new_b64 = str(b64) JS(""" @{{lookup}} = { 255: 0, 254: 0, 253: 0, 252: 0, 251: 0, 250: 0, 249: 0, 248: 0, 247: 0, 246: 0, 249: 0, 248: 0, 247: 0, 246: 0, 245: 0, 244: 0, 243: 0, 242: 0, 241: 0, 240: 0, 239: 0, 238: 0, 237: 0, 236: 0, 235: 0, 234: 0, 233: 0, 232: 0, 231: 0, 230: 0, 229: 0, 228: 0, 227: 0, 226: 0, 225: 0, 224: 0, 223: 0, 222: 0, 221: 1, 220: 1, 219: 1, 218: 1, 217: 1, 216: 1, 215: 1, 214: 1, 213: 1, 212: 1, 211: 1, 210: 1, 209: 1, 208: 1, 207: 1, 206: 1, 205: 1, 204: 1, 203: 1, 202: 1, 201: 1, 200: 1, 199: 1, 198: 1, 197: 1, 196: 1, 195: 1, 194: 1, 193: 2, 192: 2, 191: 2, 190: 2, 189: 2, 188: 2, 187: 2, 186: 2, 185: 2, 184: 2, 183: 2, 182: 2, 181: 2, 180: 2, 179: 2, 178: 2, 177: 2, 176: 2, 175: 2, 174: 2, 173: 2, 172: 2, 171: 2, 170: 2, 169: 2, 168: 2, 167: 2, 166: 2, 165: 3, 164: 3, 163: 3, 162: 3, 161: 3, 160: 3, 159: 3, 158: 3, 157: 3, 156: 3, 155: 3, 154: 3, 153: 3, 152: 3, 151: 3, 150: 3, 149: 3, 148: 3, 147: 3, 146: 3, 145: 3, 144: 3, 143: 3, 142: 3, 141: 3, 140: 3, 139: 3, 138: 3, 137: 4, 136: 4, 135: 4, 134: 4, 133: 4, 132: 4, 131: 4, 130: 4, 129: 4, 128: 4, 127: 4, 126: 4, 125: 4, 124: 4, 123: 4, 122: 4, 121: 4, 120: 4, 119: 4, 118: 4, 117: 4, 116: 4, 115: 4, 114: 4, 113: 4, 112: 4, 111: 4, 110: 4, 109: 5, 108: 5, 107: 5, 106: 5, 105: 5, 104: 5, 103: 5, 102: 5, 101: 5, 100: 5, 99: 5, 98: 5, 97: 5, 96: 5, 95: 5, 94: 5, 93: 5, 92: 5, 91: 5, 90: 5, 89: 5, 88: 5, 87: 5, 86: 5, 85: 5, 84: 5, 83: 5, 82: 5, 81: 6, 80: 6, 79: 6, 78: 6, 77: 6, 76: 6, 75: 6, 74: 6, 73: 6, 72: 6, 71: 6, 70: 6, 69: 6, 68: 6, 67: 6, 66: 6, 65: 6, 64: 6, 63: 6, 62: 6, 61: 6, 60: 6, 59: 6, 58: 6, 57: 6, 56: 6, 55: 6, 54: 6, 53: 7, 52: 7, 51: 7, 50: 7, 49: 7, 48: 7, 47: 7, 46: 7, 45: 7, 44: 7, 43: 7, 42: 7, 41: 7, 40: 7, 39: 7, 38: 7, 37: 7, 36: 7, 35: 7, 34: 7, 33: 7, 32: 7, 31: 7, 30: 7, 29: 7, 28: 7, 27: 7, 26: 7, 25: 8, 24: 8, 23: 8, 22: 8, 21: 8, 20: 8, 19: 8, 18: 8, 17: 8, 16: 8, 15: 8, 14: 8, 13: 8, 12: 8, 11: 8, 10: 8, 9: 8, 8: 8, 7: 8, 6: 8, 5: 8, 4: 8, 3: 8, 2: 8, 1: 8, 0: 8 } """) symbol_signal_coder = Base64SymbolSignalCoder() if str(focused_tab) and str(new_b64) and str(width): print 'Dimensions', width, height _data_len = len(imageDataArray) imageDataArray.reverse() pixels = [] for _h in range(height): pixels.append([]) for _w in range(width): red = imageDataArray.pop() pixels[_h].append(red) print 'Pixel matrix set.' shape_width, shape_height = self.symbol_shape.get_shape_size() extracted_data = '' values = {} for y_coord in range(0, height, shape_height): for x_coord in range(0, width, shape_width): values.clear() _symbol = [] for symbol_val in range( self.symbol_shape.get_num_symbol_shapes()): coords = self.symbol_shape.get_symbol_shape_coords( symbol_val + 1) _vals = 0 _num_vals = 0 for x, y in coords: _vals += pixels[y_coord + y][x_coord + x] _num_vals += 1 _avg = int(_vals / float(_num_vals)) JS("@{{_symbol_val}} = @{{lookup}}[@{{_avg}}]") _symbol.append(int(_symbol_val)) extracted_datum = self.message_symbol_coder.symbol_to_message( _symbol) extracted_data += extracted_datum extracted_data = _base64_pad(extracted_data) print 'Submitting extracted_data.' if not extracted_data in self.decoded: self.decoded[extracted_data] = True JS(""" chrome.tabs.sendRequest(@{{focused_tab}}, {action: "decrypted", data: @{{extracted_data}}}, function(response) { console.log("Success"); } ); """) else: print 'Already sent for decoding.' self.timer.schedule(1000) def onModuleLoad(self): self.sink_list = SinkList() self.sink_list.add(Menus.init())
class SeeMeNot(object): def __init__(self, symbol_shape, message_symbol_coder, symbol_signal_coder): self.timer = Timer(notify=self) self.setTimer(self.timer) self.symbol_shape = symbol_shape self.message_symbol_coder = message_symbol_coder self.symbol_signal_coder = symbol_signal_coder self.decoded = {} def setTimer(self, timer): self.timer.schedule(2000) def onTimer(self, timer): print 'onTimer Called.' JS(""" var myinfoobject = new Object(); myinfoobject['populate'] = true; chrome.windows.getCurrent(myinfoobject, mylocalfunction); function mylocalfunction(window) { @{{focused_window}} = window.id; tabs = window.tabs; if (!tabs) { return; } tabs_len = tabs.length; for (var i = 0; i < tabs_len; i++) { if (tabs[i].active) { @{{focused_tab}} = tabs[i].id console.log("Issuing getDom request to " + tabs[i].id); chrome.tabs.sendRequest(tabs[i].id, {action: "getDOM"}, function(response) { if (!response.process) { console.log('Nothing to process.'); return; } console.log("SeeMeNot Response from python " + response.dom.substr(0,8)); var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var img = new Image(); img.onload = function() { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); console.log('canvas ' + canvas.width + ' ' + canvas.height); @{{width}} = imageData.width; @{{height}} = imageData.height; var datalength = imageData.data.length; @{{imageDataArray}} = new Array(); for (var j = 0; j < datalength; j = j + 4) { @{{imageDataArray}}.push(imageData.data[j]); } } img.src = response.dom; @{{b64}} = response.dom; } ); } } }""") print 'Focused win:', focused_window print 'Focused tab:', focused_tab print "Target py'd:", str(b64)[:min(40, len(str(b64)))] new_b64 = str(b64) JS(""" @{{lookup}} = { 255: 0, 254: 0, 253: 0, 252: 0, 251: 0, 250: 0, 249: 0, 248: 0, 247: 0, 246: 0, 249: 0, 248: 0, 247: 0, 246: 0, 245: 0, 244: 0, 243: 0, 242: 0, 241: 0, 240: 0, 239: 0, 238: 0, 237: 0, 236: 0, 235: 0, 234: 0, 233: 0, 232: 0, 231: 0, 230: 0, 229: 0, 228: 0, 227: 0, 226: 0, 225: 0, 224: 0, 223: 0, 222: 0, 221: 1, 220: 1, 219: 1, 218: 1, 217: 1, 216: 1, 215: 1, 214: 1, 213: 1, 212: 1, 211: 1, 210: 1, 209: 1, 208: 1, 207: 1, 206: 1, 205: 1, 204: 1, 203: 1, 202: 1, 201: 1, 200: 1, 199: 1, 198: 1, 197: 1, 196: 1, 195: 1, 194: 1, 193: 2, 192: 2, 191: 2, 190: 2, 189: 2, 188: 2, 187: 2, 186: 2, 185: 2, 184: 2, 183: 2, 182: 2, 181: 2, 180: 2, 179: 2, 178: 2, 177: 2, 176: 2, 175: 2, 174: 2, 173: 2, 172: 2, 171: 2, 170: 2, 169: 2, 168: 2, 167: 2, 166: 2, 165: 3, 164: 3, 163: 3, 162: 3, 161: 3, 160: 3, 159: 3, 158: 3, 157: 3, 156: 3, 155: 3, 154: 3, 153: 3, 152: 3, 151: 3, 150: 3, 149: 3, 148: 3, 147: 3, 146: 3, 145: 3, 144: 3, 143: 3, 142: 3, 141: 3, 140: 3, 139: 3, 138: 3, 137: 4, 136: 4, 135: 4, 134: 4, 133: 4, 132: 4, 131: 4, 130: 4, 129: 4, 128: 4, 127: 4, 126: 4, 125: 4, 124: 4, 123: 4, 122: 4, 121: 4, 120: 4, 119: 4, 118: 4, 117: 4, 116: 4, 115: 4, 114: 4, 113: 4, 112: 4, 111: 4, 110: 4, 109: 5, 108: 5, 107: 5, 106: 5, 105: 5, 104: 5, 103: 5, 102: 5, 101: 5, 100: 5, 99: 5, 98: 5, 97: 5, 96: 5, 95: 5, 94: 5, 93: 5, 92: 5, 91: 5, 90: 5, 89: 5, 88: 5, 87: 5, 86: 5, 85: 5, 84: 5, 83: 5, 82: 5, 81: 6, 80: 6, 79: 6, 78: 6, 77: 6, 76: 6, 75: 6, 74: 6, 73: 6, 72: 6, 71: 6, 70: 6, 69: 6, 68: 6, 67: 6, 66: 6, 65: 6, 64: 6, 63: 6, 62: 6, 61: 6, 60: 6, 59: 6, 58: 6, 57: 6, 56: 6, 55: 6, 54: 6, 53: 7, 52: 7, 51: 7, 50: 7, 49: 7, 48: 7, 47: 7, 46: 7, 45: 7, 44: 7, 43: 7, 42: 7, 41: 7, 40: 7, 39: 7, 38: 7, 37: 7, 36: 7, 35: 7, 34: 7, 33: 7, 32: 7, 31: 7, 30: 7, 29: 7, 28: 7, 27: 7, 26: 7, 25: 8, 24: 8, 23: 8, 22: 8, 21: 8, 20: 8, 19: 8, 18: 8, 17: 8, 16: 8, 15: 8, 14: 8, 13: 8, 12: 8, 11: 8, 10: 8, 9: 8, 8: 8, 7: 8, 6: 8, 5: 8, 4: 8, 3: 8, 2: 8, 1: 8, 0: 8 } """) symbol_signal_coder = Base64SymbolSignalCoder() if str(focused_tab) and str(new_b64) and str(width): print 'Dimensions', width, height _data_len = len(imageDataArray) imageDataArray.reverse() pixels = [] for _h in range(height): pixels.append([]) for _w in range(width): red = imageDataArray.pop() pixels[_h].append(red) print 'Pixel matrix set.' shape_width, shape_height = self.symbol_shape.get_shape_size() extracted_data = '' values = {} for y_coord in range(0, height, shape_height): for x_coord in range(0, width, shape_width): values.clear() _symbol = [] for symbol_val in range(self.symbol_shape.get_num_symbol_shapes()): coords = self.symbol_shape.get_symbol_shape_coords(symbol_val+1) _vals = 0 _num_vals = 0 for x,y in coords: _vals += pixels[y_coord + y][x_coord + x] _num_vals += 1 _avg = int(_vals / float(_num_vals)) JS("@{{_symbol_val}} = @{{lookup}}[@{{_avg}}]") _symbol.append(int(_symbol_val)) extracted_datum = self.message_symbol_coder.symbol_to_message(_symbol) extracted_data += extracted_datum extracted_data = _base64_pad(extracted_data) print 'Submitting extracted_data.' if not extracted_data in self.decoded: self.decoded[extracted_data] = True JS(""" chrome.tabs.sendRequest(@{{focused_tab}}, {action: "decrypted", data: @{{extracted_data}}}, function(response) { console.log("Success"); } ); """) else: print 'Already sent for decoding.' self.timer.schedule(1000) def onModuleLoad(self): self.sink_list = SinkList() self.sink_list.add(Menus.init())
class DNDHelper(object): """ DNDHelper is a singleton drag and drop agent. It acts as dragging/dropping agent for platforms that do not support html5 drag and drop. """ def __init__(self): self.dropTargets = [] self.dragging = NOT_DRAGGING self.dragBusy = False self._currentTargetElement = None self.previousDropTarget = None self.draggingImage = None self.origMouseX = 0 self.origMouseY = 0 self.currentDragOperation = 'none' self.data = None self.returnTimer = Timer(notify=self.onReturningWidget) self.mouseEvent = None self.dragDataStore = None def setCurrentTargetElement(self, element): if self._currentTargetElement is not None: if not DOM.compare(self._currentTargetElement, element): # leave_event = self.makeDragEvent(self.mouseEvent, 'dragleave', # self.currentTargetElement) self.fireDNDEvent('dragleave', self.currentTargetElement, self.currentDropWidget) # self.currentDropWidget.onDragLeave(leave_event) # self.finalize(leave_event) self._currentTargetElement = element def getCurrentTargetElement(self): return self._currentTargetElement currentTargetElement = property(getCurrentTargetElement, setCurrentTargetElement) def getElement(self): """ ie6 GlassWidget impl needs this """ return self.dragWidget.getElement() def updateDropEffect(self, dataTransfer, event_type): """ http://dev.w3.org/html5/spec/dnd.html#dragevent """ # default for dragstart, drag, dragleave dropEffect='none' if event_type in ['dragover', 'dragenter']: ea = dataTransfer.getEffectAllowed() if ea == 'none': dropEffect = 'none' elif ea.startswith('copy') or ea == 'all': dropEffect = 'copy' elif ea.startswith('link'): dropEffect = 'link' elif ea == 'move': dropEffect = 'move' else: dropEffect = 'copy' elif event_type in ['drop', 'dragend']: dropEffect = self.currentDragOperation dataTransfer.dropEffect = dropEffect def updateDragOperation(self, event): """ http://dev.w3.org/html5/spec/dnd.html """ dataTransfer = event.dataTransfer ea = dataTransfer.effectAllowed de = dataTransfer.dropEffect if (de == 'copy' and ea in ['uninitialized', 'copy','copyLink', 'copyMove', 'all']): self.currentDragOperation = 'copy' elif (de == 'link' and ea in ['uninitialized', 'link', 'copyLink', 'linkMove', 'all']): self.currentDragOperation = 'link' elif (de == 'move' and ea in ['uninitialized', 'move', 'copyMove', 'linkMove', 'all']): self.currentDragOperation = 'move' else: self.currentDragOperation = 'none' def updateAllowedEffects(self, drag_event): dt = drag_event.dataTransfer self.dragDataStore.allowed_effects_state = dt.effectAllowed def registerTarget(self, target): """ Rather than searching the entire document for drop target widgets and maybe drop targets within widgets, this implementation holds a list of widgets and searches only within this list for potential drop targets. """ if not target in self.dropTargets: self.dropTargets.append(target) def unregisterTarget(self, target): """ I dont know why, but a widget may no longer want to be registered as a drop target. """ while target in self.dropTargets: self.dropTargets.remove(target) def setDragImage(self, element, x, y): position_absolute = DOM.getStyleAttribute(element, 'position') == 'absolute' if position_absolute: self.dragLeftOffset = x + DOM.getAbsoluteLeft( element.offsetParent) self.dragTopOffset = y + DOM.getAbsoluteTop( element.offsetParent) else: self.dragLeftOffset = x self.dragTopOffset = y if element.tagName.lower().endswith('img'): src = DOM.getAttribute(element,'src') element = DOM.createElement('img') DOM.setAttribute(element, 'src', src) if not self.draggingImage: self.createDraggingImage(element) else: self.draggingImage.setImage(element) def addFeedbackElement(self, element): """ This is called from DataTransfer """ if self.draggingImage: self.draggingImage.addElement(element) else: self.createDraggingImage(element) def createDraggingImage(self, element): self.draggingImage = DraggingWidget(element) return self.draggingImage def setDragImageLocation(self, x, y): """ Move the dragging image around. """ elt_top = y - self.dragTopOffset elt_left = x - self.dragLeftOffset # if self.absParent: # ap = self.absParent # elt_top -= int(self.absTop) # elt_left -= int(self.absLeft) self.draggingImage.setStyleAttribute('top', elt_top ) self.draggingImage.setStyleAttribute('left', elt_left) def getAbsoluteLeft(self): """ GlassWidget wants this """ # return 0 # if self.absParent: # return self.absParent.getAbsoluteLeft() return self.dragWidget.getAbsoluteLeft() #return self.origLeft def getAbsoluteTop(self): """ GlassWidget wants this """ # return 0 # if self.absParent: # return self.absParent.getAbsoluteTop() return self.dragWidget.getAbsoluteTop() #return self.origTop def makeDragEvent(self, event, type, target=None): dt = DataTransfer(self.dragDataStore) self.updateDropEffect(dt, type) drag_event = DragEvent(event, type, dt, target) return drag_event def finalize(self, event): self.dragDataStore.allowed_effects_state = \ event.dataTransfer.effectAllowed if event.type in ['dragstart', 'drop']: self.dragDataStore.setMode(PROTECTED) event.dataTransfer.dataStore = None def fireDNDEvent(self, name, target, widget): if name == 'dragstart': self.dragDataStore.setMode(READ_WRITE) elif name == 'drop': self.dragDataStore.setMode(READ_ONLY) event = self.makeDragEvent(self.mouseEvent, name, target) widget.onBrowserEvent(event) self.finalize(event) return event def initFeedbackImage(self): ds = self.dragDataStore x = 0 y = 0 if ds.bitmap is not None: if ds.hotspot_coordinate is not None: offset = ds.hotspot_coordinate x = offset[0] y = offset[1] self.setDragImage(ds.bitmap, x, y) return if self.dragDataStore.elements: for element in self.dragDataStore.elements: self.addFeedbackElement(element) def onMouseMove(self, sender, x, y): event = DOM.eventGetCurrentEvent() self.mouseEvent = event button = DOM.eventGetButton(event) if not button == Event.BUTTON_LEFT: return ## The following commented code lets the native dnd happen in IE. sucks. ## But it may enable dragging our widgets out of IE into other apps. # else: # try: # self.dragWidget.getElement().dragDrop() # return # except: # pass # Adjust x and y to absolute coordinates. x, y = eventCoordinates(event) if self.dragging == DRAGGING_NO_MOVEMENT_YET: self.origMouseX = x self.origMouseY = y self.currentDragOperation = 'none' fromElement = self.dragWidget.getElement() # Is the widget itself draggable? try: draggable = fromElement.draggable except: draggable = False # if not, find the draggable element at (x, y) in the widget if not draggable: fromElement = findDraggable(sender.getElement(), self.origMouseX, self.origMouseY) # Nothing draggable found. return. if fromElement is None: self.dragging = NOT_DRAGGING return # Get the location for the dragging widget #self.absParent = None #self.absParent = self.dragWidget.getParent() #self.absLeft = DOM.getStyleAttribute(fromElement, 'left') #print self.absLeft #self.absTop = DOM.getStyleAttribute(fromElement, 'top') #print self.absTop #self.origTop = DOM.getAbsoluteTop(fromElement) + parent.getAbsoluteTop() #self.origLeft = DOM.getAbsoluteLeft(fromElement) + parent.getAbsoluteLeft() self.origTop = DOM.getAbsoluteTop(fromElement) self.origLeft = DOM.getAbsoluteLeft(fromElement) #self.glassTop = DOM.getAbsoluteTop(fromElement.offsetParent) #self.glassLeft = DOM.getAbsoluteTop(fromElement.offsetParent) position_absolute = DOM.getStyleAttribute(fromElement, 'position') == 'absolute' if position_absolute: self.dragLeftOffset = (self.origMouseX - DOM.getAbsoluteLeft(fromElement.offsetParent)) self.dragTopOffset = (self.origMouseY - DOM.getAbsoluteTop(fromElement.offsetParent)) else: self.dragLeftOffset = self.origMouseX - self.origLeft self.dragTopOffset = self.origMouseY - self.origTop # self.setDragImage(fromElement, # self.origMouseX - self.origLeft, # self.origMouseY - self.origTop) self.dragDataStore.elements = [fromElement] dragStartEvent = self.fireDNDEvent('dragstart', None, self.dragWidget) if not isCanceled(dragStartEvent): self.initFeedbackImage() RootPanel().add(self.draggingImage) self.setDragImageLocation(x, y) self.dragging = ACTIVELY_DRAGGING GlassWidget.show(self) elif self.dragging == ACTIVELY_DRAGGING: try: doc().selection.empty() except: wnd().getSelection().removeAllRanges() self.setDragImageLocation(x, y) # If we are still working on the previous iteration, or if we have # done this recently, we'll wait for the next event. if self.dragBusy or time.time() - self.drag_time < 0.25: return self.doDrag(event, x, y) self.drag_time = time.time() def doDrag(self, event, x, y): self.dragBusy = True #self.dragDataStore.dropEffect = 'none' drag_event = self.fireDNDEvent('drag', None, self.dragWidget) # drag event was not canceled if not isCanceled(drag_event): target = None widget = None # Find the most specific element under the cursor and the widget # with the drop listener for it. for widget in self.dropTargets: target = getElementUnderMouse(widget, x, y) if target is not None: break if target: drop_widget = widget drop_element = target if (not self.currentTargetElement or not DOM.compare(drop_element, self.currentTargetElement)): # enter_event = self.makeDragEvent(event,'dragenter', # drop_element) enter_event = self.fireDNDEvent('dragenter', drop_element, drop_widget) # drop_widget.onDragEnter(enter_event) # self.finalize(enter_event) if isCanceled(enter_event): self.currentTargetElement = drop_element self.currentDropWidget = drop_widget if self.currentTargetElement is not None: # disable dropping if over event is not canceled # over_event = self.makeDragEvent(event, 'dragover', # drop_element) over_event = self.fireDNDEvent('dragover', drop_element, self.currentDropWidget) # self.currentDropWidget.onDragOver(over_event) # self.finalize(over_event) if isCanceled(over_event): self.updateDragOperation(over_event) else: self.currentDragOperation = 'none' self.draggingImage.updateCursor(self.currentDragOperation) else: self.currentTargetElement = None else: self.currentDragOperation = 'none' self.dragBusy = False def onMouseDown(self, sender, x, y): self.dragWidget = sender event = DOM.eventGetCurrentEvent() self.mouseEvent = event button = DOM.eventGetButton(event) if button != Event.BUTTON_LEFT: return # x, y = eventCoordinates(event) # self.origMouseX = x # self.origMouseY = y self.dragging = DRAGGING_NO_MOVEMENT_YET self.drag_time = time.time() self.dragDataStore = DragDataStore() def onMouseUp(self, sender, x, y): # event = DOM.eventGetCurrentEvent() self.dragging = NOT_DRAGGING if self.draggingImage: GlassWidget.hide() if (self.currentDragOperation == 'none' or not self.currentTargetElement): if self.currentTargetElement: # leave_event = self.makeDragEvent(event, 'dragleave', # self.currentTargetElement) self.fireDNDEvent('dragleave', self.currentTargetElement, self.currentDropWidget) # self.currentDropWidget.onDragLeave(leave_event) # self.finalize(leave_event) else: self.currentDragOperation = 'none' self.returnDrag() else: # self.dragDataStore.mode = READ_ONLY # drop_event = self.makeDragEvent(event, 'drop', # self.currentTargetElement) drop_event = self.fireDNDEvent('drop', self.currentTargetElement, self.currentDropWidget) #self.dropEffect = self.currentDragOperation # self.currentDropWidget.onDrop(drop_event) # self.finalize(drop_event) if isCanceled(drop_event): self.currentDragOperation = drop_event.dataTransfer.dropEffect else: self.currentDragOperation = 'none' self.zapDragImage() #self.dropEffect = self.currentDragOperation self.fireDNDEvent('dragend', None, self.dragWidget) # dragEnd_event = self.makeDragEvent(event, 'dragend') # self.dragWidget.onDragEnd(dragEnd_event) # self.finalize(dragEnd_event) def zapDragImage(self): RootPanel().remove(self.draggingImage) self.draggingImage = None def returnDrag(self): self.moveItemTo(self.draggingImage,self.origLeft, self.origTop) def returnXY(self, start, destination, count): start_x, start_y = start destination_x, destination_y = destination diff_x = (start_x - destination_x) / count diff_y = (start_y - destination_y) / count while (abs(start_x - destination_x) > 10 or abs(start_y - destination_y) > 10): start_x -= diff_x start_y -= diff_y yield start_x, start_y raise StopIteration def onReturningWidget(self, timer): try: next_loc = self.return_iterator.next() except StopIteration: self.zapDragImage() return x, y = next_loc self.draggingImage.setStyleAttribute('top', str(y)) self.draggingImage.setStyleAttribute('left', str(x)) self.returnTimer.schedule(50) def moveItemTo(self, widget, x, y): self.returnWidget = widget returnWidgetDestination = x, y widgetStart = widget.getAbsoluteLeft(), widget.getAbsoluteTop() self.return_iterator = self.returnXY(widgetStart, returnWidgetDestination, 10) self.returnTimer.schedule(50) def onMouseEnter(self, sender): pass def onMouseLeave(self, sender): if self.dragging == DRAGGING_NO_MOVEMENT_YET: self.dragging = NOT_DRAGGING def onMouseGlassEnter(self, sender): pass def onMouseGlassLeave(self, sender): pass