class Gui: def __init__(self): self.mTop=None self.mGraphics=None self.mTop=None self.mInput=None self.mTabbing=True self.mShiftPressed=False self.mMetaPressed=False self.mControlPressed=False self.mAltPressed=False self.mLastMousePressButton=0 self.mLastMousePressTimeStamp=0 self.mLastMouseX=0 self.mLastMouseY=0 self.mClickCount=1 self.mLastMouseDragButton=0 self.mFocusHandler=FocusHandler() self.mDirtyRect=DirtyRectangle() self.mKeyListeners=[] self.mWidgetWithMouseQueue=[] self.mDirtyRect.setEnabled(False) def __del__(self): #We assume that there is only one Gui object. if Widget.widgetExists(self.mTop): #self.mTop.shutDown() self.mTop.setFocusHandler(None) self.mTop=None def setDirtyRectEnabled(self,enabled): self.mDirtyRect.setEnabled(enabled) def isDirtyRectEnabled(self): return self.mDirtyRect.isEnabled() def enableDirtyRect(self): self.mDirtyRect.setEnabled(True) def disableDirtyRect(self): self.mDirtyRect.setEnabled(False) def setDrawOptimized(self,draw): self.mDirtyRect.setDrawOptimized(draw) def isDrawOptimized(self): return self.mDirtyRect.isDrawOptimized() def optimizeDraw(self): self.mDirtyRect.setDrawOptimized(True) def deoptimizeDraw(self): self.mDirtyRect.setDrawOptimized(False) def setTop(self,widget): if self.mTop != None: self.mTop.setFocusHandler(None) self.mTop.setDirtyRectangle(None) if widget != None: widget.setFocusHandler(self.mFocusHandler) widget.setDirtyRectangle(self.mDirtyRect) self.mTop=widget def getTop(self): return self.mTop def setGraphics(self,graphics): self.mGraphics=graphics def getGraphics(self): return self.mGraphics def setInput(self,input): self.mInput=input def getInput(self): return self.mInput def logic(self): if self.mTop == None: raise GCN_EXCEPTION("No top widget set.") self.handleModalFocus() self.handleModalMouseInputFocus() if self.mInput != None: self.mInput.pollInput() self.handleKeyInput() self.handleMouseInput() self.mTop.logic() def draw(self): if self.mTop == None: raise GCN_EXCEPTION("No top widget set") if self.mGraphics == None: raise GCN_EXCEPTION("No graphics set") if self.mTop.isVisible() == False: return None self.mGraphics.beginDraw() #if top has a frame, draw it before drawing top if self.mTop.getFrameSize() > 0: rec=Rectangle(self.mTop.getDimension()) rec.x-=self.mTop.getFrameSize() rec.y-=self.mTop.getFrameSize() rec.width+=2*self.mTop.getFrameSize() rec.height+=2*self.mTop.getFrameSize() self.mGraphics.pushClipArea( Rectangle(self.mTop.getDimension()) ) self.mTop.draw(self.mGraphics) self.mGraphics.popClipArea() self.mGraphics.endDraw() def focusNone(self): self.mFocusHandler.focusNone() def setTabbingEnabled(self,tabbing): self.mTabbing=tabbing def isTabbingEnabled(self): return self.mTabbing def addGlobalKeyListener(self,keyListener): self.mKeyListeners.append(keyListener) def removeGlobalKeyListener(self,keyListener): self.mKeyListeners.remove(keyListener) def handleMouseInput(self): while self.mInput.isMouseQueueEmpty() == False: mouseInput=self.mInput.dequeueMouseInput() self.mLastMouseX=mouseInput.getX() self.mLastMouseY=mouseInput.getY() type=mouseInput.getType() if type == MouseInput.PRESSED: self.handleMousePressed(mouseInput) elif type == MouseInput.RELEASED: self.handleMouseReleased(mouseInput) elif type == MouseInput.MOVED: self.handleMouseMoved(mouseInput) elif type == MouseInput.WHEEL_MOVED_DOWN: self.handleMouseWheelMovedDown(mouseInput) elif type == MouseInput.WHEEL_MOVED_UP: self.handleMouseWheelMovedUp(mouseInput) else: raise GCN_EXCEPTION("Unknown mouse input type.") def handleKeyInput(self): while self.mInput.isKeyQueueEmpty() == False: keyInput=self.mInput.dequeueKeyInput() self.mShiftPressed=keyInput.isShiftPressed() self.mControlPressed=keyInput.isControlPressed() self.mAltPressed=keyInput.isAltPressed() self.mMetaPressed=keyInput.isMetaPressed() keyEventToGlobalListeners=KeyEvent(None,self.mShiftPressed,self.mControlPressed,self.mAltPressed,self.mMetaPressed,keyInput.getType(),keyInput.isNumericPad(),keyInput.getKey()) self.distributeKeyEventToGlobalListeners(keyEventToGlobalListeners) #If a global key listener consumes the event it will not be #sent further to the source of the event. if keyEventToGlobalListeners.isConsumed() == True: continue keyEventConsumed=False #send keyInputs to focused widgets if self.mFocusHandler.getFocused() != None: keyEvent=KeyEvent(self.getKeyEventSource(),self.mShiftPressed,self.mControlPressed,self.mAltPressed,self.mMetaPressed,keyInput.getType(),keyInput.isNumericPad(),keyInput.getKey()) if self.mFocusHandler.getFocused().isFocusable() == False: self.mFocusHandler.focusNone() else: self.distributeKeyEvent(keyEvent) keyEventConsumed=keyEvent.isConsumed() #If the key event hasn't been consumed and #tabbing is enable check for tab press and #change focus. if keyEventConsumed == False and keyInput.getKey().getValue() == Key.TAB and keyInput.getType() == KeyInput.PRESSED and self.getKeyEventSource().isTabOutEnabled() == True: if keyInput.isShiftPressed() == True: self.mFocusHandler.focusPrevious() else: self.mFocusHandler.focusNext() def handleMouseMoved(self,mouseInput): if len(self.mWidgetWithMouseQueue) > 0 and ( mouseInput.getX() < 0 or mouseInput.getY() < 0 or self.mTop.getDimension().isPointInRect(mouseInput.getX(),mouseInput.getY()) ) == False: #distribute an event to all widgets in the "widget with mouse" queue. while len(self.mWidgetWithMouseQueue) > 0: widget=self.mWidgetWithMouseQueue[0] if Widget.widgetExists(widget): self.distributeMouseEvent(widget,MouseEvent.EXITED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY(),true,true) self.mWidgetWithMouseQueue.pop(0) return None #Check if there is a need to send mouse exited events by #traversing the "widget with mouse" queue. widgetWithMouseQueueCheckDone=len(self.mWidgetWithMouseQueue) == 0 while widgetWithMouseQueueCheckDone == False: iterations=0 for i in self.mWidgetWithMouseQueue: widget=i #If a widget in the "widget with mouse queue" doesn't #exist anymore it should be removed from the queue if Widget.widgetExists(widget) == False: self.mWidgetWithMouseQueue.remove(widget) break else: x, y=widget.getAbsolutePosition() if x > mouseInput.getX() or y > mouseInput.getX() or x+widget.getWidth() <= mouseInput.getX() or y+widget.getHeight() <= mouseInput.getY() or widget.isVisible() == False: self.distributeMouseEvent(widget,MouseEvent.EXITED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY(),true,true) self.mClickCount=1 self.mLastMousePressTimeStamp=0 self.mWidgetWithMouseQueue.remove(i) break iterations+=1 widgetWithMouseQueueCheckDone = iterations == len(self.mWidgetWithMouseQueue) #Check all widgets below the mouse to see if they are #present in the "widget with mouse" queue. If a widget #is not then it should be added and an entered event should #be sent to it. parent=self.getMouseEventSource(mouseInput.getX(),mouseInput.getY()) widget=parent #If a widget has modal mouse input focus then it will #always be returned from getMouseEventSource, but we only wan't to send #mouse entered events if the mouse has actually entered the widget with #modal mouse input focus, hence we need to check if that's the case. If #it's not we should simply ignore to send any mouse entered events. if self.mFocusHandler.getModalMouseInputFocused() == widget and Widget.widgetExists(widget) == True: x, y=widget.getAbsolutePosition() if x > mouseInput.getX() or y > mouseInput.getY() or x+widget.getWidth() <= mouseInput.getX() or y+widget.getHeight() <= mouseInput.getY(): parent=None while parent != None: parent=widget.getParent() # Check if the widget is present in the "widget with mouse" queue. widgetIsPresentInQueue=False for i in self.mWidgetWithMouseQueue: if i==widget: widgetIsPresentInQueue=True break # Widget is not present, send an entered event and add #it to the "widget with mouse" queue. if widgetIsPresentInQueue == False and Widget.widgetExists(widget) == True: self.distributeMouseEvent(widget,MouseEvent.ENTERED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY(),True,True) self.mWidgetWithMouseQueue.insert(0,widget) swap = widget widget = parent parent = swap.getParent() if self.mFocusHandler.getDraggedWidget() != None: #self.distributeMouseEvent(widget,MouseEvent.DRAGGED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY(),True,True) self.distributeMouseEvent(self.mFocusHandler.getDraggedWidget(),MouseEvent.DRAGGED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY(),True,True) else: self.distributeMouseEvent(widget,MouseEvent.MOVED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY(),True,True) def handleMousePressed(self,mouseInput): sourceWidget=self.getMouseEventSource(mouseInput.getX(),mouseInput.getY()) if self.mFocusHandler.getDraggedWidget() != None: sourceWidget=self.mFocusHandler.getDraggedWidget() sourceWidgetX, sourceWidgetY=sourceWidget.getAbsolutePosition() if ( self.mFocusHandler.getModalFocused() != None and sourceWidget.isModalFocused() == True ) or self.mFocusHandler.getModalFocused() == None: sourceWidget.requestFocus() self.distributeMouseEvent(sourceWidget,MouseEvent.PRESSED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY()) self.mFocusHandler.setLastWidgetPressed(sourceWidget) self.mFocusHandler.setDraggedWidget(sourceWidget) self.mLastMouseDragButton=mouseInput.getButton() if self.mLastMousePressTimeStamp < 300 and self.mLastMousePressButton == mouseInput.getButton(): self.mClickCount+=1 else: self.mClickCount=1 self.mLastMousePressButton=mouseInput.getButton() currentTimeStamp=self.mLastMousePressTimeStamp self.mLastMousePressTimeStamp=mouseInput.getTimeStamp()-currentTimeStamp def handleMouseWheelMovedUp(self,mouseInput): sourceWidget=self.getMouseEventSource(mouseInput.getX(),mouseInput.getY()) if self.mFocusHandler.getDraggedWidget() != None: sourceWidget=self.mFocusHandler.getDraggedWidget() sourceWidgetX, sourceWidgetY=sourceWidget.getAbsolutePosition() self.distributeMouseEvent(sourceWidget,MouseEvent.WHEEL_MOVED_UP,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY()) def handleMouseWheelMovedDown(self,mouseInput): sourceWidget=self.getMouseEventSource(mouseInput.getX(),mouseInput.getY()) if self.mFocusHandler.getDraggedWidget() != None: sourceWidget=self.mFocusHandler.getDraggedWidget() sourceWidgetX, sourceWidgetY=sourceWidget.getAbsolutePosition() self.distributeMouseEvent(sourceWidget,MouseEvent.WHEEL_MOVED_DOWN,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY()) def handleMouseReleased(self,mouseInput): sourceWidget=self.getMouseEventSource(mouseInput.getX(),mouseInput.getY()) if self.mFocusHandler.getDraggedWidget() != None: if sourceWidget != self.mFocusHandler.getLastWidgetPressed(): self.mFocusHandler.setLastWidgetPressed(None) sourceWidget=self.mFocusHandler.getDraggedWidget() sourceWidgetX, sourceWidgetY=sourceWidget.getAbsolutePosition() self.distributeMouseEvent(sourceWidget,MouseEvent.RELEASED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY()) if mouseInput.getButton() == self.mLastMousePressButton and self.mFocusHandler.getLastWidgetPressed() == sourceWidget: self.distributeMouseEvent(sourceWidget,MouseEvent.CLICKED,mouseInput.getButton(),mouseInput.getX(),mouseInput.getY()) else: self.mLastMousePressButton=0 self.mClickCount=0 if self.mFocusHandler.getDraggedWidget() != None: self.mFocusHandler.setDraggedWidget(None) def getWidgetAt(self,x,y): #If the widget's parent has no child then we have found the widget.. parent=self.mTop child=self.mTop while child != None: swap = child parentX, parentY = parent.getAbsolutePosition() child = parent.getWidgetAt(x-parentX,y-parentY) parent=swap return parent def getMouseEventSource(self,x,y): widget=self.getWidgetAt(x,y) if self.mFocusHandler.getModalMouseInputFocused() != None and widget.isModalMouseInputFocused(): return self.mFocusHandler.getModalMouseInputFocused() else: return widget def getKeyEventSource(self): widget=self.mFocusHandler.getFocused() while widget.getInternalFocusHandler() != None and widget.getInternalFocusHandler().getFocused() != None: widget = widget.getInternalFocusHandler().getFocused() return widget def distributeMouseEvent(self,source,type,button,x,y,force=False,toSourceOnly=False): parent=source widget=source if self.mFocusHandler.getModalFocused() != None and widget.isModalFocused() == False and force == False: return None if self.mFocusHandler.getModalMouseInputFocused() != None and widget.isModalMouseInputFocused() == False and force == False: return None mouseEvent=MouseEvent(source,self.mShiftPressed,self.mControlPressed,self.mAltPressed,self.mMetaPressed,type,button,x,y,self.mClickCount) while parent != None: #If the widget has been removed due to input #cancel the distribution. if Widget.widgetExists(widget) == False: return None parent=widget.getParent() if widget.isEnabled() == True or force == True: widgetX, widgetY=widget.getAbsolutePosition() mouseEvent.mX=x-widgetX mouseEvent.mY=y-widgetY mouseListeners=widget.getMouseListeners() type=mouseEvent.getType() #Send the event to all mouse listeners of the widget. for i in mouseListeners: if type == MouseEvent.ENTERED: i().mouseEntered(mouseEvent) elif type == MouseEvent.DRAGGED: i().mouseDragged(mouseEvent) elif type == MouseEvent.EXITED: i().mouseExited(mouseEvent) elif type == MouseEvent.MOVED: i().mouseMoved(mouseEvent) elif type == MouseEvent.PRESSED: i().mousePressed(mouseEvent) elif type == MouseEvent.RELEASED: i().mouseReleased(mouseEvent) elif type == MouseEvent.WHEEL_MOVED_UP: i().mouseWheelMovedUp(mouseEvent) elif type == MouseEvent.WHEEL_MOVED_DOWN: i().mouseWheelMovedDown(mouseEvent) elif type == MouseEvent.CLICKED: i().mouseClicked(mouseEvent) else: raise GCN_EXCEPTION("Unknown mouse event type.") if toSourceOnly == True: break swap=widget widget=parent parent=swap.getParent() #If a non modal focused widget has been reached #and we have modal focus cancel the distribution. if self.mFocusHandler.getModalFocused() != None and widget.isModalFocused() == False: break #If a non modal mouse input focused widget has been reached #and we have modal mouse input focus cancel the distribution. if self.mFocusHandler.getModalMouseInputFocused() != None and widget.isModalMouseInputFocused() == False: break def distributeKeyEvent(self,keyEvent): parent=keyEvent.getSource() widget=keyEvent.getSource() if self.mFocusHandler.getModalFocused() != None and widget.isModalFocused() == False: return None if self.mFocusHandler.getModalMouseInputFocused() != None and widget.isModalMouseInputFocused() == False: return None while parent != None: #If the widget has been removed due to input #cancel the distribution. if Widget.widgetExists(widget) == False: break parent=widget.getParent() type=keyEvent.getType() if widget.isEnabled() == True: keyListeners=widget.getKeyListeners() for i in keyListeners: if type == KeyEvent.PRESSED: i().keyPressed(keyEvent) elif type == KeyEvent.RELEASED: i().keyReleased(keyEvent) else: raise GCN_EXCEPTION("Unknown key event type.") swap=widget widget=parent parent=swap.getParent() #If a non modal focused widget has been reached #and we have modal focus cancel the distribution. if self.mFocusHandler.getModalFocused() != None and widget.isModalFocused() == False: break def distributeKeyEventToGlobalListeners(self,keyEvent): type=keyEvent.getType() for i in self.mKeyListeners: if type == KeyEvent.PRESSED: i().keyPressed(keyEvent) elif type == KeyEvent.RELEASED: i().keyReleased(keyEvent) else: raise GCN_EXCEPTION("Unknown key event type.") if keyEvent.isConsumed() == True: break def handleModalFocus(self): #Check if modal focus has been gained by a widget. if ( self.mFocusHandler.getLastWidgetWithModalFocus() != self.mFocusHandler.getModalFocused() ) and ( self.mFocusHandler.getLastWidgetWithModalFocus() == None ): self.handleModalFocusGained() self.mFocusHandler.setLastWidgetWithModalFocus(self.mFocusHandler.getModalFocused()) #Check if modal focus has been released elif ( self.mFocusHandler.getLastWidgetWithModalFocus() != self.mFocusHandler.getModalFocused() ) and ( self.mFocusHandler.getLastWidgetWithModalFocus() != None ): self.handleModalFocusReleased() self.mFocusHandler.setLastWidgetWithModalFocus(None) def handleModalMouseInputFocus(self): #Check if modal focus has been gained by a widget. if ( self.mFocusHandler.getLastWidgetWithModalMouseInputFocus() != self.mFocusHandler.getModalMouseInputFocused() ) and ( self.mFocusHandler.getLastWidgetWithModalMouseInputFocus() == None ): self.handleModalFocusGained() self.mFocusHandler.setLastWidgetWithModalMouseInputFocus(self.mFocusHandler.getModalMouseInputFocused()) #Check if modal focus has been released elif ( self.mFocusHandler.getLastWidgetWithModalMouseInputFocus() != self.mFocusHandler.getModalMouseInputFocused() ) and ( self.mFocusHandler.getLastWidgetWithModalMouseInputFocus() != None ): self.handleModalFocusReleased() self.mFocusHandler.setLastWidgetWithModalMouseInputFocus(None) def handleModalFocusGained(self): # Distribute an event to all widgets in the "widget with mouse" queue. while len(self.mWidgetWithMouseQueue) > 0: widget=self.mWidgetWithMouseQueue[0] if Widget.widgetExists(widget) == True: self.distributeMouseEvent(widget,MouseEvent.EXITED,self.mLastMousePressButton,self.mLastMousePressX,self.mLastMousePressY,true,true) self.mWidgetWithMouseQueue.pop(0) self.mFocusHandler.setLastWidgetWithModalMouseInputFocus(self.mFocusHandler.getModalMouseInputFocused()) def handleModalFocusReleased(self): #Check all widgets below the mouse to see if they are #present in the "widget with mouse" queue. If a widget #is not then it should be added and an entered event should #be sent to it. widget=self.getEventSource(self.mLastMouseX,self.mLastMouseX) parent=widget while parent != None: parent=widget.getParent() #Check if the widget is present in the "widget with mouse" queue. widgetIsPresentInQueue = false for i in self.mWidgetWithMouseQueue: if i == widget: widgetIsPresentInQueue = true break #Widget is not present, send an entered event and add #it to the "widget with mouse" queue. if widgetIsPresentInQueue == False and Widget.widgetExists(widget) == True: self.distributeMouseEvent(widget,MouseEvent.ENTERED,self.mLastMousePressButtons,self.mLastMouseX,self.mLastMouseY,False,True) self.mWidgetWithMouseQueue.insert(0,widget) swap = widget widget = parent parent = swap.getParent()