def draw(self, cr: cairo.Context) -> None: if self._extents is None: return extents = self._extents stroke_color = self._stroke_color stroke_width = self._stroke_width cr.rectangle(extents.x, extents.y, extents.w, extents.h) dx = 1 / cr.get_matrix().xx dy = 1 / cr.get_matrix().yy cr.save() if self._scale_strokes: stroke_scale = max(dx, dy) cr.identity_matrix() else: stroke_scale = 1.0 cr.set_line_width(stroke_width) cr.set_source_rgba(*stroke_color) cr.stroke() cr.restore() self._last_drawn_region = rectangle_stroke_region( extents, max(stroke_width * stroke_scale, dx, dy)) self._last_drawn_stroke_scale = stroke_scale
def ellipse(ctx: cairo.Context, cell_structure: mat.CellStructure, r: float = 2) -> None: """ Draw an ellipse in the given context. Drawing is centered relative to cell structure, and semi-major is aligned with vertical coordinate axis. :param ctx: Current context. :param cell_structure: Assumptions about structure of the cell being drawn. :param r: Semi-major over semi-minor, must be > 2. """ if not 2 <= r: raise ValueError() width, height = _get_dims(cell_structure) ctx.save() ctx.translate(cell_structure.width / 2., cell_structure.height / 2.) ctx.scale(width / (2 * r), height / 2) ctx.new_sub_path() ctx.arc(0., 0., 1., 0., 2 * math.pi) ctx.restore()
def render_picture(ctx: cairo.Context, picture: Picture) -> None: """ Render a picture at (0, 0) onto the supplied context (which should use mm units). """ ctx.save() # Load the picture image_surface = cairo.ImageSurface.create_for_data( picture.get_image_bytes(), cairo.FORMAT_ARGB32, picture.image_width, picture.image_height, ) # Scale and translate the picture according to the scale/crop mode in use. # # NB: Pattern matrix maps from page space to pixel space, hence the # apparently inverted transformation described here. ctx.set_source_surface(image_surface) pattern = ctx.get_source() m = pattern.get_matrix() m.scale(1 / picture.scale, 1 / picture.scale) m.translate(-picture.x_offset, -picture.y_offset) pattern.set_matrix(m) # Draw the picture (clipped) ctx.rectangle(0, 0, picture.width, picture.height) ctx.fill() ctx.restore()
def cairo_paint_from_source(self, set_source_fn, source, x: int, y: int, iw: int, ih: int, width: int, height: int, options): """ must be called from UI thread """ backing = self._backing log("cairo_paint_surface%s backing=%s, paint box line width=%i", (set_source_fn, source, x, y, iw, ih, width, height, options), backing, self.paint_box_line_width) if not backing: return gc = Context(backing) if self.paint_box_line_width: gc.save() gc.rectangle(x, y, width, height) gc.clip() gc.set_operator(OPERATOR_CLEAR) gc.rectangle(x, y, width, height) gc.fill() gc.set_operator(OPERATOR_SOURCE) gc.translate(x, y) if iw != width or ih != height: gc.scale(width / iw, height / ih) gc.rectangle(0, 0, width, height) set_source_fn(gc, source, 0, 0) gc.paint() if self.paint_box_line_width: gc.restore() encoding = options.get("encoding") self.cairo_paint_box(gc, encoding, x, y, width, height)
def _highlight_border(self, context: cairo.Context, row: int, col: int): width = self._total_width height = self._total_height line_width = 3 row_rectangles = [ Rectangle(Point(1, row * self.cell_height - line_width / 2), width - 2, line_width), Rectangle(Point(1, (row + 1) * self.cell_height - line_width / 2), width - 2, line_width) ] col_rectangles = [ Rectangle(Point(col * self.cell_width - line_width / 2, 1), line_width, height - 2), Rectangle(Point((col + 1) * self.cell_width - line_width / 2, 1), line_width, height - 2) ] context.save() r, g, b = self.highlight_color context.set_source_rgba(r, g, b, .6) for row_rectangle in row_rectangles: context.rectangle(row_rectangle.start.x, row_rectangle.start.y, row_rectangle.width, row_rectangle.height) context.fill() for col_rectangle in col_rectangles: context.rectangle(col_rectangle.start.x, col_rectangle.start.y, col_rectangle.width, col_rectangle.height) context.fill() context.restore()
def draw(self, cr: cairo.Context) -> None: line = self._line stroke_color = self._stroke_color stroke_width = self._stroke_width scale_strokes = self._scale_strokes if line is None: return if line.pt0 == line.pt1: return clip_extents = Rect2(cr.clip_extents()) start = line.eval(x=clip_extents.x0) end = line.eval(x=clip_extents.x1) if not clip_extents.contains(start): start = line.eval(y=clip_extents.y0 if start.y < clip_extents.y0 else clip_extents.y1) if not clip_extents.contains(end): end = line.eval(y=clip_extents. y0 if end.y < clip_extents.y0 else clip_extents.y1) cr.move_to(*start) cr.line_to(*end) cr.save() if scale_strokes: cr.identity_matrix() cr.set_source_rgb(*stroke_color) cr.set_line_width(stroke_width) cr.stroke() cr.restore()
def do_render(self, model: Dazzle.GraphModel, x_begin: int, x_end: int, y_begin: float, y_end: float, cairo_context: cairo.Context, area: cairo.RectangleInt) -> None: model_iter = Dazzle.GraphModelIter() cairo_context.save() if model.get_iter_first(model_iter): chunk = area.width / (model.props.max_samples - 1) / 2.0 last_x = self._calc_x(model_iter, x_begin, x_end, area.width) last_y = float(area.height) cairo_context.move_to(last_x, area.height) while Dazzle.GraphModel.iter_next(model_iter): x = self._calc_x(model_iter, x_begin, x_end, area.width) y = self._calc_y(model_iter, y_begin, y_end, area.height, self._column) cairo_context.curve_to(last_x + chunk, last_y, last_x + chunk, y, x, y) last_x = x last_y = y cairo_context.set_line_width(self._line_width) cairo_context.set_source_rgba(self._stacked_color_rgba.red, self._stacked_color_rgba.green, self._stacked_color_rgba.blue, self._stacked_color_rgba.alpha) cairo_context.rel_line_to(0, area.height) cairo_context.stroke_preserve() cairo_context.close_path() cairo_context.fill() if model.get_iter_first(model_iter): chunk = area.width / (model.props.max_samples - 1) / 2.0 last_x = self._calc_x(model_iter, x_begin, x_end, area.width) last_y = float(area.height) cairo_context.move_to(last_x, last_y) while Dazzle.GraphModel.iter_next(model_iter): x = self._calc_x(model_iter, x_begin, x_end, area.width) y = self._calc_y(model_iter, y_begin, y_end, area.height, self._column) cairo_context.curve_to(last_x + chunk, last_y, last_x + chunk, y, x, y) last_x = x last_y = y cairo_context.set_source_rgba(self._stroke_color_rgba.red, self._stroke_color_rgba.green, self._stroke_color_rgba.blue, self._stacked_color_rgba.alpha) cairo_context.stroke() cairo_context.restore()
def draw_trains(self, layout: Layout, cr: Context): for train in layout.trains.values(): car_start = train.position annotation = train.meta.get("annotation") for i, car in enumerate(train.cars): front_bogey_offset, rear_bogey_offset = car.bogey_offsets bogey_spacing = rear_bogey_offset - front_bogey_offset front_bogey_position = car_start - front_bogey_offset front_bogey_xy = self.transform_track_point(front_bogey_position) rear_bogey_position, rear_bogey_xy = self.point_back( front_bogey_position, bogey_spacing ) cr.save() cr.translate(front_bogey_xy[0], front_bogey_xy[1]) cr.rotate( math.pi + math.atan2( front_bogey_xy[1] - rear_bogey_xy[1], front_bogey_xy[0] - rear_bogey_xy[0], ) ) cr.set_source_rgb(*hex_to_rgb(train.meta.get("color", "#a0a0ff"))) if i == 0 and annotation: cr.move_to(0, -10) cr.set_font_size(5) cr.show_text(annotation) cr.set_line_width(4) cr.move_to(-front_bogey_offset, 0) cr.line_to(car.length - front_bogey_offset, 0) cr.stroke() cr.set_line_width(6) cr.move_to(1 - front_bogey_offset, 0) cr.line_to(car.length - front_bogey_offset - 1, 0) cr.stroke() if i == 0 and train.lights_on: cr.set_source_rgba(1, 1, 0.2, 0.5) for y in (-2.5, 2.5): cr.move_to(-front_bogey_offset - 1, y) cr.arc( -front_bogey_offset - 1, y, 10, 6 / 7 * math.pi, math.pi * 8 / 7, ) cr.close_path() cr.fill() cr.restore() car_start = rear_bogey_position - (car.length - rear_bogey_offset + 1)
def draw(self, cr: cairo.Context) -> None: cr.transform(self._transform) for artist in self._children.iter(z_ordered=True): cr.save() artist.draw(cr) cr.restore() self._last_draw_transform = self._transform
def draw_poly(poly: RegularPolygon, ctx: cairo.Context): ctx.save() v = poly.vertices() ctx.move_to(v[0][0], v[0][1]) for i in range(1, len(v)): ctx.line_to(v[i][0], v[i][1]) ctx.close_path() ctx.stroke() ctx.restore()
def draw_icon(self, context: cairo.Context, icon: str, position: Tuple[int, int]): image = cairo.ImageSurface.create_from_png( os.path.join(os.path.dirname(__file__), "icons-7", f"{icon}.png") ) context.save() context.translate(*position) context.set_source_surface(image) context.paint() context.restore()
def on_draw(self, widget: Widget, context: cairo.Context): context.save() self.shape.draw_on_context(context) context.set_source_rgb(1, 1, 1) context.fill_preserve() context.set_source_rgb(0, 0, 0) context.stroke() context.restore() super().on_draw(widget, context)
def on_draw(self, widget, cr: cairo.Context) -> bool: rect = self.area.get_allocation() Gtk.render_background(self.area.get_style_context(), cr, 0, 0, rect.width, rect.height) cr.save() self._draw_graph(cr, rect) cr.restore() self.drag_action.draw(cr) return False
def on_draw(self, widget: Widget, context: cairo.Context): for child in self.list: if child.visible: context.save() context.transform(child.fromWidgetCoords) if child.is_clip_set(): rectangle = child.clip_rectangle context.rectangle(rectangle.start.x, rectangle.start.y, rectangle.width, rectangle.height) context.clip() child.on_draw(self, context) context.restore()
def on_draw(self, widget: Widget, context: cairo.Context): for child in self.list: if child.visible: context.save() context.transform(child.fromWidgetCoords) if child.is_clip_set(): rectangle = child.clip_rectangle context.rectangle(rectangle.start.x,rectangle.start.y, rectangle.width,rectangle.height) context.clip() child.on_draw(self,context) context.restore()
def on_draw(self, widget: Widget, context: cairo.Context): context.save() context.set_source_rgb(*self.background_color) self.shape.draw_on_context(context) context.fill_preserve() context.set_source_rgb(0,0,0) context.set_line_width(1) context.stroke() context.restore() super().on_draw(widget, context)
def on_draw(self, widget: Widget, context: cairo.Context): context.save() context.set_source_rgb(*self.background_color) self.shape.draw_on_context(context) context.fill_preserve() context.set_source_rgb(0, 0, 0) context.set_line_width(1) context.stroke() context.restore() super().on_draw(widget, context)
def draw_piece(self, piece: Piece, cr: Context, drawing_options: DrawingOptions): if not piece.position: return cr.save() cr.translate(piece.position.x, piece.position.y) cr.rotate(piece.position.angle) piece.draw(cr, drawing_options) relative_positions = piece.relative_positions() for anchor_name, anchor in piece.anchors.items(): # if anchor.position != piece.position + relative_positions[anchor_name] + Position(0, 0, math.pi): # cr.move_to(0, 0) # cr.line_to(anchor.position.x, anchor.position.y) # cr.stroke() cr.save() cr.translate( relative_positions[anchor_name].x, relative_positions[anchor_name].y ) cr.rotate(relative_positions[anchor_name].angle) if len(anchor) == 2: cr.set_source_rgb(1, 0.5, 0.5) else: cr.set_source_rgb(0.5, 1, 0.5) next_piece, next_anchor_name = anchor.next(piece) cr.arc( 0, 0, 3 if (piece.placement and anchor_name == piece.anchor_names[0]) or ( next_piece and next_piece.placement and next_anchor_name == next_piece.anchor_names[0] ) else 1, 0, math.tau, ) cr.fill() cr.restore() cr.restore()
def on_draw(self, widget: Widget, context: cairo.Context): for b in self._buttons: b.set_shape_from_context(context) shapes = [b.shape for b in self._buttons] context.save() context.select_font_face("", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) xb, yb, w, h, xa, ya = context.text_extents(self.title) width = max(shape.width for shape in shapes) width = max(width, xa) container_width = self.container_size[0] translation = Point(0, self.distance) if container_width > width: translation += Point((container_width)/2, 0) else: translation += Point(width/2, 0) context.move_to(translation.x - xa/2, h + 2 * self.distance) context.show_text(self.title) context.restore() height = h + self.distance * 3 for b in self._buttons: height += b.shape.height + self.distance self.min_size = width + 2 * self.distance, height + self.distance start_point = context.get_current_point() translation += Point(0, h + self.distance * 3) context.translate(translation.x, translation.y) distance_offset = Point(0, self.distance) for b in self._buttons: context.move_to(*start_point) b.set_translate(translation.x, translation.y) context.save() b.on_draw(widget, context) context.restore() to_translate = Point(distance_offset.x, distance_offset.y + b.shape.height) context.translate(to_translate.x, to_translate.y) translation += to_translate
def on_draw(self, widget: Widget, context: cairo.Context): self.guide_line.set_shape_from_context(context) shape = self.guide_line.shape self.guide_line.set_translate(shape.width + 10, shape.height + 10) context.save() context.set_source_rgb(1, 1, 1) if self.guide_line.orientation == Orientation.HORIZONTAL: context.rectangle(10, shape.height + 10, shape.width, 20) else: context.rectangle(shape.width + 10, 10, 20, shape.height) context.fill() context.restore() super().on_draw(widget, context)
def on_draw(self, widget: Widget, context: cairo.Context): for b in self._buttons: b.set_shape_from_context(context) shapes = [b.shape for b in self._buttons] context.save() context.select_font_face("", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) xb, yb, w, h, xa, ya = context.text_extents(self.title) width = max(shape.width for shape in shapes) width = max(width, xa) container_width = self.container_size[0] translation = Point(0, self.distance) if container_width > width: translation += Point((container_width) / 2, 0) else: translation += Point(width / 2, 0) context.move_to(translation.x - xa / 2, h + 2 * self.distance) context.show_text(self.title) context.restore() height = h + self.distance * 3 for b in self._buttons: height += b.shape.height + self.distance self.min_size = width + 2 * self.distance, height + self.distance start_point = context.get_current_point() translation += Point(0, h + self.distance * 3) context.translate(translation.x, translation.y) distance_offset = Point(0, self.distance) for b in self._buttons: context.move_to(*start_point) b.set_translate(translation.x, translation.y) context.save() b.on_draw(widget, context) context.restore() to_translate = Point(distance_offset.x, distance_offset.y + b.shape.height) context.translate(to_translate.x, to_translate.y) translation += to_translate
def layout(self, context: cairo.Context): if not self.is_shape_set: context.save() context.set_font_size(self.font_size) generator = (context.text_extents(chr(letter) * 10) for letter in range(ord('A'), ord('Z') + 1)) context.restore() sizes = [(xa, h) for xb, yb, w, h, xa, ya in generator] max_height = 0 for w, h in sizes: max_height = max(h, max_height) width = self.width height = self.padding * 3 + max_height self.shape = DrawableRectangle(Point(0, 0), width, height)
def draw_sensor( self, sensor: Sensor, layout: Layout, cr: Context, drawing_options: DrawingOptions = None, ): if not sensor.position: return cr.save() cr.translate(sensor.position.x, sensor.position.y) cr.rotate(sensor.position.angle) sensor.draw(cr, drawing_options or self.drawing_options) cr.restore()
def layout(self, context: cairo.Context): context.save() context.set_font_size(self.font_size) generator = (context.text_extents(str(digit) * self.digits) for digit in range(10)) sizes = [(xa, h) for xb, yb, w, h, xa, ya in generator] max_width = 0 max_height = 0 for w, h in sizes: max_width = max(w, max_width) max_height = max(h, max_height) width = self.padding * 2 + max_width height = self.padding * 2 + max_height self.shape = DrawableRectangle(Point(0, 0), width, height) context.restore()
class MapSurface(object): """wrapper to render the map to svg/png""" def __init__(self, hexmap=None, filename=None, width=None, height=None, size=None): self.hexmap = hexmap if self.hexmap is None: raise ValueError("No map was passed to {}".format(self.__class__.__name__)) self.surface_name = filename or "test.svg" self.size = size or 32.0 self.surface_width = width if self.surface_width is None: self.surface_width = (self.hexmap.map.cols + .5) * self.size * SQRT3 self.surface_height = height if self.surface_height is None: self.surface_height = (self.hexmap.map.rows * 1.5 + .25) * self.size self.layer = [] # build base map self.surface = SVGSurface(self.surface_name + ".svg", self.surface_width, self.surface_height) self.context = Context(self.surface) # background: magenta self.context.save() self.context.set_source_rgb(1.0, 0.0, 1.0) self.context.paint() self.context.restore() def add_layer(self, renderer_cls, position=None): if not position: self.layer.append(renderer_cls(self)) else: self.layer.insert(position, renderer_cls(self)) def render(self): print "Rendering {} ({}x{})".format(self.surface_name, self.surface_width, self.surface_height) for renderer in self.layer: renderer.render() def finalise(self, with_png=False): print "finalising:" if with_png is True: print "PNG" self.surface.write_to_png(self.surface_name + ".png") print "SVG" self.surface.finish() print "DONE!"
def _highlight_border(self, context: cairo.Context, row: int, col: int): width = self._total_width height = self._total_height line_width = 3 row_rectangles = [ Rectangle( Point(1, row * self.cell_height - line_width / 2), width - 2, line_width ), Rectangle( Point(1, (row + 1) * self.cell_height - line_width / 2), width - 2, line_width ) ] col_rectangles = [ Rectangle( Point(col * self.cell_width - line_width / 2, 1), line_width, height - 2 ), Rectangle( Point((col + 1) * self.cell_width - line_width / 2, 1), line_width, height - 2 ) ] context.save() r, g, b = self.highlight_color context.set_source_rgba(r, g, b, .6) for row_rectangle in row_rectangles: context.rectangle(row_rectangle.start.x, row_rectangle.start.y, row_rectangle.width, row_rectangle.height) context.fill() for col_rectangle in col_rectangles: context.rectangle(col_rectangle.start.x, col_rectangle.start.y, col_rectangle.width, col_rectangle.height) context.fill() context.restore()
def draw(self, cr: cairo.Context, drawing_options: DrawingOptions): if self.direction == CurveDirection.left: cy = -self.radius angle1, angle2 = math.pi / 2 - math.tau / self.per_circle, math.pi / 2 else: cy = self.radius angle1, angle2 = -math.pi / 2, math.tau / self.per_circle - math.pi / 2 cr.save() cr.set_source_rgb(0.9, 0.9, 0.9) cr.move_to(0, cy) cr.arc(0, cy, self.radius + 5, angle1, angle2) cr.line_to(0, cy) cr.clip() for i in range(0, self.sleepers + 1): angle = (math.tau / self.per_circle) * (i / self.sleepers) if self.direction == CurveDirection.left: angle = -math.pi / 2 - angle else: angle = angle + math.pi / 2 cr.move_to( -math.cos(angle) * (self.radius - 4), cy - math.sin(angle) * (self.radius - 4), ) cr.line_to( -math.cos(angle) * (self.radius + 4), cy - math.sin(angle) * (self.radius + 4), ) cr.set_line_width(2) cr.set_source_rgb(*drawing_options.sleeper_color) cr.stroke() cr.set_line_width(1) cr.set_source_rgb(*drawing_options.rail_color) cr.arc(0, cy, self.radius - 2.5, angle1, angle2) cr.stroke() cr.arc(0, cy, self.radius + 2.5, angle1, angle2) cr.stroke() cr.restore()
def draw(self, cr: cairo.Context) -> None: polyline = self._polyline stroke_width = self._stroke_width stroke_color = self._stroke_color if polyline is None or len(polyline) == 0: self._last_drawn_region = None return if self._path_cache is not None: cr.append_path(self._path_cache) else: self._show_polyline(cr, polyline) self._path_cache = cr.copy_path() extents = Rect2(cr.path_extents()) dx = 1 / cr.get_matrix().xx dy = 1 / cr.get_matrix().yy cr.save() if self._scale_strokes: stroke_scale = max(dx, dy) cr.identity_matrix() else: stroke_scale = 1.0 cr.set_line_width(stroke_width) cr.set_source_rgba(*stroke_color) cr.stroke() cr.restore() extents = expand_rect(extents, max(stroke_width * stroke_scale, dx, dy)) self._last_drawn_region = cairo.Region( cairo.RectangleInt( int(math.floor(extents.x)), int(math.floor(extents.y)), int(math.ceil(extents.w)), int(math.ceil(extents.h)), ))
def draw_points_labels(self, layout: Layout, cr: Context): for i, piece in enumerate(layout.points): if not piece.position: continue cr.save() cr.set_font_size(4) cr.translate( *piece.position.as_matrix().transform_point( 4, -10 if piece.direction == "left" else 10 ) ) cr.rectangle(-4, -4, 8, 8) cr.set_source_rgb(1, 1, 1) cr.fill_preserve() cr.set_source_rgb(0, 0, 0) cr.set_line_width(1) cr.stroke() cr.move_to(-2, 2) cr.show_text(str(i)) cr.restore()
def layout(self, context: cairo.Context): super().layout(context) context.save() self.__plus_button.layout(context) context.restore() self.__minus_button.min_height = self.__plus_button.shape.height context.save() self.__minus_button.layout(context) context.restore() plus_shape = self.__plus_button.shape minus_shape = self.__minus_button.shape self.__minus_button.set_translate(self.padding, self.padding/2) self.__plus_button.set_translate( self.padding + minus_shape.width + self.padding, self.padding/2 ) self.shape = DrawableRectangle( Point(0, 0), plus_shape.width + minus_shape.width + 3 * self.padding, self.padding + max(plus_shape.height, minus_shape.height) )
def do_draw(self, cr: cairo.Context) -> None: cr.save() self._canvas_artist.draw(cr) cr.restore() cr.save() self._floating_artist.draw(cr) cr.restore() cr.save() self._widget_artist.draw(cr) cr.restore() if self.props.has_focus: Gtk.render_focus( self.get_style_context(), cr, x=0, y=0, width=self.get_allocated_width(), height=self.get_allocated_height(), )
i += 1 elif (CODES[i] == CURVE3): ctx.curve_to(VERTS[i][0],VERTS[i][1], VERTS[i+1][0],VERTS[i+1][1], # undocumented VERTS[i+1][0],VERTS[i+1][1]) i += 2 elif (CODES[i] == CURVE4): ctx.curve_to(VERTS[i][0],VERTS[i][1], VERTS[i+1][0],VERTS[i+1][1], VERTS[i+2][0],VERTS[i+2][1]) i += 3 ctx.fill_preserve() ctx.set_source_rgb(0,0,0) ctx.set_line_width(6) ctx.stroke() ctx.restore() scale2 = (height_s - 2.0 * MARGIN)/rows ctx.set_source_surface(Z, 0, 0) pattern = ctx.get_source() SurfacePattern.set_filter(pattern, FILTER_BEST) scalematrix = Matrix() scalematrix.scale(1.0/scale2, 1.0/scale2) scalematrix.translate(-( width_s/2.0 - width *scale2 /2.0 ), -MARGIN) pattern.set_matrix(scalematrix) ctx.set_source_rgba (0, 0, 0, 0.7) ctx.mask(pattern) ctx.fill()
class Canvas: def __init__(self, width: int, height: Optional[int] = None, *, normalise: bool = True): if height is None: height = width self._width = width self._height = height self._surface = ImageSurface(FORMAT_ARGB32, width, height) self._context = Context(self._surface) self._normalise = normalise if self._normalise: self.scale(self._width, self._height) @property def width(self) -> int: return self._width if not self._normalise else 1 @property def height(self) -> int: return self._height if not self._normalise else 1 # TODO depreciate @property def context(self) -> Context: # pragma: no cover return self._context def save(self) -> None: self._context.save() def restore(self) -> None: self._context.restore() # Transformation def rotate(self, angle: float) -> None: self._context.rotate(angle) def translate(self, x: float, y: float) -> None: self._context.translate(x, y) def scale(self, width: int, height: int) -> None: self._context.scale(width, height) def set_line_width(self, width: float) -> None: self._context.set_line_width(width) # Colour functionality def set_colour(self, colour: Colour) -> None: self._context.set_source_rgba(colour.red, colour.blue, colour.green, colour.alpha) def set_grey(self, colour_value: float, alpha: float = 1) -> None: colour = Colour(*(colour_value, ) * 3, alpha) self.set_colour(colour) def set_black(self) -> None: self.set_colour(BLACK) def set_white(self) -> None: self.set_colour(WHITE) def set_background(self, colour: Colour) -> None: self._context.rectangle(0, 0, self.width, self.height) self.set_colour(colour) self._context.fill() def set_line_cap(self, line_cap: LineCap) -> None: self._context.set_line_cap(line_cap.value) def set_line_join(self, line_join: LineJoin) -> None: self._context.set_line_join(line_join.value) def set_fill_rule(self, file_rule: FillRule) -> None: self._context.set_fill_rule(file_rule.value) # Render methods def fill(self, preserve: bool = False) -> None: if not preserve: self._context.fill() else: self._context.fill_preserve() def stroke(self, preserve: bool = False) -> None: if not preserve: self._context.stroke() else: self._context.stroke_preserve() def clip(self) -> None: self._context.clip() def _draw_path(self, path: Iterable[Point], close_path: bool) -> None: self._context.new_sub_path() for p in path: self._context.line_to(*p) if close_path: self._context.close_path() def draw_path(self, path: Iterable[PointType], close_path: bool = False) -> None: points = (p if isinstance(p, Point) else Point(*p) for p in path) self._draw_path(points, close_path) def draw_polygon(self, polygon: Polygon) -> None: self._draw_path(polygon.points, close_path=True) def draw_circle(self, circle: Circle, fill: bool = False, stroke: bool = True) -> None: self._context.new_sub_path() self._context.arc(*circle.centre, circle.radius, 0, 2 * pi) def write_to_png(self, file_name: str) -> None: self._surface.write_to_png(file_name)
def cairo_saved(cr: cairo.Context) -> Generator[None, Any, None]: cr.save() try: yield finally: cr.restore()
def draw(self, cr: cairo.Context) -> None: start_angle = self._start_angle delta_angle = self._delta_angle clockwise = self._clockwise arc_radius = self._arc_radius start_line_radius = self._start_line_radius end_line_radius = self._end_line_radius x = self._x y = self._y stroke_color = self._stroke_color stroke_width = self._stroke_width text_radius = self._text_radius font_size = self._font_size text_color = self._text_color scale_radii = self._scale_radii scale_text = self._scale_text scale_strokes = self._scale_strokes if not (math.isfinite(start_angle) and math.isfinite(delta_angle)): return end_angle = start_angle + delta_angle matrix = cr.get_matrix() if scale_radii: radius_scale = 1/(0.5 * (matrix.xx + matrix.yy)) else: radius_scale = 1.0 self._show_hand(cr, x, y, -start_angle, radius_scale*start_line_radius) self._show_hand(cr, x, y, -end_angle, radius_scale*end_line_radius) if clockwise: cr.arc(x, y, radius_scale*arc_radius, -start_angle, -end_angle) else: cr.arc_negative(x, y, radius_scale*arc_radius, -start_angle, -end_angle) cr.save() if scale_strokes: cr.identity_matrix() cr.set_source_rgba(*stroke_color) cr.set_line_width(stroke_width) cr.stroke() cr.restore() half_angle = (start_angle + end_angle) / 2 cr.move_to(x, y) cr.rel_move_to( radius_scale*text_radius * math.cos(half_angle), radius_scale*text_radius * -math.sin(half_angle), ) cr.save() cr.set_source_rgba(*text_color) cr.set_font_size(font_size) if scale_text: cr.identity_matrix() text = '{:.1f}°'.format(math.degrees(math.fabs(delta_angle))) text_extents = cr.text_extents(text) cr.rel_move_to(-text_extents.x_bearing, -text_extents.y_bearing) cr.rel_move_to(-text_extents.width/2, -text_extents.height/2) cr.show_text(text) cr.fill() cr.restore()
def layout(self, context: cairo.Context): for child in self.list: if child.visible: context.save() child.layout(context) context.restore()
def draw(self, cr: cairo.Context, drawing_options: DrawingOptions): cr.set_source_rgb(*drawing_options.sleeper_color) cr.set_line_width(2) # Main sleepers cr.save() cr.move_to(0, 0) cr.line_to(25, 4 * self.coordinate_sign) cr.line_to(32, 4 * self.coordinate_sign) cr.line_to(32, -4 * self.coordinate_sign) cr.line_to(0, -4 * self.coordinate_sign) cr.close_path() cr.clip() for i in range(0, 36, 4): cr.move_to(i, -4) cr.line_to(i, 4) cr.stroke() cr.restore() # Branch sleepers cr.save() cr.move_to(0, 0) cr.line_to(25, 4 * self.coordinate_sign) cr.line_to(32, 4 * self.coordinate_sign) cr.line_to(40, 4 * self.coordinate_sign) cr.line_to(40, 32 * self.coordinate_sign) cr.line_to(0, 32 * self.coordinate_sign) cr.close_path() cr.clip() # cr.stroke() for i in range(0, 10): x, y, theta = self.point_position("in", i / 9 * self.branch_length, out_anchor="branch") theta += -math.pi / 2 x_off, y_off = math.cos(theta) * 4, math.sin(theta) * 4 cr.move_to(x + x_off, y + y_off) cr.line_to(x - x_off, y - y_off) cr.stroke() cr.restore() if self.state == "out": rail_draw_order = ("branch", "out") else: rail_draw_order = ("out", "branch") cr.save() mask = cairo.ImageSurface( cairo.FORMAT_ARGB32, math.ceil(40 * drawing_options.scale), math.ceil(80 * drawing_options.scale), ) mask_cr = cairo.Context(mask) mask_cr.scale(drawing_options.scale, drawing_options.scale) mask_cr.translate(0, 40) mask_cr.set_source_rgb(0, 1, 0) for anchor_name in rail_draw_order: self.draw_rails_path(mask_cr, anchor_name) mask_cr.set_operator(cairo.OPERATOR_CLEAR) mask_cr.set_line_width(8) mask_cr.stroke_preserve() mask_cr.set_operator(cairo.OPERATOR_SOURCE) mask_cr.set_line_width(6) mask_cr.stroke_preserve() mask_cr.set_operator(cairo.OPERATOR_CLEAR) mask_cr.set_line_width(4) mask_cr.stroke() cr.set_source_rgb(*drawing_options.rail_color) cr.scale(1 / drawing_options.scale, 1 / drawing_options.scale) cr.mask_surface(mask, 0, -40 * drawing_options.scale) cr.restore()
def on_draw(self, widget: Widget, context: cairo.Context): self.min_size = 200, 150 super().on_draw(widget, context) context.save() context.set_font_size(self.font_size) if self._table_extents is None: self._update_table_extents(context) skip = max(self.skip, 0) how_many = self.how_many table_extents = self._table_extents title_extents = self._table_extents.title_extents expected_height = title_extents.total_height + self.margin entries = self.entries base = skip up_to = skip over = False while up_to < len(entries) and not over: expected_height += table_extents[up_to].total_height over = expected_height >= self._max_height if not over: up_to += 1 while base > 0 and not over: expected_height += table_extents[base-1].total_height over = expected_height >= self._max_height if not over: base -= 1 how_many = up_to - base skip = base self.base = base entries = self.entries[skip:skip + how_many] def table_extents_iterator(): return table_extents.iter_over( skip, how_many ) start_x, start_y = context.get_current_point() start_y += title_extents.total_height h = title_extents.total_height self.title_height = h for (index, cell), data in zip(enumerate(title_extents), self.title): context.save() offset = title_extents.get_cell_data_left(index) context.rectangle(start_x + offset, start_y - h, cell.width, 2*h) context.clip() context.move_to( start_x + offset, start_y ) context.show_text(data) context.restore() # start_y += self.margin curr_x, curr_y = start_x, start_y# + title_extents.total_height for line_index, (line_extent, entry) in enumerate(zip(table_extents_iterator(), entries)): h = line_extent.total_height curr_y += h if curr_y + self.margin >= self._max_height: break for (cell_index, cell), data in zip(enumerate(line_extent), entry): context.save() offset = line_extent.get_cell_data_left(cell_index) context.rectangle(curr_x + offset, curr_y - h, cell.width, 2*h) context.clip() context.move_to( curr_x + offset, curr_y ) context.show_text(data) context.restore() curr_x = start_x end_x = table_extents.entries_width curr_y = start_y + self.margin end_y = table_extents.get_height_up_to(skip, how_many) + start_y + self.margin + 1 self.table_height = end_y self.table_width = end_x for line in table_extents_iterator(): context.move_to(curr_x, curr_y) context.line_to(end_x, curr_y) context.stroke() curr_y += line.total_height context.move_to(curr_x, curr_y) context.line_to(end_x, curr_y) context.stroke() curr_x = start_x curr_y = start_y - 1 + self.margin if self._how_many > 0: line = table_extents[0] for cell in line: context.move_to(curr_x, curr_y) context.line_to(curr_x, end_y) context.stroke() curr_x += cell.total_width + 2 * self.margin context.move_to(curr_x, curr_y) context.line_to(curr_x, end_y) context.stroke() if self._to_highlight is not None: r, g, b = global_constants.highlight context.set_source_rgba(r, g, b, .6) index = self._to_highlight base = start_y + table_extents.get_height_up_to(skip, index) + self.margin h = table_extents.get_height_of(skip, how_many, index) context.rectangle(start_x, base, table_extents.entries_width, h) context.fill() context.restore() self._shown = how_many