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