1 /* Lepton EDA attribute editor
2  * Copyright (C) 2003-2010 Stuart D. Brorson.
3  * Copyright (C) 2003-2016 gEDA Contributors
4  * Copyright (C) 2017-2021 Lepton EDA Contributors
5  *
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.
10  *
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.
15  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*------------------------------------------------------------------*/
22 /*! \file
23  * \brief Functions for manipulating LeptonObjects.
24  *
25  * This file holds functions involved in manipulating the
26  * LeptonObject data structure.  LeptonObject is defined in
27  * libgeda.  An LeptonObject is a graphical primitive normally
28  * used in gschem.  Example LeptonObjects: some text, a component, a
29  * pin, a line, etc.
30  *
31  * The functions herein are functions which I wrote as wrappers to the
32  * fcns in libgeda.
33  */
34 
35 #include <config.h>
36 
37 #include <stdio.h>
38 #ifdef HAVE_STRING_H
39 #include <string.h>
40 #endif
41 #include <math.h>
42 
43 /*------------------------------------------------------------------
44  * Gattrib specific includes
45  *------------------------------------------------------------------*/
46 #include <liblepton/liblepton.h>
47 #include "../include/struct.h"     /* typdef and struct declarations */
48 #include "../include/prototype.h"  /* function prototypes */
49 #include "../include/globals.h"
50 #include "../include/gettext.h"
51 
52 
53 /*------------------------------------------------------------------
54  * Gattrib specific defines
55  *------------------------------------------------------------------*/
56 #define DEFAULT_TEXT_SIZE 10
57 
58 static LeptonObject*
59 s_object_attrib_add_attrib_in_object (LeptonPage *active_page,
60                                       char *text_string,
61                                       gint visibility,
62                                       gint show_name_value,
63                                       LeptonObject * object);
64 
65 /* ===================  Public Functions  ====================== */
66 
67 /*------------------------------------------------------------------*/
68 /*! \brief Add an attribute to an LeptonObject
69  *
70  * This fcn adds a new attrib to o_current, when o_current is a
71  * component.  It does it in the following
72  * way:
73  * -# It creates an object -- "attrib_graphic" -- and fills it in.
74  * -# It gets the position info from o_current's refdes attrib and
75  *    calls o_text_new() to add position info and name=value string
76  *    to attrib_graphic.
77  * -# It calls o_attrib_add() to wrap attrib_graphic with (attribute LeptonObject )
78  * \param toplevel LeptonToplevel structure
79  * \param o_current pointer to object to add attribute to
80  * \param new_attrib_name name of the attribute to add
81  * \param new_attrib_value value of the attribute to add
82  * \param visibility Is the attribute visible?
83  * \param show_name_value Control visibility of name and value.
84  */
85 void
s_object_add_comp_attrib_to_object(LeptonToplevel * toplevel,LeptonObject * o_current,char * new_attrib_name,char * new_attrib_value,gint visibility,gint show_name_value)86 s_object_add_comp_attrib_to_object (LeptonToplevel *toplevel,
87                                     LeptonObject *o_current,
88                                     char *new_attrib_name,
89                                     char *new_attrib_value,
90                                     gint visibility,
91                                     gint show_name_value)
92 {
93   LeptonPage *active_page = NULL;
94   char *name_value_pair;
95   g_return_if_fail (o_current != NULL);
96 
97   active_page = lepton_toplevel_get_page_current (toplevel);
98 
99   /* One last sanity check, then add attrib */
100   if (strlen(new_attrib_value) != 0) {
101     name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
102     s_object_attrib_add_attrib_in_object (active_page,
103                                           name_value_pair,
104                                           visibility,
105                                           show_name_value,
106                                           o_current);
107   }
108 
109   return;
110 
111 }
112 
113 
114 /*------------------------------------------------------------------*/
115 /*!
116  * \todo This needs to be filled in.
117  */
118 void
s_object_add_net_attrib_to_object(LeptonToplevel * toplevel,LeptonObject * o_current,char * new_attrib_name,char * new_attrib_value)119 s_object_add_net_attrib_to_object (LeptonToplevel *toplevel,
120                                    LeptonObject *o_current,
121                                    char *new_attrib_name,
122                                    char *new_attrib_value)
123 {
124   /* TBD */
125 }
126 
127 
128 /*------------------------------------------------------------------*/
129 /*! \brief Add a new attribute to an pin LeptonObject
130  *
131  * Add a new attribute to o_current, when o_current is a
132  * pin.  It does it in the following
133  * way:
134  * -# It creates an object -- "attrib_graphic" -- and fills it in.
135  * -# It gets the position info from o_current's refdes attrib and
136  *    calls o_text_new() to add position info and name=value string
137  *    to attrib_graphic.
138  * -# It calls o_attrib_add() to wrap attrib_graphic with (attribute
139       LeptonObject)
140  * \param toplevel LeptonToplevel structure
141  * \param o_current Pointer to pin object
142  * \param new_attrib_name Name of attribute to add
143  * \param new_attrib_value Value of attribute to add
144  * \todo Do I really need separate fcns for comps, nets, and
145  * pins???
146  */
147 void
s_object_add_pin_attrib_to_object(LeptonToplevel * toplevel,LeptonObject * o_current,char * new_attrib_name,char * new_attrib_value)148 s_object_add_pin_attrib_to_object (LeptonToplevel *toplevel,
149                                    LeptonObject *o_current,
150                                    char *new_attrib_name,
151                                    char *new_attrib_value)
152 {
153   LeptonPage *active_page = NULL;
154   char *name_value_pair;
155   g_return_if_fail (o_current != NULL);
156 
157   active_page = lepton_toplevel_get_page_current (toplevel);
158 
159   /* One last sanity check */
160   if (strlen(new_attrib_value) != 0) {
161     name_value_pair = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
162     s_object_attrib_add_attrib_in_object (active_page,
163                                           name_value_pair,
164                                           INVISIBLE,
165                                           SHOW_NAME_VALUE,
166                                           o_current);
167   }
168 
169   return;
170 }
171 
172 
173 /*------------------------------------------------------------------*/
174 /*! \brief Replace attribute value in object
175  *
176  * Find the instance of attrib_name on o_current, and
177  * replace its value with the new_attrib_value.
178  *
179  * \param o_current object to operate on
180  * \param new_attrib_name name of attribute to replace
181  * \param new_attrib_value value to set attribute to
182  * \param visibility set visibility of attribute
183  * \param show_name_value set visibility of attribute name and value
184  */
185 void
s_object_replace_attrib_in_object(LeptonObject * o_current,char * new_attrib_name,char * new_attrib_value,gint visibility,gint show_name_value)186 s_object_replace_attrib_in_object(LeptonObject *o_current,
187                                   char *new_attrib_name,
188                                   char *new_attrib_value,
189                                   gint visibility,
190                                   gint show_name_value)
191 {
192   GList *a_iter;
193   LeptonObject *a_current;
194   char *old_attrib_text;
195   char *old_attrib_name;
196   char *new_attrib_text;
197 
198 
199   a_iter = lepton_object_get_attribs (o_current);
200   while (a_iter != NULL) {
201     a_current = (LeptonObject*) a_iter->data;
202     if (lepton_object_is_text (a_current)
203         && a_current->text != NULL) {  /* found an attribute */
204 
205       /* may need to check more thoroughly here. . . . */
206       old_attrib_text = g_strdup (lepton_text_object_get_string (a_current));
207       old_attrib_name = u_basic_breakup_string(old_attrib_text, '=', 0);
208 
209       if (strcmp(old_attrib_name, new_attrib_name) == 0) {
210         /* create attrib=value text string */
211         new_attrib_text = g_strconcat(new_attrib_name, "=", new_attrib_value, NULL);
212         lepton_text_object_set_string (a_current, new_attrib_text);
213         if (visibility != LEAVE_VISIBILITY_ALONE)
214           lepton_text_object_set_visibility (a_current, visibility);
215         if (show_name_value != LEAVE_NAME_VALUE_ALONE)
216           lepton_text_object_set_show (a_current, show_name_value);
217         g_free(new_attrib_text);
218         g_free(old_attrib_text);
219         g_free(old_attrib_name);
220         return;     /* we are done -- leave. */
221       } else {
222         g_free(old_attrib_text);
223         g_free(old_attrib_name);
224       }  /* if (strcmp . . . . */
225     } /* if (a_current . . . . */
226 
227     a_iter = g_list_next (a_iter);
228   }  /* while */
229 
230   /* if we get here, it's because we have failed to find the attrib on the component.
231    * This is an error condition. */
232   fprintf (stderr, "s_object_replace_attrib_in_object: ");
233   fprintf (stderr,
234           _("Failed to find the attrib %1$s on the component.\n"),
235           new_attrib_name);
236   exit(-1);
237 }
238 
239 
240 /*------------------------------------------------------------------*/
241 /*!
242  * \brief Remove attribute from object
243  *
244  * Remove an attribute from an object.
245  * \param toplevel LeptonToplevel structure
246  * \param o_current Object to remove attribute from
247  * \param new_attrib_name Name of attribute to remove
248  */
249 void
s_object_remove_attrib_in_object(LeptonToplevel * toplevel,LeptonObject * o_current,char * new_attrib_name)250 s_object_remove_attrib_in_object (LeptonToplevel *toplevel,
251                                   LeptonObject *o_current,
252                                   char *new_attrib_name)
253 {
254   GList *a_iter;
255   LeptonObject *a_current;
256   LeptonObject *attribute_object;
257   char *old_attrib_text;
258   char *old_attrib_name;
259 
260   a_iter = lepton_object_get_attribs (o_current);
261   while (a_iter != NULL) {
262     a_current = (LeptonObject*) a_iter->data;
263     if (lepton_object_is_text (a_current)
264         && a_current->text != NULL) {  /* found an attribute */
265 
266       /* may need to check more thoroughly here. . . . */
267       old_attrib_text = g_strdup (lepton_text_object_get_string (a_current));
268       old_attrib_name = u_basic_breakup_string(old_attrib_text, '=', 0);
269 
270       if (strcmp(old_attrib_name, new_attrib_name) == 0) {
271         /* We've found the attrib.  Delete it and then return. */
272 
273         g_debug ("s_object_remove_attrib_in_object: "
274                  "Removing attrib with name = %1$s\n", old_attrib_name);
275 
276         attribute_object = a_current;
277         s_object_delete_text_object_in_object (toplevel, attribute_object);
278 
279         g_free(old_attrib_text);
280         g_free(old_attrib_name);
281         return;     /* we are done -- leave. */
282       }
283     g_free(old_attrib_text);
284     g_free(old_attrib_name);
285     }
286     a_iter = g_list_next (a_iter);
287   }
288 
289   /* if we get here, it's because we have failed to find the attrib on the component.
290    * This is an error condition. */
291   fprintf (stderr, "s_object_remove_attrib_in_object: ");
292   fprintf (stderr,
293            _("Failed to find the attrib %1$s on the component.\n"),
294            new_attrib_name);
295   exit(-1);
296 }
297 
298 
299 
300 /*------------------------------------------------------------------*/
301 /*! \brief Attach attribute to object.
302  *
303  * Attach the name=value pair to the LeptonObject "object". This function
304  * was stolen from gschem/src/o_attrib.c:o_attrib_add_attrib and
305  * hacked for gattrib.
306  * \param toplevel LeptonToplevel to operate on
307  * \param text_string
308  * \param visibility
309  * \param show_name_value
310  * \param o_current
311  * \returns pointer to the object
312  * \todo Does it need to return LeptonObject?
313  */
314 static LeptonObject *
s_object_attrib_add_attrib_in_object(LeptonPage * active_page,char * text_string,int visibility,int show_name_value,LeptonObject * o_current)315 s_object_attrib_add_attrib_in_object (LeptonPage *active_page,
316                                       char *text_string,
317                                       int visibility,
318                                       int show_name_value,
319                                       LeptonObject * o_current)
320 {
321   int world_x = -1, world_y = -1;
322   int color;
323   LeptonObject *new_obj;
324 
325   g_return_val_if_fail ((o_current != NULL), NULL);
326 
327   /* creating a toplevel or unattached attribute */
328   /* get coordinates of where to place the text object */
329   switch (lepton_object_get_type (o_current)) {
330   case (OBJ_COMPONENT):
331     world_x = lepton_component_object_get_x (o_current);
332     world_y = lepton_component_object_get_y (o_current);
333     color = ATTRIBUTE_COLOR;
334     break;
335 
336   case (OBJ_NET):
337     world_x = lepton_component_object_get_x (o_current);
338     world_y = lepton_component_object_get_y (o_current);
339     color = ATTRIBUTE_COLOR;
340     break;
341 
342   default:
343     fprintf (stderr, "s_object_attrib_add_attrib_in_object: ");
344     fprintf (stderr, _("Trying to add attrib to non-component or non-net!\n"));
345     exit(-1);
346   }
347 
348   /* first create text item */
349   g_debug ("s_object_attrib_add_attrib_in_object: "
350            "About to attach new text attrib with properties:\n"
351            "     color = %d\n"
352            "     text_string = %s\n"
353            "     visibility = %d\n"
354            "     show_name_value = %d\n",
355            color, text_string, visibility, show_name_value);
356 
357   new_obj = lepton_text_object_new (color,
358                                     world_x,
359                                     world_y,
360                                     LOWER_LEFT,
361                                     0, /* zero is angle */
362                                     text_string,
363                                     DEFAULT_TEXT_SIZE,
364                                     visibility,
365                                     show_name_value);
366   lepton_page_append (active_page, new_obj);
367 
368   /* Now the current active page contains the new text item. */
369 
370   /* now attach the attribute to the object */
371   /* remember that o_current contains the object to get the attribute */
372   o_attrib_attach (new_obj, o_current, FALSE);
373 
374   lepton_page_set_changed (active_page, 1);
375 
376   return new_obj;
377 }
378 
379 
380 
381 
382 /*------------------------------------------------------------------*/
383 /*! \brief Delete text object
384  *
385  * Delete the text object pointed to by text_object.  This function
386  * was shamelessly stolen from gschem/src/o_delete.c and hacked
387  * for gattrib by SDB.
388  * \param toplevel LeptonToplevel to be operated on
389  * \param test_object text object to be deleted
390  */
391 void
s_object_delete_text_object_in_object(LeptonToplevel * toplevel,LeptonObject * text_object)392 s_object_delete_text_object_in_object (LeptonToplevel *toplevel,
393                                        LeptonObject * text_object)
394 {
395   LeptonPage *active_page = lepton_toplevel_get_page_current (toplevel);
396   lepton_object_delete (text_object);
397   lepton_page_set_changed (active_page, 1);
398 }
399 
400 
401 /*------------------------------------------------------------------*/
402 /*! \brief Ensure object has a symbol file
403  *
404  * This verifies that the object has a non-null symbol file.
405  *
406  * \returns 0 = valid symbol file, 1 = no symbol file found.
407  */
s_object_has_sym_file(LeptonObject * object)408 int s_object_has_sym_file(LeptonObject *object)
409 {
410   char *filename;
411 
412   filename = lepton_component_object_get_basename (object);
413   if (filename != NULL) {
414     g_debug ("s_object_has_sym_file: Object has sym file = %s.\n", filename);
415     return 0;
416   } else {
417     g_debug ("s_object_has_sym_file: Found object with no attached symbol file.\n");
418     return 1;
419   }
420 }
421