gschem: Register a function with libgeda to provide accurate text bounds
[geda-gaf/pcjc2.git] / gschem / src / o_text.c
blob84dbeb3d468eb0f68ba94c4ec7c36ed9d0a59ea2
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2008 Ales Hvezda
4 * Copyright (C) 1998-2008 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <math.h>
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
32 #include "gschem.h"
34 #ifdef HAVE_LIBDMALLOC
35 #include <dmalloc.h>
36 #endif
38 #undef DEBUG_TEXT
41 char *unescape_text_and_overbars (char *text, PangoAttrList *attrs)
43 char *p, *sp, *strip_text;
44 char *overbar_start = NULL;
45 int escape = FALSE;
47 /* The unescaped text is alwasys shorter than the original
48 string, so just allocate the same ammount of memory. */
49 sp = strip_text = g_malloc (strlen (text) + 1);
51 for (p = text; p != NULL; p++) {
52 int finish_overbar = FALSE;
54 /* If we find an escape character "\", we note it and continue looping */
55 if (!escape && *p == '\\') {
56 escape = TRUE;
57 continue;
60 if (escape && *p == '_') {
61 /* Overbar start or end sequence */
62 if (overbar_start != NULL) {
63 finish_overbar = TRUE;
64 } else {
65 overbar_start = sp;
67 } else {
68 /* just append the character, which may have been escaped */
69 *sp++ = *p;
71 escape = FALSE;
73 if (overbar_start != NULL &&
74 (finish_overbar || *p == '\0')) {
75 PangoAttribute *attr;
77 attr = gschem_pango_attr_overbar_new (TRUE);
78 attr->start_index = overbar_start - strip_text;
79 attr->end_index = sp - strip_text;
80 pango_attr_list_insert (attrs, attr);
81 overbar_start = NULL;
84 /* end of the string, stop iterating */
85 if (*p == '\0')
86 break;
89 return strip_text;
93 float calculate_font_size (GSCHEM_TOPLEVEL *w_current, TEXT *text)
95 TOPLEVEL *toplevel = w_current->toplevel;
96 float font_size_px;
98 /* This is probably the more "theoretically" accurate scale factor: */
99 // font_size_px = SCREENabs(toplevel, text->size * 1000) / 72.0;
100 /* But the magic number used in libgeda/src/o_text_basic.c is 26 mil for a 2 pt font */
101 // font_size_px = SCREENabs (toplevel, 13 * text->size * 1000) / 1000.;
103 /* Scale by a magic number */
104 /* TODO: Define this magic number somewhere */
105 font_size_px = (float)SCREENabs(toplevel, text->size * 1000) / 72.0 * 1.3;
107 /* Clamp the minimum font-size at 1px */
108 /* TODO: Decide if we should switch to some kind of placeholder,
109 * or just skip drawing these elements at a certain size */
110 if (font_size_px < 1.0)
111 font_size_px = 1.0;
113 return font_size_px;
117 /*! \todo Finish function documentation!!!
118 * \brief
119 * \par Function Description
122 int o_text_get_rendered_bounds (void *user_data, OBJECT *o_current,
123 int *min_x, int *min_y,
124 int *max_x, int *max_y)
126 GSCHEM_TOPLEVEL *w_current = user_data;
127 TOPLEVEL *toplevel = w_current->toplevel;
128 PangoFontDescription *desc;
129 PangoLayout *layout;
130 char *font_string;
131 char *unescaped;
132 cairo_t *cr;
133 float font_size_px;
134 int sx, sy;
135 float x, y;
136 PangoFontMetrics *font_metrics;
137 PangoRectangle logical_rect;
138 PangoRectangle inked_rect;
139 PangoContext *context;
140 PangoAttrList *attrs;
141 int left, top, width, height;
143 g_return_val_if_fail (o_current != NULL, FALSE);
144 g_return_val_if_fail (o_current->text != NULL, FALSE);
146 if (o_current->visibility == INVISIBLE &&
147 !toplevel->show_hidden_text)
148 return FALSE;
150 if (o_current->text->disp_string == NULL)
151 return FALSE;
153 cr = gdk_cairo_create (w_current->drawable);
154 layout = pango_cairo_create_layout (cr);
156 WORLDtoSCREEN(toplevel, o_current->text->x, o_current->text->y, &sx, &sy);
158 font_size_px = calculate_font_size (w_current, o_current->text);
160 context = pango_layout_get_context (layout);
161 // font_string = g_strdup_printf ("Helvetica %fpx\n", font_size_px);
162 font_string = g_strdup_printf ("Arial %fpx\n", font_size_px);
163 desc = pango_font_description_from_string (font_string);
164 g_free (font_string);
165 pango_layout_set_font_description (layout, desc);
166 font_metrics = pango_context_get_metrics (context, desc, NULL);
167 pango_font_description_free (desc);
169 attrs = pango_attr_list_new ();
170 unescaped = unescape_text_and_overbars (o_current->text->disp_string, attrs);
172 pango_layout_set_text (layout, unescaped, -1);
173 g_free (unescaped);
175 pango_layout_set_attributes (layout, attrs);
176 pango_attr_list_unref (attrs);
178 pango_layout_get_pixel_extents (layout, &inked_rect, &logical_rect);
180 /*! \bug Here be dragons */
181 /*! \bug Should be using font metrics for vertical alignment */
182 #define Y_LOWER 0 // ?
183 #define Y_MIDDLE ((logical_rect.height - pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE - inked_rect.y) / 2.) // ?
184 #define Y_UPPER (logical_rect.height - pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE - inked_rect.y) // ?
186 #define X_LEFT 0 // ?
187 #define X_MIDDLE -(logical_rect.width / 2.) // ?
188 #define X_RIGHT -logical_rect.width // ?
190 switch (o_current->text->alignment) {
192 default:
193 fprintf (stderr, "BUG\n");
194 /* Fall through to LOWER_LEFT case */
195 case LOWER_LEFT: y = Y_LOWER; x = X_LEFT; break;
196 case MIDDLE_LEFT: y = Y_MIDDLE; x = X_LEFT; break;
197 case UPPER_LEFT: y = Y_UPPER; x = X_LEFT; break;
198 case LOWER_MIDDLE: y = Y_LOWER; x = X_MIDDLE; break;
199 case MIDDLE_MIDDLE: y = Y_MIDDLE; x = X_MIDDLE; break;
200 case UPPER_MIDDLE: y = Y_UPPER; x = X_MIDDLE; break;
201 case LOWER_RIGHT: y = Y_LOWER; x = X_RIGHT; break;
202 case MIDDLE_RIGHT: y = Y_MIDDLE; x = X_RIGHT; break;
203 case UPPER_RIGHT: y = Y_UPPER; x = X_RIGHT; break;
206 #undef Y_LOWER
207 #undef Y_MIDDLE
208 #undef Y_UPPER
209 #undef X_LEFT
210 #undef X_MIDDLE
211 #undef X_RIGHT
213 /* Special case turns upside-down text back upright */
214 if (o_current->text->angle == 180) {
215 x = -x - logical_rect.width;
216 y = -y + logical_rect.height; /*! /bug Might need font metrics instead */
219 if (o_current->text->angle == 90) {
220 left = y + logical_rect.y - logical_rect.height +
221 pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE;
222 top = -x - logical_rect.x - logical_rect.width;
223 width = logical_rect.height;
224 height = logical_rect.width;
225 } else if (o_current->text->angle == 270) {
226 left = -y - logical_rect.y -
227 pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE;
228 top = x + logical_rect.x;
229 width = logical_rect.height;
230 height = logical_rect.width;
231 } else {
232 /* No rotation */
233 left = x + logical_rect.x;
234 top = y + logical_rect.y - logical_rect.height +
235 pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE;
236 width = logical_rect.width;
237 height = logical_rect.height;
240 pango_font_metrics_unref (font_metrics);
242 SCREENtoWORLD (toplevel, sx + left, sy + top + height, min_x, min_y);
243 SCREENtoWORLD (toplevel, sx + left + width, sy + top, max_x, max_y);
245 g_object_unref (layout);
246 cairo_destroy (cr);
248 return TRUE;
252 /*! \todo Finish function documentation!!!
253 * \brief
254 * \par Function Description
257 void o_text_draw_lowlevel(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
259 TOPLEVEL *toplevel = w_current->toplevel;
260 PangoFontDescription *desc;
261 char *font_string;
262 char *unescaped;
263 cairo_t *cr = w_current->cr;
264 float font_size_px;
265 int sx, sy;
266 float x, y;
267 PangoFontMetrics *font_metrics;
268 PangoRectangle logical_rect;
269 PangoRectangle inked_rect;
270 PangoContext *context;
271 PangoAttrList *attrs;
273 #ifdef DEBUG_TEXT
274 double px = 1;
275 double dashlength;
276 #endif
278 g_return_if_fail (o_current != NULL);
279 g_return_if_fail (o_current->text != NULL);
281 if (o_current->visibility == INVISIBLE &&
282 !toplevel->show_hidden_text)
283 return;
285 if (o_current->text->disp_string == NULL) return;
286 WORLDtoSCREEN(toplevel, o_current->text->x, o_current->text->y, &sx, &sy);
288 font_size_px = calculate_font_size (w_current, o_current->text);
290 context = pango_layout_get_context (w_current->pl);
291 // pango_cairo_context_set_resolution (context, double dpi);
292 // font_string = g_strdup_printf ("Helvetica %fpx\n", font_size_px);
293 font_string = g_strdup_printf ("Arial %fpx\n", font_size_px);
294 desc = pango_font_description_from_string (font_string);
295 g_free (font_string);
296 pango_layout_set_font_description (w_current->pl, desc);
297 font_metrics = pango_context_get_metrics (context, desc, NULL);
298 pango_font_description_free (desc);
300 attrs = pango_attr_list_new ();
301 unescaped = unescape_text_and_overbars (o_current->text->disp_string, attrs);
303 pango_layout_set_text (w_current->pl, unescaped, -1);
304 g_free (unescaped);
306 pango_layout_set_attributes (w_current->pl, attrs);
307 pango_attr_list_unref (attrs);
309 pango_layout_get_pixel_extents (w_current->pl, &inked_rect, &logical_rect);
311 /*! \bug Here be dragons */
312 /*! \bug Should be using font metrics for vertical alignment */
313 #define Y_LOWER 0 // ?
315 /* Non gschem back-compat centering of multi-line text. Uses inked extents to cheat at a nice center position */
316 //#define Y_MIDDLE ((pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE - inked_rect.y) / 2.) // ?
317 //#define Y_UPPER (pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE - inked_rect.y) // ?
319 /* Gschem back-compat centering of multi-line text. Uses inked extents to cheat at a nice center position */
320 #define Y_MIDDLE ((logical_rect.height - pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE - inked_rect.y) / 2.) // ?
321 #define Y_UPPER (logical_rect.height - pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE - inked_rect.y) // ?
323 /* Centering on font metrics. Is possibly not gschem back-compat centering multi-line text */
324 //#define Y_MIDDLE (pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE / 2.) // ?
325 //#define Y_UPPER (pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE) // ?
327 #define X_LEFT 0 // ?
328 #define X_MIDDLE -(logical_rect.width / 2.) // ?
329 #define X_RIGHT -logical_rect.width // ?
331 switch (o_current->text->alignment) {
333 default:
334 fprintf (stderr, "BUG\n");
335 /* Fall through to LOWER_LEFT case */
336 case LOWER_LEFT: y = Y_LOWER; x = X_LEFT; break;
337 case MIDDLE_LEFT: y = Y_MIDDLE; x = X_LEFT; break;
338 case UPPER_LEFT: y = Y_UPPER; x = X_LEFT; break;
339 case LOWER_MIDDLE: y = Y_LOWER; x = X_MIDDLE; break;
340 case MIDDLE_MIDDLE: y = Y_MIDDLE; x = X_MIDDLE; break;
341 case UPPER_MIDDLE: y = Y_UPPER; x = X_MIDDLE; break;
342 case LOWER_RIGHT: y = Y_LOWER; x = X_RIGHT; break;
343 case MIDDLE_RIGHT: y = Y_MIDDLE; x = X_RIGHT; break;
344 case UPPER_RIGHT: y = Y_UPPER; x = X_RIGHT; break;
347 cairo_save (cr);
349 cairo_translate (cr, sx, sy);
351 /* Special case turns upside-down text back upright */
352 if (o_current->text->angle == 180) {
353 x = -x - logical_rect.width;
354 y = -y + Y_UPPER;
355 } else {
356 cairo_rotate (cr, - M_PI * o_current->text->angle / 180.);
359 #ifdef DEBUG_TEXT
361 /* Pick an arbitrary size constant for the construction lines */
362 // px = SCREENabs (toplevel, 2 * 10); /* Includes * 10 factor for precision */
363 px = 20;
364 /* Threshold the drawing to be above a certain size */
365 if (px < 2)
366 px = 0;
367 px = px / 10.;
369 if (px != 0.0) {
370 /* baseline, descent, ascent, height */
371 cairo_set_line_width (cr, 2 * px);
372 dashlength = 9 * px;
373 cairo_set_dash (cr, &dashlength, 1, 0);
375 /* Underline logical text rect in green, y coord is as gschem text origin */
376 cairo_set_source_rgba (cr, 0, 0.6, 0, 0.5);
377 cairo_move_to (cr, x + logical_rect.x, y);
378 cairo_rel_line_to (cr, logical_rect.width, 0);
379 cairo_stroke (cr);
381 /* Underline descent height in red */
382 cairo_set_source_rgba (cr, 1, 0, 0, 1);
383 cairo_move_to (cr, x + logical_rect.x, y + pango_font_metrics_get_descent (font_metrics)/ PANGO_SCALE);
384 cairo_rel_line_to (cr, logical_rect.width, 0);
385 cairo_stroke (cr);
387 /* Overbar ascent height in yellow */
388 cairo_set_source_rgba (cr, 1, 1, 0, 1);
389 cairo_move_to (cr, x + logical_rect.x, y - pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE);
390 cairo_rel_line_to (cr, logical_rect.width, 0);
391 cairo_stroke (cr);
393 /* Pango doesn't seem to have this */
394 // cairo_move_to (cr, x + logical_rect.x, y - font_extents.height);
395 // cairo_rel_line_to (cr, logical_rect.width, 0);
396 cairo_stroke (cr);
398 /* extents: width & height in blue*/
399 cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
400 cairo_set_line_width (cr, px);
401 dashlength = 3 * px;
402 cairo_set_dash (cr, &dashlength, 1, 0);
403 cairo_rectangle (cr, x + logical_rect.x, y - logical_rect.y + pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE,
404 logical_rect.width, - logical_rect.height);
405 cairo_stroke (cr);
407 #endif
409 /* Text */
410 gschem_cairo_set_source_color (cr,
411 (toplevel->override_color != -1) ?
412 x_color_lookup (toplevel->override_color) :
413 x_color_lookup (o_current->color));
415 // cairo_move_to (cr, x, y - logical_rect.height - logical_rect.y);
416 // cairo_move_to (cr, x, y - pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE);
417 cairo_move_to (cr, x, y - logical_rect.height + pango_font_metrics_get_descent (font_metrics) / PANGO_SCALE);
419 gschem_pango_show_layout (cr, w_current->pl);
421 #ifdef DEBUG_TEXT
422 if (px != 0.0) {
423 /* show layout origin point in black */
424 cairo_arc (cr, x, y - pango_font_metrics_get_ascent (font_metrics) / PANGO_SCALE, 3 * px, 0, 2 * M_PI);
425 cairo_set_source_rgba (cr, 0.0, 0, 0, 0.5);
426 cairo_fill (cr);
428 /* bearing */
429 cairo_set_dash (cr, NULL, 0, 0);
430 cairo_set_line_width (cr, 2 * px);
431 cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
432 cairo_move_to (cr, x, y);
433 cairo_rel_line_to (cr, logical_rect.x, -logical_rect.y);
434 cairo_stroke (cr);
436 /* text's advance in blue */
437 cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
438 cairo_arc (cr, x + logical_rect.x + logical_rect.width, y - logical_rect.y,
439 3 * px, 0, 2 * M_PI);
440 cairo_fill (cr);
442 /* reference point in red */
443 cairo_arc (cr, x, y, 3 * px, 0, 2 * M_PI);
444 cairo_set_source_rgba (cr, 0.75, 0, 0, 0.5);
445 cairo_fill (cr);
447 #endif
449 #if 0
450 printf ("String %s\n", o_current->text->disp_string);
451 printf ("x %i, y %i, width %i, height%i\n", logical_rect.x, logical_rect.y, logical_rect.width, logical_rect.height);
452 printf ("x %i, y %i, width %i, height%i\n", inked_rect.x, inked_rect.y, inked_rect.width, inked_rect.height);
453 #endif
455 pango_font_metrics_unref (font_metrics);
457 cairo_restore (cr);
460 /*! \todo Finish function documentation!!!
461 * \brief
462 * \par Function Description
465 void o_text_draw_rectangle(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
467 TOPLEVEL *toplevel = w_current->toplevel;
468 int left=0, right=0, top=0, bottom=0;
469 GdkColor *color;
471 /* text is too small so go through and draw a rectangle in
472 it's place */
474 /* NOTE THAT THE TOP AND BOTTOM ARE REVERSED THROUGHT THE WHOLE OF GEDA FOR WORLD COORDS */
475 WORLDtoSCREEN( toplevel, o_current->w_left, o_current->w_bottom, &left, &top );
476 WORLDtoSCREEN( toplevel, o_current->w_right, o_current->w_top, &right, &bottom );
478 if (toplevel->override_color != -1 ) { /* Override */
479 color = x_get_color (toplevel->override_color);
480 } else {
481 color = x_get_color (o_current->color);
483 gdk_gc_set_foreground(w_current->gc, color);
485 if (toplevel->DONT_REDRAW == 0) {
486 gdk_draw_rectangle (w_current->drawable,
487 w_current->gc,
488 FALSE,
489 left,
490 top,
491 right - left,
492 bottom - top);
496 /*! \todo Finish function documentation!!!
497 * \brief
498 * \par Function Description
501 void o_text_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
503 TOPLEVEL *toplevel = w_current->toplevel;
504 int screen_x1, screen_y1;
505 int small_dist, offset;
507 g_return_if_fail (o_current != NULL);
508 g_return_if_fail (o_current->type == OBJ_TEXT);
509 g_return_if_fail (o_current->text != NULL);
511 if (toplevel->DONT_REDRAW == 1 ||
512 (o_current->visibility == INVISIBLE && !toplevel->show_hidden_text)) {
513 return;
516 if (!w_current->fast_mousepan || !w_current->doing_pan) {
517 o_text_draw_lowlevel(w_current, o_current);
518 //return;
519 /* Indicate on the schematic that the text is invisible by */
520 /* drawing a little I on the screen at the origin */
521 if (o_current->visibility == INVISIBLE && toplevel->show_hidden_text) {
522 if (toplevel->override_color != -1 ) {
523 gdk_gc_set_foreground(w_current->gc,
524 x_get_color(toplevel->override_color));
525 } else {
527 gdk_gc_set_foreground(w_current->gc,
528 x_get_color(w_current->lock_color));
531 offset = SCREENabs(toplevel, 10);
532 small_dist = SCREENabs(toplevel, 20);
533 WORLDtoSCREEN( toplevel, o_current->text->x, o_current->text->y, &screen_x1, &screen_y1 );
534 screen_x1 += offset;
535 screen_y1 += offset;
536 if (toplevel->DONT_REDRAW == 0) {
537 /* Top part of the I */
538 gdk_draw_line (w_current->drawable, w_current->gc,
539 screen_x1,
540 screen_y1,
541 screen_x1+small_dist,
542 screen_y1);
543 /* Middle part of the I */
544 gdk_draw_line (w_current->drawable, w_current->gc,
545 screen_x1+small_dist/2,
546 screen_y1,
547 screen_x1+small_dist/2,
548 screen_y1+small_dist);
549 /* Bottom part of the I */
550 gdk_draw_line (w_current->drawable, w_current->gc,
551 screen_x1,
552 screen_y1+small_dist,
553 screen_x1+small_dist,
554 screen_y1+small_dist);
558 } else {
559 if (w_current->doing_pan) {
560 o_text_draw_rectangle(w_current, o_current);
561 return;
565 /* DEBUG */
566 // o_text_draw_rectangle(w_current, o_current);
568 /* return if text origin marker displaying is disabled */
569 if (w_current->text_origin_marker == FALSE) {
570 return;
573 small_dist = SCREENabs(toplevel, 10);
575 /* Switch of mark drawing at small sizes */
576 if (small_dist < 1) /* TODO: Define this somewhere? */
577 return;
579 /* Test to see what happens if we only display the mark for selected text */
580 if (!o_current->selected)
581 return;
583 WORLDtoSCREEN( toplevel, o_current->text->x, o_current->text->y, &screen_x1, &screen_y1 );
585 /* this is not really a fix, but a lame patch */
586 /* not having this will cause a bad draw of things when coords */
587 /* get close to the 2^15 limit of X */
588 if (screen_x1+small_dist > 32767 || screen_y1+small_dist > 32767) {
589 return;
592 if (toplevel->override_color != -1 ) {
593 gdk_gc_set_foreground(w_current->gc,
594 x_get_color(toplevel->override_color));
595 } else {
597 gdk_gc_set_foreground(w_current->gc,
598 x_get_color(w_current->lock_color));
601 if (toplevel->DONT_REDRAW == 0) {
603 /* reference point */
604 #if 1
605 gschem_cairo_set_source_color (w_current->cr,
606 (toplevel->override_color != -1) ?
607 x_color_lookup (toplevel->override_color) :
608 x_color_lookup (w_current->lock_color));
609 cairo_set_line_width (w_current->cr, 1);
610 cairo_move_to (w_current->cr, screen_x1 - small_dist, screen_y1 - small_dist);
611 cairo_line_to (w_current->cr, screen_x1 + small_dist, screen_y1 + small_dist);
612 cairo_move_to (w_current->cr, screen_x1 - small_dist, screen_y1 + small_dist);
613 cairo_line_to (w_current->cr, screen_x1 + small_dist, screen_y1 - small_dist);
615 cairo_stroke (w_current->cr);
616 #endif
618 #if 0
619 gschem_cairo_set_line_type (w_current->cr, TYPE_SOLID,
620 1, -1, -1);
621 o_line_draw_cairo (w_current->cr,
622 (toplevel->override_color != -1 ) ?
623 x_get_color(toplevel->override_color) :
624 x_get_color(w_current->lock_color),
625 CAIRO_LINE_CAP_BUTT,
626 screen_x1-small_dist,
627 screen_y1+small_dist,
628 screen_x1+small_dist,
629 screen_y1-small_dist,
631 o_line_draw_cairo (w_current->cr,
632 (toplevel->override_color != -1 ) ?
633 x_get_color(toplevel->override_color) :
634 x_get_color(w_current->lock_color),
635 CAIRO_LINE_CAP_BUTT,
636 screen_x1+small_dist,
637 screen_y1+small_dist,
638 screen_x1-small_dist,
639 screen_y1-small_dist,
641 #endif
646 /*! \todo Finish function documentation!!!
647 * \brief
648 * \par Function Description
651 void o_text_draw_xor(GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
653 TOPLEVEL *toplevel = w_current->toplevel;
654 int top, bottom, left, right;
655 int color, factor;
657 if (o_current->visibility == INVISIBLE && !toplevel->show_hidden_text) {
658 return;
661 /* always display text which is 12 or larger */
662 factor = (int) toplevel->page_current->to_world_x_constant;
663 if ((factor < w_current->text_display_zoomfactor) ||
664 o_current->text->size >= 12 ||
665 w_current->text_feedback == ALWAYS) {
666 int sdx, sdy;
667 sdx = SCREENabs (toplevel, dx);
668 sdy = -SCREENabs (toplevel, dy);
669 cairo_save (w_current->cr);
670 cairo_translate (w_current->cr, sdx, sdy);
671 o_text_draw_lowlevel (w_current, o_current);
672 cairo_restore (w_current->cr);
674 } else {
675 /* text is too small so go through and draw a line in
676 it's place */
677 WORLDtoSCREEN(toplevel, o_current->w_left + dx, o_current->w_bottom + dy, &left, &top);
678 WORLDtoSCREEN(toplevel, o_current->w_right + dx, o_current->w_top + dy, &right, &bottom);
680 if (o_current->saved_color != -1) {
681 color = o_current->saved_color;
682 } else {
683 color = o_current->color;
686 gdk_gc_set_foreground(w_current->outline_xor_gc,
687 x_get_darkcolor(color));
689 gdk_draw_rectangle (w_current->drawable,
690 w_current->outline_xor_gc,
691 FALSE,
692 left,
693 top,
694 right - left,
695 bottom - top);
700 /*! \todo Finish function documentation!!!
701 * \brief
702 * \par Function Description
705 void o_text_prepare_place(GSCHEM_TOPLEVEL *w_current, char *text)
707 TOPLEVEL *toplevel = w_current->toplevel;
709 /* Insert the new object into the buffer at world coordinates (0,0).
710 * It will be translated to the mouse coordinates during placement. */
712 w_current->first_wx = 0;
713 w_current->first_wy = 0;
715 w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
717 /* remove the old place list if it exists */
718 s_delete_object_glist(toplevel, toplevel->page_current->place_list);
719 toplevel->page_current->place_list = NULL;
721 /* here you need to add OBJ_TEXT when it's done */
722 toplevel->page_current->place_list =
723 g_list_append(toplevel->page_current->place_list,
724 o_text_new(toplevel,
725 OBJ_TEXT, w_current->text_color,
726 0, 0, LOWER_LEFT, 0, /* zero is angle */
727 text,
728 w_current->text_size,
729 /* has to be visible so you can place it */
730 /* visibility is set when you create the object */
731 VISIBLE, SHOW_NAME_VALUE));
733 w_current->inside_action = 1;
734 i_set_state (w_current, ENDTEXT);
738 /*! \todo Finish function documentation!!!
739 * \brief
740 * \par Function Description
743 void o_text_edit(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
745 /* you need to check to make sure only one object is selected */
746 /* no actually this is okay... not here in o_edit */
747 text_edit_dialog(w_current,
748 o_text_get_string (w_current->toplevel, o_current),
749 o_current->text->size, o_current->text->alignment);
752 /*! \todo Finish function documentation!!!
753 * \brief
754 * \par Function Description
757 void o_text_edit_end(GSCHEM_TOPLEVEL *w_current, char *string, int len, int text_size,
758 int text_alignment)
760 TOPLEVEL *toplevel = w_current->toplevel;
761 OBJECT *object;
762 GList *s_current;
763 int numselect;
765 /* skip over head */
766 s_current = geda_list_get_glist( toplevel->page_current->selection_list );
767 numselect = g_list_length( geda_list_get_glist( toplevel->page_current->selection_list ));
769 while(s_current != NULL) {
770 object = (OBJECT *) s_current->data;
772 if (object) {
773 if (object->type == OBJ_TEXT) {
774 o_invalidate (w_current, object);
776 object->text->size = text_size;
777 object->text->alignment = text_alignment;
779 /* probably the text object should be extended to carry a color */
780 /* and we should pass it here with a function parameter (?) */
781 object->saved_color = w_current->edit_color;
783 /* only change text string if there is only ONE text object selected */
784 if (numselect == 1 && string) {
785 o_text_set_string (w_current->toplevel, object, string);
786 /* handle slot= attribute, it's a special case */
787 if (g_ascii_strncasecmp (string, "slot=", 5) == 0) {
788 o_slot_end (w_current, string, strlen (string));
791 o_text_recreate(toplevel, object);
792 o_invalidate (w_current, object);
796 s_current = g_list_next(s_current);
799 toplevel->page_current->CHANGED = 1;
800 o_undo_savestate(w_current, UNDO_ALL);
803 /*! \todo Finish function documentation!!!
804 * \brief
805 * \par Function Description
807 * \note
808 * The object passed in should be the REAL object, NOT any copy in any
809 * selection list
811 void o_text_change(GSCHEM_TOPLEVEL *w_current, OBJECT *object, char *string,
812 int visibility, int show)
814 TOPLEVEL *toplevel = w_current->toplevel;
815 if (object == NULL) {
816 return;
819 if (object->type != OBJ_TEXT) {
820 return;
823 /* erase old object */
824 o_invalidate (w_current, object);
826 /* second change the real object */
827 o_text_set_string (toplevel, object, string);
829 object->visibility = visibility;
830 object->show_name_value = show;
831 o_text_recreate(toplevel, object);
832 o_invalidate (w_current, object);
834 /* handle slot= attribute, it's a special case */
835 if (g_ascii_strncasecmp (string, "slot=", 5) == 0) {
836 o_slot_end (w_current, string, strlen (string));
839 toplevel->page_current->CHANGED = 1;