Support default return value in o_complex_get_refdes.
[geda-gaf/berndj.git] / libgeda / src / g_smob.c
blob04edba547522dbf31535ff451a0b57f7f7106c1f
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 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 <math.h>
23 #include <stdio.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
31 #include "libgeda_priv.h"
33 #ifdef HAVE_LIBDMALLOC
34 #include <dmalloc.h>
35 #endif
37 struct st_object_smob {
38 TOPLEVEL *world; /* We need this when updating schematic */
39 OBJECT *object;
42 struct st_page_smob {
43 TOPLEVEL *world; /* We need this when updating schematic */
44 PAGE *page;
47 struct st_toplevel_smob {
48 TOPLEVEL *toplevel;
51 static long attrib_smob_tag; /*! Attribute SMOB tag */
52 static long object_smob_tag; /*! Object SMOB tag */
53 static long page_smob_tag; /*! Page SMOB tag */
54 static long toplevel_smob_tag; /*! Toplevel SMOB tag */
56 /* Private function declarations */
57 static SCM g_set_attrib_value_internal(SCM attrib_smob,
58 SCM scm_value,
59 OBJECT **o_attrib,
60 char *new_string[]);
61 static void
62 custom_world_get_single_object_bounds(OBJECT *o_current,
63 int *left, int *top,
64 int *right, int *bottom,
65 GList *exclude_attrib_list,
66 GList *exclude_obj_type_list);
68 static void
69 custom_world_get_object_list_bounds(OBJECT *o_current,
70 int *left, int *top,
71 int *right, int *bottom,
72 GList *exclude_attrib_list,
73 GList *exclude_obj_type_list);
75 static SCM g_hierarchy_traversepages(SCM toplevel_smob, SCM flags);
77 /*! \brief Free attribute smob memory.
78 * \par Function Description
79 * Free the memory allocated by the attribute smob and return its size.
81 * \param [in] attrib_smob The attribute smob to free.
82 * \return Size of attribute smob.
84 static scm_sizet g_free_attrib_smob(SCM attrib_smob)
86 struct st_attrib_smob *attribute =
87 (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
89 scm_gc_free(attribute, sizeof (*attribute), "attribute");
90 return 0;
93 /*! \brief Prints attribute smob to port.
94 * \par Function Description
95 * This function prints the given attribute smob to the port.
96 * It just prints a string showing it is an attribute and its string.
98 * \param [in] attrib_smob The attribute smob.
99 * \param [in] port The port to print to.
100 * \param [in] pstate Unused.
101 * \return non-zero means success.
103 static int g_print_attrib_smob(SCM attrib_smob, SCM port,
104 scm_print_state *pstate G_GNUC_UNUSED)
106 struct st_attrib_smob *attribute =
107 (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
109 if (attribute) {
110 char const *representation = o_text_get_string(attribute->attribute);
111 scm_simple_format(port, scm_from_locale_string("#<attribute ~a>"),
112 scm_list_1(scm_from_locale_string(representation)));
115 /* non-zero means success */
116 return 1;
120 /*! \brief Creates a name-value smob
121 * \par Function Description
122 * This function Creates and returns a new attribute smob,
123 * based on the given TOPLEVEL curr_w and attribute curr_attr.
125 * \param [in] curr_attr The current attribute.
126 * \return SCM
128 SCM g_make_attrib_smob(OBJECT *curr_attr)
130 struct st_attrib_smob *smob_attribute;
132 smob_attribute = scm_gc_malloc(sizeof(struct st_attrib_smob), "attribute");
134 smob_attribute->attribute = curr_attr;
136 /* Assumes Guile version >= 1.3.2 */
137 SCM_RETURN_NEWSMOB(attrib_smob_tag, smob_attribute);
140 /*! \todo Finish function documentation!!!
141 * \brief
142 * \par Function Description
145 /* Makes a list of all attributes currently connected to object. *
146 * Principle stolen from o_attrib_return_attribs */
147 SCM g_make_attrib_smob_list(OBJECT *object)
149 OBJECT *a_current;
150 GList *a_iter;
151 SCM smob_list = SCM_EOL;
153 if (!object) {
154 return(SCM_EOL);
157 if (!object->attribs) {
158 return(SCM_EOL);
161 /* go through attribs */
162 a_iter = object->attribs;
163 while(a_iter != NULL) {
164 a_current = a_iter->data;
165 if (a_current->type == OBJ_TEXT) {
166 if (o_text_get_string(a_current)) {
167 smob_list = scm_cons(g_make_attrib_smob(a_current), smob_list);
170 a_iter = g_list_next (a_iter);
173 return smob_list;
176 /*! \brief Get name and value of attribute.
177 * \par Function Description
178 * Returns a list with the name and value of the given attribute smob
180 * \param [in] attrib_smob The attribute smob to get name and value from.
181 * \return A list containing the name and value of the attribute.
183 SCM g_get_attrib_name_value(SCM attrib_smob)
185 struct st_attrib_smob *attribute;
186 char *name = NULL;
187 char *value = NULL;
188 char const *attrib_chars = NULL;
189 SCM returned = SCM_EOL;
191 SCM_ASSERT ( SCM_NIMP(attrib_smob) &&
192 ((long) SCM_CAR(attrib_smob) == attrib_smob_tag),
193 attrib_smob, SCM_ARG1, "get-attribute-name-value");
195 attribute = (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
197 if (attribute && attribute->attribute) {
198 attrib_chars = o_text_get_string(attribute->attribute);
201 if (attrib_chars) {
202 o_attrib_get_name_value(attrib_chars, &name, &value );
203 returned = scm_cons(scm_from_locale_string(name),
204 scm_from_locale_string(value));
205 g_free(name);
206 g_free(value);
209 return returned;
212 /*! \brief Set the attribute value.
213 * \par Function Description
214 * This function puts the attribute smob name into a new_string and
215 * the new scm_value (attribute=value format). It also returns the
216 * TOPLEVEL and OBJECT pointers.
218 * \param [in] attrib_smob The attribute to update.
219 * \param [in] scm_value The new value of the attribute.
220 * \param [in,out] o_attrib Pointer to the updated attribute smob.
221 * \param [in] new_string Returns the attribute=value format string for the
222 * updated attribute.
223 * \return Always SCM_UNDEFINED
225 static SCM g_set_attrib_value_internal(SCM attrib_smob, SCM scm_value,
226 OBJECT **o_attrib,
227 char *new_string[])
229 struct st_attrib_smob *attribute;
230 char *name = NULL;
231 char *value = NULL;
232 char const *attrib_chars = NULL;
234 SCM_ASSERT ( SCM_NIMP(attrib_smob) &&
235 ((long) SCM_CAR(attrib_smob) == attrib_smob_tag),
236 attrib_smob, SCM_ARG1, "set-attribute-value!");
237 SCM_ASSERT (scm_is_string(scm_value), scm_value, SCM_ARG2,
238 "set-attribute-value!");
240 scm_dynwind_begin(0);
241 attribute = (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
242 value = scm_to_locale_string(scm_value);
243 scm_dynwind_free(value);
245 if (attribute && attribute->attribute) {
246 attrib_chars = o_text_get_string(attribute->attribute);
249 if (attrib_chars) {
250 o_attrib_get_name_value(attrib_chars, &name, NULL);
252 *new_string = g_strconcat (name, "=", value, NULL);
254 *o_attrib = attribute->attribute;
256 g_free(name);
259 scm_dynwind_end();
260 return SCM_UNDEFINED;
263 /*! \brief Calculate the attribute bounds as it has the given properties.
264 * \par Function Description
265 * Given an attribute, and a new angle, position and alignment,
266 * this function calculates the bounds of the attribute with the new properties,
267 * but without modifying the attribute.
269 * \param [in] attrib_smob The attribute.
270 * \param [in] scm_alignment The new alignment of the attribute.
271 * String with the alignment of the text. Possible values are:
272 * "" : Keep the previous alignment.
273 * "Lower Left"
274 * "Middle Left"
275 * "Upper Left"
276 * "Lower Middle"
277 * "Middle Middle"
278 * "Upper Middle"
279 * "Lower Right"
280 * "Middle Right"
281 * "Upper Right"
282 * \param [in] angle_scm The new angle of the attribute,
283 * or -1 to keep the previous angle.
284 * \param [in] x_scm The new x position of the attribute
285 * or -1 to keep the previous value.
286 * \param [in] y_scm The new y position of the attribute
287 * or -1 to keep the previous value.
288 * \return A list of the form ( (x1 x2) (y1 y2) ) with:
289 * (x1, y1): bottom left corner.
290 * (x2, y2): upper right corner.
292 SCM g_calculate_new_attrib_bounds(SCM attrib_smob, SCM scm_alignment,
293 SCM angle_scm, SCM x_scm, SCM y_scm)
295 OBJECT *object = NULL;
296 struct st_attrib_smob *attribute;
297 char *alignment_string;
298 int alignment = -2;
299 int angle = 0;
300 int x = -1, y = -1;
301 int old_angle, old_x, old_y, old_alignment;
302 int left=0, right=0, top=0, bottom=0;
303 SCM vertical = SCM_EOL;
304 SCM horizontal = SCM_EOL;
305 SCM returned = SCM_EOL;
307 SCM_ASSERT (scm_is_string(scm_alignment), scm_alignment,
308 SCM_ARG2, "calculate-new-attrib-bounds");
309 SCM_ASSERT(scm_is_integer(angle_scm),
310 angle_scm, SCM_ARG3, "calculate-new-attrib-bounds");
311 SCM_ASSERT(scm_is_integer(x_scm),
312 x_scm, SCM_ARG4, "calculate-new-attrib-bounds");
313 SCM_ASSERT(scm_is_integer(y_scm),
314 y_scm, SCM_ARG5, "calculate-new-attrib-bounds");
316 angle = scm_to_int(angle_scm);
317 x = scm_to_int(x_scm);
318 y = scm_to_int(y_scm);
320 alignment_string = scm_to_locale_string(scm_alignment);
322 if (strlen(alignment_string) == 0) {
323 alignment = -1;
325 if (strcmp(alignment_string, "Lower Left") == 0) {
326 alignment = 0;
328 if (strcmp(alignment_string, "Middle Left") == 0) {
329 alignment = 1;
331 if (strcmp(alignment_string, "Upper Left") == 0) {
332 alignment = 2;
334 if (strcmp(alignment_string, "Lower Middle") == 0) {
335 alignment = 3;
337 if (strcmp(alignment_string, "Middle Middle") == 0) {
338 alignment = 4;
340 if (strcmp(alignment_string, "Upper Middle") == 0) {
341 alignment = 5;
343 if (strcmp(alignment_string, "Lower Right") == 0) {
344 alignment = 6;
346 if (strcmp(alignment_string, "Middle Right") == 0) {
347 alignment = 7;
349 if (strcmp(alignment_string, "Upper Right") == 0) {
350 alignment = 8;
353 free(alignment_string);
355 if (alignment == -2) {
356 /* Bad specified */
357 SCM_ASSERT (scm_is_string(scm_alignment), scm_alignment,
358 SCM_ARG2, "calculate-new-attrib-bounds");
361 attribute = (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
363 SCM_ASSERT ( attribute &&
364 attribute->attribute &&
365 attribute->attribute->type == OBJ_TEXT,
366 attrib_smob, SCM_ARG1, "calculate-new-attrib-bounds");
368 object = attribute->attribute;
370 /* Store the previous values */
371 old_alignment = object->text->alignment;
372 old_angle = object->text->angle;
373 old_x = object->text->x;
374 old_y = object->text->y;
376 /* Set the new ones */
377 if (alignment != -1)
378 object->text->alignment = alignment;
379 if (angle != -1)
380 object->text->angle = angle;
381 if (x != -1)
382 object->text->x = x;
383 if (y != -1)
384 object->text->y = y;
386 o_text_recreate(object);
388 /* Get the new bounds */
389 world_get_text_bounds(object, &left, &top, &right, &bottom);
391 /* Restore the original attributes */
392 object->text->alignment = old_alignment;
393 object->text->angle = old_angle;
394 object->text->x = old_x;
395 object->text->y = old_y;
397 o_text_recreate(object);
399 /* Construct the return value */
400 horizontal = scm_cons (scm_from_int(left), scm_from_int(right));
401 vertical = scm_cons (scm_from_int(top), scm_from_int(bottom));
402 returned = scm_cons (horizontal, vertical);
404 return returned;
407 /*! \brief Initialize the framework to support an attribute smob.
408 * \par Function Description
409 * Initialize the framework to support an attribute smob.
412 void g_init_attrib_smob(void)
415 attrib_smob_tag = scm_make_smob_type("attribute",
416 sizeof (struct st_attrib_smob));
417 scm_set_smob_mark(attrib_smob_tag, 0);
418 scm_set_smob_free(attrib_smob_tag, g_free_attrib_smob);
419 scm_set_smob_print(attrib_smob_tag, g_print_attrib_smob);
421 scm_c_define_gsubr("get-attribute-name-value", 1, 0, 0,
422 g_get_attrib_name_value);
424 scm_c_define_gsubr ("get-attribute-bounds", 1, 0, 0, g_get_attrib_bounds);
425 scm_c_define_gsubr ("get-attribute-angle", 1, 0, 0, g_get_attrib_angle);
426 scm_c_define_gsubr("calculate-new-attrib-bounds", 5, 0, 0,
427 g_calculate_new_attrib_bounds);
428 /* Keep the misnamed interface around in case someone uses it. */
429 scm_c_define_gsubr("calcule-new-attrib-bounds", 5, 0, 0,
430 g_calculate_new_attrib_bounds);
432 return;
435 /*! \brief Get the bounds of an attribute.
436 * \par Function Description
437 * Get the bounds of an attribute.
438 * WARNING: top and bottom are mis-named in world-coords,
439 * top is the smallest "y" value, and bottom is the largest.
440 * Be careful! This doesn't correspond to what you'd expect,
441 * nor to the coordinate system whose origin is the bottom, left of the page.
442 * \param[in] attrib_smob the attribute.
443 * \return a list of the bounds of the <B>attrib smob</B>.
444 * The list has the format: ( (left right) (top bottom) )
446 SCM g_get_attrib_bounds(SCM attrib_smob)
448 struct st_attrib_smob *attribute;
449 SCM vertical = SCM_EOL;
450 SCM horizontal = SCM_EOL;
451 int left=0, right=0, bottom=0, top=0;
452 SCM returned = SCM_EOL;
454 SCM_ASSERT ( SCM_NIMP(attrib_smob) &&
455 ((long) SCM_CAR(attrib_smob) == attrib_smob_tag),
456 attrib_smob, SCM_ARG1, "get-attribute-bounds");
458 attribute = (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
460 if (attribute &&
461 attribute->attribute &&
462 attribute->attribute->type == OBJ_TEXT) {
463 world_get_text_bounds(attribute->attribute, &left, &top, &right, &bottom);
465 horizontal = scm_cons (scm_from_int(left), scm_from_int(right));
466 vertical = scm_cons (scm_from_int(top), scm_from_int(bottom));
467 returned = scm_cons (horizontal, vertical);
470 return returned;
473 /*! \brief Get the angle of an attribute.
474 * \par Function Description
475 * Get the angle of an attribute.
476 * \param[in] attrib_smob the attribute.
477 * \return the angle of the <B>attrib smob</B>.
479 SCM g_get_attrib_angle(SCM attrib_smob)
481 struct st_attrib_smob *attribute;
483 SCM_ASSERT ( SCM_NIMP(attrib_smob) &&
484 ((long) SCM_CAR(attrib_smob) == attrib_smob_tag),
485 attrib_smob, SCM_ARG1, "get-attribute-angle");
487 attribute = (struct st_attrib_smob *) SCM_SMOB_DATA (attrib_smob);
489 SCM_ASSERT ( attribute &&
490 attribute->attribute &&
491 attribute->attribute->text,
492 attrib_smob, SCM_ARG1, "get-attribute-angle");
494 return scm_from_int(attribute->attribute->text->angle);
497 /*! \brief Free object smob memory.
498 * \par Function Description
499 * Free the memory allocated by the object smob and return its size.
501 * \param [in] object_smob The object smob to free.
502 * \return Size of object smob.
504 static scm_sizet g_free_object_smob(SCM object_smob)
506 struct st_object_smob *object =
507 (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
509 scm_gc_free(object, sizeof (*object), "object");
510 return 0;
513 /*! \brief Prints object smob to port.
514 * \par Function Description
515 * This function prints the given object smob to the port.
516 * It just prints a string showing it is an object and the object name.
518 * \param [in] object_smob The object smob.
519 * \param [in] port The port to print to.
520 * \param [in] pstate Unused.
521 * \return non-zero means success.
523 static int g_print_object_smob(SCM object_smob, SCM port,
524 scm_print_state *pstate G_GNUC_UNUSED)
526 struct st_object_smob *object =
527 (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
529 if (object &&
530 object->object &&
531 object->object->name) {
532 char const *representation = object->object->name;
533 scm_simple_format(port, scm_from_locale_string("#<object ~a>"),
534 scm_list_1(scm_from_locale_string(representation)));
537 /* non-zero means success */
538 return 1;
541 /*! \brief Creates a object smob
542 * \par Function Description
543 * This function creates and returns a new object smob,
544 * from the given TOPLEVEL curr_w and object pointers.
546 * \param [in] curr_w The current TOPLEVEL object.
547 * \param [in] object The current object.
548 * \return SCM
550 SCM g_make_object_smob(TOPLEVEL *curr_w, OBJECT *object)
552 struct st_object_smob *smob_object;
554 g_assert(object);
556 smob_object = scm_gc_malloc(sizeof(struct st_object_smob), "object");
558 smob_object->world = curr_w;
559 smob_object->object = object;
561 /* Assumes Guile version >= 1.3.2 */
562 SCM_RETURN_NEWSMOB(object_smob_tag, smob_object);
565 /*! \brief Get all object attributes in a list.
566 * \par Function Description
567 * This function returns a list with all the attributes of a given object smob.
569 * \param [in] object_smob The object smob to get attributes from.
570 * \return A list of attributes associated with this object smob.
572 SCM g_get_object_attributes(SCM object_smob)
574 struct st_object_smob *object;
575 SCM returned = SCM_EOL;
576 GList *a_iter;
577 OBJECT *a_current;
579 SCM_ASSERT ( SCM_NIMP(object_smob) &&
580 ((long) SCM_CAR(object_smob) == object_smob_tag),
581 object_smob, SCM_ARG1, "get-object-attributes");
583 object = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
585 if (object &&
586 object->object) {
588 a_iter = object->object->attribs;
589 while (a_iter != NULL) {
590 a_current = a_iter->data;
591 if (a_current && a_current->text) {
592 returned = scm_cons(g_make_attrib_smob(a_current), returned);
594 a_iter = g_list_next (a_iter);
598 return returned;
601 /*! \brief Get the value(s) of the attributes with the given name in the
602 * given object.
603 * \par Function Description
604 * This function returns a list with all the attribute values, providing that
605 * its attribute name is the given name, in a given object smob.
607 * \param [in] object_smob The object smob to get attributes from.
608 * \param [in] scm_attrib_name The name of the attribute you want the value.
609 * \return A list of attribute values.
611 SCM g_get_attrib_value_by_attrib_name(SCM object_smob, SCM scm_attrib_name)
613 struct st_object_smob *object;
614 gchar *attrib_name=NULL;
615 SCM returned = SCM_EOL;
616 gchar *name=NULL, *value=NULL;
617 GList *a_iter;
618 OBJECT *a_current;
620 SCM_ASSERT ( SCM_NIMP(object_smob) &&
621 ((long) SCM_CAR(object_smob) == object_smob_tag),
622 object_smob, SCM_ARG1, "get-attrib-value-by-attrib-name");
624 SCM_ASSERT (scm_is_string(scm_attrib_name), scm_attrib_name,
625 SCM_ARG2, "get-attrib-value-by-attrib-name");
627 scm_dynwind_begin(0);
629 /* Get parameters */
630 object = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
631 attrib_name = scm_to_locale_string(scm_attrib_name);
632 scm_dynwind_free(attrib_name);
634 if (object && object->object) {
635 a_iter = object->object->attribs;
636 while (a_iter != NULL) {
637 a_current = a_iter->data;
638 if (a_current) {
639 o_attrib_get_name_value(o_text_get_string(a_current), &name, &value );
640 if (strcmp(name, attrib_name) == 0) {
641 returned = scm_cons(scm_from_locale_string(value), returned);
644 a_iter = g_list_next (a_iter);
648 scm_dynwind_end();
649 return returned;
652 /*! \todo Finish function documentation!!!
653 * \brief
654 * \par Function Description
657 SCM g_set_attrib_value_x(SCM attrib_smob, SCM scm_value)
659 SCM returned;
660 OBJECT *o_attrib;
661 char *new_string = NULL;
663 returned = g_set_attrib_value_internal(attrib_smob, scm_value,
664 &o_attrib, &new_string);
666 if (new_string) {
667 o_text_change(o_attrib, new_string,
668 o_attrib->visibility, o_attrib->show_name_value);
669 g_free(new_string);
672 return returned;
675 /*! \brief Get the object type.
676 * \par Function Description
677 * This function returns a string with the type of a given object smob.
679 * \param [in] object_smob The object smob to get the type from.
680 * \return A string with the type of the given object.
681 * Actually it is the object->type character converted into a string.
683 SCM g_get_object_type(SCM object_smob)
685 struct st_object_smob *object_struct;
686 OBJECT *object;
687 SCM returned = SCM_EOL;
689 SCM_ASSERT ( SCM_NIMP(object_smob) &&
690 ((long) SCM_CAR(object_smob) == object_smob_tag),
691 object_smob, SCM_ARG1, "get-object-type");
693 object_struct = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
695 g_assert(object_struct);
696 g_assert(object_struct->object);
698 object = object_struct->object;
700 returned = SCM_MAKE_CHAR((unsigned char) object->type);
702 return returned;
706 * Returns a list with coords of the ends of the given pin <B>object</B>.
707 The list is ( (x0 y0) (x1 y1) ), where the beginning is at (x0,y0) and the end at (x1,y1).
708 The active connection end of the pin is the beginning, so this function cares about the whichend property of the pin object. If whichend is 1, then it has to reverse the ends.
710 SCM g_get_pin_ends(SCM object)
712 OBJECT *o_current;
713 SCM coord1 = SCM_EOL;
714 SCM coord2 = SCM_EOL;
715 SCM coords = SCM_EOL;
716 int x1, y1, x2, y2;
718 /* Get toplevel and o_current */
719 SCM_ASSERT(g_get_data_from_object_smob(object, NULL, &o_current),
720 object, SCM_ARG1, "get-pin-ends");
722 /* Check that it is a pin object */
723 SCM_ASSERT (o_current != NULL,
724 object, SCM_ARG1, "get-pin-ends");
725 SCM_ASSERT (o_current->type == OBJ_PIN,
726 object, SCM_ARG1, "get-pin-ends");
727 SCM_ASSERT (o_current->line != NULL,
728 object, SCM_ARG1, "get-pin-ends");
730 s_basic_get_grip(o_current, GRIP_1, &x1, &y1);
731 s_basic_get_grip(o_current, GRIP_2, &x2, &y2);
733 coord1 = scm_cons(scm_from_int(x1), scm_from_int(y1));
734 coord2 = scm_cons(scm_from_int(x2), scm_from_int(y2));
735 if (o_current->whichend == 0) {
736 coords = scm_cons(coord1, scm_list(coord2));
737 } else {
738 coords = scm_cons(coord2, scm_list(coord1));
741 return coords;
744 SCM g_swap_pins(SCM component, SCM n1, SCM n2)
746 OBJECT *owner, *attrib;
747 char *packagepins, *vpads, *pin1, *pin2;
748 char *pad1 = NULL, *pad2 = NULL;
750 SCM_ASSERT(g_get_data_from_object_smob(component, NULL, &owner),
751 component, SCM_ARG1, "swap-pins");
752 SCM_ASSERT(scm_is_string(n1), n1, SCM_ARG2, "swap-pins");
753 SCM_ASSERT(scm_is_string(n2), n2, SCM_ARG3, "swap-pins");
755 scm_dynwind_begin(0);
757 pin1 = scm_to_locale_string(n1);
758 scm_dynwind_free(pin1);
759 pin2 = scm_to_locale_string(n2);
760 scm_dynwind_free(pin2);
762 /* First find which pads correspond to the pins. */
763 packagepins = o_attrib_search_name_single(owner, "packagepins", &attrib);
764 if (packagepins) {
765 char *pair, *s;
766 gboolean shorted_pads = FALSE;
768 for (s = packagepins; s != NULL; ) {
769 char *equals;
770 char *pad, *pin;
771 char **ppin, **ppad;
772 int i;
774 pair = u_basic_split(&s, ',');
775 equals = strchr(pair, '=');
777 if (!equals) {
778 /* I think this should be bad, but for now just assume identity. */
779 g_free(pair);
780 continue;
783 *equals = 0;
784 pad = pair;
785 pin = equals + 1;
787 /* If this entry assigns one of the pins, remember the pad. */
788 for (i = 0, ppad = &pad1, ppin = &pin1; i < 2;
789 i++, ppad = &pad2, ppin = &pin2) {
790 if (strcmp(pin, *ppin) == 0) {
791 if (*ppad) {
792 /* An earlier entry already used the pad. */
793 shorted_pads = TRUE;
794 g_free(*ppad);
796 *ppad = g_strdup(pad);
800 g_free(pair);
803 if (shorted_pads) {
804 char *refdes = o_complex_get_refdes(owner, _("(unknown part)"));
806 g_warning(_("Component %s #<object %s> has shorted pads\n"),
807 refdes, owner->name);
808 g_free(refdes);
811 g_free(packagepins);
813 /* If there is no package map, assume an identity map. */
814 if (!pad1) {
815 pad1 = g_strdup(pin1);
817 if (!pad2) {
818 pad2 = g_strdup(pin2);
821 vpads = o_attrib_search_name_single(owner, "vpads", &attrib);
822 if (vpads) {
823 char *pair, *s;
824 GString *newmap;
825 int pad1_seen = 0, pad2_seen = 0;
827 newmap = g_string_sized_new(0);
829 for (s = vpads; s != NULL; ) {
830 char *equals;
831 char *vpad, *pad;
833 pair = u_basic_split(&s, ',');
834 equals = strchr(pair, '=');
836 *equals = 0;
837 vpad = pair;
838 pad = equals + 1;
840 /* Do the swap. */
841 if (strcmp(pad, pad1) == 0) {
842 g_string_append_printf(newmap, ",%s=%s", vpad, pad2);
843 pad1_seen++;
844 } else if (strcmp(pad, pad2) == 0) {
845 g_string_append_printf(newmap, ",%s=%s", vpad, pad1);
846 pad2_seen++;
847 } else {
848 g_string_append_printf(newmap, ",%s=%s", vpad, pad);
852 /* Build the new attribute, skipping the leading comma. */
853 g_free(vpads);
854 vpads = g_strdup_printf("vpads=%s", newmap->len ? newmap->str + 1 : "");
855 g_string_free(newmap, TRUE);
857 if (pad1_seen != 1 || pad2_seen != 1) {
858 /* Component doesn't have exactly one of each of the named pads. */
859 char *refdes = o_complex_get_refdes(owner, _("(unknown part)"));
861 scm_dynwind_unwind_handler(g_free, refdes, SCM_F_WIND_EXPLICITLY);
862 g_warning(_("Component %s #<object %s> has broken vpads attribute\n"),
863 refdes, owner->name);
864 g_free(vpads);
865 scm_dynwind_end();
867 return SCM_BOOL_F;
870 /* Signal handler will update OBJECT::pad_to_pin. */
871 o_text_change(attrib, vpads, attrib->visibility, attrib->show_name_value);
872 } else {
873 /* Component doesn't support pin swapping at all. */
874 char *refdes = o_complex_get_refdes(owner, _("(unknown part)"));
876 scm_dynwind_unwind_handler(g_free, refdes, SCM_F_WIND_EXPLICITLY);
877 g_warning(_("Component %s #<object %s> does not support pin swapping\n"),
878 refdes, owner->name);
879 scm_dynwind_end();
881 return SCM_BOOL_F;
884 g_free(vpads);
885 scm_dynwind_end();
887 return SCM_BOOL_T;
890 /*! \brief Get the object bounds of the given object, excluding the object
891 * types given as parameters.
892 * \par Function Description
893 * Get the object bounds without considering the attributes in
894 * exclude_attrib_list, neither the object types included in
895 * exclude_obj_type_list
896 * \param [in] o_current The object we want to know the bounds of.
897 * \param [in] exclude_attrib_list A list with the attribute names we don't
898 * want to include when calculating the bounds.
899 * \param [in] exclude_obj_type_list A list with the object types we don't
900 * want to include when calculating the bounds.
901 * The object types are those used in (OBJECT *)->type converted into strings.
902 * \param [out] left Left bound of the object.
903 * \param [out] top Top bound of the object.
904 * \param [out] right Right bound of the object.
905 * \param [out] bottom Bottom bound of the object.
908 static void
909 custom_world_get_single_object_bounds(OBJECT *o_current,
910 int *left, int *top,
911 int *right, int *bottom,
912 GList *exclude_attrib_list,
913 GList *exclude_obj_type_list) {
914 OBJECT *a_current;
915 GList *a_iter;
916 int rleft, rright, rbottom, rtop;
917 const gchar *text_value;
918 char *name_ptr, aux_ptr[2];
919 gboolean include_text;
921 rleft = *left;
922 rright = *right;
923 rtop = *top;
924 rbottom = *bottom;
926 sprintf(aux_ptr, "%c", o_current->type);
927 include_text = TRUE;
928 if (!g_list_find_custom(exclude_obj_type_list, aux_ptr,
929 (GCompareFunc) &strcmp)) {
930 switch (o_current->type) {
931 case (OBJ_PIN):
932 world_get_single_object_bounds(o_current,
933 &rleft, &rtop, &rright, &rbottom);
934 break;
935 case (OBJ_TEXT):
936 text_value = o_text_get_string(o_current);
937 if (text_value) {
938 if (o_attrib_get_name_value(text_value, &name_ptr, NULL) &&
939 g_list_find_custom(exclude_attrib_list, name_ptr, (GCompareFunc) &strcmp)) {
940 include_text = FALSE;
942 if (g_list_find_custom(exclude_attrib_list, "all",
943 (GCompareFunc) &strcmp)) {
944 include_text = FALSE;
946 if (include_text) {
947 world_get_single_object_bounds(o_current,
948 &rleft, &rtop, &rright, &rbottom);
950 g_free(name_ptr);
952 break;
953 case (OBJ_COMPLEX):
954 case (OBJ_PLACEHOLDER):
955 custom_world_get_object_list_bounds(o_current->complex->prim_objs,
956 left, top, right, bottom,
957 exclude_attrib_list,
958 exclude_obj_type_list);
959 break;
961 default:
962 world_get_single_object_bounds(o_current,
963 &rleft, &rtop, &rright, &rbottom);
964 break;
967 if (rleft < *left) *left = rleft;
968 if (rtop < *top) *top = rtop;
969 if (rright > *right) *right = rright;
970 if (rbottom > *bottom) *bottom = rbottom;
972 /* If it's a pin object, check the pin attributes */
973 if (o_current->type == OBJ_PIN) {
974 a_iter = o_current->attribs;
975 while (a_iter != NULL) {
976 a_current = a_iter->data;
978 if (a_current->type == OBJ_TEXT) {
979 custom_world_get_single_object_bounds(a_current,
980 &rleft, &rtop,
981 &rright, &rbottom,
982 exclude_attrib_list,
983 exclude_obj_type_list);
984 if (rleft < *left) *left = rleft;
985 if (rtop < *top) *top = rtop;
986 if (rright > *right) *right = rright;
987 if (rbottom > *bottom) *bottom = rbottom;
990 a_iter = g_list_next (a_iter);
996 static void
997 custom_world_get_object_list_bounds(OBJECT *o_current,
998 int *left, int *top,
999 int *right, int *bottom,
1000 GList *exclude_attrib_list,
1001 GList *exclude_obj_type_list) {
1002 int rleft, rtop, rright, rbottom;
1004 rleft = *left;
1005 rtop = *top;
1006 rright = *right;
1007 rbottom = *bottom;
1009 while (o_current != NULL) {
1010 custom_world_get_single_object_bounds(o_current, &rleft, &rtop,
1011 &rright, &rbottom,
1012 exclude_attrib_list,
1013 exclude_obj_type_list);
1014 if (rleft < *left) *left = rleft;
1015 if (rtop < *top) *top = rtop;
1016 if (rright > *right) *right = rright;
1017 if (rbottom > *bottom) *bottom = rbottom;
1019 o_current = o_current->next;
1023 /*! \brief Get the object bounds of the given object, excluding the object
1024 * types or the attributes given as parameters.
1025 * \par Function Description
1026 * Get the object bounds without considering the attributes in
1027 * scm_exclude_attribs, neither the object types included in
1028 * scm_exclude_object_type
1029 * \param [in] object_smob Get this object's bounds
1030 * \param [in] scm_exclude_attribs Ignore attributes with these names.
1031 * \param [in] scm_exclude_object_type Ignore objects of these types.
1032 * The object types are those used in (OBJECT *)->type converted into strings.
1033 * \return a list of the bounds of the <B>object smob</B>.
1034 * The list has the format: ( (left right) (top bottom) )
1035 * WARNING: top and bottom are mis-named in world-coords,
1036 * top is the smallest "y" value, and bottom is the largest.
1037 * Be careful! This doesn't correspond to what you'd expect,
1038 * nor to the coordinate system whose origin is the bottom, left of the page.
1040 SCM g_get_object_bounds (SCM object_smob, SCM scm_exclude_attribs, SCM scm_exclude_object_type)
1042 OBJECT *object=NULL;
1043 int left=G_MAXINT, right=0, bottom=0, top=G_MAXINT;
1044 SCM returned = SCM_EOL;
1045 SCM vertical = SCM_EOL;
1046 SCM horizontal = SCM_EOL;
1047 GList *exclude_attrib_list = NULL, *exclude_obj_type_list = NULL;
1048 SCM rest;
1050 SCM_ASSERT (scm_list_p(scm_exclude_attribs), scm_exclude_attribs,
1051 SCM_ARG2, "get-object-bounds");
1052 SCM_ASSERT (scm_list_p(scm_exclude_object_type), scm_exclude_object_type,
1053 SCM_ARG3, "get-object-bounds");
1055 scm_dynwind_begin(0);
1057 /* Build the exclude attrib list */
1058 for (rest = scm_exclude_attribs; !scm_is_null(rest); rest = SCM_CDR(rest)) {
1059 char *attrib_name;
1061 SCM_ASSERT(scm_is_string(SCM_CAR(rest)), SCM_CAR(rest), SCM_ARG2,
1062 "get-object-bounds");
1064 attrib_name = scm_to_locale_string(SCM_CAR(rest));
1065 scm_dynwind_free(attrib_name);
1067 exclude_attrib_list = g_list_prepend(exclude_attrib_list, attrib_name);
1070 /* Build the exclude object type list */
1071 for (rest = scm_exclude_object_type;
1072 !scm_is_null(rest);
1073 rest = SCM_CDR(rest)) {
1074 char *object_type;
1076 SCM_ASSERT(scm_is_string(SCM_CAR(rest)), SCM_CAR(rest), SCM_ARG3,
1077 "get-object-bounds");
1079 object_type = scm_to_locale_string(SCM_CAR(rest));
1080 scm_dynwind_free(object_type);
1082 exclude_obj_type_list = g_list_prepend(exclude_obj_type_list, object_type);
1085 /* Get toplevel and o_current. */
1086 g_get_data_from_object_smob(object_smob, NULL, &object);
1088 SCM_ASSERT(object, object_smob, SCM_ARG1, "get-object-bounds");
1090 custom_world_get_single_object_bounds(object, &left, &top, &right, &bottom,
1091 exclude_attrib_list,
1092 exclude_obj_type_list);
1094 g_list_free(exclude_attrib_list);
1095 g_list_free(exclude_obj_type_list);
1096 scm_dynwind_end();
1098 horizontal = scm_cons (scm_from_int(left), scm_from_int(right));
1099 vertical = scm_cons (scm_from_int(top), scm_from_int(bottom));
1100 returned = scm_cons (horizontal, vertical);
1102 return (returned);
1105 /*! \todo Finish function documentation!!!
1106 * \brief
1107 * \par Function Description
1111 *Returns a list of the pins of the <B>object smob</B>.
1113 SCM g_get_object_pins (SCM object_smob)
1115 TOPLEVEL *toplevel=NULL;
1116 OBJECT *object=NULL;
1117 OBJECT *prim_obj;
1118 SCM returned=SCM_EOL;
1120 /* Get toplevel and o_current */
1121 SCM_ASSERT (g_get_data_from_object_smob (object_smob, &toplevel, &object),
1122 object_smob, SCM_ARG1, "get-object-pins");
1124 if (!object) {
1125 return (returned);
1127 if (object->complex && object->complex->prim_objs) {
1128 prim_obj = object->complex->prim_objs;
1129 while (prim_obj != NULL) {
1130 if (prim_obj->type == OBJ_PIN) {
1131 returned = scm_cons (g_make_object_smob(toplevel, prim_obj),returned);
1133 prim_obj = prim_obj->next;
1137 return (returned);
1140 /*! \brief Get the line width used to draw an object.
1141 * \par Function Description
1142 * This function returns the line width used to draw an object.
1144 * \param [in] object_smob The object smob to get the line width.
1145 * \return The line width.
1146 * Actually it is the object->line_width.
1148 SCM g_get_line_width(SCM object_smob)
1150 struct st_object_smob *object_struct;
1151 OBJECT *object;
1152 SCM returned = SCM_EOL;
1154 SCM_ASSERT ( SCM_NIMP(object_smob) &&
1155 ((long) SCM_CAR(object_smob) == object_smob_tag),
1156 object_smob, SCM_ARG1, "get-line-width");
1158 object_struct = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
1160 g_assert (object_struct && object_struct->object);
1162 object = object_struct->object;
1164 returned = scm_from_int(object->line_width);
1166 return returned;
1169 struct get_slots_context {
1170 TOPLEVEL *toplevel;
1171 SCM retval;
1174 static void get_slots_visitor(OBJECT *o, void *context)
1176 struct get_slots_context *ctx = context;
1177 SCM slot_smob;
1179 if (o->type != OBJ_SLOT) {
1180 return;
1183 slot_smob = g_make_object_smob(ctx->toplevel, o);
1185 ctx->retval = scm_cons(slot_smob, ctx->retval);
1188 /*! \brief Get all slots in a list.
1189 * \par Function Description
1190 * This function returns a list with all the slots in an object.
1192 * \param [in] object_smob The object smob to get slots from.
1193 * \return A list of slots belonging to \a object_smob.
1195 SCM g_get_object_slots(SCM object_smob)
1197 struct st_object_smob *object;
1198 SCM returned = SCM_EOL;
1200 SCM_ASSERT ( SCM_NIMP(object_smob) &&
1201 ((long) SCM_CAR(object_smob) == object_smob_tag),
1202 object_smob, SCM_ARG1, "get-object-slots");
1204 object = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
1206 if (object->object->type != OBJ_COMPLEX) {
1207 g_warning(_("g_get_object_attributes: object is not a component\n"));
1208 return SCM_BOOL_F;
1211 if (object && object->object) {
1212 TOPLEVEL *toplevel;
1213 struct get_slots_context ctx;
1215 toplevel = object->world;
1217 ctx.toplevel = toplevel;
1218 ctx.retval = returned;
1220 s_visit(object->object, &get_slots_visitor, &ctx, VISIT_UNORDERED, 2);
1222 returned = ctx.retval;
1225 return returned;
1228 /*! \brief Get the occupant of a slot object
1229 * \par Function Description
1230 * This function returns the abstract symbol occupying a slot
1232 * \param [in] object_smob The object smob of a slot object
1233 * \return The abstract symbol object
1235 SCM g_get_slot_occupant(SCM object_smob)
1237 struct st_object_smob *object_struct;
1238 TOPLEVEL *toplevel;
1239 OBJECT *object;
1240 SCM returned = SCM_EOL;
1242 SCM_ASSERT ( SCM_NIMP(object_smob) &&
1243 ((long) SCM_CAR(object_smob) == object_smob_tag),
1244 object_smob, SCM_ARG1, "get-slot-occupant");
1246 object_struct = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
1248 g_assert (object_struct && object_struct->object);
1250 toplevel = object_struct->world;
1251 object = object_struct->object;
1253 if (object->type != OBJ_SLOT) {
1254 g_warning(_("g_get_slot_occupant: object is not a slot\n"));
1255 return SCM_BOOL_F;
1258 if (object->slot->symbol) {
1259 OBJECT *occupant;
1261 occupant = s_slot_get_occupant(object);
1262 returned = g_make_object_smob(toplevel, occupant);
1265 return returned;
1268 /*! \brief Determine if an object is compatible with a slot
1269 * \par Function Description
1271 * \param [in] object_smob An object to put in a slot
1272 * \param [in] slot_smob A slot object
1273 * \return True if \a object_smob is compatible with \a slot_smob.
1275 SCM g_object_compatiblep(SCM object_smob, SCM slot_smob)
1277 struct st_object_smob *object_data;
1278 struct st_object_smob *slot_data;
1279 SCM retval = SCM_BOOL_F;
1281 SCM_ASSERT ( SCM_NIMP(object_smob) &&
1282 ((long) SCM_CAR(object_smob) == object_smob_tag),
1283 object_smob, SCM_ARG1, "object-compatible?");
1284 SCM_ASSERT ( SCM_NIMP(slot_smob) &&
1285 ((long) SCM_CAR(slot_smob) == object_smob_tag),
1286 slot_smob, SCM_ARG2, "object-compatible?");
1288 object_data = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
1289 slot_data = (struct st_object_smob *) SCM_SMOB_DATA(slot_smob);
1291 g_assert (object_data && object_data->object);
1292 g_assert (slot_data && slot_data->object);
1294 if (slot_data->object->type != OBJ_SLOT) {
1295 g_warning(_("g_object_compatiblep: object is not a slot\n"));
1296 return SCM_BOOL_F;
1299 if (s_slot_compatible(object_data->object, slot_data->object)) {
1300 retval = SCM_BOOL_T;
1303 return retval;
1306 /*! \brief Put a component into a slot
1307 * \par Function Description
1309 * \param [in] object_smob An object to put in a slot
1310 * \param [in] symbol_smob A slot object
1311 * \return True iff the slot-link succeeded.
1313 SCM g_slot_link(SCM object_smob, SCM symbol_smob)
1315 struct st_object_smob *object_data;
1316 struct st_object_smob *symbol_data;
1317 TOPLEVEL *toplevel;
1318 OBJECT *object, *symbol;
1319 SCM retval = SCM_BOOL_F;
1321 SCM_ASSERT ( SCM_NIMP(object_smob) &&
1322 ((long) SCM_CAR(object_smob) == object_smob_tag),
1323 object_smob, SCM_ARG1, "slot-link");
1324 SCM_ASSERT ( SCM_NIMP(symbol_smob) &&
1325 ((long) SCM_CAR(symbol_smob) == object_smob_tag),
1326 symbol_smob, SCM_ARG2, "slot-link");
1328 object_data = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
1329 symbol_data = (struct st_object_smob *) SCM_SMOB_DATA(symbol_smob);
1331 g_assert (object_data && object_data->object);
1332 g_assert (symbol_data && symbol_data->object);
1334 /* FIXME: Don't infer toplevel. */
1335 toplevel = object_data->world;
1336 object = object_data->object;
1337 symbol = symbol_data->object;
1339 if (s_slot_link(toplevel, object, symbol) == 0) {
1340 retval = SCM_BOOL_T;
1343 return retval;
1346 /*! \brief Remove a component from its slot
1347 * \par Function Description
1349 * \param [in] object_smob An object to remove from its slot
1350 * \return True iff the slot-link succeeded.
1352 SCM g_slot_unlink(SCM object_smob)
1354 struct st_object_smob *object_data;
1355 OBJECT *object, *old_slot;
1356 TOPLEVEL *toplevel;
1357 SCM retval = SCM_BOOL_F;
1359 SCM_ASSERT ( SCM_NIMP(object_smob) &&
1360 ((long) SCM_CAR(object_smob) == object_smob_tag),
1361 object_smob, SCM_ARG1, "slot-unlink");
1363 object_data = (struct st_object_smob *) SCM_SMOB_DATA(object_smob);
1365 g_assert (object_data && object_data->object);
1367 toplevel = object_data->world;
1368 object = object_data->object;
1370 old_slot = s_slot_unlink(object);
1371 s_slot_reset_attribs(object);
1372 if (old_slot) {
1373 retval = g_make_object_smob(toplevel, old_slot);
1376 return retval;
1379 /*! \brief Initialize the framework to support an object smob.
1380 * \par Function Description
1381 * Initialize the framework to support an object smob.
1384 void g_init_object_smob(void)
1387 object_smob_tag = scm_make_smob_type("object", sizeof (struct st_object_smob));
1388 scm_set_smob_mark(object_smob_tag, 0);
1389 scm_set_smob_free(object_smob_tag, g_free_object_smob);
1390 scm_set_smob_print(object_smob_tag, g_print_object_smob);
1392 scm_c_define_gsubr("get-attrib-value-by-attrib-name", 2, 0, 0,
1393 g_get_attrib_value_by_attrib_name);
1394 scm_c_define_gsubr("get-object-type", 1, 0, 0, g_get_object_type);
1395 scm_c_define_gsubr("get-line-width", 1, 0, 0, g_get_line_width);
1397 scm_c_define_gsubr("get-object-slots", 1, 0, 0, g_get_object_slots);
1398 scm_c_define_gsubr("get-slot-occupant", 1, 0, 0, g_get_slot_occupant);
1399 scm_c_define_gsubr("object-compatible?", 2, 0, 0, g_object_compatiblep);
1400 scm_c_define_gsubr("slot-link", 2, 0, 0, g_slot_link);
1401 scm_c_define_gsubr("slot-unlink", 1, 0, 0, g_slot_unlink);
1403 return;
1407 /*! \brief Get the TOPLEVEL and OBJECT data from an object smob.
1408 * \par Function Description
1409 * Get the TOPLEVEL and OBJECT data from an object smob.
1411 * \param [in] object_smob The object smob to get data from.
1412 * \param [out] toplevel The TOPLEVEL to write data to.
1413 * \param [out] object The OBJECT to write data to.
1414 * \return TRUE on success, FALSE otherwise
1416 gboolean g_get_data_from_object_smob(SCM object_smob, TOPLEVEL **toplevel,
1417 OBJECT **object)
1420 if ( (!SCM_NIMP(object_smob)) ||
1421 ((long) SCM_CAR(object_smob) != object_smob_tag) ) {
1422 return(FALSE);
1424 if (toplevel != NULL) {
1425 *toplevel = (TOPLEVEL *)
1426 (((struct st_object_smob *) SCM_SMOB_DATA(object_smob))->world);
1428 if (object != NULL) {
1429 *object = (((struct st_object_smob *) SCM_SMOB_DATA(object_smob))->object);
1431 return (TRUE);
1434 /*! \brief Free page smob memory.
1435 * \par Function Description
1436 * Free the memory allocated by the page smob and return its size.
1438 * \param [in] page_smob The page smob to free.
1439 * \return Size of page smob.
1441 static scm_sizet g_free_page_smob(SCM page_smob)
1443 struct st_page_smob *page =
1444 (struct st_page_smob *) SCM_SMOB_DATA(page_smob);
1446 scm_gc_free(page, sizeof (*page), "page");
1447 return 0;
1450 /*! \brief Prints page smob to port.
1451 * \par Function Description
1452 * This function prints the given page smob to the port.
1453 * It just prints a string showing it is a page and the page name.
1455 * \param [in] page_smob The page smob.
1456 * \param [in] port The port to print to.
1457 * \param [in] pstate Unused.
1458 * \return non-zero means success.
1460 static int g_print_page_smob(SCM page_smob, SCM port,
1461 scm_print_state *pstate G_GNUC_UNUSED)
1463 struct st_page_smob *page =
1464 (struct st_page_smob *) SCM_SMOB_DATA(page_smob);
1466 if (page &&
1467 page->page &&
1468 page->page->page_filename) {
1469 char const *representation = page->page->page_filename;
1470 scm_simple_format(port, scm_from_locale_string("#<page ~a>"),
1471 scm_list_1(scm_from_locale_string(representation)));
1474 /* non-zero means success */
1475 return 1;
1478 /*! \brief Initialize the framework to support a page smob.
1479 * \par Function Description
1480 * Initialize the framework to support a page smob.
1483 void g_init_page_smob(void)
1486 page_smob_tag = scm_make_smob_type("page",
1487 sizeof (struct st_page_smob));
1488 scm_set_smob_mark(page_smob_tag, 0);
1489 scm_set_smob_free(page_smob_tag, g_free_page_smob);
1490 scm_set_smob_print(page_smob_tag, g_print_page_smob);
1492 scm_c_define_gsubr ("get-page-filename", 1, 0, 0, g_get_page_filename);
1494 return;
1497 /*! \brief Creates a page smob
1498 * \par Function Description
1499 * This function creates and returns a new page smob,
1500 * from the given TOPLEVEL curr_w and page pointers.
1502 * \param [in] curr_w The current TOPLEVEL object.
1503 * \param [in] page The page object.
1504 * \return SCM The new page smob
1506 SCM g_make_page_smob(TOPLEVEL *curr_w, PAGE *page)
1508 struct st_page_smob *smob_page;
1510 smob_page = scm_gc_malloc(sizeof(struct st_page_smob), "page");
1512 smob_page->world = curr_w;
1513 smob_page->page = page;
1515 /* Assumes Guile version >= 1.3.2 */
1516 SCM_RETURN_NEWSMOB(page_smob_tag, smob_page);
1519 /*! \brief Get the TOPLEVEL and PAGE data from a page smob.
1520 * \par Function Description
1521 * Get the TOPLEVEL and OBJECT data from a page smob.
1523 * \param [in] page_smob The page smob to get data from.
1524 * \param [out] toplevel The TOPLEVEL to write data to.
1525 * \param [out] page The PAGE to write data to.
1526 * \return TRUE on success, FALSE otherwise
1528 gboolean g_get_data_from_page_smob(SCM page_smob, TOPLEVEL **toplevel,
1529 PAGE **page)
1532 if ( (!SCM_NIMP(page_smob)) ||
1533 ((long) SCM_CAR(page_smob) != page_smob_tag) ) {
1534 return(FALSE);
1536 if (toplevel != NULL) {
1537 *toplevel = (TOPLEVEL *)
1538 (((struct st_page_smob *) SCM_SMOB_DATA (page_smob))->world);
1540 if (page != NULL) {
1541 *page = (PAGE *)
1542 (((struct st_page_smob *) SCM_SMOB_DATA (page_smob))->page);
1544 return (TRUE);
1547 /*! \brief Get the page filename from a page smob.
1548 * \par Function Description
1549 * Get the page filename from a page smob.
1551 * \param [in] page_smob The page smob to get the filename from.
1552 * \return the page filename or SCM_EOL if there was some error.
1554 SCM g_get_page_filename(SCM page_smob)
1556 SCM returned = SCM_EOL;
1557 PAGE *page;
1559 SCM_ASSERT ( SCM_NIMP(page_smob) &&
1560 ((long) SCM_CAR(page_smob) == page_smob_tag),
1561 page_smob, SCM_ARG1, "get-page-filename");
1563 page = (PAGE *)
1564 (((struct st_page_smob *) SCM_SMOB_DATA (page_smob))->page);
1566 if (page->page_filename) {
1567 returned = scm_from_locale_string(page->page_filename);
1570 return (returned);
1573 /*! \brief Add a component to the page.
1574 * \par Function Description
1575 * Adds a component <B>comp_name_scm</B> to the schematic, at
1576 * position (<B>x_scm</B>, <B>y_scm</B>), with some properties set by
1577 * the parameters:
1578 * \param [in] x_scm Coordinate X of the symbol.
1579 * \param [in] y_scm Coordinate Y of the symbol.
1580 * \param [in] angle_scm Angle of rotation of the symbol.
1581 * \param [in] selectable_scm True if the symbol is selectable, false otherwise.
1582 * \param [in] mirror_scm True if the symbol is mirrored, false otherwise.
1583 * If comp_name_scm is a scheme empty list, SCM_BOOL_F, or an empty
1584 * string (""), then g_add_component returns SCM_BOOL_F without writing
1585 * to the log.
1586 * \return TRUE if the component was added, FALSE otherwise.
1589 SCM g_add_component(SCM page_smob, SCM comp_name_scm, SCM x_scm, SCM y_scm,
1590 SCM angle_scm, SCM selectable_scm, SCM mirror_scm)
1592 TOPLEVEL *toplevel;
1593 PAGE *page;
1594 gboolean selectable, mirror;
1595 gchar *comp_name;
1596 int x, y, angle;
1597 OBJECT *new_obj;
1598 const CLibSymbol *clib;
1600 /* Return if comp_name_scm is NULL (an empty list) or scheme's FALSE */
1601 if (SCM_NULLP(comp_name_scm) ||
1602 (SCM_BOOLP(comp_name_scm) && !(SCM_NFALSEP(comp_name_scm))) ) {
1603 return SCM_BOOL_F;
1606 /* Get toplevel and the page */
1607 SCM_ASSERT (g_get_data_from_page_smob (page_smob, &toplevel, &page),
1608 page_smob, SCM_ARG1, "add-component-at-xy");
1609 /* Check the arguments */
1610 SCM_ASSERT(scm_is_string(comp_name_scm), comp_name_scm,
1611 SCM_ARG2, "add-component-at-xy");
1612 SCM_ASSERT(scm_is_integer(x_scm), x_scm,
1613 SCM_ARG3, "add-component-at-xy");
1614 SCM_ASSERT(scm_is_integer(y_scm), y_scm,
1615 SCM_ARG4, "add-component-at-xy");
1616 SCM_ASSERT(scm_is_integer(angle_scm), angle_scm,
1617 SCM_ARG5, "add-component-at-xy");
1618 SCM_ASSERT(scm_boolean_p(selectable_scm), selectable_scm,
1619 SCM_ARG6, "add-component-at-xy");
1620 SCM_ASSERT(scm_boolean_p(mirror_scm), mirror_scm,
1621 SCM_ARG7, "add-component-at-xy");
1623 scm_dynwind_begin(0);
1625 /* Get the parameters */
1626 comp_name = scm_to_locale_string(comp_name_scm);
1627 scm_dynwind_free(comp_name);
1628 x = scm_to_int(x_scm);
1629 y = scm_to_int(y_scm);
1630 angle = scm_to_int(angle_scm);
1631 selectable = SCM_NFALSEP(selectable_scm);
1632 mirror = SCM_NFALSEP(mirror_scm);
1634 SCM_ASSERT(comp_name, comp_name_scm, SCM_ARG2, "add-component-at-xy");
1636 if (strcmp(comp_name, "") == 0) {
1637 scm_dynwind_end();
1638 return SCM_BOOL_F;
1641 clib = s_clib_get_symbol_by_name (comp_name);
1643 new_obj = o_complex_new (toplevel, 'C', WHITE, x, y, angle, mirror,
1644 clib, comp_name, selectable);
1645 s_page_append(page, new_obj);
1646 o_complex_promote_attribs(toplevel, page, new_obj);
1647 o_attrib_fix_uuid(new_obj);
1648 s_toplevel_register_object(toplevel, new_obj);
1651 * For now, do not redraw the newly added complex, since this might cause
1652 * flicker if you are zoom/panning right after this function executes
1654 #if 0
1655 /* Now the new component should be added to the object's list and
1656 drawn in the screen */
1657 o_redraw_single(toplevel, new_object);
1658 #endif
1660 scm_dynwind_end();
1661 return SCM_BOOL_T;
1664 /*! \brief Return the objects in a page.
1665 * \par Function Description
1666 * Returns an object smob list with all the objects in the given page.
1667 * \param [in] page_smob Page to look at.
1668 * \return the object smob list with the objects in the page.
1671 SCM g_get_objects_in_page(SCM page_smob) {
1672 TOPLEVEL *toplevel;
1673 PAGE *page;
1674 OBJECT *object;
1675 SCM return_list=SCM_EOL;
1677 /* Get toplevel and the page */
1678 SCM_ASSERT (g_get_data_from_page_smob (page_smob, &toplevel, &page),
1679 page_smob, SCM_ARG1, "get-objects-in-page");
1681 if (page && page->object_head && page->object_head->next) {
1682 object = page->object_head->next;
1683 while (object) {
1684 return_list = scm_cons (g_make_object_smob(toplevel, object),
1685 return_list);
1686 object = object->next;
1690 return return_list;
1693 /*! \brief Free toplevel smob memory.
1694 * \par Function Description
1695 * Free the memory allocated by the toplevel smob and return its size.
1697 * \param [in] toplevel_smob The toplevel smob to free.
1698 * \return Size of toplevel smob.
1700 static scm_sizet g_free_toplevel_smob(SCM toplevel_smob)
1702 struct st_toplevel_smob *toplevel =
1703 (struct st_toplevel_smob *) SCM_SMOB_DATA(toplevel_smob);
1705 scm_gc_free(toplevel, sizeof (*toplevel), "geda-toplevel");
1706 return 0;
1709 /*! \brief Initialize the framework to support a toplevel smob.
1710 * \par Function Description
1711 * Initialize the framework to support a toplevel smob.
1714 void g_init_toplevel_smob(void)
1717 toplevel_smob_tag = scm_make_smob_type("geda-toplevel",
1718 sizeof (struct st_toplevel_smob));
1719 scm_set_smob_mark(toplevel_smob_tag, 0);
1720 scm_set_smob_free(toplevel_smob_tag, g_free_toplevel_smob);
1722 scm_c_define_gsubr("get-toplevel-from", 1, 0, 0, g_get_toplevel_from);
1723 scm_c_define_gsubr("get-toplevel-pages", 1, 0, 0, g_get_toplevel_pages);
1724 scm_c_define_gsubr("hierarchy-traverse-pages", 2, 0, 0,
1725 &g_hierarchy_traversepages);
1727 return;
1730 /*! \brief Creates a toplevel smob
1731 * \par Function Description
1732 * This function creates and returns a new toplevel smob,
1733 * from the given TOPLEVEL toplevel pointer.
1735 * \param [in] toplevel The current TOPLEVEL object.
1736 * \return SCM The new toplevel smob
1738 SCM g_make_toplevel_smob(TOPLEVEL *toplevel)
1740 struct st_toplevel_smob *smob_toplevel;
1742 smob_toplevel = scm_gc_malloc(sizeof(struct st_toplevel_smob), "geda-toplevel");
1744 smob_toplevel->toplevel = toplevel;
1746 /* Assumes Guile version >= 1.3.2 */
1747 SCM_RETURN_NEWSMOB(toplevel_smob_tag, smob_toplevel);
1750 /*! \brief Get the TOPLEVEL in which another smob exists.
1751 * \par Function Description
1752 * This function returns a TOPLEVEL in which a PAGE or OBJECT exist.
1754 * \param [in] smob The PAGE or OBJECT smob to get TOPLEVEL from.
1755 * \return A TOPLEVEL smob.
1757 SCM g_get_toplevel_from(SCM smob)
1759 SCM returned = SCM_BOOL_F;
1760 TOPLEVEL *toplevel = NULL;
1762 SCM_ASSERT(SCM_NIMP(smob), smob, SCM_ARG1, "get-toplevel-from");
1764 if ((long) SCM_CAR(smob) == object_smob_tag) {
1765 struct st_object_smob *object =
1766 (struct st_object_smob *) SCM_SMOB_DATA(smob);
1767 toplevel = object->world;
1768 } else if ((long) SCM_CAR(smob) == page_smob_tag) {
1769 struct st_page_smob *page =
1770 (struct st_page_smob *) SCM_SMOB_DATA(smob);
1771 toplevel = page->world;
1772 } else {
1773 SCM_ASSERT(0, smob, SCM_ARG1, "get-toplevel-from");
1776 returned = g_make_toplevel_smob(toplevel);
1778 return returned;
1781 /*! \brief Get all pages in a list.
1782 * \par Function Description
1783 * This function returns a list with all the pages of a given toplevel smob.
1785 * \param [in] toplevel_smob The toplevel smob to get pages from.
1786 * \return A list of pages associated with this toplevel smob.
1788 SCM g_get_toplevel_pages(SCM toplevel_smob)
1790 struct st_toplevel_smob *toplevel;
1791 SCM returned = SCM_EOL;
1793 SCM_ASSERT ( SCM_NIMP(toplevel_smob) &&
1794 ((long) SCM_CAR(toplevel_smob) == toplevel_smob_tag),
1795 toplevel_smob, SCM_ARG1, "get-toplevel-pages");
1797 toplevel = (struct st_toplevel_smob *) SCM_SMOB_DATA(toplevel_smob);
1799 if (toplevel && toplevel->toplevel) {
1800 const GList *iter;
1802 for (iter = geda_list_get_glist(toplevel->toplevel->pages);
1803 iter != NULL;
1804 iter = g_list_next(iter)) {
1805 PAGE *page = iter->data;
1806 returned = scm_cons(g_make_page_smob(toplevel->toplevel, page),
1807 returned);
1811 return returned;
1814 /*! \brief Find a component from the global UUID map.
1815 * \par Function Description
1816 * Look up a UUID in the TOPLEVEL uuidmap and return the object found.
1818 * \param [in] toplevel_smob The TOPLEVEL smob containing the map.
1819 * \param [in] uuid_smob The UUID of the desired object.
1821 * \return OBJECT smob for the found object, or #f if not found.
1823 SCM g_lookup_uuid(SCM toplevel_smob, SCM uuid_smob)
1825 OBJECT *component;
1826 struct st_toplevel_smob *metatoplevel;
1827 TOPLEVEL *toplevel;
1828 char *uuid;
1829 SCM retval = SCM_BOOL_F;
1831 SCM_ASSERT(SCM_NIMP(toplevel_smob) &&
1832 ((long) SCM_CAR(toplevel_smob) == toplevel_smob_tag),
1833 toplevel_smob, SCM_ARG1, "lookup-uuid");
1834 SCM_ASSERT(scm_is_string(uuid_smob), uuid_smob, SCM_ARG2, "lookup-uuid");
1835 metatoplevel = (struct st_toplevel_smob *) SCM_SMOB_DATA(toplevel_smob);
1836 SCM_ASSERT(metatoplevel && metatoplevel->toplevel,
1837 toplevel_smob, SCM_ARG1, "lookup-uuid");
1838 toplevel = metatoplevel->toplevel;
1840 uuid = scm_to_locale_string(uuid_smob);
1841 component = g_hash_table_lookup(toplevel->uuidmap, uuid);
1842 free(uuid);
1844 if (component) {
1845 retval = g_make_object_smob(toplevel, component);
1848 return retval;
1851 /*! \brief Get a list of pages rooted at the current page.
1853 static SCM g_hierarchy_traversepages(SCM toplevel_smob, SCM flags)
1855 struct st_toplevel_smob *toplevel;
1856 SCM retval = SCM_EOL;
1857 const GList *iter;
1858 GList *pages;
1860 SCM_ASSERT(SCM_NIMP(toplevel_smob) &&
1861 ((long) SCM_CAR(toplevel_smob) == toplevel_smob_tag),
1862 toplevel_smob, SCM_ARG1, "hierarchy-traverse-pages");
1863 toplevel = (struct st_toplevel_smob *) SCM_SMOB_DATA(toplevel_smob);
1864 SCM_ASSERT(toplevel && toplevel->toplevel, toplevel_smob, SCM_ARG1,
1865 "hierarchy-traverse-pages");
1867 SCM_ASSERT(scm_is_integer(flags), flags, SCM_ARG2,
1868 "hierarchy-traverse-pages");
1870 pages = s_hierarchy_traversepages(toplevel->toplevel,
1871 toplevel->toplevel->page_current,
1872 scm_to_int(flags));
1874 /* Consing up the scheme list reverses the order. */
1875 pages = g_list_reverse(pages);
1877 for (iter = pages; iter; iter = iter->next) {
1878 SCM page = g_make_page_smob(toplevel->toplevel, iter->data);
1879 retval = scm_cons(page, retval);
1882 return retval;