libgeda

o_text_basic.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines