def draw_text(self, g, text, position, x, y, dx, dy, image=None): """ Draws a specified string within the specified graphics context using the specified *position* and theme information, and positioned within the region specified by (x, y, dx, dy ). It will also draw an optional image to the left of the text using the same alignment as the text. A *position* value of None is the same as TOP and LEFT. """ # Set the clipping bounds to the drawable interior region of the theme: x, y, dx, dy = g.clipping_bounds = self.bounds(x, y, dx, dy) # Calculate the size of the text (if any): tdx = tdy = 0 if text != "": lines = text.split("\n") sizes = [] ts = g.text_size for line in lines: if line.strip() == "": ldx, ldy = ts("|") else: ldx, ldy = ts(line) tdx = max(tdx, ldx) tdy += ldy sizes.append((ldx, ldy)) # Calculate the size of the image (if any): idx = idy = 0 if image is not None: idx = image.width + (4 * (tdx > 0)) idy = image.height # Make sure we have a valid position to use: if not isinstance(position, int): position = AlignmentMap.get(position, TOP_LEFT) # Use the alignment to calculate the 'x' coordinate to draw at: if (position & LEFT) != 0: tx = bx = x elif (position & RIGHT) != 0: bx = x + dx tx = bx - tdx - idx else: bx = x + (dx / 2) tx = bx - ((tdx + idx) / 2) # Use the alignment to calculate the 'y' coordinate to draw at: if (position & TOP) != 0: ty = iy = y elif (position & BOTTOM) != 0: ty = iy = y + dy ty -= tdy iy -= idy else: my = y + (dy / 2) + 1 ty = my - (tdy / 2) - 2 iy = my - (idy / 2) # Draw the image (if any): if idx > 0: g.draw_bitmap(image.bitmap, tx, iy) tx += idx # Draw the text (if any): if tdx > 0: g.text_color = self.content_color if len(lines) == 1: g.draw_text(lines[0], tx, ty) else: ey = y + dy for i, line in enumerate(lines): ldx, ldy = sizes[i] if (i > 0) and (ty + ldy) > ey: break if (position & RIGHT) != 0: tx = bx - ldx elif (position & LEFT) == 0: tx = bx - (ldx / 2) g.draw_text(line, tx, ty) ty += ldy # Reset the clipping bounds: g.clipping_bounds = None # Returns the size of the bounding box for the text and image drawn: return (tdx + idx, max(tdy, idy))
def draw_label(self, g, text, position, x, y, dx, dy, image=None): """ Draws a specified string within the specified graphics context using the specified *position* and theme information, and positioned within the region specified by (x, y, dx, dy ). It will also draw an optional image to the left of the text using the same alignment as the text. This is similar to the 'draw_text' method but will only draw a single line of text and draws into the label portion of the theme, if it has one. If no label area is defined by the theme, then nothing is drawn. Returns True if the label was drawn, and False otherwise. If *position* is None, the default label alignment for the theme is used. """ # Get the minimum height needed and exit immediately if there is not # enough room to draw the label: idx = idy = 0 if image is not None: idx = image.width + 4 idy = image.height g.font = self.label_font tdx, tdy = g.text_size(text) mdy = max(tdy, idy) + 4 slice = self.image_slice if (slice is None) or (mdy > max(slice.xtop, slice.xbottom)): return False label = self.label xtop = slice.xtop xbottom = slice.xbottom cl = x + slice.xleft + label.left cr = x + dx - slice.xright - label.right if ((tdy + label.top + label.bottom) <= xtop) and (xtop >= xbottom): by = y + (label.top + xtop - label.bottom) / 2 else: by = y + dy + ((label.top - xbottom - label.bottom) / 2) # Calculate the x coordinate for the specified alignment type: if position is None: position = AlignmentMap.get(self.alignment, CENTER) if (position & LEFT) != 0: tx = cl elif (position & RIGHT) != 0: tx = cr - tdx - idx else: tx = (cl + cr - tdx - idx) / 2 # Draw the (clipped) image and text string (note that we increase the # clipping bounds height a small amount because too tight a bounds can # cause clipping of text descenders: g.clipping_bounds = (cl, by - (mdy / 2), cr - cl, mdy + 2) if idx > 0: g.draw_bitmap(image.bitmap, tx, by - (idy / 2) + 1) tx += idx if tdx > 0: g.text_color = self.label_color g.draw_text(text, tx, by - (tdy / 2)) g.clipping_bounds = None return True
def draw ( self, g, x, y, dx, dy, visible = None ): """ Renders the text (and optional image) using the graphics context *g* within the bounds specified by *x*, *y*, *dx*, *dy*. If *visible* is not None, it should be a tuple containing the visible bounds of the drawing area in the form: (x, y, dx, dy). """ # If we have not yet analyzed the text, do so now: if self.info is None: self._analyze( g ) self.tags = tags = [] end_y = y + dy info = self.info low, high = 0, len( info ) if (visible is not None) and (high > 0): # If there is a visible bounds specified, find the range of visible # text fragments we have to render: _, vy, _, vdy = visible low = self._info_at( vy - y ) high = self._info_at( vy + vdy - y + info[0][ INFO_DY ] ) end_y = min( end_y, vy + vdy ) # Get everything ready to go: g.clipping_bounds = x, y, dx, dy text = self.full_text colors = self.colors alignment = AlignmentMap.get( self.alignment, TOP_LEFT ) # Draw the image (if any): image = self.image if image is not None: if alignment & TOP: iy = y elif alignment & BOTTOM: iy = y + dy - image.height else: iy = y + ((dy - image.height) / 2) g.draw_bitmap( image.bitmap, x, iy ) x += (image.width + 4) # Calculate the text starting y point based on the alignment: bdy = self.bounds[1] if alignment & BOTTOM: y += dy - bdy elif (alignment & TOP) == 0: y += (dy - bdy - 1) / 2 # Render all of the selected text fragments: for i in xrange( low, high ): start, end, fy, fdx, fdy, tdx, color_index, tag_index = info[ i ] # Get the text y coordinate and exit if we are past the end of the # region being drawn into: ty = y + fy if ty >= end_y: break # Check for the start of a new line: if tdx >= 0: cdx = tdx cx = 0 # Calculate the x coordinate based on the alignment of the text: if alignment & LEFT: tx = x + cx elif alignment & RIGHT: tx = x + dx - cdx + cx else: tx = x + cx + ((dx - cdx) / 2) # Set the correct text color (if necessary), then draw the fragment: if color_index is not None: g.text_color = colors[ color_index ] g.draw_text( text[ start: end ], tx, ty ) # Create the 'tags' table entry (if necessary): if tag_index is not None: if tag_index >= 0: tags.append( ( tag_index, tx, ty, tx + fdx, ty + fdy ) ) # Draw an underline to identify it is a tag: g.opacity = 0.38 y0 = ty + fdy - 1 g.draw_line( tx, y0, tx + fdx - 1, y0 ) g.opacity = 1.0 else: # Handle the case of a 'separator': y0 = ty + (fdy / 2) + 1 g.draw_line( x, y0, x + dx - 1, y0 ) # Advance to the next text fragment on this line: cx += fdx # Reset the clipping bounds: g.clipping_bounds = None