def export_svg(fn, paths, size, line_with=0.1, scale_factor=None): from cairo import SVGSurface, Context from numpy import array from ddd import spatial_sort_2d as sort if not scale_factor: scale_factor = size one = 1.0/size s = SVGSurface(fn, size, size) c = Context(s) c.set_line_width(0.1) paths = sort(paths) for path in paths: path *= scale_factor c.new_path() c.move_to(*path[0,:]) for p in path[1:]: c.line_to(*p) c.stroke() c.save()
def export_svg(fn, paths, size, line_with=0.1, scale_factor=None): from cairo import SVGSurface, Context from .ddd import spatial_sort_2d as sort if not scale_factor: scale_factor = size s = SVGSurface(fn, size, size) c = Context(s) c.set_line_width(0.1) paths = sort(paths) for path in paths: path *= scale_factor c.new_path() c.move_to(*path[0, :]) for p in path[1:]: c.line_to(*p) c.stroke() c.save()
def draw_circular_roman( ctx: cairo.Context, rng: Generator, pos_x: float, pos_y: float, radius_outer: float, radius_inner: float, ): chunks = rng.integers(6, 16) _calendar_base(ctx, pos_x, pos_y, radius_outer, radius_inner, chunks) ctx.select_font_face("Noto Sans Symbols") font_size = 0.8 * (radius_outer - radius_inner) ctx.set_font_size(font_size) angle_offset = pi / chunks for i, (x, y) in enumerate( points_along_arc( pos_x, pos_y, (radius_inner + radius_outer) / 2.0, angle_offset, angle_offset + tau, chunks, ), 1, ): with translation(ctx, x, y), rotation(ctx, (i * tau / chunks) + (pi / 2) - angle_offset): roman = int_to_roman(i) extents = ctx.text_extents(roman) ctx.move_to(-1 * extents.width / 2.0, extents.height / 2.0) ctx.show_text(roman) ctx.new_path()
def fill( self, ctx: cairo.Context, rng: Generator, x1: float, y1: float, x2: float, y2: float, ): with source(ctx, self.stops[-1].to_pattern()): ctx.fill_preserve() # Orient the canvas so that our gradient goes straight in direction of +Y. gradient_angle = angle((x1, y1), (x2, y2)) - (pi / 2) with translation(ctx, x1, y1), rotation(ctx, gradient_angle), source( ctx, self.stops[0].to_pattern()): # We translated and rotated the canvas, so our gradient control # vector is now from (0, 0) straight up: grad_control_y = distance((x1, y1), (x2, y2)) # Get a bounding box of what needs to be filled: start_x, start_y, end_x, end_y = ctx.fill_extents() ctx.new_path() for cx, cy, cr in self.pattern.func( rng, (start_x, start_y), (end_x, end_y), (0, 0), (0, grad_control_y), self.dot_radius, ): ctx.arc(cx, cy, cr, 0, tau) ctx.fill()
def _polygon(self, ctx: cairo.Context, points, color, outline=None): ctx.new_path() for point in points: ctx.line_to(*point) ctx.close_path() ctx.set_source_rgba(*color) if outline is not None: ctx.fill_preserve() ctx.set_source_rgba(*outline) ctx.set_line_width(1) ctx.stroke() else: ctx.fill()
def draw_highlight(self, _area: Gtk.DrawingArea, context: Context) -> None: if self.current_region and self.t: poly: Polygon = self.current_region.poly poly = poly.buffer(1, single_sided=True) # TODO: 239, 134, 97, 0.7 taken from gtk.css, possible to get it from os???? context.set_source_rgba(239 / 255.0, 134 / 255.0, 97 / 255.0, 0.7) context.set_line_width( clamp(self.configurators['scale'].get_exp() * 12, 0.5, 5)) context.new_path() # Nice idea, but didnt work with scrolling: context.set_matrix(Matrix(1.0/self.t.scale, 0, 0, 1.0/self.t.scale, -self.t.tx, -self.t.ty)) for coord in poly.exterior.coords: context.line_to(*self.t.inverse(*coord)) context.close_path() context.stroke()
def export_svg(fn, paths, w, h, line_width=0.1): from cairo import SVGSurface, Context s = SVGSurface(fn, w, h) c = Context(s) c.set_line_width(line_width) for path in paths: c.new_path() c.move_to(*path[0, :]) for p in path[1:]: c.line_to(*p) c.stroke() c.save()
def export_svg(fn, paths, w, h, line_width=0.1): from cairo import SVGSurface, Context s = SVGSurface(fn, w, h) c = Context(s) c.set_line_width(line_width) for path in paths: c.new_path() c.move_to(*path[0,:]) for p in path[1:]: c.line_to(*p) c.stroke() c.save()
def _calendar_mapped( ctx: cairo.Context, rng: Generator, pos_x: float, pos_y: float, radius_outer: float, radius_inner: float, mapping: Sequence[str], font_family: str = "Noto Sans Symbols", ): chunks = rng.integers(6, min(len(mapping), 24)) _calendar_base(ctx, pos_x, pos_y, radius_outer, radius_inner, chunks) ctx.select_font_face(font_family) font_size = 0.8 * (radius_outer - radius_inner) ctx.set_font_size(font_size) symbols = rng.choice(mapping, size=chunks, replace=False) angle_offset = pi / chunks for i, (x, y) in enumerate( points_along_arc( pos_x, pos_y, (radius_inner + radius_outer) / 2.0, angle_offset, angle_offset + tau, chunks, ), 1, ): with translation(ctx, x, y), rotation(ctx, (i * tau / chunks) + (pi / 2) - angle_offset): symbol = symbols[i - 1] extents = ctx.text_extents(symbol) ctx.move_to(-1 * extents.width / 2.0, extents.height / 2.0) ctx.show_text(symbol) ctx.new_path()
def _do_draw(self, _, cr: cairo.Context): height = self.get_allocated_height() timeline_canvas = self.timeline_canvas # Show a guiding line under the mouse if self.current_moused_datetime is not None: timeline_x = timeline_canvas.timeline_helper.datetime_to_pixel( self.current_moused_datetime) cr.set_source_rgb(0.55, 0.55, 0.55) cr.new_path() cr.move_to(timeline_x, 0) cr.line_to(timeline_x, height) cr.stroke() current_guidingline_rectangle = cairo.RectangleInt( int(timeline_x) - 2, 0, 4, height) self.dirty_rectangles.append(current_guidingline_rectangle) # Highlight the hovered over entry moused_entry = None if self.moused_over_entity is None else self.moused_over_entity.entry if type(moused_entry) is LoggedEntry: le = self.moused_over_entity cr.set_source_rgba(0.7, 0.7, 0.7, 0.2) cr.rectangle(le.start_x, timeline_canvas.le_start_y, le.width, timeline_canvas.timeline_height) cr.fill() elif type(moused_entry) is TaggedEntry: te = self.moused_over_entity cr.set_source_rgba(0.7, 0.7, 0.7, 0.2) cr.rectangle(te.start_x, timeline_canvas.te_start_y, te.width, timeline_canvas.timeline_height) cr.fill() # Show the tooltip if self.tooltip_attributes is not None: self._show_details_tooltip(self.tooltip_attributes, cr) return True
ctx.move_to(outline.points[start][0],outline.points[start][1]) for j in range(start, end+1): point = outline.points[j] ctx.line_to(point[0],point[1]) #back to origin ctx.line_to(outline.points[start][0], outline.points[start][1]) start = end+1 ctx.fill_preserve() ctx.set_source_rgb(0,1,0) ctx.stroke() start, end = 0, 0 for i in range(len(outline.contours)): end = outline.contours[i] ctx.new_path() ctx.set_source_rgb(0,0,1) for j in range(start, end+1): if ( Curve_Tag[j] == FT_Curve_Tag_On ): point = outline.points[j] ctx.move_to(point[0],point[1]) ctx.arc(point[0], point[1], 40, 0, 2 * math.pi) ctx.fill() ctx.new_path() ctx.set_source_rgb(1,0,0) for j in range(start, end+1): if ( Curve_Tag[j] != FT_Curve_Tag_On ): point = outline.points[j] ctx.move_to(point[0],point[1]) ctx.arc(point[0], point[1], 10, 0, 2 * math.pi)
def _do_draw(self, _, cr: cairo.Context): # Get the size drawing_area_height = self.get_allocated_height() canvas_width = self.get_allocated_width() clip_start_x, _, clip_stop_x, _ = cr.clip_extents() # Show the activity as a background for the time area for ae in self.visible_activity_entries: if ae.stop_x < clip_start_x or clip_stop_x < ae.start_x: continue r, g, b = ae.color cr.set_source_rgb(r, g, b) cr.rectangle(ae.start_x, 0, ae.width, drawing_area_height) cr.fill() # Draw the hour lines cr.set_font_size(16) cr.set_source_rgb(0.35, 0.35, 0.35) cr.rectangle(0, 0, canvas_width, self.guidingline_on_timeline_start + 10) cr.fill() for timeline_timeline in self.timeline_timelines: # Hour line hx = timeline_timeline.x cr.set_source_rgb(0.7, 0.7, 0.7) cr.new_path() cr.move_to(hx, self.guidingline_on_timeline_start) cr.line_to(hx, self.guidingline_on_timeline_start + 10) cr.stroke() # Hour text time = timeline_timeline.time if time.minute == 0: cr.set_source_rgb(0.9, 0.9, 0.3) else: cr.set_source_rgb(0.2, 0.8, 1) tx, hour_text_width = timeline_timeline.text_extents cr.move_to(hx - tx - (hour_text_width / 2), self.time_guidingline_text_height) cr.show_text(timeline_timeline.text) # Draw the rectangles for the entries by colors for color, drawing_entries in self.timeline_entries_by_color.items(): cr.set_source_rgb(*color) for drawing_entry in drawing_entries: if drawing_entry.stop_x < clip_start_x or clip_stop_x < drawing_entry.start_x: continue cr.rectangle(drawing_entry.start_x, drawing_entry.start_y, drawing_entry.width, drawing_entry.height) cr.fill() # The marker for the logged entries cr.set_source_rgb(0.3, 0.3, 0.8) for le in self.visible_logged_entries: if le.stop_x < clip_start_x or clip_stop_x < le.start_x: continue cr.rectangle(le.start_x, self.le_start_y, le.width, 10) cr.fill() # The marker for the tagged entries cr.set_source_rgb(1, 0.64, 0) for te in self.visible_tagged_entries: if te.stop_x < clip_start_x or clip_stop_x < te.start_x: continue cr.rectangle(te.start_x, self.te_end_y - 10, te.width, 10) cr.fill() if self.current_tagged_entry is not None: start_x = self.timeline_helper.datetime_to_pixel( self.current_tagged_entry.start) stop_x = self.timeline_helper.datetime_to_pixel( self.current_tagged_entry.stop) cr.set_source_rgba(0.2, 0.2, 0.2, 0.4) cr.rectangle(start_x, 0, stop_x - start_x, drawing_area_height) cr.fill() # Draw the sides cr.set_source_rgba(0.5, 0.5, 0.5, 0.5) cr.rectangle(0, 0, self.timeline_side_padding, drawing_area_height) cr.fill() cr.rectangle(canvas_width - self.timeline_side_padding, 0, canvas_width, drawing_area_height) cr.fill()