class TextWindow: """ Encapsulates the drawing of a single line of text, with optional rounded corners and an optional "override width", which overides the default width (margins + text width). """ def __init__(self, height, position): """ Creates the underlying TransparentWindow and Cairo context. Position and height should be in pixels. """ # Use the maximum width that we can, i.e., the desktop width. width, _ = graphics.getDesktopSize() left, top = graphics.getDesktopOffset() xPos, yPos = position self.__window = TransparentWindow(xPos + left, yPos + top, width, height) self.__context = self.__window.makeCairoContext() def getHeight(self): """ LONGTERM TODO: Document this. """ return self.__window.getHeight() def draw(self, document): """ Draws the text described by document. An updating call; at the end of this method, the displayed window should reflect the drawn content. """ width = document.ragWidth + layout.L_MARGIN + layout.R_MARGIN height = self.__window.getMaxHeight() cr = self.__context # Clear the areas where the corners of the rounded rectangle will be. cr.save() cr.set_source_rgba(0, 0, 0, 0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.rectangle(width - rounded_rect.CORNER_RADIUS, height - rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS) cr.rectangle(width - rounded_rect.CORNER_RADIUS, 0, rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS) cr.paint() # Draw the background rounded rectangle. corners = [] if document.roundUpperRight: corners.append(rounded_rect.UPPER_RIGHT) if document.roundLowerRight: corners.append(rounded_rect.LOWER_RIGHT) cr.set_source_rgba(*document.background) rounded_rect.drawRoundedRect(context=cr, rect=(0, 0, width, height), softenedCorners=corners) cr.fill_preserve() cr.restore() # Next, draw the text. document.draw(layout.L_MARGIN, document.shrinkOffset, self.__context) width = min(self.__window.getMaxWidth(), width) height = min(self.__window.getMaxHeight(), height) self.__window.setSize(width, height) self.__window.update() def hide(self): """ Clears the window's surface (making it disappear). """ # LONGTERM TODO: Clearing the surface, i.e., painting it # clear, seems like a potential performance bottleneck. self.__window.setSize(1, 1) # Frankly, I don't know why this works, but after this # function, the resulting window is totally clear. I find it # odd, since the alpha value is not being set. It is a # wierdness of Cairo. -- Andrew self.__context.set_operator(cairo.OPERATOR_CLEAR) self.__context.paint() self.__context.set_operator(cairo.OPERATOR_OVER) self.__window.update()
class TextWindow: """ Encapsulates the drawing of a single line of text, with optional rounded corners and an optional "override width", which overides the default width (margins + text width). """ def __init__( self, height, position ): """ Creates the underlying TransparentWindow and Cairo context. Position and height should be in pixels. """ # Use the maximum width that we can, i.e., the desktop width. width, _ = graphics.getDesktopSize() left, top = graphics.getDesktopOffset() xPos, yPos = position self.__window = TransparentWindow(xPos + left, yPos, width, height ) self.__context = self.__window.makeCairoContext() def getHeight( self ): """ LONGTERM TODO: Document this. """ return self.__window.getHeight() def draw( self, document ): """ Draws the text described by document. An updating call; at the end of this method, the displayed window should reflect the drawn content. """ width = document.ragWidth + layout.L_MARGIN + layout.R_MARGIN height = self.__window.getMaxHeight() cr = self.__context # Clear the areas where the corners of the rounded rectangle will be. cr.save() cr.set_source_rgba( 0, 0, 0, 0 ) cr.set_operator( cairo.OPERATOR_SOURCE ) cr.rectangle( width - rounded_rect.CORNER_RADIUS, height - rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS ) cr.rectangle( width - rounded_rect.CORNER_RADIUS, 0, rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS ) cr.paint() # Draw the background rounded rectangle. corners = [] if document.roundUpperRight: corners.append( rounded_rect.UPPER_RIGHT ) if document.roundLowerRight: corners.append( rounded_rect.LOWER_RIGHT ) cr.set_source_rgba( *document.background ) rounded_rect.drawRoundedRect( context = cr, rect = ( 0, 0, width, height ), softenedCorners = corners ) cr.fill_preserve() cr.restore() # Next, draw the text. document.draw( layout.L_MARGIN, document.shrinkOffset, self.__context ) width = min( self.__window.getMaxWidth(), width ) height = min( self.__window.getMaxHeight(), height ) self.__window.setSize( width, height ) self.__window.update() def hide( self ): """ Clears the window's surface (making it disappear). """ # LONGTERM TODO: Clearing the surface, i.e., painting it # clear, seems like a potential performance bottleneck. self.__window.setSize( 1, 1 ) # Frankly, I don't know why this works, but after this # function, the resulting window is totally clear. I find it # odd, since the alpha value is not being set. It is a # wierdness of Cairo. -- Andrew self.__context.set_operator (cairo.OPERATOR_CLEAR) self.__context.paint () self.__context.set_operator (cairo.OPERATOR_OVER) self.__window.update()
class MessageWindow: """ A generic message window class, combining the TransparentWindow functionality with a Cairo context to create a usable message window class, with sizing, positioning, and drawing methods. """ def __init__(self, maxSize): """ Initialize the message window. """ self.__maxSize = maxSize self.__currSize = (1, 1) self.__currPos = (0, 0) self.__setupWindow() def __setupWindow(self): """ Creates the MessageWindow's underlying TransparentWindow and Cairo Context objects, once and for all. """ width = self.__maxSize[0] height = self.__maxSize[1] xPos = self.__currPos[0] yPos = self.__currPos[1] # The following are protected to allow subclasses access # to them. self._wind = TransparentWindow(xPos, yPos, width, height) self._context = self._wind.makeCairoContext() def getSize(self): return self.__currSize def getMaxSize(self): return self.__maxSize def getPos(self): return self.__currPos # LONGTERM TODO: Consider replacing setSize,setPos with setBox, and # establish a clipping function isOnScreen for use in the contract. def setSize(self, width, height): """ Sets the current size of the message window the width, height. Using the function appropriately vastly improves performance, as it reduces the visible size of the window and the number of pixels that must be copied on window updates. """ assert width <= self.getMaxSize()[0] assert height <= self.getMaxSize()[1] self.__currSize = width, height if self._wind != None: self._wind.setSize(width, height) def setPos(self, xPos, yPos): """ Sets the current position of the window to xPos, yPos, which should be in points. """ self.__currPos = xPos, yPos if self._wind != None: self._wind.setPosition(xPos, yPos) def hide(self): """ Sets the underlying TransparentWindow's size to (1,1) so that the window essentially vanishes. This effectively "hides" the window, causing it to cease interfering with performance of windows that are "underneath" the message window. """ # LONGTERM TODO: This method should eventually be # re-implmeneted or removed; merely setting the size of the # window to 1x1 pixels can still result in performance # degredation (see trac ticket #290). self._wind.setSize(1, 1) self._wind.update() def show(self): """ Sets the underlying TransparentWindow's size to the stored "current size" variable, essentially re-correlating the actual displayed rectangle on the screen to the size required by the MessageWindow's underlying content. """ self.setSize(*self.getSize()) self._wind.update() def clearWindow(self): """ "Clears" the underlying cairo context. """ # Works by blanking the whole surface. # The cairo paint() method does the whole (clipped) cairo # surface. cr = self._context cr.set_source_rgba(0, 0, 0, 0) cr.paint()
class MessageWindow(object): """ A generic message window class, combining the TransparentWindow functionality with a Cairo context to create a usable message window class, with sizing, positioning, and drawing methods. """ def __init__(self, maxSize): """ Initialize the message window. """ self.__maxSize = maxSize self.__currSize = (1, 1) self.__currPos = (0, 0) self._wind = None self._context = None # The TransparentWindow should not be instantiated here. # As the position/size is not yet known, TransparentWindow # is created with default position and size and that causes # ugly flickering on Linux when the window is really drawn later. # We should instead create TransparentWindow in lazy manner # shortly before it needs to be drawn. # self.__setupWindow() def __setupWindow(self): """ Creates the MessageWindow's underlying TransparentWindow and Cairo Context objects, once and for all. """ # Lazy initialization of TransparentWindow if self._wind is None: width = self.__maxSize[0] height = self.__maxSize[1] xPos = self.__currPos[0] yPos = self.__currPos[1] # The following are protected to allow subclasses access # to them. self._wind = TransparentWindow(xPos, yPos, width, height) self._context = self._wind.makeCairoContext() def getSize(self): return self.__currSize def getMaxSize(self): return self.__maxSize def getPos(self): return self.__currPos def _getContext(self): self.__setupWindow() return self._context # LONGTERM TODO: Consider replacing setSize,setPos with setBox, and # establish a clipping function isOnScreen for use in the contract. def setSize(self, width, height, refresh=True): """ Sets the current size of the message window the width, height. Using the function appropriately vastly improves performance, as it reduces the visible size of the window and the number of pixels that must be copied on window updates. """ assert width <= self.getMaxSize()[0],\ "Window width (%d) is larger than maximum window width (%d)"\ % (width, self.getMaxSize()[0]) assert height <= self.getMaxSize()[1],\ "Window height (%d) is larger than maximum window height (%d)"\ % (height, self.getMaxSize()[1]) self.__currSize = width, height if self._wind is not None and refresh: self._wind.setSize(width, height) def setPos(self, xPos, yPos): """ Sets the current position of the window to xPos, yPos, which should be in points. """ self.__currPos = xPos, yPos if self._wind is not None: self._wind.setPosition(xPos, yPos) def hide(self): """ Sets the underlying TransparentWindow's size to (1,1) so that the window essentially vanishes. This effectively "hides" the window, causing it to cease interfering with performance of windows that are "underneath" the message window. """ # LONGTERM TODO: This method should eventually be # re-implmeneted or removed; merely setting the size of the # window to 1x1 pixels can still result in performance # degredation (see trac ticket #290). self.__setupWindow() # This is prtobably only needed on Win32: #self._wind.setSize( 1, 1 ) self._wind.update() def show(self): """ Sets the underlying TransparentWindow's size to the stored "current size" variable, essentially re-correlating the actual displayed rectangle on the screen to the size required by the MessageWindow's underlying content. """ self.__setupWindow() width, height = self.getSize() self.setSize(width, height, False) self._wind.update() def clearWindow(self): """ "Clears" the underlying cairo context. """ # Works by blanking the whole surface. # The cairo paint() method does the whole (clipped) cairo # surface. self.__setupWindow() cr = self._context cr.set_source_rgba(0, 0, 0, 0) cr.set_operator( cairo.OPERATOR_SOURCE ) # IGNORE:E1101 @UndefinedVariable Keep PyLint and PyDev happy cr.paint()
class MessageWindow: """ A generic message window class, combining the TransparentWindow functionality with a Cairo context to create a usable message window class, with sizing, positioning, and drawing methods. """ def __init__( self, maxSize ): """ Initialize the message window. """ self.__maxSize = maxSize self.__currSize = ( 1, 1 ) self.__currPos = ( 0, 0 ) self.__setupWindow() def __setupWindow( self ): """ Creates the MessageWindow's underlying TransparentWindow and Cairo Context objects, once and for all. """ width = self.__maxSize[0] height = self.__maxSize[1] xPos = self.__currPos[0] yPos = self.__currPos[1] # The following are protected to allow subclasses access # to them. self._wind = TransparentWindow( xPos, yPos, width, height ) self._context = self._wind.makeCairoContext() def getSize( self ): return self.__currSize def getMaxSize( self ): return self.__maxSize def getPos( self ): return self.__currPos # LONGTERM TODO: Consider replacing setSize,setPos with setBox, and # establish a clipping function isOnScreen for use in the contract. def setSize( self, width, height ): """ Sets the current size of the message window the width, height. Using the function appropriately vastly improves performance, as it reduces the visible size of the window and the number of pixels that must be copied on window updates. """ assert width <= self.getMaxSize()[0] assert height <= self.getMaxSize()[1] self.__currSize = width, height if self._wind != None: self._wind.setSize( width, height ) def setPos( self, xPos, yPos ): """ Sets the current position of the window to xPos, yPos, which should be in points. """ assert xPos <= graphics.getDesktopSize()[0] assert yPos <= graphics.getDesktopSize()[1] self.__currPos = xPos, yPos if self._wind != None: self._wind.setPosition( xPos, yPos ) def hide( self ): """ Sets the underlying TransparentWindow's size to (1,1) so that the window essentially vanishes. This effectively "hides" the window, causing it to cease interfering with performance of windows that are "underneath" the message window. """ # LONGTERM TODO: This method should eventually be # re-implmeneted or removed; merely setting the size of the # window to 1x1 pixels can still result in performance # degredation (see trac ticket #290). self._wind.setSize( 1, 1 ) self._wind.update() def show( self ): """ Sets the underlying TransparentWindow's size to the stored "current size" variable, essentially re-correlating the actual displayed rectangle on the screen to the size required by the MessageWindow's underlying content. """ self.setSize( *self.getSize() ) self._wind.update() def clearWindow( self ): """ "Clears" the underlying cairo context. """ # Works by blanking the whole surface. # The cairo paint() method does the whole (clipped) cairo # surface. cr = self._context cr.set_source_rgba( 0, 0, 0, 0 ) cr.paint()
class ParameterSuggestionWindow(object): """ Encapsulates the drawing of a single line of text, with optional rounded corners and an optional "override width", which overides the default width (margins + text width). """ def __init__(self, height, position): """ Creates the underlying TransparentWindow and Cairo context. Position and height should be in pixels. """ # Use the maximum width that we can, i.e., the desktop width. desk_width, desk_height = graphics.getDesktopSize() desk_left, desk_top = graphics.getDesktopOffset() xPos, yPos = position if yPos + height > desk_height: pass self.__window = TransparentWindow( xPos + desk_left, yPos + desk_top, desk_width, desk_height - desk_top - yPos) self.__context = self.__window.makeCairoContext() self.__is_visible = False self.__animatingShow = False self.__animatingHide = False self.__timeSinceDismissal = 0 self.__evtManager = EventManager.get() def getHeight(self): """ LONGTERM TODO: Document this. """ return self.__window.getHeight() def getPosition(self): """ LONGTERM TODO: Document this. """ return Position(self.__window.getX(), self.__window.getY()) def setPosition(self, x, y): """ LONGTERM TODO: Document this. """ self.__window.setPosition(x, y) def draw(self, document, activeIndex): """ Draws the text described by document. An updating call; at the end of this method, the displayed window should reflect the drawn content. """ def _computeWidth(doc): lines = [] for b in doc.blocks: lines.extend(b.lines) if len(lines) == 0: return 0 return max([l.xMax for l in lines]) def _computeHeight(doc): height = 0 for b in doc.blocks: height += b.height # for line in b.lines: # height += line.lineHeight return height width = _computeWidth(document) + layout.L_MARGIN + layout.R_MARGIN width = max(width, 300) height = document.height # _computeHeight(document) cr = self.__context # Clear the areas where the corners of the rounded rectangle will be. cr.save() cr.set_source_rgba(0, 0, 0, 0) cr.set_operator(cairo.OPERATOR_SOURCE) # IGNORE:E1101 @UndefinedVariable cr.rectangle(width - rounded_rect.CORNER_RADIUS, height - rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS) cr.rectangle(width - rounded_rect.CORNER_RADIUS, 0, rounded_rect.CORNER_RADIUS, rounded_rect.CORNER_RADIUS) cr.paint() """ # Draw the background rounded rectangle. corners = [] #corners.append( rounded_rect.UPPER_LEFT ) #if document.roundUpperRight: corners.append( rounded_rect.UPPER_RIGHT ) #if document.roundLowerRight: corners.append( rounded_rect.LOWER_RIGHT ) #if document.roundLowerLeft: corners.append( rounded_rect.LOWER_LEFT ) """ corners = { rounded_rect.UPPER_RIGHT: None, rounded_rect.LOWER_RIGHT: 14, rounded_rect.LOWER_LEFT: None } document.background = xmltextlayout.colorHashToRgba( layout.MAIN_BACKGROUND_COLOR) cr.set_source_rgba(*document.background) rounded_rect.drawRoundedRect(context=cr, rect=(0, 0, width, height), softenedCorners=corners) cr.fill_preserve() cr.set_source_rgba(*xmltextlayout.colorHashToRgba("#404040")) cr.set_line_width(1.0) if activeIndex is not None: bar_left = layout.L_MARGIN - 2 bar_width = width - bar_left - layout.L_MARGIN + 2 bar_height = document.blocks[0].height bar_top = activeIndex * bar_height + document.marginTop rounded_rect.drawRoundedRect(context=cr, rect=( bar_left, bar_top, bar_width, bar_height), softenedCorners=rounded_rect.ALL_CORNERS, radius=2) cr.fill_preserve() # cr.stroke() cr.restore() # Next, draw the text. document.draw(layout.L_MARGIN, document.shrinkOffset, self.__context) width = min(self.__window.getMaxWidth(), width) # height = document.blocks[0].height * len(document.blocks) #layout.PARAMETERSUGGESTION_SCALE[-1]*layout.HEIGHT_FACTOR #height = min( self.__window.getMaxHeight(), height ) #self.__window.setSize( width, height ) if not self.__is_visible and not self.__animatingShow: self.__animatingShow = True self.__animatingHide = False self.__is_visible = True self.__timeSinceDismissal = 0 with suppress(AssertionError): self.__evtManager.registerResponder( self.animationTick, "timer") else: # Just refreshing started = time.time() self.__window.setOpacity(MAX_OPACITY) # print time.time() - started self.__window.update() # print time.time() - started def hide(self, animated=True): """ Clears the window's surface (making it disappear). """ if not self.__is_visible: return if self.__animatingHide or self.__animatingShow: self.__onAnimationFinished() return # LONGTERM TODO: Clearing the surface, i.e., painting it # clear, seems like a potential performance bottleneck. #self.__window.setSize( 1, 1 ) # Frankly, I don't know why this works, but after this # function, the resulting window is totally clear. I find it # odd, since the alpha value is not being set. It is a # wierdness of Cairo. -- Andrew #self.__context.set_operator (cairo.OPERATOR_CLEAR) #self.__context.paint () #self.__context.set_operator (cairo.OPERATOR_OVER) # self.__window.update() if animated: self.__timeSinceDismissal = 0 self.__animatingHide = True self.__animatingShow = False self.__evtManager.registerResponder(self.animationTick, "timer") else: self.__window.hide() self.__animatingHide = False self.__animatingShow = False def animationTick(self, msPassed): """ Called on a timer event to animate the window fadeout """ self.__timeSinceDismissal += msPassed if self.__timeSinceDismissal > ANIMATION_TIME: if self.__animatingShow and self.__is_visible: self.__onAnimationFinished() return timeLeft = ANIMATION_TIME - self.__timeSinceDismissal frac = timeLeft / float(ANIMATION_TIME) opacity = int(MAX_OPACITY * frac) if self.__animatingHide: self.__window.setOpacity(opacity) if opacity == 0: self.__is_visible = False elif self.__animatingShow: self.__is_visible = True self.__window.setOpacity(MAX_OPACITY - opacity) self.__window.update() def __onAnimationFinished(self): self.__evtManager.removeResponder(self.animationTick) if self.__animatingHide: self.__animatingHide = False self.__window.hide() self.__is_visible = False elif self.__animatingShow: self.__animatingShow = False