1 /* gEDA - GPL Electronic Design Automation
2  * libgeda - gEDA's library - Scheme API
3  * Copyright (C) 2010-2012 Peter Brett <peter@peter-b.co.uk>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
18  */
19 
20 /*!
21  * \file scheme_object.c
22  * \brief Scheme API object manipulation procedures.
23  */
24 
25 #include <config.h>
26 
27 #include "libgeda_priv.h"
28 #include "libgedaguile_priv.h"
29 
30 SCM_SYMBOL (wrong_type_arg_sym , "wrong-type-arg");
31 SCM_SYMBOL (line_sym , "line");
32 SCM_SYMBOL (net_sym , "net");
33 SCM_SYMBOL (bus_sym , "bus");
34 SCM_SYMBOL (box_sym , "box");
35 SCM_SYMBOL (picture_sym , "picture");
36 SCM_SYMBOL (circle_sym , "circle");
37 SCM_SYMBOL (complex_sym , "complex");
38 SCM_SYMBOL (text_sym , "text");
39 SCM_SYMBOL (path_sym , "path");
40 SCM_SYMBOL (pin_sym , "pin");
41 SCM_SYMBOL (arc_sym , "arc");
42 
43 SCM_SYMBOL (lower_left_sym , "lower-left");
44 SCM_SYMBOL (middle_left_sym , "middle-left");
45 SCM_SYMBOL (upper_left_sym , "upper-left");
46 SCM_SYMBOL (lower_center_sym , "lower-center");
47 SCM_SYMBOL (middle_center_sym , "middle-center");
48 SCM_SYMBOL (upper_center_sym , "upper-center");
49 SCM_SYMBOL (lower_right_sym , "lower-right");
50 SCM_SYMBOL (middle_right_sym , "middle-right");
51 SCM_SYMBOL (upper_right_sym , "upper-right");
52 
53 SCM_SYMBOL (name_sym , "name");
54 SCM_SYMBOL (value_sym , "value");
55 SCM_SYMBOL (both_sym , "both");
56 
57 SCM_SYMBOL (none_sym, "none");
58 SCM_SYMBOL (square_sym , "square");
59 SCM_SYMBOL (round_sym , "round");
60 
61 SCM_SYMBOL (solid_sym , "solid");
62 SCM_SYMBOL (dotted_sym , "dotted");
63 SCM_SYMBOL (dashed_sym , "dashed");
64 SCM_SYMBOL (center_sym , "center");
65 SCM_SYMBOL (phantom_sym , "phantom");
66 
67 SCM_SYMBOL (hollow_sym , "hollow");
68 SCM_SYMBOL (mesh_sym , "mesh");
69 SCM_SYMBOL (hatch_sym , "hatch");
70 
71 SCM_SYMBOL (moveto_sym , "moveto");
72 SCM_SYMBOL (lineto_sym , "lineto");
73 SCM_SYMBOL (curveto_sym , "curveto");
74 SCM_SYMBOL (closepath_sym , "closepath");
75 
o_page_changed(TOPLEVEL * t,OBJECT * o)76 void o_page_changed (TOPLEVEL *t, OBJECT *o)
77 {
78   PAGE *p = o_get_page (t, o);
79   if (p != NULL) p->CHANGED = TRUE;
80 }
81 
82 /*! \brief Convert a Scheme object list to a GList.
83  * \par Function Description
84  * Takes a Scheme list of #OBJECT smobs, and returns a GList
85  * containing the objects. If \a objs is not a list of #OBJECT smobs,
86  * throws a Scheme error.
87  *
88  * \warning If the #OBJECT structures in the GList are to be stored by
89  * C code and later free()'d directly, the smobs must be marked as
90  * unsafe for garbage collection (by calling edascm_c_set_gc()).
91  *
92  * \param [in] objs a Scheme list of #OBJECT smobs.
93  * \param [in] subr the name of the Scheme subroutine (used for error
94  *                  messages).
95  * \return a #GList of #OBJECT.
96  */
97 GList *
edascm_to_object_glist(SCM objs,const char * subr)98 edascm_to_object_glist (SCM objs, const char *subr)
99 {
100   GList *result = NULL;
101   SCM lst;
102 
103   SCM_ASSERT (scm_is_true (scm_list_p (objs)), objs, SCM_ARGn, subr);
104 
105   scm_dynwind_begin (0);
106   scm_dynwind_unwind_handler ((void (*)(void *))g_list_free, result, 0);
107 
108   for (lst = objs; lst != SCM_EOL; lst = SCM_CDR (lst)) {
109     SCM smob = SCM_CAR (lst);
110     result = g_list_prepend (result, (gpointer) edascm_to_object (smob));
111   }
112 
113   scm_remember_upto_here_1 (lst);
114 
115   scm_dynwind_end ();
116 
117   return g_list_reverse (result);
118 }
119 
120 /*! \brief Convert a GList of objects into a Scheme list.
121  * \par Function Description
122  * Takes a GList of #OBJECT and returns a Scheme list of corresponding
123  * object smobs.
124  *
125  * \warning If the #OBJECT structures are to be subsequently managed
126  * only by Scheme, the smobs in the returned list must be marked as
127  * safe for garbage collection (by calling edascm_c_set_gc()).
128  *
129  * \param [in] objs a #GList of #OBJECT instances.
130  * \return a Scheme list of smobs corresponding to each #OBJECT.
131  */
132 SCM
edascm_from_object_glist(const GList * objs)133 edascm_from_object_glist (const GList *objs)
134 {
135   SCM lst = SCM_EOL;
136   SCM rlst;
137   GList *iter = (GList *) objs;
138 
139   while (iter != NULL) {
140     lst = scm_cons (edascm_from_object (iter->data), lst);
141     iter = g_list_next (iter);
142   }
143 
144   rlst = scm_reverse (lst);
145 
146   scm_remember_upto_here_1 (lst);
147   return rlst;
148 }
149 
150 /*! \brief Test if an object smob is of a particular type.
151  * \par Function Description
152  * Checks if \a smob contains an #OBJECT of the given \a type. This is
153  * intended to be used by C-based Scheme procedures for working with
154  * particular object types.
155  *
156  * \param [in] smob Scheme value to check type for.
157  * \param [in] type Type to check against (e.g. OBJ_LINE).
158  * \return non-zero if \a smob is an #OBJECT smob of \a type.
159  */
160 int
edascm_is_object_type(SCM smob,int type)161 edascm_is_object_type (SCM smob, int type)
162 {
163   if (!EDASCM_OBJECTP(smob)) return 0;
164 
165   OBJECT *obj = edascm_to_object (smob);
166   return (obj->type == type);
167 }
168 
169 /*! \brief Copy an object.
170  * \par Function Description
171  * Returns a copy of the #OBJECT contained in smob \a obj_s as a new
172  * smob.
173  *
174  * \note Scheme API: Implements the %copy-object procedure in the
175  * (geda core object) module.
176  *
177  * \param [in] obj_s an #OBJECT smob.
178  * \return a new #OBJECT smob containing a copy of the #OBJECT in \a obj_s.
179  */
180 SCM_DEFINE (copy_object, "%copy-object", 1, 0, 0,
181             (SCM obj_s), "Copy an object.")
182 {
183   SCM result;
184   SCM_ASSERT (EDASCM_OBJECTP (obj_s), obj_s,
185               SCM_ARG1, s_copy_object);
186 
187   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
188   OBJECT *obj = edascm_to_object (obj_s);
189 
190   result = edascm_from_object (o_object_copy (toplevel, obj));
191 
192   /* At the moment, the only pointer to the object is owned by the
193    * smob. */
194   edascm_c_set_gc (result, TRUE);
195 
196   return result;
197 }
198 
199 /*! \brief Get the type of an object.
200  * \par Function Description
201  * Returns a symbol describing the type of the #OBJECT smob \a obj_s.
202  *
203  * \note Scheme API: Implements the %object-type procedure in the
204  * (geda core object) module.
205  *
206  * \param [in] obj_s an #OBJECT smob.
207  * \return a Scheme symbol representing the object type.
208  */
209 SCM_DEFINE (object_type, "%object-type", 1, 0, 0,
210             (SCM obj_s), "Get an object smob's type")
211 {
212   SCM result;
213 
214   SCM_ASSERT (EDASCM_OBJECTP (obj_s), obj_s,
215               SCM_ARG1, s_object_type);
216 
217   OBJECT *obj = edascm_to_object (obj_s);
218   switch (obj->type) {
219   case OBJ_LINE:    result = line_sym;       break;
220   case OBJ_NET:     result = net_sym;        break;
221   case OBJ_BUS:     result = bus_sym;        break;
222   case OBJ_BOX:     result = box_sym;        break;
223   case OBJ_PICTURE: result = picture_sym;    break;
224   case OBJ_CIRCLE:  result = circle_sym;     break;
225   case OBJ_PLACEHOLDER:
226   case OBJ_COMPLEX: result = complex_sym;    break;
227   case OBJ_TEXT:    result = text_sym;       break;
228   case OBJ_PATH:    result = path_sym;       break;
229   case OBJ_PIN:     result = pin_sym;        break;
230   case OBJ_ARC:     result = arc_sym;        break;
231   default:
232     scm_misc_error (s_object_type, _("Object ~A has bad type '~A'"),
233                     scm_list_2 (obj_s,
234                                 scm_integer_to_char (scm_from_int (obj->type))));
235   }
236 
237   return result;
238 }
239 
240 /*! \brief Get the bounds of a list of objects
241  * \par Function Description
242  * Returns the bounds of the objects in the variable-length argument
243  * list \a rst_s. The bounds are returned as a pair structure of the
244  * form:
245  *
246  * \code
247  * ((left . top) . (right . bottom))
248  * \endcode
249  *
250  * If \a rst_s is empty, or none of the objects has any bounds
251  * (e.g. because they are all empty components and/or text strings),
252  * returns SCM_BOOL_F.
253  *
254  * \warning This function always returns the actual bounds of the
255  * objects, not the visible bounds.
256  *
257  * \note Scheme API: Implements the %object-bounds procedure in the
258  * (geda core object) module.  The procedure takes any number of
259  * #OBJECT smobs as arguments.
260  *
261  * \param [in] rst_s Variable-length list of #OBJECT arguments.
262  * \return bounds of objects or SCM_BOOL_F.
263  */
264 SCM_DEFINE (object_bounds, "%object-bounds", 0, 0, 1,
265             (SCM rst_s), "Get the bounds of a list of objects")
266 {
267   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
268 
269   GList *obj_list = edascm_to_object_glist (rst_s, s_object_bounds);
270 
271   int success, left, top, right, bottom;
272   if (toplevel->show_hidden_text) {
273     success = world_get_object_glist_bounds (toplevel, obj_list,
274                                              &left, &top, &right, &bottom);
275   } else {
276     toplevel->show_hidden_text = TRUE;
277     o_recalc_object_glist (toplevel, obj_list);
278 
279     success = world_get_object_glist_bounds (toplevel, obj_list,
280                                              &left, &top, &right, &bottom);
281 
282     toplevel->show_hidden_text = FALSE;
283     o_recalc_object_glist (toplevel, obj_list);
284   }
285 
286   SCM result = SCM_BOOL_F;
287   if (success) {
288     result = scm_cons (scm_cons (scm_from_int (min(left, right)),
289                                  scm_from_int (max(top, bottom))),
290                        scm_cons (scm_from_int (max(left, right)),
291                                  scm_from_int (min(top, bottom))));
292   }
293 
294   scm_remember_upto_here_1 (rst_s);
295   return result;
296 }
297 
298 
299 /*! \brief Get the stroke properties of an object.
300  * \par Function Description
301  * Returns the stroke settings of the object \a obj_s.  If \a obj_s is
302  * not a line, box, circle, arc, or path, throws a Scheme error.  The
303  * return value is a list of parameters:
304  *
305  * -# stroke width
306  * -# cap style (a symbol: none, square or round)
307  * -# dash style (a symbol: solid, dotted, dashed, center or phantom)
308  * -# up to two dash parameters, depending on dash style:
309  *    -# For solid lines, no parameters.
310  *    -# For dotted lines, dot spacing.
311  *    -# For other styles, dot/dash spacing and dash length.
312  *
313  * \note Scheme API: Implements the %object-stroke procedure in the
314  * (geda core object) module.
315  *
316  * \param obj_s object to get stroke settings for.
317  * \return a list of stroke parameters.
318  */
319 SCM_DEFINE (object_stroke, "%object-stroke", 1, 0, 0,
320             (SCM obj_s), "Get the stroke properties of an object.")
321 {
322   SCM_ASSERT ((edascm_is_object_type (obj_s, OBJ_LINE)
323                || edascm_is_object_type (obj_s, OBJ_BOX)
324                || edascm_is_object_type (obj_s, OBJ_CIRCLE)
325                || edascm_is_object_type (obj_s, OBJ_ARC)
326                || edascm_is_object_type (obj_s, OBJ_PATH)),
327               obj_s, SCM_ARG1, s_object_stroke);
328 
329   OBJECT *obj = edascm_to_object (obj_s);
330 
331   int end, type, width, length, space;
332   o_get_line_options (obj, (OBJECT_END *) &end, (OBJECT_TYPE *) &type, &width,
333                       &length, &space);
334 
335   SCM width_s = scm_from_int (width);
336   SCM length_s = scm_from_int (length);
337   SCM space_s = scm_from_int (space);
338 
339   SCM cap_s;
340   switch (end) {
341   case END_NONE: cap_s = none_sym; break;
342   case END_SQUARE: cap_s = square_sym; break;
343   case END_ROUND: cap_s = round_sym; break;
344   default:
345     scm_misc_error (s_object_stroke,
346                     _("Object ~A has invalid stroke cap style ~A"),
347                     scm_list_2 (obj_s, scm_from_int (end)));
348   }
349 
350   SCM dash_s;
351   switch (type) {
352   case TYPE_SOLID: dash_s = solid_sym; break;
353   case TYPE_DOTTED: dash_s = dotted_sym; break;
354   case TYPE_DASHED: dash_s = dashed_sym; break;
355   case TYPE_CENTER: dash_s = center_sym; break;
356   case TYPE_PHANTOM: dash_s = phantom_sym; break;
357   default:
358     scm_misc_error (s_object_stroke,
359                     _("Object ~A has invalid stroke dash style ~A"),
360                     scm_list_2 (obj_s, scm_from_int (type)));
361   }
362 
363   switch (type) {
364   case TYPE_DASHED:
365   case TYPE_CENTER:
366   case TYPE_PHANTOM:
367     return scm_list_5 (width_s, cap_s, dash_s, space_s, length_s);
368   case TYPE_DOTTED:
369     return scm_list_4 (width_s, cap_s, dash_s, space_s);
370   default:
371     return scm_list_3 (width_s, cap_s, dash_s);
372   }
373 }
374 
375 /*! \brief Set the stroke properties of an object.
376  * \par Function Description
377  * Updates the stroke settings of the object \a obj_s.  If \a obj_s is
378  * not a line, box, circle, arc, or path, throws a Scheme error.  The
379  * optional parameters \a space_s and \a length_s can be set to
380  * SCM_UNDEFINED if not required by the dash style \a dash_s.
381  *
382  * \note Scheme API: Implements the %object-stroke procedure in the
383  * (geda core object) module.
384  *
385  * \param obj_s object to set stroke settings for.
386  * \param width_s new stroke width for \a obj_s.
387  * \param cap_s new stroke cap style for \a obj_s.
388  * \param dash_s new dash style for \a obj_s.
389  * \param space_s dot/dash spacing for dash styles other than solid.
390  * \param length_s dash length for dash styles other than solid or
391  *                 dotted.
392  * \return \a obj_s.
393  */
394 SCM_DEFINE (set_object_stroke_x, "%set-object-stroke!", 4, 2, 0,
395             (SCM obj_s, SCM width_s, SCM cap_s, SCM dash_s, SCM space_s,
396              SCM length_s), "Set the stroke properties of an object.")
397 {
398   SCM_ASSERT ((edascm_is_object_type (obj_s, OBJ_LINE)
399                || edascm_is_object_type (obj_s, OBJ_BOX)
400                || edascm_is_object_type (obj_s, OBJ_CIRCLE)
401                || edascm_is_object_type (obj_s, OBJ_ARC)
402                || edascm_is_object_type (obj_s, OBJ_PATH)),
403               obj_s, SCM_ARG1, s_set_object_stroke_x);
404 
405   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
406   OBJECT *obj = edascm_to_object (obj_s);
407   int cap, type, width, length = -1, space = -1;
408 
409   SCM_ASSERT (scm_is_integer (width_s), width_s,
410               SCM_ARG2, s_set_object_stroke_x);
411   SCM_ASSERT (scm_is_symbol (cap_s), cap_s,
412               SCM_ARG3, s_set_object_stroke_x);
413   SCM_ASSERT (scm_is_symbol (dash_s), dash_s,
414               SCM_ARG4, s_set_object_stroke_x);
415 
416   width = scm_to_int (width_s);
417 
418   if      (cap_s == none_sym)   { cap = END_NONE;   }
419   else if (cap_s == square_sym) { cap = END_SQUARE; }
420   else if (cap_s == round_sym)  { cap = END_ROUND;  }
421   else {
422     scm_misc_error (s_set_object_stroke_x,
423                     _("Invalid stroke cap style ~A."),
424                     scm_list_1 (cap_s));
425   }
426 
427   if      (dash_s == solid_sym)   { type = TYPE_SOLID;   }
428   else if (dash_s == dotted_sym)  { type = TYPE_DOTTED;  }
429   else if (dash_s == dashed_sym)  { type = TYPE_DASHED;  }
430   else if (dash_s == center_sym)  { type = TYPE_CENTER;  }
431   else if (dash_s == phantom_sym) { type = TYPE_PHANTOM; }
432   else {
433     scm_misc_error (s_set_object_stroke_x,
434                     _("Invalid stroke dash style ~A."),
435                     scm_list_1 (dash_s));
436   }
437 
438   switch (type) {
439   case TYPE_DASHED:
440   case TYPE_CENTER:
441   case TYPE_PHANTOM:
442     if (length_s == SCM_UNDEFINED) {
443       scm_misc_error (s_set_object_stroke_x,
444                       _("Missing dash length parameter for dash style ~A."),
445                       scm_list_1 (length_s));
446     }
447     SCM_ASSERT (scm_is_integer (length_s), length_s,
448                 SCM_ARG6, s_set_object_stroke_x);
449     length = scm_to_int (length_s);
450     /* This case intentionally falls through */
451   case TYPE_DOTTED:
452     if (space_s == SCM_UNDEFINED) {
453       scm_misc_error (s_set_object_stroke_x,
454                       _("Missing dot/dash space parameter for dash style ~A."),
455                       scm_list_1 (space_s));
456     }
457     SCM_ASSERT (scm_is_integer (space_s), space_s,
458                 SCM_ARG5, s_set_object_stroke_x);
459     space = scm_to_int (space_s);
460     /* This case intentionally falls through */
461   }
462 
463   o_set_line_options (toplevel, obj, cap, type, width, length, space);
464   o_page_changed (toplevel, obj);
465 
466   return obj_s;
467 }
468 
469 /*! \brief Get the fill properties of an object.
470  * \par Function Description
471  * Returns the fill settings of the object \a obj_s.  If \a obj_s is
472  * not a box, circle, or path, throws a Scheme error.  The return
473  * value is a list of parameters:
474  *
475  * -# fill style (a symbol: hollow, solid, mesh or hatch)
476  * -# up to five fill parameters, depending on fill style:
477  *   -# none for hollow or solid fills
478  *   -# line width, line angle, and line spacing for hatch fills.
479  *   -# line width, first angle and spacing, and second angle and
480  *      spacing for mesh fills.
481  *
482  * \note Scheme API: Implements the %object-fill procedure in the
483  * (geda core object) module.
484  *
485  * \param obj_s object to get fill settings for.
486  * \return a list of fill parameters.
487  */
488 SCM_DEFINE (object_fill, "%object-fill", 1, 0, 0,
489             (SCM obj_s), "Get the fill properties of an object.")
490 {
491   SCM_ASSERT ((edascm_is_object_type (obj_s, OBJ_BOX)
492                || edascm_is_object_type (obj_s, OBJ_CIRCLE)
493                || edascm_is_object_type (obj_s, OBJ_PATH)),
494               obj_s, SCM_ARG1, s_object_fill);
495 
496   OBJECT *obj = edascm_to_object (obj_s);
497 
498   int type, width, pitch1, angle1, pitch2, angle2;
499   o_get_fill_options (obj, (OBJECT_FILLING *) &type, &width, &pitch1, &angle1,
500                       &pitch2, &angle2);
501 
502   SCM width_s = scm_from_int (width);
503   SCM pitch1_s = scm_from_int (pitch1);
504   SCM angle1_s = scm_from_int (angle1);
505   SCM pitch2_s = scm_from_int (pitch2);
506   SCM angle2_s = scm_from_int (angle2);
507 
508   SCM type_s;
509   switch (type) {
510   case FILLING_HOLLOW: type_s = hollow_sym; break;
511   case FILLING_FILL: type_s = solid_sym; break;
512   case FILLING_MESH: type_s = mesh_sym; break;
513   case FILLING_HATCH: type_s = hatch_sym; break;
514   default:
515     scm_misc_error (s_object_fill,
516                     _("Object ~A has invalid fill style ~A"),
517                     scm_list_2 (obj_s, scm_from_int (type)));
518   }
519 
520   switch (type) {
521   case FILLING_MESH:
522     return scm_list_n (type_s, width_s, pitch1_s, angle1_s, pitch2_s, angle2_s,
523                        SCM_UNDEFINED);
524   case FILLING_HATCH:
525     return scm_list_4 (type_s, width_s, pitch1_s, angle1_s);
526   default:
527     return scm_list_1 (type_s);
528   }
529 }
530 
531 /*! \brief Set the fill properties of an object.
532  * \par Function Description
533 
534  * Updates the fill settings of the object \a obj_s.  If \a obj_s is
535  * not a box, circle, or path, throws a Scheme error.  The optional
536  * parameters \a width_s, \a angle1_s, \a space1_s, \a angle2_s and
537  * space2_s
538  *
539  * \note Scheme API: Implements the %object-fill procedure in the
540  * (geda core object) module.
541  *
542  * \param obj_s object to set fill settings for.
543  * \return \a obj_s.
544  */
545 SCM_DEFINE (set_object_fill_x, "%set-object-fill!", 2, 5, 0,
546             (SCM obj_s, SCM type_s, SCM width_s, SCM space1_s, SCM angle1_s,
547              SCM space2_s, SCM angle2_s),
548             "Set the fill properties of an object.")
549 {
550   SCM_ASSERT ((edascm_is_object_type (obj_s, OBJ_BOX)
551                || edascm_is_object_type (obj_s, OBJ_CIRCLE)
552                || edascm_is_object_type (obj_s, OBJ_PATH)),
553               obj_s, SCM_ARG1, s_set_object_fill_x);
554 
555   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
556   OBJECT *obj = edascm_to_object (obj_s);
557   int type, width = -1, angle1 = -1, space1 = -1, angle2 = -1, space2 = -1;
558 
559   if      (type_s == hollow_sym)   { type = FILLING_HOLLOW;   }
560   else if (type_s == solid_sym) { type = FILLING_FILL; }
561   else if (type_s == hatch_sym)  { type = FILLING_HATCH;  }
562   else if (type_s == mesh_sym)  { type = FILLING_MESH;  }
563   else {
564     scm_misc_error (s_set_object_fill_x,
565                     _("Invalid fill style ~A."),
566                     scm_list_1 (type_s));
567   }
568 
569   switch (type) {
570   case FILLING_MESH:
571     if (space2_s == SCM_UNDEFINED) {
572       scm_misc_error (s_set_object_fill_x,
573                       _("Missing second space parameter for fill style ~A."),
574                       scm_list_1 (space2_s));
575     }
576     SCM_ASSERT (scm_is_integer (space2_s), space2_s,
577                 SCM_ARG6, s_set_object_fill_x);
578     space2 = scm_to_int (space2_s);
579 
580     if (angle2_s == SCM_UNDEFINED) {
581       scm_misc_error (s_set_object_fill_x,
582                       _("Missing second angle parameter for fill style ~A."),
583                       scm_list_1 (angle2_s));
584     }
585     SCM_ASSERT (scm_is_integer (angle2_s), angle2_s,
586                 SCM_ARG7, s_set_object_fill_x);
587     angle2 = scm_to_int (angle2_s);
588     /* This case intentionally falls through */
589   case FILLING_HATCH:
590     if (width_s == SCM_UNDEFINED) {
591       scm_misc_error (s_set_object_fill_x,
592                       _("Missing stroke width parameter for fill style ~A."),
593                       scm_list_1 (width_s));
594     }
595     SCM_ASSERT (scm_is_integer (width_s), width_s,
596                 SCM_ARG3, s_set_object_fill_x);
597     width = scm_to_int (width_s);
598 
599     if (space1_s == SCM_UNDEFINED) {
600       scm_misc_error (s_set_object_fill_x,
601                       _("Missing space parameter for fill style ~A."),
602                       scm_list_1 (space1_s));
603     }
604     SCM_ASSERT (scm_is_integer (space1_s), space1_s,
605                 SCM_ARG4, s_set_object_fill_x);
606     space1 = scm_to_int (space1_s);
607 
608     if (angle1_s == SCM_UNDEFINED) {
609       scm_misc_error (s_set_object_fill_x,
610                       _("Missing angle parameter for fill style ~A."),
611                       scm_list_1 (angle1_s));
612     }
613     SCM_ASSERT (scm_is_integer (angle1_s), angle1_s,
614                 SCM_ARG5, s_set_object_fill_x);
615     angle1 = scm_to_int (angle1_s);
616     /* This case intentionally falls through */
617   }
618 
619   o_set_fill_options (toplevel, obj, type, width,
620                       space1, angle1, space2, angle2);
621   o_page_changed (toplevel, obj);
622 
623   return obj_s;
624 }
625 
626 /*! \brief Get the color of an object.
627  * \par Function Description
628  * Returns the colormap index of the color used to draw the #OBJECT
629  * smob \a obj_s. Note that the color may not be meaningful for some
630  * object types.
631  *
632  * \note Scheme API: Implements the %object-color procedure in the
633  * (geda core object) module.
634  *
635  * \param [in] obj_s #OBJECT smob to inspect.
636  * \return The colormap index used by \a obj_s.
637  */
638 SCM_DEFINE (object_color, "%object-color", 1, 0, 0,
639             (SCM obj_s), "Get the color of an object.")
640 {
641   SCM_ASSERT (EDASCM_OBJECTP (obj_s), obj_s,
642               SCM_ARG1, s_object_color);
643 
644   OBJECT *obj = edascm_to_object (obj_s);
645   return scm_from_int (obj->color);
646 }
647 
648 /*! \brief Set the color of an object.
649  * \par Function Description
650  * Set the colormap index of the color used to draw the #OBJECT smob
651  * \a obj_s to \a color_s. Note that the color may not be meaningful
652  * for some object types.
653  *
654  * \note Scheme API: Implements the %set-object-color! procedure in
655  * the (geda core object) module.
656  *
657  * \param obj_s   #OBJECT smob to modify.
658  * \param color_s new colormap index to use for \a obj_s.
659  * \return the modified \a obj_s.
660  */
661 SCM_DEFINE (set_object_color_x, "%set-object-color!", 2, 0, 0,
662             (SCM obj_s, SCM color_s), "Set the color of an object.")
663 {
664   SCM_ASSERT (EDASCM_OBJECTP (obj_s), obj_s,
665               SCM_ARG1, s_set_object_color_x);
666   SCM_ASSERT (scm_is_integer (color_s), color_s,
667               SCM_ARG2, s_set_object_color_x);
668 
669   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
670   OBJECT *obj = edascm_to_object (obj_s);
671   o_set_color (toplevel, obj, scm_to_int (color_s));
672 
673   o_page_changed (toplevel, obj);
674 
675   return obj_s;
676 }
677 
678 /*! \brief Create a new line.
679  * \par Function Description
680  * Creates a new line object, with all its parameters set to default
681  * values.
682  *
683  * \note Scheme API: Implements the %make-line procedure in the (geda
684  * core object) module.
685  *
686  * \return a newly-created line object.
687  */
688 SCM_DEFINE (make_line, "%make-line", 0, 0, 0,
689             (), "Create a new line object.")
690 {
691   OBJECT *obj = o_line_new (edascm_c_current_toplevel (),
692                             OBJ_LINE, DEFAULT_COLOR,
693                             0, 0, 0, 0);
694 
695   SCM result = edascm_from_object (obj);
696 
697   /* At the moment, the only pointer to the object is owned by the
698    * smob. */
699   edascm_c_set_gc (result, TRUE);
700 
701   return result;
702 }
703 
704 /*! \brief Set line parameters.
705  * \par Function Description
706  * Modifies a line object by setting its parameters to new values.
707  *
708  * \note Scheme API: Implements the %set-line! procedure in the (geda
709  * core object) module.
710  *
711  * This function also works on net, bus and pin objects.  For pins,
712  * the start is the connectable point on the pin.
713  *
714  * \param line_s the line object to modify.
715  * \param x1_s   the new x-coordinate of the start of the line.
716  * \param y1_s   the new y-coordinate of the start of the line.
717  * \param x2_s   the new x-coordinate of the end of the line.
718  * \param y2_s   the new y-coordinate of the end of the line.
719  * \param color  the colormap index of the color to be used for
720  *               drawing the line.
721  *
722  * \return the modified line object.
723  */
724 SCM_DEFINE (set_line_x, "%set-line!", 6, 0, 0,
725             (SCM line_s, SCM x1_s, SCM y1_s, SCM x2_s, SCM y2_s, SCM color_s),
726             "Set line parameters.")
727 {
728   SCM_ASSERT ((edascm_is_object_type (line_s, OBJ_LINE)
729                || edascm_is_object_type (line_s, OBJ_NET)
730                || edascm_is_object_type (line_s, OBJ_BUS)
731                || edascm_is_object_type (line_s, OBJ_PIN)),
732               line_s, SCM_ARG1, s_set_line_x);
733 
734   SCM_ASSERT (scm_is_integer (x1_s),    x1_s,    SCM_ARG2, s_set_line_x);
735   SCM_ASSERT (scm_is_integer (y1_s),    y1_s,    SCM_ARG3, s_set_line_x);
736   SCM_ASSERT (scm_is_integer (x2_s),    x2_s,    SCM_ARG4, s_set_line_x);
737   SCM_ASSERT (scm_is_integer (y2_s),    y2_s,    SCM_ARG5, s_set_line_x);
738   SCM_ASSERT (scm_is_integer (color_s), color_s, SCM_ARG6, s_set_line_x);
739 
740   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
741   OBJECT *obj = edascm_to_object (line_s);
742   int x1 = scm_to_int (x1_s);
743   int y1 = scm_to_int (y1_s);
744   int x2 = scm_to_int (x2_s);
745   int y2 = scm_to_int (y2_s);
746 
747   /* We may need to update connectivity. */
748   s_conn_remove_object (toplevel, obj);
749 
750   switch (obj->type) {
751   case OBJ_LINE:
752     o_line_modify (toplevel, obj, x1, y1, LINE_END1);
753     o_line_modify (toplevel, obj, x2, y2, LINE_END2);
754     break;
755   case OBJ_NET:
756     o_net_modify (toplevel, obj, x1, y1, 0);
757     o_net_modify (toplevel, obj, x2, y2, 1);
758     break;
759   case OBJ_BUS:
760     o_bus_modify (toplevel, obj, x1, y1, 0);
761     o_bus_modify (toplevel, obj, x2, y2, 1);
762     break;
763   case OBJ_PIN:
764     /* Swap ends according to pin's whichend flag. */
765     o_pin_modify (toplevel, obj, x1, y1, obj->whichend ? 1 : 0);
766     o_pin_modify (toplevel, obj, x2, y2, obj->whichend ? 0 : 1);
767     break;
768   default:
769     return line_s;
770   }
771   o_set_color (toplevel, obj, scm_to_int (color_s));
772 
773   /* We may need to update connectivity. */
774   s_tile_update_object (toplevel, obj);
775   s_conn_update_object (toplevel, obj);
776 
777   o_page_changed (toplevel, obj);
778 
779   return line_s;
780 }
781 
782 /*! \brief Get line parameters.
783  * \par Function Description
784  * Retrieves the parameters of a line object. The return value is a
785  * list of parameters:
786  *
787  * -# X-coordinate of start of line
788  * -# Y-coordinate of start of line
789  * -# X-coordinate of end of line
790  * -# Y-coordinate of end of line
791  * -# Colormap index of color to be used for drawing the line
792  *
793  * This function also works on net, bus and pin objects.  For pins,
794  * the start is the connectable point on the pin.
795  *
796  * \param line_s the line object to inspect.
797  * \return a list of line parameters.
798  */
799 SCM_DEFINE (line_info, "%line-info", 1, 0, 0,
800             (SCM line_s), "Get line parameters.")
801 {
802   SCM_ASSERT ((edascm_is_object_type (line_s, OBJ_LINE)
803                || edascm_is_object_type (line_s, OBJ_NET)
804                || edascm_is_object_type (line_s, OBJ_BUS)
805                || edascm_is_object_type (line_s, OBJ_PIN)),
806               line_s, SCM_ARG1, s_line_info);
807 
808   OBJECT *obj = edascm_to_object (line_s);
809   SCM x1 = scm_from_int (obj->line->x[0]);
810   SCM y1 = scm_from_int (obj->line->y[0]);
811   SCM x2 = scm_from_int (obj->line->x[1]);
812   SCM y2 = scm_from_int (obj->line->y[1]);
813   SCM color = scm_from_int (obj->color);
814 
815   /* Swap ends according to pin's whichend flag. */
816   if ((obj->type == OBJ_PIN) && obj->whichend) {
817     SCM s;
818     s = x1; x1 = x2; x2 = s;
819     s = y1; y1 = y2; y2 = s;
820   }
821 
822   return scm_list_n (x1, y1, x2, y2, color, SCM_UNDEFINED);
823 }
824 
825 /*! \brief Create a new net.
826  * \par Function Description
827  * Creates a new net object, with all its parameters set to default
828  * values.
829  *
830  * \note Scheme API: Implements the %make-net procedure in the (geda
831  * core object) module.
832  *
833  * \return a newly-created net object.
834  */
835 SCM_DEFINE (make_net, "%make-net", 0, 0, 0,
836             (), "Create a new net object.")
837 {
838   OBJECT *obj;
839   SCM result;
840 
841   obj = o_net_new (edascm_c_current_toplevel (),
842                    OBJ_NET, NET_COLOR, 0, 0, 0, 0);
843 
844 
845   result = edascm_from_object (obj);
846 
847   /* At the moment, the only pointer to the object is owned by the
848    * smob. */
849   edascm_c_set_gc (result, 1);
850 
851   return result;
852 }
853 
854 /*! \brief Create a new bus.
855  * \par Function Description
856  * Creates a new bus object, with all its parameters set to default
857  * values.
858  *
859  * \note Scheme API: Implements the %make-bus procedure in the (geda
860  * core object) module.
861  *
862  * \todo Do we need a way to get/set bus ripper direction?
863  *
864  * \return a newly-created bus object.
865  */
866 SCM_DEFINE (make_bus, "%make-bus", 0, 0, 0,
867             (), "Create a new bus object.")
868 {
869   OBJECT *obj;
870   SCM result;
871 
872   obj = o_bus_new (edascm_c_current_toplevel (),
873                    OBJ_BUS, BUS_COLOR, 0, 0, 0, 0,
874                    0); /* Bus ripper direction */
875 
876   result = edascm_from_object (obj);
877 
878   /* At the moment, the only pointer to the object is owned by the
879    * smob. */
880   edascm_c_set_gc (result, 1);
881 
882   return result;
883 }
884 
885 /*! \brief Create a new pin.
886  * \par Function description
887  * Creates a new pin object, with all parameters set to default
888  * values.  type_s is a Scheme symbol indicating whether the pin
889  * should be a "net" pin or a "bus" pin.
890  *
891  * \note Scheme API: Implements the %make-pin procedure in the (geda
892  * core object) module.
893  *
894  * \return a newly-created pin object.
895  */
896 SCM_DEFINE (make_pin, "%make-pin", 1, 0, 0,
897             (SCM type_s), "Create a new pin object.")
898 {
899   SCM_ASSERT (scm_is_symbol (type_s),
900               type_s, SCM_ARG1, s_make_pin);
901 
902   int type;
903   if (type_s == net_sym) {
904     type = PIN_TYPE_NET;
905   } else if (type_s == bus_sym) {
906     type = PIN_TYPE_BUS;
907   } else {
908     scm_misc_error (s_make_pin,
909                     _("Invalid pin type ~A, must be 'net or 'bus"),
910                     scm_list_1 (type_s));
911   }
912 
913   OBJECT *obj = o_pin_new (edascm_c_current_toplevel (),
914                            OBJ_PIN, PIN_COLOR, 0, 0, 0, 0, type, 0);
915   SCM result = edascm_from_object (obj);
916 
917   /* At the moment, the only pointer to the object is owned by the
918    * smob. */
919   edascm_c_set_gc (result, 1);
920 
921   return result;
922 }
923 
924 /*! \brief Get the type of a pin object.
925  * \par Function Description
926  * Returns a symbol describing the pin type of the pin object \a
927  * pin_s.
928  *
929  * \note Scheme API: Implements the %make-pin procedure in the (geda
930  * core object) module.
931  *
932  * \return the symbol 'pin or 'bus.
933  */
934 SCM_DEFINE (pin_type, "%pin-type", 1, 0, 0,
935             (SCM pin_s), "Get the type of a pin object.")
936 {
937   SCM_ASSERT (edascm_is_object_type (pin_s, OBJ_PIN), pin_s,
938               SCM_ARG1, s_pin_type);
939 
940   OBJECT *obj = edascm_to_object (pin_s);
941   SCM result;
942 
943   switch (obj->pin_type) {
944   case PIN_TYPE_NET:
945     result = net_sym;
946     break;
947   case PIN_TYPE_BUS:
948     result = bus_sym;
949     break;
950   default:
951     scm_misc_error (s_make_pin,
952                     _("Object ~A has invalid pin type."),
953                     scm_list_1 (pin_s));
954   }
955 
956   return result;
957 }
958 
959 /*! \brief Create a new box.
960  * \par Function Description
961  * Creates a new box object, with all its parameters set to default
962  * values.
963  *
964  * \note Scheme API: Implements the %make-box procedure in the (geda
965  * core object) module.
966  *
967  * \return a newly-created box object.
968  */
969 SCM_DEFINE (make_box, "%make-box", 0, 0, 0,
970             (), "Create a new box object.")
971 {
972   OBJECT *obj = o_box_new (edascm_c_current_toplevel (),
973                            OBJ_BOX, DEFAULT_COLOR,
974                            0, 0, 0, 0);
975 
976   SCM result = edascm_from_object (obj);
977 
978   /* At the moment, the only pointer to the object is owned by the
979    * smob. */
980   edascm_c_set_gc (result, 1);
981 
982   return result;
983 }
984 
985 /*! \brief Set box parameters.
986  * \par Function Description
987  * Modifies a box object by setting its parameters to new values.
988  *
989  * \note Scheme API: Implements the %set-box! procedure in the (geda
990  * core object) module.
991  *
992  * \param box_s  the box object to modify.
993  * \param x1_s   the new x-coordinate of the top left of the box.
994  * \param y1_s   the new y-coordinate of the top left of the box.
995  * \param x2_s   the new x-coordinate of the bottom right of the box.
996  * \param y2_s   the new y-coordinate of the bottom right of the box.
997  * \param color  the colormap index of the color to be used for
998  *               drawing the box.
999  *
1000  * \return the modified box object.
1001  */
1002 SCM_DEFINE (set_box_x, "%set-box!", 6, 0, 0,
1003             (SCM box_s, SCM x1_s, SCM y1_s, SCM x2_s, SCM y2_s, SCM color_s),
1004             "Set box parameters.")
1005 {
1006   SCM_ASSERT (edascm_is_object_type (box_s, OBJ_BOX), box_s,
1007               SCM_ARG1, s_set_box_x);
1008   SCM_ASSERT (scm_is_integer (x1_s),    x1_s,    SCM_ARG2, s_set_box_x);
1009   SCM_ASSERT (scm_is_integer (y1_s),    y1_s,    SCM_ARG3, s_set_box_x);
1010   SCM_ASSERT (scm_is_integer (x2_s),    x2_s,    SCM_ARG4, s_set_box_x);
1011   SCM_ASSERT (scm_is_integer (y2_s),    y2_s,    SCM_ARG5, s_set_box_x);
1012   SCM_ASSERT (scm_is_integer (color_s), color_s, SCM_ARG6, s_set_box_x);
1013 
1014   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1015   OBJECT *obj = edascm_to_object (box_s);
1016   o_box_modify_all (toplevel, obj,
1017                     scm_to_int (x1_s), scm_to_int (y1_s),
1018                     scm_to_int (x2_s), scm_to_int (y2_s));
1019   o_set_color (toplevel, obj, scm_to_int (color_s));
1020 
1021   o_page_changed (toplevel, obj);
1022 
1023   return box_s;
1024 }
1025 
1026 /*! \brief Get box parameters.
1027  * \par Function Description
1028  * Retrieves the parameters of a box object. The return value is a
1029  * list of parameters:
1030  *
1031  * -# X-coordinate of top left of box
1032  * -# Y-coordinate of top left of box
1033  * -# X-coordinate of bottom right of box
1034  * -# Y-coordinate of bottom right of box
1035  * -# Colormap index of color to be used for drawing the box
1036  *
1037  * \param box_s the box object to inspect.
1038  * \return a list of box parameters.
1039  */
1040 SCM_DEFINE (box_info, "%box-info", 1, 0, 0,
1041             (SCM box_s), "Get box parameters.")
1042 {
1043   SCM_ASSERT (edascm_is_object_type (box_s, OBJ_BOX), box_s,
1044               SCM_ARG1, s_box_info);
1045 
1046   OBJECT *obj = edascm_to_object (box_s);
1047 
1048   return scm_list_n (scm_from_int (obj->box->upper_x),
1049                      scm_from_int (obj->box->upper_y),
1050                      scm_from_int (obj->box->lower_x),
1051                      scm_from_int (obj->box->lower_y),
1052                      scm_from_int (obj->color),
1053                      SCM_UNDEFINED);
1054 }
1055 
1056 /*! \brief Create a new circle.
1057  * \par Function Description
1058 
1059  * Creates a new circle object, with all its parameters set to default
1060  * values.
1061  *
1062  * \note Scheme API: Implements the %make-circle procedure in the
1063  * (geda core object) module.
1064  *
1065  * \return a newly-created circle object.
1066  */
1067 SCM_DEFINE (make_circle, "%make-circle", 0, 0, 0,
1068             (), "Create a new circle object.")
1069 {
1070   OBJECT *obj = o_circle_new (edascm_c_current_toplevel (),
1071                               OBJ_CIRCLE, DEFAULT_COLOR,
1072                               0, 0, 1);
1073 
1074   SCM result = edascm_from_object (obj);
1075 
1076   /* At the moment, the only pointer to the object is owned by the
1077    * smob. */
1078   edascm_c_set_gc (result, 1);
1079 
1080   return result;
1081 }
1082 
1083 /*! \brief Set circle parameters.
1084  * \par Function Description
1085  * Modifies a circle object by setting its parameters to new values.
1086  *
1087  * \note Scheme API: Implements the %set-circle! procedure in the
1088  * (geda core object) module.
1089  *
1090  * \param circle_s the circle object to modify.
1091  * \param x_s    the new x-coordinate of the center of the circle.
1092  * \param y_s    the new y-coordinate of the center of the circle.
1093  * \param r_s    the new radius of the circle.
1094  * \param color  the colormap index of the color to be used for
1095  *               drawing the circle.
1096  *
1097  * \return the modified circle object.
1098  */
1099 SCM_DEFINE (set_circle_x, "%set-circle!", 5, 0, 0,
1100             (SCM circle_s, SCM x_s, SCM y_s, SCM r_s, SCM color_s),
1101             "Set circle parameters")
1102 {
1103   SCM_ASSERT (edascm_is_object_type (circle_s, OBJ_CIRCLE), circle_s,
1104               SCM_ARG1, s_set_circle_x);
1105   SCM_ASSERT (scm_is_integer (x_s),     x_s,     SCM_ARG2, s_set_circle_x);
1106   SCM_ASSERT (scm_is_integer (y_s),     y_s,     SCM_ARG3, s_set_circle_x);
1107   SCM_ASSERT (scm_is_integer (r_s),     r_s,     SCM_ARG4, s_set_circle_x);
1108   SCM_ASSERT (scm_is_integer (color_s), color_s, SCM_ARG5, s_set_circle_x);
1109 
1110   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1111   OBJECT *obj = edascm_to_object (circle_s);
1112   o_circle_modify (toplevel, obj, scm_to_int(x_s), scm_to_int(y_s),
1113                    CIRCLE_CENTER);
1114   o_circle_modify (toplevel, obj, scm_to_int(r_s), 0, CIRCLE_RADIUS);
1115   o_set_color (toplevel, obj, scm_to_int (color_s));
1116 
1117   o_page_changed (toplevel, obj);
1118 
1119   return circle_s;
1120 }
1121 
1122 /*! \brief Get circle parameters.
1123  * \par Function Description
1124 
1125  * Retrieves the parameters of a circle object. The return value is a
1126  * list of parameters:
1127  *
1128  * -# X-coordinate of center of circle
1129  * -# Y-coordinate of center of circle
1130  * -# Radius of circle
1131  * -# Colormap index of color to be used for drawing the circle
1132  *
1133  * \param circle_s the circle object to inspect.
1134  * \return a list of circle parameters.
1135  */
1136 SCM_DEFINE (circle_info, "%circle-info", 1, 0, 0,
1137             (SCM circle_s), "Get circle parameters.")
1138 {
1139   SCM_ASSERT (edascm_is_object_type (circle_s, OBJ_CIRCLE),
1140               circle_s, SCM_ARG1, s_circle_info);
1141 
1142   OBJECT *obj = edascm_to_object (circle_s);
1143 
1144   return scm_list_n (scm_from_int (obj->circle->center_x),
1145                      scm_from_int (obj->circle->center_y),
1146                      scm_from_int (obj->circle->radius),
1147                      scm_from_int (obj->color),
1148                      SCM_UNDEFINED);
1149 }
1150 
1151 /*! \brief Create a new arc.
1152  * \par Function Description
1153  * Creates a new arc object, with all its parameters set to default
1154  * values.
1155  *
1156  * \note Scheme API: Implements the %make-arc procedure in the
1157  * (geda core object) module.
1158  *
1159  * \return a newly-created arc object.
1160  */
1161 SCM_DEFINE (make_arc, "%make-arc", 0, 0, 0,
1162             (), "Create a new arc object.")
1163 {
1164   OBJECT *obj = o_arc_new (edascm_c_current_toplevel (),
1165                               OBJ_ARC, DEFAULT_COLOR,
1166                            0, 0, 1, 0, 0);
1167 
1168   SCM result = edascm_from_object (obj);
1169 
1170   /* At the moment, the only pointer to the object is owned by the
1171    * smob. */
1172   edascm_c_set_gc (result, 1);
1173 
1174   return result;
1175 }
1176 
1177 /*! \brief Set arc parameters.
1178  * \par Function Description
1179  * Modifies a arc object by setting its parameters to new values.
1180  *
1181  * \note Scheme API: Implements the %set-arc! procedure in the
1182  * (geda core object) module.
1183  *
1184  * \param arc_s         the arc object to modify.
1185  * \param x_s           the new x-coordinate of the center of the arc.
1186  * \param y_s           the new y-coordinate of the center of the arc.
1187  * \param r_s           the new radius of the arc.
1188  * \param start_angle_s the start angle of the arc.
1189  * \param end_angle_s   the start angle of the arc.
1190  * \param color_s       the colormap index of the color to be used for
1191  *                      drawing the arc.
1192  *
1193  * \return the modified arc object.
1194  */
1195 SCM_DEFINE (set_arc_x, "%set-arc!", 7, 0, 0,
1196             (SCM arc_s, SCM x_s, SCM y_s, SCM r_s, SCM start_angle_s,
1197              SCM end_angle_s, SCM color_s),
1198             "Set arc parameters")
1199 {
1200   SCM_ASSERT (edascm_is_object_type (arc_s, OBJ_ARC), arc_s,
1201               SCM_ARG1, s_set_arc_x);
1202   SCM_ASSERT (scm_is_integer (x_s),     x_s,     SCM_ARG2, s_set_arc_x);
1203   SCM_ASSERT (scm_is_integer (y_s),     y_s,     SCM_ARG3, s_set_arc_x);
1204   SCM_ASSERT (scm_is_integer (r_s),     r_s,     SCM_ARG4, s_set_arc_x);
1205   SCM_ASSERT (scm_is_integer (color_s), color_s, SCM_ARG7, s_set_arc_x);
1206   SCM_ASSERT (scm_is_integer (start_angle_s),
1207                                   start_angle_s, SCM_ARG5, s_set_arc_x);
1208   SCM_ASSERT (scm_is_integer (end_angle_s),
1209                                   end_angle_s, SCM_ARG6, s_set_arc_x);
1210 
1211   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1212   OBJECT *obj = edascm_to_object (arc_s);
1213   o_arc_modify (toplevel, obj, scm_to_int(x_s), scm_to_int(y_s),
1214                    ARC_CENTER);
1215   o_arc_modify (toplevel, obj, scm_to_int(r_s), 0, ARC_RADIUS);
1216   o_arc_modify (toplevel, obj, scm_to_int(start_angle_s), 0, ARC_START_ANGLE);
1217   o_arc_modify (toplevel, obj, scm_to_int(end_angle_s), 0, ARC_END_ANGLE);
1218   o_set_color (toplevel, obj, scm_to_int (color_s));
1219 
1220   o_page_changed (toplevel, obj);
1221 
1222   return arc_s;
1223 }
1224 
1225 /*! \brief Get arc parameters.
1226  * \par Function Description
1227  * Retrieves the parameters of a arc object. The return value is a
1228  * list of parameters:
1229  *
1230  * -# X-coordinate of center of arc
1231  * -# Y-coordinate of center of arc
1232  * -# Radius of arc
1233  * -# Start angle of arc
1234  * -# End angle of arc
1235  * -# Colormap index of color to be used for drawing the arc
1236  *
1237  * \note Scheme API: Implements the %arc-info procedure in the
1238  * (geda core object) module.
1239  *
1240  * \param arc_s the arc object to inspect.
1241  * \return a list of arc parameters.
1242  */
1243 SCM_DEFINE (arc_info, "%arc-info", 1, 0, 0,
1244             (SCM arc_s), "Get arc parameters.")
1245 {
1246   SCM_ASSERT (edascm_is_object_type (arc_s, OBJ_ARC),
1247               arc_s, SCM_ARG1, s_arc_info);
1248 
1249   OBJECT *obj = edascm_to_object (arc_s);
1250 
1251   return scm_list_n (scm_from_int (obj->arc->x),
1252                      scm_from_int (obj->arc->y),
1253                      scm_from_int (obj->arc->width / 2),
1254                      scm_from_int (obj->arc->start_angle),
1255                      scm_from_int (obj->arc->end_angle),
1256                      scm_from_int (obj->color),
1257                      SCM_UNDEFINED);
1258 }
1259 
1260 /*! \brief Create a new text item.
1261  * \par Function Description
1262  * Creates a new text object, with all its parameters set to default
1263  * values.
1264  *
1265  * \note Scheme API: Implements the %make-text procedure in the
1266  * (geda core object) module.
1267  *
1268  * \return a newly-created text object.
1269  */
1270 SCM_DEFINE (make_text, "%make-text", 0, 0, 0,
1271             (), "Create a new text object.")
1272 {
1273   OBJECT *obj = o_text_new (edascm_c_current_toplevel (),
1274                             OBJ_TEXT, DEFAULT_COLOR,
1275                             0, 0, LOWER_LEFT, 0, "", 10,
1276                             VISIBLE, SHOW_NAME_VALUE);
1277 
1278   SCM result = edascm_from_object (obj);
1279 
1280   /* At the moment, the only pointer to the object is owned by the
1281    * smob. */
1282   edascm_c_set_gc (result, 1);
1283 
1284   return result;
1285 }
1286 
1287 /*! \brief Set text parameters.
1288  * \par Function Description
1289  * Modifies a text object by setting its parameters to new values.
1290  *
1291  * The alignment \a align_s should be a symbol of the form "x-y" where
1292  * x can be one of "lower", "middle", or "upper", and y can be one of
1293  * "left", "center" or "right". \a show_s determines which parts of an
1294  * attribute-formatted string should be shown, and should be one of
1295  * the symbols "name", "value" or "both".
1296  *
1297  * \note Scheme API: Implements the %set-text! procedure in the
1298  * (geda core object) module.
1299  *
1300  * \param text_s    the text object to modify.
1301  * \param x_s       the new x-coordinate of the anchor of the text.
1302  * \param y_s       the new y-coordinate of the anchor of the text.
1303  * \param align_s   the new alignment of the text on the anchor.
1304  * \param angle_s   the angle the text in degrees (0, 90, 180 or 270).
1305  * \param string_s  the new string to display.
1306  * \param size_s    the new text size.
1307  * \param visible_s the new text visibility (SCM_BOOL_T or SCM_BOOL_F).
1308  * \param show_s    the new attribute part visibility setting.
1309  * \param color_s   the colormap index of the color to be used for
1310  *                  drawing the text.
1311  *
1312  * \return the modified text object.
1313  */
1314 SCM_DEFINE (set_text_x, "%set-text!", 10, 0, 0,
1315             (SCM text_s, SCM x_s, SCM y_s, SCM align_s, SCM angle_s,
1316              SCM string_s, SCM size_s, SCM visible_s, SCM show_s, SCM color_s),
1317             "Set text parameters")
1318 {
1319   SCM_ASSERT (edascm_is_object_type (text_s, OBJ_TEXT), text_s,
1320               SCM_ARG1, s_set_text_x);
1321   SCM_ASSERT (scm_is_integer (x_s),     x_s,      SCM_ARG2, s_set_text_x);
1322   SCM_ASSERT (scm_is_integer (y_s),     y_s,      SCM_ARG3, s_set_text_x);
1323   SCM_ASSERT (scm_is_symbol (align_s),  align_s,  SCM_ARG4, s_set_text_x);
1324   SCM_ASSERT (scm_is_integer (angle_s), angle_s,  SCM_ARG5, s_set_text_x);
1325   SCM_ASSERT (scm_is_string (string_s), string_s, SCM_ARG6, s_set_text_x);
1326   SCM_ASSERT (scm_is_integer (size_s),  size_s,   SCM_ARG7, s_set_text_x);
1327 
1328   SCM_ASSERT (scm_is_symbol (show_s),    show_s,     9, s_set_text_x);
1329   SCM_ASSERT (scm_is_integer (color_s),  color_s,   10, s_set_text_x);
1330 
1331   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1332   OBJECT *obj = edascm_to_object (text_s);
1333 
1334   /* Alignment. Sadly we can't switch on pointers. :-( */
1335   int align;
1336   if      (align_s == lower_left_sym)    { align = LOWER_LEFT;    }
1337   else if (align_s == middle_left_sym)   { align = MIDDLE_LEFT;   }
1338   else if (align_s == upper_left_sym)    { align = UPPER_LEFT;    }
1339   else if (align_s == lower_center_sym)  { align = LOWER_MIDDLE;  }
1340   else if (align_s == middle_center_sym) { align = MIDDLE_MIDDLE; }
1341   else if (align_s == upper_center_sym)  { align = UPPER_MIDDLE;  }
1342   else if (align_s == lower_right_sym)   { align = LOWER_RIGHT;   }
1343   else if (align_s == middle_right_sym)  { align = MIDDLE_RIGHT;  }
1344   else if (align_s == upper_right_sym)   { align = UPPER_RIGHT;   }
1345   else {
1346     scm_misc_error (s_set_text_x,
1347                     _("Invalid text alignment ~A."),
1348                     scm_list_1 (align_s));
1349   }
1350 
1351   /* Angle */
1352   int angle = scm_to_int (angle_s);
1353   switch (angle) {
1354   case 0:
1355   case 90:
1356   case 180:
1357   case 270:
1358     /* These are all fine. */
1359     break;
1360   default:
1361     /* Otherwise, not fine. */
1362     scm_misc_error (s_set_text_x,
1363                     _("Invalid text angle ~A. Must be 0, 90, 180, or 270 degrees"),
1364                     scm_list_1 (angle_s));
1365   }
1366 
1367   /* Visibility */
1368   int visibility;
1369   if (scm_is_false (visible_s)) {
1370     visibility = INVISIBLE;
1371   } else {
1372     visibility = VISIBLE;
1373   }
1374 
1375   /* Name/value visibility */
1376   int show;
1377   if      (show_s == name_sym)  { show = SHOW_NAME;       }
1378   else if (show_s == value_sym) { show = SHOW_VALUE;      }
1379   else if (show_s == both_sym)  { show = SHOW_NAME_VALUE; }
1380   else {
1381     scm_misc_error (s_set_text_x,
1382                     _("Invalid text name/value visibility ~A."),
1383                     scm_list_1 (show_s));
1384   }
1385 
1386   /* Actually make changes */
1387   o_emit_pre_change_notify (toplevel, obj);
1388 
1389   obj->text->x = scm_to_int (x_s);
1390   obj->text->y = scm_to_int (y_s);
1391   obj->text->alignment = align;
1392   obj->text->angle = angle;
1393 
1394   obj->text->size = scm_to_int (size_s);
1395   obj->visibility = visibility;
1396   obj->show_name_value = show;
1397 
1398   o_emit_change_notify (toplevel, obj);
1399 
1400   char *tmp = scm_to_utf8_string (string_s);
1401   o_text_set_string (toplevel, obj, tmp);
1402   free (tmp);
1403 
1404   o_text_recreate (toplevel, obj);
1405 
1406   /* Color */
1407   o_set_color (toplevel, obj, scm_to_int (color_s));
1408 
1409   o_page_changed (toplevel, obj);
1410 
1411   return text_s;
1412 }
1413 
1414 /*! \brief Get text parameters.
1415  * \par Function Description
1416  * Retrieves the parameters of a text object. The return value is a
1417  * list of parameters:
1418  *
1419  * -# X-coordinate of anchor of text
1420  * -# Y-coordinate of anchor of text
1421  * -# Alignment of text
1422  * -# Angle of text
1423  * -# The string contained in the text object
1424  * -# Size of text
1425  * -# Text visibility
1426  * -# Which part(s) of an text attribute are shown
1427  * -# Colormap index of color to be used for drawing the text
1428  *
1429  * \note Scheme API: Implements the %text-info procedure in the
1430  * (geda core object) module.
1431  *
1432  * \param text_s the text object to inspect.
1433  * \return a list of text parameters.
1434  */
1435 SCM_DEFINE (text_info, "%text-info", 1, 0, 0,
1436             (SCM text_s), "Get text parameters.")
1437 {
1438   SCM_ASSERT (edascm_is_object_type (text_s, OBJ_TEXT),
1439               text_s, SCM_ARG1, s_text_info);
1440 
1441   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1442   OBJECT *obj = edascm_to_object (text_s);
1443   SCM align_s, visible_s, show_s;
1444 
1445   switch (obj->text->alignment) {
1446   case LOWER_LEFT:    align_s = lower_left_sym;    break;
1447   case MIDDLE_LEFT:   align_s = middle_left_sym;   break;
1448   case UPPER_LEFT:    align_s = upper_left_sym;    break;
1449   case LOWER_MIDDLE:  align_s = lower_center_sym;  break;
1450   case MIDDLE_MIDDLE: align_s = middle_center_sym; break;
1451   case UPPER_MIDDLE:  align_s = upper_center_sym;  break;
1452   case LOWER_RIGHT:   align_s = lower_right_sym;   break;
1453   case MIDDLE_RIGHT:  align_s = middle_right_sym;  break;
1454   case UPPER_RIGHT:   align_s = upper_right_sym;   break;
1455   default:
1456     scm_misc_error (s_text_info,
1457                     _("Text object ~A has invalid text alignment ~A"),
1458                     scm_list_2 (text_s, scm_from_int (obj->text->alignment)));
1459   }
1460 
1461   switch (obj->visibility) {
1462   case VISIBLE:   visible_s = SCM_BOOL_T; break;
1463   case INVISIBLE: visible_s = SCM_BOOL_F; break;
1464   default:
1465     scm_misc_error (s_text_info,
1466                     _("Text object ~A has invalid visibility ~A"),
1467                     scm_list_2 (text_s, scm_from_int (obj->visibility)));
1468   }
1469 
1470   switch (obj->show_name_value) {
1471   case SHOW_NAME:       show_s = name_sym;  break;
1472   case SHOW_VALUE:      show_s = value_sym; break;
1473   case SHOW_NAME_VALUE: show_s = both_sym;  break;
1474   default:
1475     scm_misc_error (s_text_info,
1476                     _("Text object ~A has invalid text attribute visibility ~A"),
1477                     scm_list_2 (text_s, scm_from_int (obj->show_name_value)));
1478   }
1479 
1480   return scm_list_n (scm_from_int (obj->text->x),
1481                      scm_from_int (obj->text->y),
1482                      align_s,
1483                      scm_from_int (obj->text->angle),
1484                      scm_from_utf8_string (o_text_get_string (toplevel, obj)),
1485                      scm_from_int (obj->text->size),
1486                      visible_s,
1487                      show_s,
1488                      scm_from_int (obj->color),
1489                      SCM_UNDEFINED);
1490 }
1491 
1492 /*! \brief Get objects that are connected to an object.
1493  * \par Function Description
1494  * Returns a list of all objects directly connected to \a obj_s.  If
1495  * \a obj_s is not included in a page, throws a Scheme error.  If \a
1496  * obj_s is not a pin, net, bus, or complex object, returns the empty
1497  * list.
1498  *
1499  * \note Scheme API: Implements the %object-connections procedure of
1500  * the (geda core object) module.
1501  *
1502  * \param obj_s #OBJECT smob for object to get connections for.
1503  * \return a list of #OBJECT smobs.
1504  */
1505 SCM_DEFINE (object_connections, "%object-connections", 1, 0, 0,
1506             (SCM obj_s), "Get objects that are connected to an object.")
1507 {
1508   /* Ensure that the argument is an object smob */
1509   SCM_ASSERT (edascm_is_object (obj_s), obj_s,
1510               SCM_ARG1, s_object_connections);
1511 
1512   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1513   OBJECT *obj = edascm_to_object (obj_s);
1514   if (o_get_page (toplevel, obj) == NULL) {
1515     scm_error (edascm_object_state_sym,
1516                s_object_connections,
1517                _("Object ~A is not included in a page."),
1518                scm_list_1 (obj_s), SCM_EOL);
1519   }
1520 
1521   GList *lst = s_conn_return_others (NULL, obj);
1522   SCM result = edascm_from_object_glist (lst);
1523   g_list_free (lst);
1524   return result;
1525 }
1526 
1527 /*! \brief Get the complex object that contains an object.
1528  * \par Function Description
1529  * Returns the complex object that contains the object \a obj_s.  If
1530  * \a obj_s is not part of a component, returns SCM_BOOL_F.
1531  *
1532  * \note Scheme API: Implements the %object-complex procedure of the
1533  * (geda core object) module.
1534  *
1535  * \param obj_s #OBJECT smob for object to get component of.
1536  * \return the #OBJECT smob of the containing component, or SCM_BOOL_F.
1537  */
1538 SCM_DEFINE (object_complex, "%object-complex", 1, 0, 0,
1539             (SCM obj_s), "Get containing complex object of an object.")
1540 {
1541   /* Ensure that the argument is an object smob */
1542   SCM_ASSERT (edascm_is_object (obj_s), obj_s,
1543               SCM_ARG1, s_object_complex);
1544 
1545   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1546   OBJECT *obj = edascm_to_object (obj_s);
1547   OBJECT *parent = o_get_parent (toplevel, obj);
1548 
1549   if (parent == NULL) return SCM_BOOL_F;
1550 
1551   return edascm_from_object (parent);
1552 }
1553 
1554 /*! \brief Make a new, empty path object.
1555  * \par Function Description
1556  * Creates a new, empty path object with default color, stroke and
1557  * fill options.
1558  *
1559  * \note Scheme API: Implements the %make-path procedure in the (geda
1560  * core object) module.
1561  *
1562  * \return a newly-created path object.
1563  */
1564 SCM_DEFINE (make_path, "%make-path", 0, 0, 0,
1565             (), "Create a new path object")
1566 {
1567   OBJECT *obj = o_path_new (edascm_c_current_toplevel (),
1568                             OBJ_PATH, DEFAULT_COLOR, "");
1569 
1570   SCM result = edascm_from_object (obj);
1571 
1572   /* At the moment, the only pointer to the object is owned by the
1573    * smob. */
1574   edascm_c_set_gc (result, TRUE);
1575 
1576   return result;
1577 }
1578 
1579 /*! \brief Get the number of elements in a path.
1580  * \par Function Description
1581  * Retrieves the number of path elements in the path object \a obj_s.
1582  *
1583  * \note Scheme API: Implements the %path-length procedure in the
1584  * (geda core object) module.
1585  *
1586  * \param obj_s #OBJECT smob for path object to inspect.
1587  * \return The number of path elements in \a obj_s.
1588  */
1589 SCM_DEFINE (path_length, "%path-length", 1, 0, 0,
1590             (SCM obj_s), "Get number of elements in a path object.")
1591 {
1592   /* Ensure that the argument is a path object */
1593   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PATH), obj_s,
1594               SCM_ARG1, s_path_length);
1595 
1596   OBJECT *obj = edascm_to_object (obj_s);
1597   return scm_from_int (obj->path->num_sections);
1598 }
1599 
1600 /*! \brief Get one of the elements from a path.
1601  * \par Function Description
1602  * Retrieves a path element at index \a index_s from the path object
1603  * \a obj_s.  If \a index_s is not a valid index, raises a Scheme
1604  * "out-of-range" error.
1605  *
1606  * The return value is a list.  The first element in the list is a
1607  * symbol indicating the type of path element ("moveto", "lineto",
1608  * "curveto" or "closepath"), and the remainder of the list contains
1609  * zero or more control point coordinates, depending on the type of
1610  * path element.  Each element is evaluated relative to the current
1611  * path position.
1612  *
1613  * - moveto: x and y coordinates of position to step to.
1614  * - lineto: x and y coordinates of straight line endpoint.
1615  * - curveto: coordinates of first Bezier control point; coordinates
1616  *   of second control point; and coordinates of curve endpoint.
1617  * - closepath: No coordinate parameters.
1618  *
1619  * All coordinates are absolute.
1620  *
1621  * \note Scheme API: Implements the %path-ref procedure in the (geda
1622  * core object) module.
1623  *
1624  * \param obj_s   #OBJECT smob of path object to get element from.
1625  * \param index_s Index of element to retrieve from \a obj_s
1626  * \return A list containing the requested path element data.
1627  */
1628 SCM_DEFINE (path_ref, "%path-ref", 2, 0, 0,
1629             (SCM obj_s, SCM index_s),
1630             "Get a path element from a path object.")
1631 {
1632   /* Ensure that the arguments are a path object and integer */
1633   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PATH), obj_s,
1634               SCM_ARG1, s_path_ref);
1635   SCM_ASSERT (scm_is_integer (index_s), index_s, SCM_ARG2, s_path_ref);
1636 
1637   OBJECT *obj = edascm_to_object (obj_s);
1638   int idx = scm_to_int (index_s);
1639 
1640   /* Check index is valid for path */
1641   if ((idx < 0) || (idx >= obj->path->num_sections)) {
1642     scm_out_of_range (s_path_ref, index_s);
1643   }
1644 
1645   PATH_SECTION *section = &obj->path->sections[idx];
1646 
1647   switch (section->code) {
1648   case PATH_MOVETO:
1649   case PATH_MOVETO_OPEN:
1650     return scm_list_3 (moveto_sym,
1651                        scm_from_int (section->x3),
1652                        scm_from_int (section->y3));
1653   case PATH_LINETO:
1654     return scm_list_3 (lineto_sym,
1655                        scm_from_int (section->x3),
1656                        scm_from_int (section->y3));
1657   case PATH_CURVETO:
1658     return scm_list_n (curveto_sym,
1659                        scm_from_int (section->x1),
1660                        scm_from_int (section->y1),
1661                        scm_from_int (section->x2),
1662                        scm_from_int (section->y2),
1663                        scm_from_int (section->x3),
1664                        scm_from_int (section->y3),
1665                        SCM_UNDEFINED);
1666   case PATH_END:
1667     return scm_list_1 (closepath_sym);
1668   default:
1669     scm_misc_error (s_path_ref,
1670                     _("Path object ~A has invalid element type ~A at index ~A"),
1671                     scm_list_3 (obj_s, scm_from_int (section->code), index_s));
1672   }
1673 
1674 }
1675 
1676 /*! \brief Remove an element from a path.
1677  * \par Function Description
1678  * Removes the path element at index \a index_s from the path object
1679  * \a obj_s. If \a index_s is not a valid index, raises a Scheme
1680  * "out-of-range" error.
1681  *
1682  * \note Scheme API: Implements the %path-remove! procedure in the
1683  * (geda core object) module.
1684  *
1685  * \param obj_s   #OBJECT smob of path object to remove element from.
1686  * \param index_s Index of element to remove from \a obj_s.
1687  * \return \a obj_s.
1688  */
1689 SCM_DEFINE (path_remove_x, "%path-remove!", 2, 0, 0,
1690             (SCM obj_s, SCM index_s),
1691             "Remove a path element from a path object.")
1692 {
1693   /* Ensure that the arguments are a path object and integer */
1694   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PATH), obj_s,
1695               SCM_ARG1, s_path_ref);
1696   SCM_ASSERT (scm_is_integer (index_s), index_s, SCM_ARG2, s_path_ref);
1697 
1698   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1699   OBJECT *obj = edascm_to_object (obj_s);
1700   int idx = scm_to_int (index_s);
1701 
1702   if ((idx < 0) || (idx >= obj->path->num_sections)) {
1703     /* Index is valid for path */
1704     scm_out_of_range (s_path_ref, index_s);
1705 
1706   }
1707 
1708   o_emit_pre_change_notify (toplevel, obj);
1709 
1710   if (idx + 1 == obj->path->num_sections) {
1711     /* Section is last in path */
1712     obj->path->num_sections--;
1713 
1714   } else {
1715     /* Remove section at index by moving all sections above index one
1716      * location down. */
1717     memmove (&obj->path->sections[idx],
1718              &obj->path->sections[idx+1],
1719              sizeof (PATH_SECTION) * (obj->path->num_sections - idx - 1));
1720     obj->path->num_sections--;
1721   }
1722 
1723   o_emit_change_notify (toplevel, obj);
1724   o_page_changed (toplevel, obj);
1725 
1726   return obj_s;
1727 }
1728 
1729 /*! \brief Insert an element into a path.
1730  * \par Function Description
1731  * Inserts a path element into the path object \a obj_s at index \a
1732  * index_s.  The type of element to be inserted is specified by the
1733  * symbol \a type_s, and the remaining optional integer arguments
1734  * provide as many absolute coordinate pairs as are required by that
1735  * element type:
1736  *
1737  * - "closepath" elements require no coordinate arguments;
1738  * - "moveto" and "lineto" elements require one coordinate pair, for
1739  *   the endpoint;
1740  * - "curveto" elements require the coordinates of the first control
1741  *   point, coordinates of the second control point, and coordinates
1742  *   of the endpoint.
1743  *
1744  * If the index is negative, or is greater than or equal to the number
1745  * of elements currently in the path, the new element will be appended
1746  * to the path.
1747  *
1748  * \note Scheme API: Implements the %path-insert! procedure of the
1749  * (geda core object) module.
1750  *
1751  * \param obj_s   #OBJECT smob for the path object to modify.
1752  * \param index_s Index at which to insert new element.
1753  * \param type_s  Symbol indicating what type of element to insert.
1754  * \param x1_s    X-coordinate of first coordinate pair.
1755  * \param y1_s    Y-coordinate of first coordinate pair.
1756  * \param x2_s    X-coordinate of second coordinate pair.
1757  * \param y2_s    Y-coordinate of second coordinate pair.
1758  * \param x3_s    X-coordinate of third coordinate pair.
1759  * \param y3_s    Y-coordinate of third coordinate pair.
1760  * \return \a obj_s.
1761  */
1762 SCM_DEFINE (path_insert_x, "%path-insert", 3, 6, 0,
1763             (SCM obj_s, SCM index_s, SCM type_s,
1764              SCM x1_s, SCM y1_s, SCM x2_s, SCM y2_s, SCM x3_s, SCM y3_s),
1765             "Insert a path element into a path object.")
1766 {
1767   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PATH), obj_s,
1768               SCM_ARG1, s_path_insert_x);
1769   SCM_ASSERT (scm_is_integer (index_s), index_s, SCM_ARG2, s_path_insert_x);
1770   SCM_ASSERT (scm_is_symbol (type_s), type_s, SCM_ARG3, s_path_insert_x);
1771 
1772   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1773   OBJECT *obj = edascm_to_object (obj_s);
1774   PATH *path = obj->path;
1775   PATH_SECTION section = {0, 0, 0, 0, 0, 0, 0};
1776 
1777   /* Check & extract path element type. */
1778   if      (type_s == closepath_sym) { section.code = PATH_END;     }
1779   else if (type_s == moveto_sym)    { section.code = PATH_MOVETO;  }
1780   else if (type_s == lineto_sym)    { section.code = PATH_LINETO;  }
1781   else if (type_s == curveto_sym)   { section.code = PATH_CURVETO; }
1782   else {
1783     scm_misc_error (s_path_insert_x,
1784                     _("Invalid path element type ~A."),
1785                     scm_list_1 (type_s));
1786   }
1787 
1788   /* Check the right number of coordinates have been provided. */
1789   switch (section.code) {
1790   case PATH_CURVETO:
1791     SCM_ASSERT (scm_is_integer (x1_s), x1_s, SCM_ARG4, s_path_insert_x);
1792     section.x1 = scm_to_int (x1_s);
1793     SCM_ASSERT (scm_is_integer (y1_s), y1_s, SCM_ARG5, s_path_insert_x);
1794     section.y1 = scm_to_int (y1_s);
1795     SCM_ASSERT (scm_is_integer (x2_s), x2_s, SCM_ARG6, s_path_insert_x);
1796     section.x2 = scm_to_int (x2_s);
1797     SCM_ASSERT (scm_is_integer (y2_s), y2_s, SCM_ARG7, s_path_insert_x);
1798     section.y2 = scm_to_int (y2_s);
1799     SCM_ASSERT (scm_is_integer (x3_s), x3_s, 8, s_path_insert_x);
1800     section.x3 = scm_to_int (x3_s);
1801     SCM_ASSERT (scm_is_integer (y3_s), y3_s, 9, s_path_insert_x);
1802     section.y3 = scm_to_int (y3_s);
1803     break;
1804   case PATH_MOVETO:
1805   case PATH_MOVETO_OPEN:
1806   case PATH_LINETO:
1807     SCM_ASSERT (scm_is_integer (x1_s), x1_s, SCM_ARG4, s_path_insert_x);
1808     section.x3 = scm_to_int (x1_s);
1809     SCM_ASSERT (scm_is_integer (y1_s), y1_s, SCM_ARG5, s_path_insert_x);
1810     section.y3 = scm_to_int (y1_s);
1811     break;
1812   case PATH_END:
1813     break;
1814   }
1815 
1816   /* Start making changes */
1817   o_emit_pre_change_notify (toplevel, obj);
1818 
1819   /* Make sure there's enough space for the new element */
1820   if (path->num_sections == path->num_sections_max) {
1821     path->sections = g_realloc (path->sections,
1822                                 (path->num_sections_max <<= 1) * sizeof (PATH_SECTION));
1823   }
1824 
1825   /* Move path contents to make a gap in the right place. */
1826   int idx = scm_to_int (index_s);
1827 
1828   if ((idx < 0) || (idx > path->num_sections)) {
1829     idx = path->num_sections;
1830   } else {
1831     memmove (&path->sections[idx+1], &path->sections[idx],
1832              sizeof (PATH_SECTION) * (path->num_sections - idx));
1833   }
1834 
1835   path->num_sections++;
1836   path->sections[idx] = section;
1837 
1838   o_emit_change_notify (toplevel, obj);
1839   o_page_changed (toplevel, obj);
1840 
1841   return obj_s;
1842 }
1843 
1844 /*! \brief Create a new, empty picture object.
1845  * \par Function Description
1846  * Creates a new picture object with no filename, no image data and
1847  * all other parameters set to default values.  It is initially set to
1848  * be embedded.
1849  *
1850  * \note Scheme API: Implements the %make-picture procedure in the
1851  * (geda core object) module.
1852  *
1853  * \return a newly-created picture object.
1854  */
1855 SCM_DEFINE (make_picture, "%make-picture", 0, 0, 0, (),
1856             "Create a new picture object")
1857 {
1858   OBJECT *obj = o_picture_new (edascm_c_current_toplevel (),
1859                                NULL, 0, NULL, OBJ_PICTURE,
1860                                0, 0, 0, 0, 0, FALSE, TRUE);
1861   SCM result = edascm_from_object (obj);
1862 
1863   /* At the moment, the only pointer to the object is owned by the
1864    * smob. */
1865   edascm_c_set_gc (result, 1);
1866 
1867   return result;
1868 }
1869 
1870 /*! \brief Get picture object parameters.
1871  * \par Function Description
1872  * Retrieves the parameters of a picture object.  The return value is
1873  * a list of parameters:
1874  *
1875  * -# Filename of picture.
1876  * -# X-coordinate of top left of picture.
1877  * -# Y-coordinate of top left of picture.
1878  * -# X-coordinate of bottom right of picture.
1879  * -# Y-coordinate of bottom right of picture.
1880  * -# Rotation angle.
1881  * -# Whether object is mirrored.
1882  *
1883  * \note Scheme API: Implements the %picture-info procedure in the
1884  * (geda core object) module.
1885  *
1886  * \param obj_s the picture object to inspect.
1887  * \return a list of picture object parameters.
1888  */
1889 SCM_DEFINE (picture_info, "%picture-info", 1, 0, 0,
1890             (SCM obj_s), "Get picture object parameters")
1891 {
1892   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PICTURE), obj_s,
1893               SCM_ARG1, s_picture_info);
1894 
1895   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1896   OBJECT *obj = edascm_to_object (obj_s);
1897   const gchar *filename = o_picture_get_filename (toplevel, obj);
1898 
1899   SCM filename_s = SCM_BOOL_F;
1900   if (filename != NULL) {
1901     filename_s = scm_from_utf8_string (filename);
1902   }
1903 
1904   return scm_list_n (filename_s,
1905                      scm_from_int (obj->picture->upper_x),
1906                      scm_from_int (obj->picture->upper_y),
1907                      scm_from_int (obj->picture->lower_x),
1908                      scm_from_int (obj->picture->lower_y),
1909                      scm_from_int (obj->picture->angle),
1910                      (obj->picture->mirrored ? SCM_BOOL_T : SCM_BOOL_F),
1911                      SCM_UNDEFINED);
1912 }
1913 
1914 /* \brief Set picture object parameters.
1915  * \par Function Description
1916  * Sets the parameters of the picture object \a obj_s.
1917  *
1918  * \note Scheme API: Implements the %set-picture! procedure in the
1919  * (geda core object) module.
1920  *
1921  * \param obj_s       the picture object to modify
1922  * \param x1_s  the new x-coordinate of the top left of the picture.
1923  * \param y1_s  the new y-coordinate of the top left of the picture.
1924  * \param x2_s  the new x-coordinate of the bottom right of the picture.
1925  * \param y2_s  the new y-coordinate of the bottom right of the picture.
1926  * \param angle_s     the new rotation angle.
1927  * \param mirror_s    whether the picture object should be mirrored.
1928  * \return the modify \a obj_s.
1929  */
1930 SCM_DEFINE (set_picture_x, "%set-picture!", 7, 0, 0,
1931             (SCM obj_s, SCM x1_s, SCM y1_s, SCM x2_s, SCM y2_s, SCM angle_s,
1932              SCM mirror_s), "Set picture object parameters")
1933 {
1934   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PICTURE), obj_s,
1935               SCM_ARG1, s_set_picture_x);
1936   SCM_ASSERT (scm_is_integer (x1_s), x1_s, SCM_ARG2, s_set_picture_x);
1937   SCM_ASSERT (scm_is_integer (y1_s), x1_s, SCM_ARG3, s_set_picture_x);
1938   SCM_ASSERT (scm_is_integer (x2_s), x1_s, SCM_ARG4, s_set_picture_x);
1939   SCM_ASSERT (scm_is_integer (y2_s), x1_s, SCM_ARG5, s_set_picture_x);
1940   SCM_ASSERT (scm_is_integer (angle_s), angle_s, SCM_ARG6, s_set_picture_x);
1941 
1942   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
1943   OBJECT *obj = edascm_to_object (obj_s);
1944 
1945   /* Angle */
1946   int angle = scm_to_int (angle_s);
1947   switch (angle) {
1948   case 0:
1949   case 90:
1950   case 180:
1951   case 270:
1952     /* These are all fine. */
1953     break;
1954   default:
1955     /* Otherwise, not fine. */
1956     scm_misc_error (s_set_picture_x,
1957                     _("Invalid picture angle ~A. Must be 0, 90, 180, or 270 degrees"),
1958                     scm_list_1 (angle_s));
1959   }
1960 
1961   o_emit_pre_change_notify (toplevel, obj);
1962 
1963   obj->picture->angle = scm_to_int (angle_s);
1964   obj->picture->mirrored = scm_is_true (mirror_s);
1965   o_picture_modify_all (toplevel, obj,
1966                         scm_to_int (x1_s), scm_to_int (y1_s),
1967                         scm_to_int (x2_s), scm_to_int (y2_s));
1968 
1969   o_emit_change_notify (toplevel, obj);
1970   return obj_s;
1971 }
1972 
1973 /*! \brief Set a picture object's data from a vector.
1974  * \par Function Description
1975  * Sets the image data for the picture object \a obj_s from the vector
1976  * \a data_s, and set its \a filename.  If the contents of \a data_s
1977  * could not be successfully loaded as an image, raises an error.  The
1978  * contents of \a data_s should be image data encoded in on-disk
1979  * format.
1980  *
1981  * \note Scheme API: Implements the %set-picture-data/vector!
1982  * procedure in the (geda core object) module.
1983  *
1984  * \param obj_s       The picture object to modify.
1985  * \param data_s      Vector containing encoded image data.
1986  * \param filename_s  New filename for \a obj_s.
1987  * \return \a obj_s.
1988  */
1989 SCM_DEFINE (set_picture_data_vector_x, "%set-picture-data/vector!", 3, 0, 0,
1990             (SCM obj_s, SCM data_s, SCM filename_s),
1991             "Set a picture object's data from a vector.")
1992 {
1993   SCM vec_s = scm_any_to_s8vector (data_s);
1994   /* Check argument types */
1995   SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PICTURE), obj_s,
1996               SCM_ARG1, s_set_picture_data_vector_x);
1997   SCM_ASSERT (scm_is_true (scm_s8vector_p (vec_s)), data_s, SCM_ARG2,
1998               s_set_picture_data_vector_x);
1999   SCM_ASSERT (scm_is_string (filename_s), filename_s, SCM_ARG3,
2000               s_set_picture_data_vector_x);
2001 
2002   scm_dynwind_begin (0);
2003 
2004   /* Convert vector to contiguous buffer */
2005   scm_t_array_handle handle;
2006   size_t len;
2007   ssize_t inc;
2008   const scm_t_int8 *elt = scm_s8vector_elements (vec_s, &handle, &len, &inc);
2009   gchar *buf = g_malloc (len);
2010   int i;
2011 
2012   scm_dynwind_unwind_handler (g_free, buf, SCM_F_WIND_EXPLICITLY);
2013 
2014   for (i = 0; i < len; i++, elt += inc) {
2015     buf[i] = (gchar) *elt;
2016   }
2017   scm_array_handle_release (&handle);
2018 
2019   gboolean status;
2020   GError *error = NULL;
2021   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
2022   OBJECT *obj = edascm_to_object (obj_s);
2023   gchar *filename = scm_to_utf8_string (filename_s);
2024   scm_dynwind_unwind_handler (g_free, filename, SCM_F_WIND_EXPLICITLY);
2025 
2026   status = o_picture_set_from_buffer (toplevel, obj, filename,
2027                                       buf, len, &error);
2028 
2029   if (!status) {
2030     scm_dynwind_unwind_handler ((void (*)(void *)) g_error_free, error,
2031                                 SCM_F_WIND_EXPLICITLY);
2032     scm_misc_error (s_set_picture_data_vector_x,
2033                     "Failed to set picture image data from vector: ~S",
2034                     scm_list_1 (scm_from_utf8_string (error->message)));
2035   }
2036 
2037   o_page_changed (toplevel, obj);
2038   scm_dynwind_end ();
2039   return obj_s;
2040 }
2041 
2042 
2043 
2044 /*! \brief Translate an object.
2045  * \par Function Description
2046  * Translates \a obj_s by \a dx_s in the x-axis and \a dy_s in the
2047  * y-axis.
2048  *
2049  * \note Scheme API: Implements the %translate-object! procedure of the
2050  * (geda core object) module.
2051  *
2052  * \param obj_s  #OBJECT smob for object to translate.
2053  * \param dx_s   Integer distance to translate along x-axis.
2054  * \param dy_s   Integer distance to translate along y-axis.
2055  * \return \a obj_s.
2056  */
2057 SCM_DEFINE (translate_object_x, "%translate-object!", 3, 0, 0,
2058             (SCM obj_s, SCM dx_s, SCM dy_s), "Translate an object.")
2059 {
2060   /* Check argument types */
2061   SCM_ASSERT (edascm_is_object (obj_s), obj_s,
2062               SCM_ARG1, s_translate_object_x);
2063   SCM_ASSERT (scm_is_integer (dx_s), dx_s,
2064               SCM_ARG2, s_translate_object_x);
2065   SCM_ASSERT (scm_is_integer (dy_s), dy_s,
2066               SCM_ARG3, s_translate_object_x);
2067 
2068   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
2069   OBJECT *obj = edascm_to_object (obj_s);
2070   int dx = scm_to_int (dx_s);
2071   int dy = scm_to_int (dy_s);
2072 
2073   o_emit_pre_change_notify (toplevel, obj);
2074   o_translate_world (toplevel, dx, dy, obj);
2075   o_emit_change_notify (toplevel, obj);
2076   o_page_changed (toplevel, obj);
2077 
2078   return obj_s;
2079 }
2080 
2081 /*! \brief Rotate an object.
2082  * \par Function Description
2083  * Rotates \a obj_s anti-clockwise by \a angle_s about the point
2084  * specified by \a x_s and \a y_s.  \a angle_s must be an integer
2085  * multiple of 90 degrees.
2086  *
2087  * \note Scheme API: Implements the %rotate-object! procedure of the
2088  * (geda core object) module.
2089  *
2090  * \param obj_s    #OBJECT smob for object to translate.
2091  * \param x_s      x-coordinate of centre of rotation.
2092  * \param y_s      y-coordinate of centre of rotation.
2093  * \param angle_s  Angle to rotate by.
2094  * \return \a obj_s.
2095  */
2096 SCM_DEFINE (rotate_object_x, "%rotate-object!", 4, 0, 0,
2097             (SCM obj_s, SCM x_s, SCM y_s, SCM angle_s),
2098             "Rotate an object.")
2099 {
2100   /* Check argument types */
2101   SCM_ASSERT (edascm_is_object (obj_s), obj_s,
2102               SCM_ARG1, s_rotate_object_x);
2103   SCM_ASSERT (scm_is_integer (x_s), x_s,
2104               SCM_ARG2, s_rotate_object_x);
2105   SCM_ASSERT (scm_is_integer (y_s), y_s,
2106               SCM_ARG3, s_rotate_object_x);
2107   SCM_ASSERT (scm_is_integer (angle_s), angle_s,
2108               SCM_ARG4, s_rotate_object_x);
2109 
2110   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
2111   OBJECT *obj = edascm_to_object (obj_s);
2112   int x = scm_to_int (x_s);
2113   int y = scm_to_int (y_s);
2114   int angle = scm_to_int (angle_s);
2115 
2116   /* FIXME Work around horribly broken libgeda behaviour.  Some
2117    * libgeda functions treat a rotation of -90 degrees as a rotation
2118    * of +90 degrees, etc., which is not sane. */
2119   while (angle < 0) angle += 360;
2120   while (angle >= 360) angle -= 360;
2121   SCM_ASSERT (angle % 90 == 0, angle_s,
2122               SCM_ARG4, s_rotate_object_x);
2123 
2124   o_emit_pre_change_notify (toplevel, obj);
2125   o_rotate_world (toplevel, x, y, angle, obj);
2126   o_emit_change_notify (toplevel, obj);
2127   o_page_changed (toplevel, obj);
2128 
2129   return obj_s;
2130 }
2131 
2132 /*! \brief Mirror an object.
2133  * \par Function Description
2134  * Mirrors \a obj_s in the line x = \a x_s.
2135  *
2136  * \note Scheme API: Implements the %mirror-object! procedure of the
2137  * (geda core object) module.
2138  *
2139  * \param obj_s    #OBJECT smob for object to translate.
2140  * \param x_s      x-coordinate of centre of rotation.
2141  * \return \a obj_s.
2142  */
2143 SCM_DEFINE (mirror_object_x, "%mirror-object!", 2, 0, 0,
2144             (SCM obj_s, SCM x_s),
2145             "Mirror an object.")
2146 {
2147   /* Check argument types */
2148   SCM_ASSERT (edascm_is_object (obj_s), obj_s,
2149               SCM_ARG1, s_mirror_object_x);
2150   SCM_ASSERT (scm_is_integer (x_s), x_s,
2151               SCM_ARG2, s_mirror_object_x);
2152 
2153   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
2154   OBJECT *obj = edascm_to_object (obj_s);
2155   int x = scm_to_int (x_s);
2156 
2157   o_emit_pre_change_notify (toplevel, obj);
2158   o_mirror_world (toplevel, x, 0, obj);
2159   o_emit_change_notify (toplevel, obj);
2160   o_page_changed (toplevel, obj);
2161 
2162   return obj_s;
2163 }
2164 
2165 /*!
2166  * \brief Create the (geda core object) Scheme module.
2167  * \par Function Description
2168  * Defines procedures in the (geda core object) module. The module can
2169  * be accessed using (use-modules (geda core object)).
2170  */
2171 static void
init_module_geda_core_object()2172 init_module_geda_core_object ()
2173 {
2174   /* Register the functions and symbols */
2175   #include "scheme_object.x"
2176 
2177   /* Add them to the module's public definitions. */
2178   scm_c_export (s_object_type, s_copy_object, s_object_bounds,
2179                 s_object_stroke, s_set_object_stroke_x,
2180                 s_object_fill, s_set_object_fill_x,
2181                 s_object_color, s_set_object_color_x,
2182                 s_make_line, s_make_net, s_make_bus,
2183                 s_make_pin, s_pin_type,
2184                 s_set_line_x, s_line_info,
2185                 s_make_box, s_set_box_x, s_box_info,
2186                 s_make_circle, s_set_circle_x, s_circle_info,
2187                 s_make_arc, s_set_arc_x, s_arc_info,
2188                 s_make_text, s_set_text_x, s_text_info,
2189                 s_object_connections, s_object_complex,
2190                 s_make_path, s_path_length, s_path_ref,
2191                 s_path_remove_x, s_path_insert_x,
2192                 s_make_picture, s_picture_info, s_set_picture_x,
2193                 s_set_picture_data_vector_x,
2194                 s_translate_object_x, s_rotate_object_x,
2195                 s_mirror_object_x,
2196                 NULL);
2197 }
2198 
2199 /*!
2200  * \brief Initialise the basic gEDA object manipulation procedures.
2201  * \par Function Description
2202  * Registers some Scheme procedures for working with #OBJECT
2203  * smobs. Should only be called by scheme_api_init().
2204  */
2205 void
edascm_init_object()2206 edascm_init_object ()
2207 {
2208   /* Define the (geda core object) module */
2209   scm_c_define_module ("geda core object",
2210                        init_module_geda_core_object,
2211                        NULL);
2212 }
2213