libgeda
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * libgeda - gEDA's library 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00062 #include <config.h> 00063 #include <missing.h> 00064 00065 #include <stdio.h> 00066 #include <math.h> 00067 #include <sys/stat.h> 00068 #ifdef HAVE_STRING_H 00069 #include <string.h> 00070 #endif 00071 #ifdef HAVE_UNISTD_H 00072 #include <unistd.h> 00073 #endif 00074 00075 #include "libgeda_priv.h" 00076 00077 #ifdef HAVE_LIBDMALLOC 00078 #include <dmalloc.h> 00079 #endif 00080 00091 #define GEDA_FONT_FACTOR 1.3 00092 00099 #define PRINT_LINE_SPACING 1.12 00100 00102 int tab_in_chars = 8; 00103 00113 static void update_disp_string (OBJECT *object) 00114 { 00115 char *name = NULL; 00116 char *value = NULL; 00117 TEXT *text = object->text; 00118 00119 g_free (text->disp_string); 00120 00121 if (o_attrib_get_name_value (object, &name, &value)) { 00122 switch (object->show_name_value) { 00123 case (SHOW_NAME_VALUE): 00124 text->disp_string = g_strdup (text->string); 00125 break; 00126 00127 case (SHOW_NAME): 00128 if (name[0] != '\0') { 00129 text->disp_string = g_strdup (name); 00130 } else { 00131 g_critical ("Got an improper attribute: %s\n", 00132 text->string); 00133 text->disp_string = g_strdup ("invalid"); 00134 } 00135 break; 00136 00137 case (SHOW_VALUE): 00138 if (value[0] != '\0') { 00139 text->disp_string = g_strdup(value); 00140 } else { 00141 g_critical ("Got an improper attribute: %s\n", 00142 text->string); 00143 text->disp_string = g_strdup ("invalid"); 00144 } 00145 break; 00146 } 00147 /* free the strings allocated by o_attrib_get_name_value */ 00148 g_free(name); 00149 g_free(value); 00150 } else { 00151 text->disp_string = g_strdup (text->string); 00152 } 00153 } 00154 00166 int world_get_text_bounds(TOPLEVEL *toplevel, OBJECT *o_current, int *left, 00167 int *top, int *right, int *bottom) 00168 { 00169 if (toplevel->rendered_text_bounds_func != NULL) { 00170 return 00171 toplevel->rendered_text_bounds_func (toplevel->rendered_text_bounds_data, 00172 o_current, 00173 left, top, right, bottom); 00174 } 00175 00176 return FALSE; 00177 } 00178 00189 gboolean o_text_get_position (TOPLEVEL *toplevel, gint *x, gint *y, 00190 OBJECT *object) 00191 { 00192 *x = object->text->x; 00193 *y = object->text->y; 00194 return TRUE; 00195 } 00196 00197 00206 int o_text_num_lines(const char *string) 00207 { 00208 int line_count = 0; 00209 const gchar *aux; 00210 gunichar current_char; 00211 00212 if (string == NULL) { 00213 return 0; 00214 } 00215 00216 /* if it's not null, then we have at least one line */ 00217 line_count++; 00218 /* Count how many \n are in the string */ 00219 aux = string; 00220 while (aux && ((gunichar) (*aux) != 0) ) { 00221 current_char = g_utf8_get_char_validated(aux, -1); 00222 if (current_char == '\n') 00223 line_count++; 00224 aux = g_utf8_find_next_char(aux, NULL); 00225 } 00226 00227 return (line_count); 00228 } 00229 00230 00251 OBJECT *o_text_new(TOPLEVEL *toplevel, 00252 char type, int color, int x, int y, int alignment, 00253 int angle, const char *string, int size, 00254 int visibility, int show_name_value) 00255 { 00256 OBJECT *new_node=NULL; 00257 TEXT *text; 00258 00259 if (string == NULL) { 00260 return(NULL); 00261 } 00262 00263 new_node = s_basic_new_object(type, "text"); 00264 00265 text = (TEXT *) g_malloc(sizeof(TEXT)); 00266 00267 text->string = g_strdup (string); 00268 text->disp_string = NULL; /* We'll fix this up later */ 00269 text->length = strlen(string); 00270 text->size = size; 00271 text->alignment = alignment; 00272 text->x = x; 00273 text->y = y; 00274 text->angle = angle; 00275 00276 new_node->text = text; 00277 00278 new_node->color = color; 00279 o_set_visibility (toplevel, new_node, visibility); 00280 new_node->show_name_value = show_name_value; 00281 00282 update_disp_string (new_node); 00283 00284 /* Update bounding box */ 00285 new_node->w_bounds_valid = FALSE; 00286 00287 return new_node; 00288 } 00289 00297 void o_text_recalc(TOPLEVEL *toplevel, OBJECT *o_current) 00298 { 00299 int left, right, top, bottom; 00300 00301 if ((!o_is_visible (toplevel, o_current)) && 00302 (!toplevel->show_hidden_text)) { 00303 return; 00304 } 00305 00306 if ( !world_get_text_bounds(toplevel, o_current, &left, &top, &right, &bottom) ) 00307 return; 00308 00309 o_current->w_left = left; 00310 o_current->w_top = top; 00311 o_current->w_right = right; 00312 o_current->w_bottom = bottom; 00313 o_current->w_bounds_valid = TRUE; 00314 } 00315 00330 OBJECT *o_text_read (TOPLEVEL *toplevel, 00331 const char *first_line, 00332 TextBuffer *tb, 00333 unsigned int release_ver, 00334 unsigned int fileformat_ver, 00335 GError **err) 00336 { 00337 OBJECT *new_obj; 00338 char type; 00339 int x, y; 00340 int color; 00341 int size; 00342 int visibility; 00343 int show_name_value; 00344 int angle; 00345 int alignment; 00346 int num_lines = 0; 00347 int i; 00348 char* string = NULL; 00349 GString *textstr; 00350 00351 if (fileformat_ver >= 1) { 00352 if (sscanf(first_line, "%c %d %d %d %d %d %d %d %d %d\n", &type, &x, &y, 00353 &color, &size, 00354 &visibility, &show_name_value, 00355 &angle, &alignment, &num_lines) != 10) { 00356 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object")); 00357 return NULL; 00358 } 00359 } else if (release_ver < VERSION_20000220) { 00360 /* yes, above less than (not less than and equal) is correct. The format */ 00361 /* change occurred in 20000220 */ 00362 if (sscanf(first_line, "%c %d %d %d %d %d %d %d\n", &type, &x, &y, 00363 &color, &size, 00364 &visibility, &show_name_value, 00365 &angle) != 8) { 00366 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object")); 00367 return NULL; 00368 } 00369 alignment = LOWER_LEFT; /* older versions didn't have this */ 00370 num_lines = 1; /* only support a single line */ 00371 } else { 00372 if (sscanf(first_line, "%c %d %d %d %d %d %d %d %d\n", &type, &x, &y, 00373 &color, &size, 00374 &visibility, &show_name_value, 00375 &angle, &alignment) != 9) { 00376 g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse text object")); 00377 return NULL; 00378 } 00379 num_lines = 1; /* only support a single line */ 00380 } 00381 00382 if (size == 0) { 00383 s_log_message(_("Found a zero size text string [ %c %d %d %d %d %d %d %d %d ]\n"), type, x, y, color, size, visibility, show_name_value, angle, alignment); 00384 } 00385 00386 switch(angle) { 00387 00388 case(0): 00389 case(90): 00390 case(180): 00391 case(270): 00392 break; 00393 00394 default: 00395 s_log_message(_("Found an unsupported text angle [ %c %d %d %d %d %d %d %d %d ]\n"), 00396 type, x, y, color, size, visibility, show_name_value, angle, alignment); 00397 s_log_message(_("Setting angle to 0\n")); 00398 angle=0; 00399 break; 00400 00401 } 00402 00403 switch(alignment) { 00404 case(LOWER_LEFT): 00405 case(MIDDLE_LEFT): 00406 case(UPPER_LEFT): 00407 case(LOWER_MIDDLE): 00408 case(MIDDLE_MIDDLE): 00409 case(UPPER_MIDDLE): 00410 case(LOWER_RIGHT): 00411 case(MIDDLE_RIGHT): 00412 case(UPPER_RIGHT): 00413 00414 break; 00415 00416 default: 00417 s_log_message(_("Found an unsupported text alignment [ %c %d %d %d %d %d %d %d %d ]\n"), 00418 type, x, y, color, size, visibility, show_name_value, angle, alignment); 00419 s_log_message(_("Setting alignment to LOWER_LEFT\n")); 00420 alignment = LOWER_LEFT; 00421 break; 00422 } 00423 00424 if (color < 0 || color > MAX_COLORS) { 00425 s_log_message(_("Found an invalid color [ %s ]\n"), first_line); 00426 s_log_message(_("Setting color to default color\n")); 00427 color = DEFAULT_COLOR; 00428 } 00429 00430 g_assert(num_lines && num_lines > 0); 00431 00432 textstr = g_string_new (""); 00433 for (i = 0; i < num_lines; i++) { 00434 const gchar *line; 00435 00436 line = s_textbuffer_next_line (tb); 00437 00438 if (line == NULL) { 00439 g_string_free (textstr, TRUE); 00440 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Unexpected end-of-file after %d lines"), i); 00441 return NULL; 00442 } 00443 00444 textstr = g_string_append (textstr, line); 00445 } 00446 /* retrieve the character string from the GString */ 00447 string = g_string_free (textstr, FALSE); 00448 00449 string = remove_last_nl(string); 00450 00451 /* convert the character string to UTF-8 if necessary */ 00452 if (!g_utf8_validate (string, -1, NULL)) { 00453 /* if it is not utf-8, it is ISO_8859-15 */ 00454 gchar *tmp = g_convert (string, strlen (string), 00455 "UTF-8", "ISO_8859-15", 00456 NULL, NULL, NULL); 00457 if (tmp == NULL) { 00458 fprintf (stderr, "Failed to convert text string to UTF-8: %s.\n", 00459 string); 00460 } else { 00461 /* successfully converted string, now use tmp as string */ 00462 g_free (string); 00463 string = tmp; 00464 } 00465 } 00466 00467 new_obj = o_text_new(toplevel, type, color, x, y, 00468 alignment, angle, string, 00469 size, visibility, show_name_value); 00470 g_free(string); 00471 00472 return new_obj; 00473 } 00474 00475 00485 char *o_text_save(TOPLEVEL *toplevel, OBJECT *object) 00486 { 00487 int x, y; 00488 int size; 00489 char *string; 00490 char *buf; 00491 int num_lines; 00492 00493 x = object->text->x; 00494 y = object->text->y; 00495 00496 string = object->text->string; 00497 size = object->text->size; 00498 00499 /* string can have multiple lines (seperated by \n's) */ 00500 num_lines = o_text_num_lines(string); 00501 00502 buf = g_strdup_printf ("%c %d %d %d %d %d %d %d %d %d\n%s", object->type, 00503 x, y, object->color, size, 00504 o_is_visible (toplevel, object) ? VISIBLE : INVISIBLE, 00505 object->show_name_value, object->text->angle, 00506 object->text->alignment, num_lines, string); 00507 00508 return(buf); 00509 } 00510 00519 void o_text_recreate(TOPLEVEL *toplevel, OBJECT *o_current) 00520 { 00521 o_emit_pre_change_notify (toplevel, o_current); 00522 update_disp_string (o_current); 00523 o_current->w_bounds_valid = FALSE; 00524 o_emit_change_notify (toplevel, o_current); 00525 } 00526 00536 void o_text_translate_world(TOPLEVEL *toplevel, 00537 int dx, int dy, OBJECT *o_current) 00538 { 00539 o_current->text->x = o_current->text->x + dx; 00540 o_current->text->y = o_current->text->y + dy; 00541 00542 /* Update bounding box */ 00543 o_current->w_bounds_valid = FALSE; 00544 } 00545 00554 OBJECT *o_text_copy(TOPLEVEL *toplevel, OBJECT *o_current) 00555 { 00556 OBJECT *new_obj; 00557 00558 new_obj = o_text_new (toplevel, OBJ_TEXT, o_current->color, 00559 o_current->text->x, o_current->text->y, 00560 o_current->text->alignment, 00561 o_current->text->angle, 00562 o_current->text->string, 00563 o_current->text->size, 00564 o_is_visible (toplevel, o_current) ? VISIBLE : INVISIBLE, 00565 o_current->show_name_value); 00566 00567 return new_obj; 00568 } 00569 00570 00582 void o_text_print_text_string(FILE *fp, char *string, int unicode_count, 00583 gunichar *unicode_table) 00584 { 00585 int j; 00586 gchar *aux; 00587 gunichar current_char, c; 00588 00589 if (!string) 00590 { 00591 return; 00592 } 00593 00594 aux = string; 00595 00596 fprintf(fp, "("); 00597 00598 while (aux && ((gunichar) (*aux) != 0)) { 00599 current_char = g_utf8_get_char_validated(aux, -1); 00600 if (current_char == '(' || current_char == ')' || current_char == '\\') { 00601 fprintf(fp, "\\"); 00602 } 00603 00604 c = current_char; 00605 if (c >= 128) { 00606 current_char = '?'; 00607 if (unicode_count) { 00608 for (j = 0; j < unicode_count; j++) 00609 if (c == unicode_table[j]) { 00610 current_char = j + 128; 00611 break; 00612 } 00613 } 00614 } 00615 00616 00617 if (current_char == '\t') { 00618 /* Output eight spaces instead of the tab character */ 00619 fprintf(fp, " "); 00620 } else { 00621 fprintf(fp, "%c", current_char); 00622 } 00623 00624 aux = g_utf8_find_next_char(aux, NULL); 00625 } 00626 00627 fprintf(fp,") "); 00628 } 00629 00630 00643 void o_text_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, 00644 int origin_x, int origin_y, 00645 int unicode_count, gunichar *unicode_table) 00646 { 00647 int alignment; 00648 char *centering_control = NULL; 00649 char *p,*s; 00650 char *output_string = NULL; 00651 char *name = NULL; 00652 char *value = NULL; 00653 int x, y, angle, len; 00654 float font_size; 00655 00656 00657 if (!o_current->text->string) { 00658 return; 00659 } 00660 00661 f_print_set_color(toplevel, fp, o_current->color); 00662 00663 00664 if (o_attrib_get_name_value (o_current, &name, &value)) { 00665 switch(o_current->show_name_value) { 00666 case(SHOW_NAME_VALUE): 00667 output_string = g_strdup(o_current->text->string); 00668 break; 00669 00670 case(SHOW_NAME): 00671 if (name[0] != '\0') { 00672 output_string = g_strdup(name); 00673 } else { 00674 fprintf(stderr, 00675 "Got an improper attribute: %s\n", 00676 o_current->text->string); 00677 output_string = g_strdup("invalid"); 00678 } 00679 break; 00680 00681 case(SHOW_VALUE): 00682 if (value[0] != '\0') { 00683 output_string = g_strdup(value); 00684 } else { 00685 /* you probably can remove this now... */ 00686 /* since improper attributes will never get here */ 00687 fprintf(stderr, 00688 "Got an improper attribute: %s\n", 00689 o_current->text->string); 00690 output_string = g_strdup("invalid"); 00691 } 00692 break; 00693 00694 default: 00695 g_return_if_reached (); 00696 00697 } 00698 } else { 00699 output_string = g_strdup(o_current->text->string); 00700 } 00701 00702 /* Apply alignment map to apply when text is 180 degrees rotated. 00703 * We want the text on the printer to appear upside right, even 00704 * though mathematically it aught to be upside down. To make this 00705 * work, we will reset the angle to 0, when it's equal to 180 00706 * degrees, then apply a transformation to the origin location as if 00707 * the text was rotated about that point. E.g. if the text origin 00708 * was at the lower left, and the text was rotated by 180 degrees, 00709 * it would be as if the origin was at the upper right. The same 00710 * reasoning has been applied to all 8 other text origins. 00711 * MIDDLE_MIDDLE maps to itself. 00712 */ 00713 alignment = o_current->text->alignment; 00714 angle = o_current->text->angle; 00715 if(angle == 180) { 00716 angle = 0; /* reset angle to 0 to make text upright */ 00717 switch(alignment) { 00718 case(LOWER_LEFT): alignment = UPPER_RIGHT; 00719 break; 00720 case(MIDDLE_LEFT): alignment = MIDDLE_RIGHT; 00721 break; 00722 case(UPPER_LEFT): alignment = LOWER_RIGHT; 00723 break; 00724 case(LOWER_MIDDLE): alignment = UPPER_MIDDLE; 00725 break; 00726 case(MIDDLE_MIDDLE): alignment = MIDDLE_MIDDLE; 00727 break; 00728 case(UPPER_MIDDLE): alignment = LOWER_MIDDLE; 00729 break; 00730 case(LOWER_RIGHT): alignment = UPPER_LEFT; 00731 break; 00732 case(MIDDLE_RIGHT): alignment = MIDDLE_LEFT; 00733 break; 00734 case(UPPER_RIGHT): alignment = LOWER_LEFT; 00735 break; 00736 } 00737 } 00738 00739 /* Create an appropriate control string for the centering. */ 00740 switch(alignment) { 00741 /* hcenter rjustify vcenter vjustify */ 00742 case(LOWER_LEFT): centering_control = "false false false false"; 00743 break; 00744 case(MIDDLE_LEFT): centering_control = "false false true false"; 00745 break; 00746 case(UPPER_LEFT): centering_control = "false false false true"; 00747 break; 00748 case(LOWER_MIDDLE): centering_control = "true false false false"; 00749 break; 00750 case(MIDDLE_MIDDLE): centering_control = "true false true false"; 00751 break; 00752 case(UPPER_MIDDLE): centering_control = "true false false true"; 00753 break; 00754 case(LOWER_RIGHT): centering_control = "false true false false"; 00755 break; 00756 case(MIDDLE_RIGHT): centering_control = "false true true false"; 00757 break; 00758 case(UPPER_RIGHT): centering_control = "false true false true"; 00759 break; 00760 } 00761 00762 font_size = o_text_get_font_size_in_points (toplevel, o_current) 00763 / 72.0 * 1000.0; 00764 fprintf(fp,"%s %f [",centering_control, font_size * PRINT_LINE_SPACING); 00765 00766 /* split the line at each newline and print them */ 00767 p = output_string; /* Current point */ 00768 s = output_string; /* Start of the current string */ 00769 len = strlen(output_string)+1; 00770 while(len != 0) { 00771 /* Have we reached the end of a line? */ 00772 if((*p == '\n') || (*p == '\0')) { 00773 /* Yes, replace the newline with a NULL and output the string */ 00774 *p = '\0'; 00775 o_text_print_text_string(fp,s,unicode_count,unicode_table); 00776 /* Update output string start for next string */ 00777 s = p+1; /* One past the current character. */ 00778 } 00779 p++; /* Advance to next character */ 00780 len--; /* Keep track of how many characters left to process */ 00781 } 00782 00783 /* Finish up with the rest of the text print command */ 00784 /* Collect pertinent info about the text location */ 00785 x = o_current->text->x; 00786 y = o_current->text->y; 00787 fprintf(fp,"] %d %d %d %f text\n",angle,x,y,font_size); 00788 00789 00790 g_free(output_string); 00791 g_free(name); 00792 g_free(value); 00793 } 00794 00795 00808 void o_text_rotate_world(TOPLEVEL *toplevel, 00809 int world_centerx, int world_centery, 00810 int angle, OBJECT *object) 00811 { 00812 int x, y; 00813 int newx, newy; 00814 00815 g_return_if_fail(object != NULL); 00816 g_return_if_fail(object->type == OBJ_TEXT); 00817 00818 object->text->angle = ( object->text->angle + angle ) % 360; 00819 00820 x = object->text->x + (-world_centerx); 00821 y = object->text->y + (-world_centery); 00822 00823 rotate_point_90(x, y, angle, &newx, &newy); 00824 00825 x = newx + (world_centerx); 00826 y = newy + (world_centery); 00827 00828 o_text_translate_world(toplevel, x-object->text->x, y-object->text->y, object); 00829 00830 o_text_recreate(toplevel, object); 00831 } 00832 00833 00844 void o_text_mirror_world(TOPLEVEL *toplevel, 00845 int world_centerx, int world_centery, 00846 OBJECT *object) 00847 { 00848 int origx, origy; 00849 int x, y; 00850 00851 origx = object->text->x; 00852 origy = object->text->y; 00853 00854 x = origx + (-world_centerx); 00855 y = origy + (-world_centery); 00856 00857 if ((object->text->angle%180)==0) { 00858 switch(object->text->alignment) { 00859 case(LOWER_LEFT): 00860 object->text->alignment=LOWER_RIGHT; 00861 break; 00862 00863 case(MIDDLE_LEFT): 00864 object->text->alignment=MIDDLE_RIGHT; 00865 break; 00866 00867 case(UPPER_LEFT): 00868 object->text->alignment=UPPER_RIGHT; 00869 break; 00870 00871 case(LOWER_RIGHT): 00872 object->text->alignment=LOWER_LEFT; 00873 break; 00874 00875 case(MIDDLE_RIGHT): 00876 object->text->alignment=MIDDLE_LEFT; 00877 break; 00878 00879 case(UPPER_RIGHT): 00880 object->text->alignment=UPPER_LEFT; 00881 break; 00882 00883 default: 00884 break; 00885 } 00886 } else { 00887 switch(object->text->alignment) { 00888 case(LOWER_LEFT): 00889 object->text->alignment=UPPER_LEFT; 00890 break; 00891 00892 case(UPPER_LEFT): 00893 object->text->alignment=LOWER_LEFT; 00894 break; 00895 00896 case(LOWER_RIGHT): 00897 object->text->alignment=UPPER_RIGHT; 00898 break; 00899 00900 case(UPPER_RIGHT): 00901 object->text->alignment=LOWER_RIGHT; 00902 break; 00903 00904 case(LOWER_MIDDLE): 00905 object->text->alignment=UPPER_MIDDLE; 00906 break; 00907 00908 case(UPPER_MIDDLE): 00909 object->text->alignment=LOWER_MIDDLE; 00910 break; 00911 00912 default: 00913 break; 00914 } 00915 } 00916 00917 object->text->x = -x + (world_centerx); 00918 object->text->y = y + (world_centery); 00919 00920 o_text_recreate(toplevel, object); 00921 } 00922 00938 double o_text_shortest_distance (OBJECT *object, int x, int y, int force_solid) 00939 { 00940 double dx, dy; 00941 00942 g_return_val_if_fail (object->text != NULL, G_MAXDOUBLE); 00943 00944 dx = min (x - object->w_left, object->w_right - x); 00945 dy = min (y - object->w_top, object->w_bottom - y); 00946 00947 dx = min (dx, 0); 00948 dy = min (dy, 0); 00949 00950 return sqrt ((dx * dx) + (dy * dy)); 00951 } 00952 00961 void o_text_set_string (TOPLEVEL *toplevel, OBJECT *obj, 00962 const gchar *new_string) 00963 { 00964 g_return_if_fail (toplevel != NULL); 00965 g_return_if_fail (obj != NULL); 00966 g_return_if_fail (obj->type == OBJ_TEXT); 00967 g_return_if_fail (obj->text != NULL); 00968 g_return_if_fail (new_string != NULL); 00969 00970 g_free (obj->text->string); 00971 obj->text->string = g_strdup (new_string); 00972 00973 o_text_recreate (toplevel, obj); 00974 00975 if (obj->attached_to != NULL) 00976 o_attrib_emit_attribs_changed (toplevel, obj->attached_to); 00977 } 00978 00979 00980 00990 const gchar *o_text_get_string (TOPLEVEL *toplevel, OBJECT *obj) 00991 { 00992 g_return_val_if_fail (toplevel != NULL, NULL); 00993 g_return_val_if_fail (obj != NULL, NULL); 00994 g_return_val_if_fail (obj->type == OBJ_TEXT, NULL); 00995 g_return_val_if_fail (obj->text != NULL, NULL); 00996 00997 return obj->text->string; 00998 } 00999 01009 void o_text_set_rendered_bounds_func (TOPLEVEL *toplevel, 01010 RenderedBoundsFunc func, 01011 void *user_data) { 01012 toplevel->rendered_text_bounds_func = func; 01013 toplevel->rendered_text_bounds_data = user_data; 01014 } 01015 01016 01028 double o_text_get_font_size_in_points (TOPLEVEL *toplevel, OBJECT *object) 01029 { 01030 g_return_val_if_fail (object->type == OBJ_TEXT, 0.); 01031 01032 return object->text->size * GEDA_FONT_FACTOR; 01033 }