1 /* gEDA - GPL Electronic Design Automation
2 * libgedacairo - Rendering gEDA schematics with Cairo
3 * Copyright (C) 2010-2019 gEDA Contributors (see ChangeLog for details)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <glib-object.h>
27 #include <pango/pangocairo.h>
28 #include <gdk-pixbuf/gdk-pixbuf.h>
30 #include <libgeda/libgeda.h>
32 #include "edarenderer.h"
35 #include "edapangorenderer.h"
37 /* We don't use gettext */
41 PROP_CAIRO_CONTEXT
= 1,
49 FLAG_HINTING
= EDA_RENDERER_FLAG_HINTING
,
50 FLAG_PICTURE_OUTLINE
= EDA_RENDERER_FLAG_PICTURE_OUTLINE
,
51 FLAG_TEXT_HIDDEN
= EDA_RENDERER_FLAG_TEXT_HIDDEN
,
52 FLAG_TEXT_OUTLINE
= EDA_RENDERER_FLAG_TEXT_OUTLINE
,
53 FLAG_TEXT_ORIGIN
= EDA_RENDERER_FLAG_TEXT_ORIGIN
,
59 struct _EdaRendererPrivate
74 /* Cache of font metrics for different font sizes. */
75 GHashTable
*metrics_cache
;
78 static inline gboolean
79 EDA_RENDERER_CHECK_FLAG (EdaRenderer
*r
, int f
) {
80 return r
->priv
->flags
& f
;
84 EDA_RENDERER_SET_FLAG (EdaRenderer *r, int f, gboolean e) {
85 if (e) { r->priv->flags |= f; } else { r->priv->flags &= ~f; }
88 static inline unsigned int
89 EDA_RENDERER_CAIRO_FLAGS (EdaRenderer
*r
) {
90 return EDA_RENDERER_CHECK_FLAG (r
, FLAG_HINTING
) ? EDA_CAIRO_ENABLE_HINTS
: 0;
93 EDA_RENDERER_STROKE_WIDTH (EdaRenderer
*r
, double width
) {
94 /* For now, the minimum line width possible is half the net width. */
95 return fmax (width
, NET_WIDTH
/ 2);
98 #define DEFAULT_FONT_NAME "Arial"
99 #define GRIP_STROKE_COLOR SELECT_COLOR
100 #define GRIP_FILL_COLOR BACKGROUND_COLOR
101 #define TEXT_MARKER_SIZE 10
102 #define TEXT_MARKER_COLOR LOCK_COLOR
104 static GObject
*eda_renderer_constructor (GType type
,
105 guint n_construct_properties
,
106 GObjectConstructParam
*construct_params
);
107 static void eda_renderer_finalize (GObject
*object
);
108 static void eda_renderer_dispose (GObject
*object
);
109 static void eda_renderer_set_property (GObject
*object
, guint property_id
,
110 const GValue
*value
, GParamSpec
*pspec
);
111 static void eda_renderer_get_property (GObject
*object
, guint property_id
,
112 GValue
*value
, GParamSpec
*pspec
);
113 static void eda_renderer_update_contexts (EdaRenderer
*renderer
, cairo_t
*new_cr
,
114 PangoContext
*new_pc
);
116 static void eda_renderer_set_color (EdaRenderer
*renderer
, int color
);
117 static int eda_renderer_is_drawable (EdaRenderer
*renderer
, OBJECT
*object
);
118 static int eda_renderer_draw_hatch (EdaRenderer
*renderer
, OBJECT
*object
);
120 static void eda_renderer_default_draw (EdaRenderer
*renderer
, OBJECT
*object
);
121 static void eda_renderer_draw_list (EdaRenderer
*renderer
, GList
*objects
);
122 static void eda_renderer_draw_line (EdaRenderer
*renderer
, OBJECT
*object
);
123 static void eda_renderer_draw_pin (EdaRenderer
*renderer
, OBJECT
*object
);
124 static void eda_renderer_draw_net (EdaRenderer
*renderer
, OBJECT
*object
);
125 static void eda_renderer_draw_bus (EdaRenderer
*renderer
, OBJECT
*object
);
126 static void eda_renderer_draw_box (EdaRenderer
*renderer
, OBJECT
*object
);
127 static void eda_renderer_draw_arc (EdaRenderer
*renderer
, OBJECT
*object
);
128 static void eda_renderer_draw_circle (EdaRenderer
*renderer
, OBJECT
*object
);
129 static void eda_renderer_draw_path (EdaRenderer
*renderer
, OBJECT
*object
);
130 static void eda_renderer_draw_text (EdaRenderer
*renderer
, OBJECT
*object
);
131 static int eda_renderer_get_font_descent (EdaRenderer
*renderer
,
132 PangoFontDescription
*desc
);
133 static int eda_renderer_prepare_text (EdaRenderer
*renderer
, OBJECT
*object
);
134 static void eda_renderer_calc_text_position (EdaRenderer
*renderer
, OBJECT
*object
,
135 int descent
, double *x
, double *y
);
136 static void eda_renderer_draw_picture (EdaRenderer
*renderer
, OBJECT
*object
);
137 static void eda_renderer_draw_complex (EdaRenderer
*renderer
, OBJECT
*object
);
139 static void eda_renderer_default_draw_grips (EdaRenderer
*renderer
, OBJECT
*object
);
140 /*static void eda_renderer_draw_grips_list (EdaRenderer *renderer, GList *objects);*/
141 static void eda_renderer_draw_grips_impl (EdaRenderer
*renderer
, int type
, int n_grips
, ...);
142 static void eda_renderer_draw_arc_grips (EdaRenderer
*renderer
, OBJECT
*object
);
143 static void eda_renderer_draw_path_grips (EdaRenderer
*renderer
, OBJECT
*object
);
144 static void eda_renderer_draw_text_grips (EdaRenderer
*renderer
, OBJECT
*object
);
146 static void eda_renderer_default_draw_cues (EdaRenderer
*renderer
, OBJECT
*object
);
147 static void eda_renderer_draw_cues_list (EdaRenderer
*renderer
, GList
*objects
);
148 static void eda_renderer_draw_end_cues (EdaRenderer
*renderer
, OBJECT
*object
,
150 static void eda_renderer_draw_mid_cues (EdaRenderer
*renderer
, OBJECT
*object
);
151 static void eda_renderer_draw_junction_cue (EdaRenderer
*renderer
, int x
, int y
,
154 static int eda_renderer_default_get_user_bounds (EdaRenderer
*renderer
, OBJECT
*object
,
155 double *left
, double *top
,
156 double *right
, double *bottom
);
157 static int eda_renderer_get_text_user_bounds (EdaRenderer
*renderer
, OBJECT
*object
,
158 double *left
, double *top
,
159 double *right
, double *bottom
);
161 G_DEFINE_TYPE_WITH_PRIVATE (EdaRenderer
, eda_renderer
, G_TYPE_OBJECT
)
164 eda_renderer_flags_get_type ()
166 static const GFlagsValue values
[] = {
167 {FLAG_HINTING
, "hinting", _("Enable hinting")},
168 {FLAG_PICTURE_OUTLINE
, "picture-outline", _("Picture outlines")},
169 {FLAG_TEXT_HIDDEN
, "text-hidden", _("Hidden text")},
170 {FLAG_TEXT_OUTLINE
, "text-outline", _("Text outlines")},
171 {FLAG_TEXT_ORIGIN
, "text-origin", _("Text origins")},
174 static GType flags_type
= 0;
175 if (flags_type
== 0) {
176 flags_type
= g_flags_register_static ("EdaRendererFlags",
183 eda_renderer_class_init (EdaRendererClass
*klass
)
185 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
186 GParamFlags param_flags
;
188 /* Register functions with base class */
189 gobject_class
->constructor
= eda_renderer_constructor
;
190 gobject_class
->finalize
= eda_renderer_finalize
;
191 gobject_class
->dispose
= eda_renderer_dispose
;
192 gobject_class
->set_property
= eda_renderer_set_property
;
193 gobject_class
->get_property
= eda_renderer_get_property
;
195 /* Install default implementations of virtual public methods */
196 klass
->draw
= eda_renderer_default_draw
;
197 klass
->draw_grips
= eda_renderer_default_draw_grips
;
198 klass
->draw_cues
= eda_renderer_default_draw_cues
;
199 klass
->user_bounds
= eda_renderer_default_get_user_bounds
;
201 /* Install properties */
202 param_flags
= (G_PARAM_READWRITE
| G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
|
203 G_PARAM_STATIC_BLURB
);
205 g_object_class_install_property (gobject_class
, PROP_CAIRO_CONTEXT
,
206 g_param_spec_pointer ("cairo-context",
208 _("The Cairo context for rendering"),
210 g_object_class_install_property (gobject_class
, PROP_PANGO_CONTEXT
,
211 g_param_spec_pointer ("pango-context",
213 _("The Pango context for text rendering"),
215 g_object_class_install_property (gobject_class
, PROP_FONT_NAME
,
216 g_param_spec_string ("font-name",
218 _("The name of the font to use for text rendering"),
221 g_object_class_install_property (gobject_class
, PROP_COLOR_MAP
,
222 g_param_spec_pointer ("color-map",
224 _("Map for determining colors from color indices"),
226 g_object_class_install_property (gobject_class
, PROP_OVERRIDE_COLOR
,
227 g_param_spec_int ("override-color",
229 _("Index of color to force used for all drawing."),
232 g_object_class_install_property (gobject_class
, PROP_GRIP_SIZE
,
233 g_param_spec_double ("grip-size",
235 _("Size in user coordinates to draw grips"),
238 g_object_class_install_property (gobject_class
, PROP_RENDER_FLAGS
,
239 g_param_spec_flags ("render-flags",
240 _("Rendering flags"),
241 _("Flags controlling rendering"),
242 EDA_TYPE_RENDERER_FLAGS
,
243 FLAG_HINTING
| FLAG_TEXT_ORIGIN
,
248 eda_renderer_init (EdaRenderer
*renderer
)
250 renderer
->priv
= eda_renderer_get_instance_private (renderer
);
252 /* Set some sensible default options */
253 renderer
->priv
->font_name
= g_strdup (DEFAULT_FONT_NAME
);
254 renderer
->priv
->override_color
= -1;
255 renderer
->priv
->grip_size
= 100;
257 /* Font metrics are expensive to compute, so we need to cache them. */
258 renderer
->priv
->metrics_cache
=
259 g_hash_table_new_full (g_int_hash
, g_int_equal
, g_free
,
260 (GDestroyNotify
) pango_font_metrics_unref
);
264 eda_renderer_constructor (GType type
,
265 guint n_construct_properties
,
266 GObjectConstructParam
*construct_params
) {
268 GObjectClass
*parent_object_class
;
270 parent_object_class
= G_OBJECT_CLASS (eda_renderer_parent_class
);
271 object
= parent_object_class
->constructor (type
, n_construct_properties
,
278 eda_renderer_dispose (GObject
*object
)
280 EdaRenderer
*renderer
= (EdaRenderer
*) object
;
282 if (renderer
->priv
->pc
!= NULL
) {
283 g_object_unref (renderer
->priv
->pc
);
284 renderer
->priv
->pc
= NULL
;
287 if (renderer
->priv
->pl
!= NULL
) {
288 g_object_unref (renderer
->priv
->pl
);
289 renderer
->priv
->pl
= NULL
;
292 if (renderer
->priv
->pr
!= NULL
) {
293 g_object_unref (renderer
->priv
->pr
);
294 renderer
->priv
->pr
= NULL
;
297 /* Chain up to the parent class */
298 G_OBJECT_CLASS (eda_renderer_parent_class
)->dispose (object
);
302 eda_renderer_finalize (GObject
*object
)
304 EdaRenderer
*renderer
= (EdaRenderer
*) object
;
306 g_hash_table_destroy (renderer
->priv
->metrics_cache
);
307 renderer
->priv
->metrics_cache
= NULL
;
309 cairo_destroy (renderer
->priv
->cr
);
310 renderer
->priv
->cr
= NULL
;
312 g_free (renderer
->priv
->font_name
);
313 renderer
->priv
->font_name
= NULL
;
315 /* Chain up to the parent class */
316 G_OBJECT_CLASS (eda_renderer_parent_class
)->finalize (object
);
321 eda_renderer_set_property (GObject
*object
, guint property_id
,
322 const GValue
*value
, GParamSpec
*pspec
)
324 EdaRenderer
*renderer
= EDA_RENDERER (object
);
326 switch (property_id
) {
327 case PROP_CAIRO_CONTEXT
:
328 eda_renderer_update_contexts (renderer
,
329 (cairo_t
*) g_value_get_pointer (value
),
332 case PROP_PANGO_CONTEXT
:
333 eda_renderer_update_contexts (renderer
, NULL
,
334 PANGO_CONTEXT (g_value_get_pointer (value
)));
337 if (renderer
->priv
->font_name
!= NULL
)
338 g_free (renderer
->priv
->font_name
);
339 renderer
->priv
->font_name
= g_value_dup_string (value
);
340 /* Clear font metrics cache */
341 g_hash_table_remove_all (renderer
->priv
->metrics_cache
);
344 renderer
->priv
->color_map
= g_value_get_pointer (value
);
346 case PROP_OVERRIDE_COLOR
:
347 renderer
->priv
->override_color
= g_value_get_int (value
);
350 renderer
->priv
->grip_size
= g_value_get_double (value
);
352 case PROP_RENDER_FLAGS
:
353 renderer
->priv
->flags
= g_value_get_flags (value
);
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
361 eda_renderer_get_property (GObject
*object
, guint property_id
,
362 GValue
*value
, GParamSpec
*pspec
)
364 EdaRenderer
*renderer
= EDA_RENDERER (object
);
366 switch (property_id
) {
367 case PROP_CAIRO_CONTEXT
:
368 g_value_set_pointer (value
, renderer
->priv
->cr
);
370 case PROP_PANGO_CONTEXT
:
371 g_value_set_pointer (value
, renderer
->priv
->pc
);
374 g_value_set_string (value
, renderer
->priv
->font_name
);
377 g_value_set_pointer (value
, renderer
->priv
->color_map
);
379 case PROP_OVERRIDE_COLOR
:
380 g_value_set_int (value
, renderer
->priv
->override_color
);
383 g_value_set_double (value
, renderer
->priv
->grip_size
);
385 case PROP_RENDER_FLAGS
:
386 g_value_set_flags (value
, renderer
->priv
->flags
);
389 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
394 eda_renderer_update_contexts (EdaRenderer
*renderer
, cairo_t
*new_cr
,
395 PangoContext
*new_pc
)
397 /* First figure out what's invalidated */
398 if (new_cr
!= NULL
) {
399 cairo_destroy (renderer
->priv
->cr
);
400 renderer
->priv
->cr
= NULL
;
401 if (renderer
->priv
->pr
!= NULL
) {
402 g_object_unref (renderer
->priv
->pr
);
403 renderer
->priv
->pr
= NULL
;
406 /* If the PangoContext was created from the previous Cairo
407 * context, it needs destroying too. */
408 if (renderer
->priv
->pc_from_cr
) {
409 if (renderer
->priv
->pc
!= NULL
) {
410 g_object_unref (renderer
->priv
->pc
);
411 renderer
->priv
->pc
= NULL
;
413 if (renderer
->priv
->pl
!= NULL
) {
414 g_object_unref (renderer
->priv
->pl
);
415 renderer
->priv
->pl
= NULL
;
419 renderer
->priv
->cr
= cairo_reference (new_cr
);
422 if (new_pc
!= NULL
) {
423 if (renderer
->priv
->pc
!= NULL
) {
424 g_object_unref (G_OBJECT (renderer
->priv
->pc
));
425 renderer
->priv
->pc
= NULL
;
427 if (renderer
->priv
->pl
!= NULL
) {
428 g_object_unref (G_OBJECT (renderer
->priv
->pl
));
429 renderer
->priv
->pl
= NULL
;
432 renderer
->priv
->pc
= PANGO_CONTEXT (g_object_ref (G_OBJECT (new_pc
)));
433 renderer
->priv
->pc_from_cr
= 0;
436 /* Now recreate anything necessary */
437 if ((renderer
->priv
->pc
== NULL
) && (renderer
->priv
->cr
!= NULL
)) {
438 cairo_save (renderer
->priv
->cr
);
439 cairo_identity_matrix (renderer
->priv
->cr
);
440 renderer
->priv
->pc
= pango_cairo_create_context (renderer
->priv
->cr
);
441 cairo_restore (renderer
->priv
->cr
);
442 renderer
->priv
->pc_from_cr
= 1;
445 if ((renderer
->priv
->pl
== NULL
) && (renderer
->priv
->pc
!= NULL
)) {
446 renderer
->priv
->pl
= pango_layout_new (renderer
->priv
->pc
);
449 if ((renderer
->priv
->pr
== NULL
) && (renderer
->priv
->cr
!= NULL
)) {
451 (EdaPangoRenderer
*) eda_pango_renderer_new (renderer
->priv
->cr
);
455 /* ================================================================
457 * ================================================================ */
460 eda_renderer_draw_list (EdaRenderer
*renderer
, GList
*objects
)
464 for (iter
= objects
; iter
!= NULL
; iter
= g_list_next (iter
)) {
465 eda_renderer_draw (renderer
, (OBJECT
*) iter
->data
);
470 eda_renderer_draw (EdaRenderer
*renderer
, OBJECT
*object
)
472 g_return_if_fail (EDA_IS_RENDERER(renderer
));
474 EDA_RENDERER_GET_CLASS (renderer
)->draw (renderer
, object
);
478 eda_renderer_default_draw (EdaRenderer
*renderer
, OBJECT
*object
)
480 void (*draw_func
)(EdaRenderer
*, OBJECT
*);
482 g_return_if_fail (object
!= NULL
);
483 g_return_if_fail (renderer
->priv
->cr
!= NULL
);
484 g_return_if_fail (renderer
->priv
->pl
!= NULL
);
485 g_return_if_fail (renderer
->priv
->color_map
!= NULL
);
487 if (!eda_renderer_is_drawable (renderer
, object
)) return;
489 switch (object
->type
) {
490 case OBJ_LINE
: draw_func
= eda_renderer_draw_line
; break;
491 case OBJ_NET
: draw_func
= eda_renderer_draw_net
; break;
492 case OBJ_BUS
: draw_func
= eda_renderer_draw_bus
; break;
493 case OBJ_PIN
: draw_func
= eda_renderer_draw_pin
; break;
494 case OBJ_BOX
: draw_func
= eda_renderer_draw_box
; break;
495 case OBJ_ARC
: draw_func
= eda_renderer_draw_arc
; break;
496 case OBJ_CIRCLE
: draw_func
= eda_renderer_draw_circle
; break;
497 case OBJ_PATH
: draw_func
= eda_renderer_draw_path
; break;
498 case OBJ_TEXT
: draw_func
= eda_renderer_draw_text
; break;
499 case OBJ_PICTURE
: draw_func
= eda_renderer_draw_picture
; break;
502 case OBJ_PLACEHOLDER
: draw_func
= eda_renderer_draw_complex
; break;
505 g_return_if_reached ();
508 eda_renderer_set_color (renderer
, object
->color
);
509 draw_func (renderer
, object
);
513 eda_renderer_set_color (EdaRenderer
*renderer
, int color
)
515 if (renderer
->priv
->override_color
!= -1) {
516 color
= renderer
->priv
->override_color
;
518 eda_cairo_set_source_color (renderer
->priv
->cr
, color
,
519 renderer
->priv
->color_map
);
523 eda_renderer_is_drawable_color (EdaRenderer
*renderer
, int color
,
526 GArray
*map
= renderer
->priv
->color_map
;
527 /* Check for override color */
528 if ((renderer
->priv
->override_color
>= 0) && use_override
) {
529 color
= renderer
->priv
->override_color
;
531 /* If color index out of color map bounds, don't draw */
532 g_return_val_if_fail ((map
!= NULL
), FALSE
);
533 g_return_val_if_fail ((color
>= 0) || (color
< map
->len
), FALSE
);
535 /* Otherwise, return enabled flag of object's color */
536 return (&g_array_index (map
, COLOR
, color
))->enabled
;
540 eda_renderer_is_drawable (EdaRenderer
*renderer
, OBJECT
*object
)
542 int color
= object
->color
;
543 /* Always attempt to draw complex objects */
544 if ((object
->type
== OBJ_COMPLEX
) || (object
->type
== OBJ_PLACEHOLDER
)) {
547 return eda_renderer_is_drawable_color (renderer
, color
, TRUE
);
551 eda_renderer_draw_hatch (EdaRenderer
*renderer
, OBJECT
*object
)
553 void (*hatch_func
)(void *, gint
, gint
, GArray
*);
558 /* Horrible horrible hacks! */
559 switch (object
->type
) {
561 hatch_func
= (void *) m_hatch_box
;
562 hatch_data
= (void (*)(void *, gint
, gint
, GArray
*)) object
->box
;
565 hatch_func
= (void *) m_hatch_circle
;
566 hatch_data
= (void (*)(void *, gint
, gint
, GArray
*)) object
->circle
;
569 hatch_func
= (void *) m_hatch_path
;
570 hatch_data
= (void (*)(void *, gint
, gint
, GArray
*)) object
->path
;
573 g_return_val_if_reached (FALSE
);
576 /* Handle solid and hollow fill types */
577 switch (object
->fill_type
) {
586 g_return_val_if_reached (FALSE
);
589 /* Handle mesh and hatch fill types */
590 fill_lines
= g_array_new (FALSE
, FALSE
, sizeof (LINE
));
591 switch (object
->fill_type
) {
593 hatch_func (hatch_data
, object
->fill_angle2
, object
->fill_pitch2
, fill_lines
);
594 /* Intentionally fall through */
596 hatch_func (hatch_data
, object
->fill_angle1
, object
->fill_pitch1
, fill_lines
);
602 /* Draw fill pattern */
603 for (i
= 0; i
< fill_lines
->len
; i
++) {
604 LINE
*line
= &g_array_index (fill_lines
, LINE
, i
);
605 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
606 END_NONE
, object
->fill_width
,
607 line
->x
[0], line
->y
[0], line
->x
[1], line
->y
[1]);
609 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
610 TYPE_SOLID
, END_NONE
,
611 EDA_RENDERER_STROKE_WIDTH (renderer
, object
->fill_width
),
614 g_array_free (fill_lines
, TRUE
);
619 eda_renderer_draw_complex (EdaRenderer
*renderer
, OBJECT
*object
)
622 eda_renderer_draw_list (renderer
, object
->complex->prim_objs
);
626 eda_renderer_draw_line (EdaRenderer
*renderer
, OBJECT
*object
)
628 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
631 object
->line
->x
[0], object
->line
->y
[0],
632 object
->line
->x
[1], object
->line
->y
[1]);
633 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
636 EDA_RENDERER_STROKE_WIDTH (renderer
, object
->line_width
),
642 eda_renderer_draw_net (EdaRenderer
*renderer
, OBJECT
*object
)
644 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
645 END_SQUARE
, NET_WIDTH
,
646 object
->line
->x
[0], object
->line
->y
[0],
647 object
->line
->x
[1], object
->line
->y
[1]);
648 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
649 TYPE_SOLID
, END_SQUARE
,
650 EDA_RENDERER_STROKE_WIDTH (renderer
, NET_WIDTH
),
655 eda_renderer_draw_bus (EdaRenderer
*renderer
, OBJECT
*object
)
657 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
658 END_SQUARE
, BUS_WIDTH
,
659 object
->line
->x
[0], object
->line
->y
[0],
660 object
->line
->x
[1], object
->line
->y
[1]);
661 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
662 TYPE_SOLID
, END_SQUARE
,
663 EDA_RENDERER_STROKE_WIDTH (renderer
, BUS_WIDTH
),
668 eda_renderer_draw_pin (EdaRenderer
*renderer
, OBJECT
*object
)
671 switch (object
->pin_type
) {
673 width
= PIN_WIDTH_NET
;
676 width
= PIN_WIDTH_BUS
;
679 g_return_if_reached ();
682 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
684 object
->line
->x
[0], object
->line
->y
[0],
685 object
->line
->x
[1], object
->line
->y
[1]);
686 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
687 TYPE_SOLID
, END_SQUARE
,
688 EDA_RENDERER_STROKE_WIDTH (renderer
, width
),
693 eda_renderer_draw_box (EdaRenderer
*renderer
, OBJECT
*object
)
695 int fill_solid
= FALSE
;
698 fill_solid
= eda_renderer_draw_hatch (renderer
, object
);
700 /* Draw outline of box */
701 eda_cairo_box (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
703 object
->box
->lower_x
, object
->box
->lower_y
,
704 object
->box
->upper_x
, object
->box
->upper_y
);
705 if (fill_solid
) cairo_fill_preserve (renderer
->priv
->cr
);
706 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
707 object
->line_type
, object
->line_end
,
708 EDA_RENDERER_STROKE_WIDTH (renderer
, object
->line_width
),
709 object
->line_length
, object
->line_space
);
713 eda_renderer_draw_arc (EdaRenderer
*renderer
, OBJECT
*object
)
715 eda_cairo_arc (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
720 object
->arc
->start_angle
,
721 object
->arc
->sweep_angle
);
723 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
726 EDA_RENDERER_STROKE_WIDTH (renderer
, object
->line_width
),
732 eda_renderer_draw_circle (EdaRenderer
*renderer
, OBJECT
*object
)
734 int fill_solid
= FALSE
;
737 fill_solid
= eda_renderer_draw_hatch (renderer
, object
);
739 /* Draw outline of circle */
740 eda_cairo_arc (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
742 object
->circle
->center_x
, object
->circle
->center_y
,
743 object
->circle
->radius
, 0, 360);
744 if (fill_solid
) cairo_fill_preserve (renderer
->priv
->cr
);
745 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
746 object
->line_type
, object
->line_end
,
747 EDA_RENDERER_STROKE_WIDTH (renderer
, object
->line_width
),
748 object
->line_length
, object
->line_space
);
752 eda_renderer_draw_path (EdaRenderer
*renderer
, OBJECT
*object
)
754 int fill_solid
= FALSE
;
757 fill_solid
= eda_renderer_draw_hatch (renderer
, object
);
759 /* Draw outline of path */
760 eda_cairo_path (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
761 object
->line_width
, object
->path
->num_sections
,
762 object
->path
->sections
);
764 if (fill_solid
) cairo_fill_preserve (renderer
->priv
->cr
);
765 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
766 object
->line_type
, object
->line_end
,
767 EDA_RENDERER_STROKE_WIDTH (renderer
, object
->line_width
),
768 object
->line_length
, object
->line_space
);
772 eda_renderer_draw_text (EdaRenderer
*renderer
, OBJECT
*object
)
775 double dummy
= 0, small_dist
= TEXT_MARKER_SIZE
;
777 /* First check if this is hidden text. */
778 if (object
->visibility
== INVISIBLE
779 && !EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_TEXT_HIDDEN
)) {
783 /* Also, check that we actually need to display a string */
784 if (object
->text
->disp_string
== NULL
)
787 /* If text outline mode is selected, draw an outline */
788 if (EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_TEXT_OUTLINE
)) {
789 eda_cairo_box (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
790 0, object
->w_left
, object
->w_bottom
,
791 object
->w_right
, object
->w_top
);
792 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
793 TYPE_SOLID
, END_SQUARE
,
794 EDA_RENDERER_STROKE_WIDTH (renderer
, 0),
799 /* Otherwise, actually draw the text */
800 cairo_save (renderer
->priv
->cr
);
801 if (eda_renderer_prepare_text (renderer
, object
)) {
802 eda_pango_renderer_show_layout (renderer
->priv
->pr
, renderer
->priv
->pl
,
804 cairo_restore (renderer
->priv
->cr
);
806 cairo_restore (renderer
->priv
->cr
);
810 /* If the text is flagged invisible, and we're showing hidden text,
811 * draw a little "I". */
812 if (object
->visibility
!= INVISIBLE
)
815 /* Check that color is enabled */
816 if (!eda_renderer_is_drawable_color (renderer
, TEXT_MARKER_COLOR
, FALSE
))
819 /* If the text marker is too tiny, don't draw it. */
820 if (EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_HINTING
)) {
821 cairo_user_to_device_distance (renderer
->priv
->cr
, &small_dist
, &dummy
);
822 if (small_dist
< 1) return;
825 eda_renderer_set_color (renderer
, TEXT_MARKER_COLOR
);
827 /* Centre of marker is just below and to the right of the text
828 * object's origin. */
829 x
= object
->text
->x
+ 2 * TEXT_MARKER_SIZE
;
830 y
= object
->text
->y
- 2 * TEXT_MARKER_SIZE
;
832 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
833 END_NONE
, 0, /* Top */
834 x
- TEXT_MARKER_SIZE
, y
+ TEXT_MARKER_SIZE
,
835 x
+ TEXT_MARKER_SIZE
, y
+ TEXT_MARKER_SIZE
);
836 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
837 END_NONE
, 0, /* Vertical */
838 x
, y
+ TEXT_MARKER_SIZE
,
839 x
, y
- TEXT_MARKER_SIZE
);
840 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
841 END_NONE
, 0, /* Bottom */
842 x
- TEXT_MARKER_SIZE
, y
- TEXT_MARKER_SIZE
,
843 x
+ TEXT_MARKER_SIZE
, y
- TEXT_MARKER_SIZE
);
844 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
845 TYPE_SOLID
, END_NONE
,
846 EDA_RENDERER_STROKE_WIDTH (renderer
, 0),
851 eda_renderer_get_font_descent (EdaRenderer
*renderer
,
852 PangoFontDescription
*desc
)
854 PangoFontMetrics
*metrics
;
855 int size
= pango_font_description_get_size (desc
);
858 /* Lookup the font size in the metrics cache, and get the metrics
859 * from there if available. Otherwise, calculate the metrics and
861 metrics
= g_hash_table_lookup (renderer
->priv
->metrics_cache
, &size
);
862 if (metrics
== NULL
) {
863 metrics
= pango_context_get_metrics (renderer
->priv
->pc
, desc
, NULL
);
864 key
= g_new (int, 1);
866 g_hash_table_insert (renderer
->priv
->metrics_cache
, key
, metrics
);
868 return pango_font_metrics_get_descent (metrics
);
872 eda_renderer_prepare_text (EdaRenderer
*renderer
, OBJECT
*object
)
874 double points_size
, dx
, dy
;
877 cairo_font_options_t
*options
;
878 PangoFontDescription
*desc
;
879 PangoAttrList
*attrs
;
881 points_size
= o_text_get_font_size_in_points (object
); /* FIXME */
882 size
= lrint (points_size
* PANGO_SCALE
);
884 /* Set hinting as appropriate */
885 options
= cairo_font_options_create ();
886 cairo_font_options_set_hint_metrics (options
, CAIRO_HINT_METRICS_OFF
);
887 if (EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_HINTING
)) {
888 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_MEDIUM
);
890 cairo_font_options_set_hint_style (options
, CAIRO_HINT_STYLE_NONE
);
892 pango_cairo_context_set_font_options (renderer
->priv
->pc
, options
);
893 cairo_font_options_destroy (options
);
895 pango_cairo_context_set_resolution (renderer
->priv
->pc
, 1000);
897 /* Set font name and size, and obtain descent metric */
898 desc
= pango_font_description_from_string (renderer
->priv
->font_name
);
899 pango_font_description_set_size (desc
, size
);
900 pango_layout_set_font_description (renderer
->priv
->pl
, desc
);
901 descent
= eda_renderer_get_font_descent (renderer
, desc
);
902 pango_font_description_free (desc
);
904 /* Extract text to display and Pango text attributes, and then set
906 if (!eda_pango_parse_overbars (object
->text
->disp_string
, -1,
907 &attrs
, &draw_string
)) {
910 pango_layout_set_text (renderer
->priv
->pl
, draw_string
, -1);
911 pango_layout_set_attributes (renderer
->priv
->pl
, attrs
);
912 g_free (draw_string
);
913 pango_attr_list_unref (attrs
);
915 /* Calculate text position. */
916 eda_renderer_calc_text_position (renderer
, object
, descent
, &dx
, &dy
);
918 cairo_translate (renderer
->priv
->cr
, object
->text
->x
, object
->text
->y
);
920 /* Special case turns upside-down text back upright */
921 if (object
->text
->angle
!= 180) {
922 cairo_rotate (renderer
->priv
->cr
,
923 M_PI
* object
->text
->angle
/ 180.);
926 cairo_scale (renderer
->priv
->cr
, 1, -1);
927 cairo_translate (renderer
->priv
->cr
, dx
, dy
);
929 if (EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_HINTING
)) {
930 /* NB: Shift the position by 0.5px to match the hinting applied to single
931 * pixel wide lines. This means the text will sit correctly on top of
932 * the grid lines, and ensures consistency with other lines when the
933 * page view is zoomed out. */
935 cairo_device_to_user_distance (renderer
->priv
->cr
, &dx
, &dy
);
936 cairo_translate (renderer
->priv
->cr
, dx
, dy
);
939 cairo_save (renderer
->priv
->cr
);
940 cairo_identity_matrix (renderer
->priv
->cr
);
941 pango_cairo_update_layout (renderer
->priv
->cr
, renderer
->priv
->pl
);
942 cairo_restore (renderer
->priv
->cr
);
946 /* Calculate position to draw text relative to text origin marker, in
947 * world coordinates. */
949 eda_renderer_calc_text_position (EdaRenderer
*renderer
, OBJECT
*object
,
950 int descent
, double *x
, double *y
)
952 PangoRectangle inked_rect
, logical_rect
;
954 double y_lower
, y_middle
, y_upper
;
955 double x_left
, x_middle
, x_right
;
957 pango_layout_get_extents (renderer
->priv
->pl
,
958 &inked_rect
, &logical_rect
);
961 x_middle
= -logical_rect
.width
/ 2.0;
962 x_right
= -logical_rect
.width
;
964 /*! \note Ideally, we would be using just font / logical metrics for vertical
965 * alignment, however this way seems to be more backward compatible
966 * with the old gschem rendering.
968 * Lower alignment is at the baseline of the bottom text line, whereas
969 * middle and upper alignment is based upon the inked extents of the
972 y_upper
= -inked_rect
.y
; /* Top of inked extents */
973 y_middle
= y_upper
- inked_rect
.height
/ 2.; /* Middle of inked extents */
974 y_lower
= descent
- logical_rect
.height
; /* Baseline of bottom line */
976 /* Special case flips attachment point to opposite corner when
977 * the text is rotated to 180 degrees, since the drawing code
978 * does not rotate the text to be shown upside down.
980 if (object
->text
->angle
== 180) {
981 temp
= y_lower
; y_lower
= y_upper
; y_upper
= temp
;
982 temp
= x_left
; x_left
= x_right
; x_right
= temp
;
985 switch (object
->text
->alignment
) {
987 /* Fall through to LOWER_left case */
988 case LOWER_LEFT
: *y
= y_lower
; *x
= x_left
; break;
989 case MIDDLE_LEFT
: *y
= y_middle
; *x
= x_left
; break;
990 case UPPER_LEFT
: *y
= y_upper
; *x
= x_left
; break;
991 case LOWER_MIDDLE
: *y
= y_lower
; *x
= x_middle
; break;
992 case MIDDLE_MIDDLE
: *y
= y_middle
; *x
= x_middle
; break;
993 case UPPER_MIDDLE
: *y
= y_upper
; *x
= x_middle
; break;
994 case LOWER_RIGHT
: *y
= y_lower
; *x
= x_right
; break;
995 case MIDDLE_RIGHT
: *y
= y_middle
; *x
= x_right
; break;
996 case UPPER_RIGHT
: *y
= y_upper
; *x
= x_right
; break;
1004 eda_renderer_draw_picture (EdaRenderer
*renderer
, OBJECT
*object
)
1007 double orig_width
, orig_height
;
1010 /* Get a pixbuf. If image doesn't exist, libgeda should
1011 * provide a fallback image. */
1012 pixbuf
= g_object_ref (object
->picture
->pixbuf
);
1014 /* If no pixbuf was found, fall back to drawing an outline */
1015 if (pixbuf
== NULL
|| EDA_RENDERER_CHECK_FLAG (renderer
,
1016 FLAG_PICTURE_OUTLINE
)) {
1017 eda_cairo_box (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1019 object
->picture
->lower_x
, object
->picture
->lower_y
,
1020 object
->picture
->upper_x
, object
->picture
->upper_y
);
1021 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1022 TYPE_SOLID
, END_SQUARE
,
1023 EDA_RENDERER_STROKE_WIDTH (renderer
, 0),
1028 g_return_if_fail (GDK_IS_PIXBUF (pixbuf
));
1030 cairo_save (renderer
->priv
->cr
);
1032 swap_wh
= ((object
->picture
->angle
== 90) || (object
->picture
->angle
== 270));
1033 orig_width
= swap_wh
? gdk_pixbuf_get_height (object
->picture
->pixbuf
)
1034 : gdk_pixbuf_get_width (object
->picture
->pixbuf
);
1035 orig_height
= swap_wh
? gdk_pixbuf_get_width (object
->picture
->pixbuf
)
1036 : gdk_pixbuf_get_height (object
->picture
->pixbuf
);
1038 cairo_translate (renderer
->priv
->cr
,
1039 object
->picture
->upper_x
, object
->picture
->upper_y
);
1040 cairo_scale (renderer
->priv
->cr
,
1041 abs (object
->picture
->upper_x
- object
->picture
->lower_x
) / orig_width
,
1042 - abs (object
->picture
->upper_y
- object
->picture
->lower_y
) / orig_height
);
1044 /* Evil magic translates picture origin to the right position for a given rotation */
1045 switch (object
->picture
->angle
) {
1047 case 90: cairo_translate (renderer
->priv
->cr
, 0, orig_height
); break;
1048 case 180: cairo_translate (renderer
->priv
->cr
, orig_width
, orig_height
); break;
1049 case 270: cairo_translate (renderer
->priv
->cr
, orig_width
, 0 ); break;
1052 cairo_rotate (renderer
->priv
->cr
, -object
->picture
->angle
* M_PI
/ 180.);
1053 if (object
->picture
->mirrored
) {
1054 cairo_translate (renderer
->priv
->cr
, gdk_pixbuf_get_width (pixbuf
), 0);
1055 cairo_scale (renderer
->priv
->cr
, -1, 1);
1058 gdk_cairo_set_source_pixbuf (renderer
->priv
->cr
,
1059 object
->picture
->pixbuf
, 0,0);
1060 cairo_rectangle (renderer
->priv
->cr
, 0, 0,
1061 gdk_pixbuf_get_width (object
->picture
->pixbuf
),
1062 gdk_pixbuf_get_height (object
->picture
->pixbuf
));
1064 cairo_clip (renderer
->priv
->cr
);
1065 cairo_paint (renderer
->priv
->cr
);
1067 cairo_restore (renderer
->priv
->cr
);
1068 g_object_unref (pixbuf
);
1071 /* ================================================================
1073 * ================================================================ */
1077 eda_renderer_draw_grips_list (EdaRenderer *renderer, GList *objects)
1080 for (iter = objects; iter != NULL; iter = g_list_next (iter)) {
1081 eda_renderer_draw_grips (renderer, (OBJECT *) iter->data);
1087 eda_renderer_draw_grips (EdaRenderer
*renderer
, OBJECT
*object
)
1089 g_return_if_fail (EDA_IS_RENDERER (renderer
));
1091 EDA_RENDERER_GET_CLASS (renderer
)->draw_grips (renderer
, object
);
1095 eda_renderer_default_draw_grips (EdaRenderer
*renderer
, OBJECT
*object
)
1097 g_return_if_fail (object
!= NULL
);
1098 g_return_if_fail (EDA_IS_RENDERER (renderer
));
1099 g_return_if_fail (renderer
->priv
->cr
!= NULL
);
1101 if (!eda_renderer_is_drawable (renderer
, object
))
1103 if (!eda_renderer_is_drawable_color (renderer
, GRIP_STROKE_COLOR
, FALSE
))
1106 switch (object
->type
) {
1111 eda_renderer_draw_grips_impl (renderer
, GRIP_SQUARE
, 2,
1112 object
->line
->x
[0], object
->line
->y
[0],
1113 object
->line
->x
[1], object
->line
->y
[1]);
1116 eda_renderer_draw_grips_impl (renderer
, GRIP_SQUARE
, 4,
1117 object
->box
->upper_x
, object
->box
->upper_y
,
1118 object
->box
->lower_x
, object
->box
->upper_y
,
1119 object
->box
->upper_x
, object
->box
->lower_y
,
1120 object
->box
->lower_x
, object
->box
->lower_y
);
1123 eda_renderer_draw_arc_grips (renderer
, object
);
1126 /* Grip at bottom right of containing square */
1127 eda_renderer_draw_grips_impl (renderer
, GRIP_SQUARE
, 1,
1128 object
->circle
->center_x
+ object
->circle
->radius
,
1129 object
->circle
->center_y
- object
->circle
->radius
);
1132 eda_renderer_draw_path_grips (renderer
, object
);
1135 eda_renderer_draw_text_grips (renderer
, object
);
1138 eda_renderer_draw_grips_impl (renderer
, GRIP_SQUARE
, 4,
1139 object
->picture
->upper_x
, object
->picture
->upper_y
,
1140 object
->picture
->lower_x
, object
->picture
->upper_y
,
1141 object
->picture
->upper_x
, object
->picture
->lower_y
,
1142 object
->picture
->lower_x
, object
->picture
->lower_y
);
1145 case OBJ_PLACEHOLDER
:
1149 g_return_if_reached ();
1154 eda_renderer_draw_grips_impl (EdaRenderer
*renderer
, int type
, int n_grips
, ...)
1156 va_list coordinates
;
1159 va_start (coordinates
, n_grips
);
1160 for (i
= 0; i
< n_grips
; i
++) {
1161 int x
= va_arg (coordinates
, int);
1162 int y
= va_arg (coordinates
, int);
1166 eda_cairo_center_box (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1168 renderer
->priv
->grip_size
,
1169 renderer
->priv
->grip_size
);
1172 eda_cairo_center_arc (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1174 renderer
->priv
->grip_size
,
1178 g_return_if_reached ();
1181 eda_cairo_set_source_color (renderer
->priv
->cr
, GRIP_FILL_COLOR
,
1182 renderer
->priv
->color_map
);
1183 cairo_fill_preserve (renderer
->priv
->cr
);
1185 eda_cairo_set_source_color (renderer
->priv
->cr
, GRIP_STROKE_COLOR
,
1186 renderer
->priv
->color_map
);
1188 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1189 TYPE_SOLID
, END_NONE
,
1192 va_end (coordinates
);
1196 eda_renderer_draw_arc_grips (EdaRenderer
*renderer
, OBJECT
*object
)
1198 double radius
, start_angle
, sweep_angle
;
1199 int x1
, y1
, x2
, y2
, x3
, y3
;
1202 * An arc has three grips:
1204 * <DT>*</DT><DD>one at the center that allows changes on the
1205 * radius - at (<B>x</B>,<B>y</B>).
1206 * <DT>*</DT><DD>one at the start of the arc - at (<B>x1</B>,<B>y1</B>).
1207 * <DT>*</DT><DD>one at the end of the arc - at (<B>x2</B>,<B>y2</B>).
1210 x1
= object
->arc
->x
;
1211 y1
= object
->arc
->y
;
1213 radius
= object
->arc
->radius
;
1214 start_angle
= object
->arc
->start_angle
;
1215 sweep_angle
= object
->arc
->sweep_angle
;
1217 x2
= x1
+ radius
* cos ( start_angle
* M_PI
/ 180);
1218 y2
= y1
+ radius
* sin ( start_angle
* M_PI
/ 180);
1219 x3
= x1
+ radius
* cos ((start_angle
+ sweep_angle
) * M_PI
/ 180);
1220 y3
= y1
+ radius
* sin ((start_angle
+ sweep_angle
) * M_PI
/ 180);
1222 eda_renderer_draw_grips_impl (renderer
, GRIP_SQUARE
, 3,
1223 x1
, y1
, /* center */
1224 x2
, y2
, /* start_angle */
1225 x3
, y3
); /* end_angle */
1229 eda_renderer_draw_path_grips (EdaRenderer
*renderer
, OBJECT
*object
)
1231 int i
, last_x
= 0, last_y
= 0, next_x
, next_y
;
1232 for (i
= 0; i
< object
->path
->num_sections
; i
++) {
1233 PATH_SECTION
*section
= object
->path
->sections
+ i
;
1235 if (section
->code
!= PATH_END
) {
1236 next_x
= section
->x3
;
1237 next_y
= section
->y3
;
1240 switch (section
->code
) {
1242 /* Two control point lines */
1243 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1245 last_x
, last_y
, section
->x1
, section
->y1
);
1246 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1248 next_x
, next_y
, section
->x2
, section
->y2
);
1249 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1250 TYPE_SOLID
, END_NONE
,
1251 EDA_RENDERER_STROKE_WIDTH (renderer
, 0), -1, -1);
1252 /* Two control point grips */
1253 eda_renderer_draw_grips_impl (renderer
, GRIP_CIRCLE
, 2,
1254 section
->x1
, section
->y1
,
1255 section
->x2
, section
->y2
);
1256 /* Deliberately fall through */
1258 case PATH_MOVETO_OPEN
:
1262 /* One control point grip */
1263 eda_renderer_draw_grips_impl (renderer
, GRIP_SQUARE
, 1,
1264 section
->x3
, section
->y3
);
1273 eda_renderer_draw_text_grips (EdaRenderer
*renderer
, OBJECT
*object
)
1275 double dummy
= 0, small_dist
= TEXT_MARKER_SIZE
;
1276 int x
= object
->text
->x
;
1277 int y
= object
->text
->y
;
1279 /* First check if this is hidden text. */
1280 if (object
->visibility
== INVISIBLE
1281 && !EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_TEXT_HIDDEN
)) {
1285 /* Check that color is enabled */
1286 if (!eda_renderer_is_drawable_color (renderer
, TEXT_MARKER_COLOR
, FALSE
))
1289 /* If the text marker is too tiny, don't draw it. */
1290 cairo_user_to_device_distance (renderer
->priv
->cr
, &small_dist
, &dummy
);
1291 if (small_dist
< 1) return;
1293 eda_cairo_set_source_color (renderer
->priv
->cr
, TEXT_MARKER_COLOR
,
1294 renderer
->priv
->color_map
);
1296 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1298 x
- TEXT_MARKER_SIZE
, y
- TEXT_MARKER_SIZE
,
1299 x
+ TEXT_MARKER_SIZE
, y
+ TEXT_MARKER_SIZE
);
1300 eda_cairo_line (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1302 x
- TEXT_MARKER_SIZE
, y
+ TEXT_MARKER_SIZE
,
1303 x
+ TEXT_MARKER_SIZE
, y
- TEXT_MARKER_SIZE
);
1304 eda_cairo_stroke (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1305 TYPE_SOLID
, END_NONE
,
1306 EDA_RENDERER_STROKE_WIDTH (renderer
, 0),
1310 /* ================================================================
1312 * ================================================================ */
1315 eda_renderer_draw_cues_list (EdaRenderer
*renderer
, GList
*objects
)
1319 for (iter
= objects
; iter
!= NULL
; iter
= g_list_next (iter
)) {
1320 eda_renderer_draw_cues (renderer
, (OBJECT
*) iter
->data
);
1325 eda_renderer_draw_cues (EdaRenderer
*renderer
, OBJECT
*object
)
1327 g_return_if_fail (EDA_IS_RENDERER (renderer
));
1328 EDA_RENDERER_GET_CLASS (renderer
)->draw_cues (renderer
, object
);
1332 eda_renderer_default_draw_cues (EdaRenderer
*renderer
, OBJECT
*object
)
1334 g_return_if_fail (object
!= NULL
);
1335 g_return_if_fail (renderer
->priv
->cr
!= NULL
);
1337 switch (object
->type
) {
1347 case OBJ_PLACEHOLDER
:
1349 eda_renderer_draw_cues_list (renderer
, object
->complex->prim_objs
);
1353 eda_renderer_draw_mid_cues (renderer
, object
);
1354 eda_renderer_draw_end_cues (renderer
, object
, 0);
1355 eda_renderer_draw_end_cues (renderer
, object
, 1);
1358 g_return_if_fail ((object
->whichend
== 1) || (object
->whichend
== 0));
1359 eda_renderer_draw_end_cues (renderer
, object
, object
->whichend
);
1362 g_return_if_reached ();
1367 eda_renderer_draw_end_cues (EdaRenderer
*renderer
, OBJECT
*object
, int end
)
1369 int x
= object
->line
->x
[end
], y
= object
->line
->y
[end
];
1371 int conn_type
= CONN_ENDPOINT
;
1375 /* We should never be at the unconnectable end of a pin */
1376 g_return_if_fail ((object
->type
!= OBJ_PIN
) || (object
->whichend
== end
));
1378 /* Check whether the current object is a bus or bus pin */
1379 is_bus
= ((object
->type
== OBJ_BUS
)
1380 || ((object
->type
== OBJ_PIN
)
1381 && (object
->pin_type
== PIN_TYPE_BUS
)));
1383 for (iter
= object
->conn_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
1384 CONN
*conn
= (CONN
*) iter
->data
;
1385 if ((conn
->x
!= x
) || (conn
->y
!= y
)) continue;
1387 /* Check whether the connected object is a bus or bus pin */
1388 is_bus
|= ((conn
->other_object
->type
== OBJ_BUS
)
1389 || ((conn
->other_object
->type
== OBJ_PIN
)
1390 && (conn
->other_object
->pin_type
== PIN_TYPE_BUS
)));
1392 if (conn
->type
== CONN_MIDPOINT
) {
1393 /* If it's a mid-line connection, we can stop already. */
1394 conn_type
= CONN_MIDPOINT
;
1401 /* Draw a midpoint, if necessary */
1402 if ((conn_type
== CONN_MIDPOINT
)
1403 || ((object
->type
== OBJ_NET
) && (conn_count
> 1))) {
1404 eda_renderer_draw_junction_cue (renderer
, x
, y
, is_bus
);
1408 /* Only things left to be drawn are end point cues */
1409 if (!eda_renderer_is_drawable_color (renderer
, NET_ENDPOINT_COLOR
, TRUE
))
1411 eda_renderer_set_color (renderer
, NET_ENDPOINT_COLOR
);
1413 switch (object
->type
) {
1416 /* If less than one thing was connected to this end of the net
1417 * segment or pin, draw box cue */
1418 if (conn_count
> 0) break;
1420 eda_cairo_center_box (renderer
->priv
->cr
,
1421 EDA_RENDERER_CAIRO_FLAGS (renderer
),
1422 -1, -1, x
, y
, CUE_BOX_SIZE
, CUE_BOX_SIZE
);
1423 cairo_fill (renderer
->priv
->cr
);
1429 g_return_if_reached ();
1434 eda_renderer_draw_mid_cues (EdaRenderer
*renderer
, OBJECT
*object
)
1437 for (iter
= object
->conn_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
1438 CONN
*conn
= (CONN
*) iter
->data
;
1440 if (conn
->type
== CONN_MIDPOINT
) {
1441 int is_bus
= ((object
->type
== OBJ_BUS
)
1442 || (conn
->other_object
->type
== OBJ_BUS
)
1443 || ((conn
->other_object
->type
== OBJ_PIN
)
1444 && (conn
->other_object
->pin_type
== PIN_TYPE_BUS
)));
1445 eda_renderer_draw_junction_cue (renderer
, conn
->x
, conn
->y
, is_bus
);
1451 eda_renderer_draw_junction_cue (EdaRenderer
*renderer
, int x
, int y
, int is_bus
)
1453 double width
= (is_bus
? BUS_WIDTH
: NET_WIDTH
);
1454 double radius
= (is_bus
? JUNCTION_CUE_SIZE_BUS
: JUNCTION_CUE_SIZE_NET
) / 2.0;
1456 if (!eda_renderer_is_drawable_color (renderer
, JUNCTION_COLOR
, 1)) {
1460 eda_cairo_center_arc (renderer
->priv
->cr
, EDA_RENDERER_CAIRO_FLAGS (renderer
),
1461 width
, -1, x
, y
, radius
, 0, 360);
1462 eda_renderer_set_color (renderer
, JUNCTION_COLOR
);
1463 cairo_fill (renderer
->priv
->cr
);
1466 /* ================================================================
1468 * ================================================================ */
1471 eda_renderer_get_user_bounds (EdaRenderer
*renderer
, OBJECT
*object
,
1472 double *left
, double *top
,
1473 double *right
, double *bottom
)
1475 g_return_val_if_fail (EDA_IS_RENDERER (renderer
), FALSE
);
1477 return EDA_RENDERER_GET_CLASS (renderer
)->user_bounds (renderer
, object
,
1483 eda_renderer_default_get_user_bounds (EdaRenderer
*renderer
, OBJECT
*object
,
1484 double *left
, double *top
,
1485 double *right
, double *bottom
)
1487 g_return_val_if_fail ((object
!= NULL
), FALSE
);
1488 g_return_val_if_fail ((renderer
->priv
->cr
!= NULL
), FALSE
);
1490 switch (object
->type
) {
1492 return eda_renderer_get_text_user_bounds (renderer
, object
,
1493 left
, top
, right
, bottom
);
1501 case OBJ_PLACEHOLDER
:
1505 /* No rendered bounds available for most OBJECT types. */
1508 g_return_val_if_reached (FALSE
);
1513 eda_renderer_get_text_user_bounds (EdaRenderer
*renderer
, OBJECT
*object
,
1514 double *left
, double *top
,
1515 double *right
, double *bottom
)
1517 PangoRectangle inked_rect
, logical_rect
;
1518 PangoAttrList
*attr_list
;
1519 PangoAttrIterator
*attr_iterator
;
1520 gboolean has_overbars
;
1522 /* First check if this is hidden text. */
1523 if (object
->visibility
== INVISIBLE
1524 && !EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_TEXT_HIDDEN
)) {
1528 /* Also, check that we actually need to display a string */
1529 if (object
->text
->disp_string
== NULL
)
1532 cairo_save (renderer
->priv
->cr
);
1534 /* Set up the text and check it worked. */
1535 if (!eda_renderer_prepare_text (renderer
, object
))
1538 /* Figure out the bounds, send them back. Note that Pango thinks in
1539 * device coordinates, but we need world coordinates. */
1540 pango_layout_get_pixel_extents (renderer
->priv
->pl
,
1541 &inked_rect
, &logical_rect
);
1543 /* The logic for factoring overbar/strikethrough into the text
1544 * extents is hard-coded into Pango, so we need to simulate this
1545 * as good as we can here. */
1546 attr_list
= pango_layout_get_attributes (renderer
->priv
->pl
);
1547 attr_iterator
= pango_attr_list_get_iterator (attr_list
);
1548 has_overbars
= pango_attr_iterator_next (attr_iterator
);
1549 pango_attr_iterator_destroy (attr_iterator
);
1551 /* Since we can't access the values which we'd need for getting
1552 * the height exactly right and since the overbar goes up *almost*
1553 * to zero, just pretend it does go up to zero. */
1554 inked_rect
.height
+= inked_rect
.y
;
1556 /* The overbar reaches out beyond the ink dimensions to the left
1557 * and right. Checking whether the left-/rightmost letter is
1558 * actually covered by an overbar would be overkill, so just
1559 * assume the whole logical width is covered by the overbar. */
1560 inked_rect
.x
= logical_rect
.x
;
1561 inked_rect
.width
= logical_rect
.width
;
1564 *left
= (double) inked_rect
.x
;
1565 *top
= (double) inked_rect
.y
;
1566 *right
= (double) inked_rect
.x
+ inked_rect
.width
;
1567 *bottom
= (double) inked_rect
.y
+ inked_rect
.height
;
1568 cairo_user_to_device (renderer
->priv
->cr
, left
, top
);
1569 cairo_user_to_device (renderer
->priv
->cr
, right
, bottom
);
1571 cairo_restore (renderer
->priv
->cr
);
1573 cairo_device_to_user (renderer
->priv
->cr
, left
, top
);
1574 cairo_device_to_user (renderer
->priv
->cr
, right
, bottom
);
1580 /* ================================================================
1581 * MISCELLANEOUS (CREATION, DESTRUCTION, ACCESSORS)
1582 * ================================================================ */
1585 eda_renderer_new (cairo_t
*cr
, PangoContext
*pc
)
1587 return g_object_new (EDA_TYPE_RENDERER
,
1588 "cairo-context", cr
,
1589 "pango-context", pc
,
1594 eda_renderer_destroy (EdaRenderer
*renderer
)
1596 g_object_unref (G_OBJECT (renderer
));
1600 eda_renderer_get_cairo_context (EdaRenderer
*renderer
)
1603 g_return_val_if_fail (EDA_IS_RENDERER (renderer
), NULL
);
1604 g_object_get (G_OBJECT (renderer
), "cairo-context", &cr
, NULL
);
1609 eda_renderer_get_hinting_enabled (EdaRenderer
*renderer
)
1611 g_return_val_if_fail (EDA_IS_RENDERER (renderer
), FALSE
);
1612 return EDA_RENDERER_CHECK_FLAG (renderer
, FLAG_HINTING
);
1616 eda_renderer_get_color_map (EdaRenderer
*renderer
)
1619 g_return_val_if_fail (EDA_IS_RENDERER (renderer
), NULL
);
1620 g_object_get (G_OBJECT (renderer
), "color-map", &map
, NULL
);
1625 eda_renderer_set_color_map (EdaRenderer
*renderer
, GArray
*map
)
1627 g_return_if_fail (EDA_IS_RENDERER (renderer
));
1628 g_object_set (G_OBJECT (renderer
), "color-map", map
, NULL
);
1632 eda_renderer_get_cairo_flags (EdaRenderer
*renderer
)
1634 g_return_val_if_fail (EDA_IS_RENDERER (renderer
), 0);
1635 return EDA_RENDERER_CAIRO_FLAGS (renderer
);