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
31 #include "libgeda_priv.h"
33 #ifdef HAVE_LIBDMALLOC
37 struct st_object_smob
{
38 TOPLEVEL
*world
; /* We need this when updating schematic */
43 TOPLEVEL
*world
; /* We need this when updating schematic */
47 struct st_toplevel_smob
{
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
,
62 custom_world_get_single_object_bounds(OBJECT
*o_current
,
64 int *right
, int *bottom
,
65 GList
*exclude_attrib_list
,
66 GList
*exclude_obj_type_list
);
69 custom_world_get_object_list_bounds(OBJECT
*o_current
,
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");
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
);
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 */
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.
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!!!
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
)
151 SCM smob_list
= SCM_EOL
;
157 if (!object
->attribs
) {
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
);
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
;
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
);
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
));
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
223 * \return Always SCM_UNDEFINED
225 static SCM
g_set_attrib_value_internal(SCM attrib_smob
, SCM scm_value
,
229 struct st_attrib_smob
*attribute
;
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
);
250 o_attrib_get_name_value(attrib_chars
, &name
, NULL
);
252 *new_string
= g_strconcat (name
, "=", value
, NULL
);
254 *o_attrib
= attribute
->attribute
;
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.
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
;
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) {
325 if (strcmp(alignment_string
, "Lower Left") == 0) {
328 if (strcmp(alignment_string
, "Middle Left") == 0) {
331 if (strcmp(alignment_string
, "Upper Left") == 0) {
334 if (strcmp(alignment_string
, "Lower Middle") == 0) {
337 if (strcmp(alignment_string
, "Middle Middle") == 0) {
340 if (strcmp(alignment_string
, "Upper Middle") == 0) {
343 if (strcmp(alignment_string
, "Lower Right") == 0) {
346 if (strcmp(alignment_string
, "Middle Right") == 0) {
349 if (strcmp(alignment_string
, "Upper Right") == 0) {
353 free(alignment_string
);
355 if (alignment
== -2) {
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 */
378 object
->text
->alignment
= alignment
;
380 object
->text
->angle
= angle
;
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
);
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
);
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
);
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
);
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");
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
);
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 */
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.
550 SCM
g_make_object_smob(TOPLEVEL
*curr_w
, OBJECT
*object
)
552 struct st_object_smob
*smob_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
;
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
);
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
);
601 /*! \brief Get the value(s) of the attributes with the given name in the
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
;
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);
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
;
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
);
652 /*! \todo Finish function documentation!!!
654 * \par Function Description
657 SCM
g_set_attrib_value_x(SCM attrib_smob
, SCM scm_value
)
661 char *new_string
= NULL
;
663 returned
= g_set_attrib_value_internal(attrib_smob
, scm_value
,
664 &o_attrib
, &new_string
);
667 o_text_change(o_attrib
, new_string
,
668 o_attrib
->visibility
, o_attrib
->show_name_value
);
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
;
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
);
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
)
713 SCM coord1
= SCM_EOL
;
714 SCM coord2
= SCM_EOL
;
715 SCM coords
= SCM_EOL
;
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
));
738 coords
= scm_cons(coord2
, scm_list(coord1
));
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
);
766 gboolean shorted_pads
= FALSE
;
768 for (s
= packagepins
; s
!= NULL
; ) {
774 pair
= u_basic_split(&s
, ',');
775 equals
= strchr(pair
, '=');
778 /* I think this should be bad, but for now just assume identity. */
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) {
792 /* An earlier entry already used the pad. */
796 *ppad
= g_strdup(pad
);
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
);
813 /* If there is no package map, assume an identity map. */
815 pad1
= g_strdup(pin1
);
818 pad2
= g_strdup(pin2
);
821 vpads
= o_attrib_search_name_single(owner
, "vpads", &attrib
);
825 int pad1_seen
= 0, pad2_seen
= 0;
827 newmap
= g_string_sized_new(0);
829 for (s
= vpads
; s
!= NULL
; ) {
833 pair
= u_basic_split(&s
, ',');
834 equals
= strchr(pair
, '=');
841 if (strcmp(pad
, pad1
) == 0) {
842 g_string_append_printf(newmap
, ",%s=%s", vpad
, pad2
);
844 } else if (strcmp(pad
, pad2
) == 0) {
845 g_string_append_printf(newmap
, ",%s=%s", vpad
, pad1
);
848 g_string_append_printf(newmap
, ",%s=%s", vpad
, pad
);
852 /* Build the new attribute, skipping the leading comma. */
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
);
870 /* Signal handler will update OBJECT::pad_to_pin. */
871 o_text_change(attrib
, vpads
, attrib
->visibility
, attrib
->show_name_value
);
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
);
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.
909 custom_world_get_single_object_bounds(OBJECT
*o_current
,
911 int *right
, int *bottom
,
912 GList
*exclude_attrib_list
,
913 GList
*exclude_obj_type_list
) {
916 int rleft
, rright
, rbottom
, rtop
;
917 const gchar
*text_value
;
918 char *name_ptr
, aux_ptr
[2];
919 gboolean include_text
;
926 sprintf(aux_ptr
, "%c", o_current
->type
);
928 if (!g_list_find_custom(exclude_obj_type_list
, aux_ptr
,
929 (GCompareFunc
) &strcmp
)) {
930 switch (o_current
->type
) {
932 world_get_single_object_bounds(o_current
,
933 &rleft
, &rtop
, &rright
, &rbottom
);
936 text_value
= o_text_get_string(o_current
);
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
;
947 world_get_single_object_bounds(o_current
,
948 &rleft
, &rtop
, &rright
, &rbottom
);
954 case (OBJ_PLACEHOLDER
):
955 custom_world_get_object_list_bounds(o_current
->complex->prim_objs
,
956 left
, top
, right
, bottom
,
958 exclude_obj_type_list
);
962 world_get_single_object_bounds(o_current
,
963 &rleft
, &rtop
, &rright
, &rbottom
);
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
,
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
);
997 custom_world_get_object_list_bounds(OBJECT
*o_current
,
999 int *right
, int *bottom
,
1000 GList
*exclude_attrib_list
,
1001 GList
*exclude_obj_type_list
) {
1002 int rleft
, rtop
, rright
, rbottom
;
1009 while (o_current
!= NULL
) {
1010 custom_world_get_single_object_bounds(o_current
, &rleft
, &rtop
,
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
;
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
)) {
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
;
1073 rest
= SCM_CDR(rest
)) {
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
);
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
);
1105 /*! \todo Finish function documentation!!!
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
;
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");
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
;
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
;
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
);
1169 struct get_slots_context
{
1174 static void get_slots_visitor(OBJECT
*o
, void *context
)
1176 struct get_slots_context
*ctx
= context
;
1179 if (o
->type
!= OBJ_SLOT
) {
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"));
1211 if (object
&& object
->object
) {
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
;
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
;
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"));
1258 if (object
->slot
->symbol
) {
1261 occupant
= s_slot_get_occupant(object
);
1262 returned
= g_make_object_smob(toplevel
, occupant
);
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"));
1299 if (s_slot_compatible(object_data
->object
, slot_data
->object
)) {
1300 retval
= SCM_BOOL_T
;
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
;
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
;
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
;
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
);
1373 retval
= g_make_object_smob(toplevel
, old_slot
);
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
);
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
,
1420 if ( (!SCM_NIMP(object_smob
)) ||
1421 ((long) SCM_CAR(object_smob
) != object_smob_tag
) ) {
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
);
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");
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
);
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 */
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
);
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
,
1532 if ( (!SCM_NIMP(page_smob
)) ||
1533 ((long) SCM_CAR(page_smob
) != page_smob_tag
) ) {
1536 if (toplevel
!= NULL
) {
1537 *toplevel
= (TOPLEVEL
*)
1538 (((struct st_page_smob
*) SCM_SMOB_DATA (page_smob
))->world
);
1542 (((struct st_page_smob
*) SCM_SMOB_DATA (page_smob
))->page
);
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
;
1559 SCM_ASSERT ( SCM_NIMP(page_smob
) &&
1560 ((long) SCM_CAR(page_smob
) == page_smob_tag
),
1561 page_smob
, SCM_ARG1
, "get-page-filename");
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
);
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
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
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
)
1594 gboolean selectable
, mirror
;
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
))) ) {
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) {
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
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
);
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
) {
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
;
1684 return_list
= scm_cons (g_make_object_smob(toplevel
, object
),
1686 object
= object
->next
;
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");
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
);
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
;
1773 SCM_ASSERT(0, smob
, SCM_ARG1
, "get-toplevel-from");
1776 returned
= g_make_toplevel_smob(toplevel
);
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
) {
1802 for (iter
= geda_list_get_glist(toplevel
->toplevel
->pages
);
1804 iter
= g_list_next(iter
)) {
1805 PAGE
*page
= iter
->data
;
1806 returned
= scm_cons(g_make_page_smob(toplevel
->toplevel
, page
),
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
)
1826 struct st_toplevel_smob
*metatoplevel
;
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
);
1845 retval
= g_make_object_smob(toplevel
, component
);
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
;
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
,
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
);