libgeda

scheme_complex.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library - Scheme API
00003  * Copyright (C) 2010 Peter Brett <peter@peter-b.co.uk>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
00018  */
00019 
00025 #include <config.h>
00026 
00027 #include "libgeda_priv.h"
00028 #include "libgedaguile_priv.h"
00029 
00041 SCM_DEFINE (make_complex, "%make-complex", 1, 0, 0,
00042             (SCM basename_s), "Create a new complex object.")
00043 {
00044   SCM_ASSERT (scm_is_string (basename_s), basename_s, SCM_ARG1, s_make_complex);
00045 
00046   char *tmp = scm_to_utf8_string (basename_s);
00047   OBJECT *obj = o_complex_new_embedded (edascm_c_current_toplevel (),
00048                                         OBJ_COMPLEX, DEFAULT_COLOR, 0, 0, 0,
00049                                         FALSE, tmp, TRUE);
00050   free (tmp);
00051 
00052   SCM result = edascm_from_object (obj);
00053 
00054   /* At the moment, the only pointer to the object is owned by the
00055    * smob. */
00056   edascm_c_set_gc (result, TRUE);
00057 
00058   return result;
00059 }
00060 
00077 SCM_DEFINE (make_complex_library, "%make-complex/library", 1, 0, 0,
00078             (SCM basename_s),
00079             "Instantiate a complex object from the component library.")
00080 {
00081   SCM_ASSERT (scm_is_string (basename_s), basename_s, SCM_ARG1,
00082               s_make_complex_library);
00083 
00084   char *basename = scm_to_utf8_string (basename_s);
00085   scm_dynwind_begin (0);
00086   scm_dynwind_unwind_handler (free, basename, SCM_F_WIND_EXPLICITLY);
00087 
00088   SCM result = SCM_BOOL_F;
00089   const CLibSymbol *clib = s_clib_get_symbol_by_name (basename);
00090   if (clib != NULL) {
00091     OBJECT *obj = o_complex_new (edascm_c_current_toplevel (),
00092                                  OBJ_COMPLEX, DEFAULT_COLOR, 0, 0, 0,
00093                                  FALSE, clib, basename, TRUE);
00094 
00095     result = edascm_from_object (obj);
00096 
00097     /* At the moment, the only pointer to the object is owned by the
00098      * smob. */
00099     edascm_c_set_gc (result, TRUE);
00100   }
00101 
00102   scm_dynwind_end ();
00103   return result;
00104 }
00105 
00123 SCM_DEFINE (set_complex_x, "%set-complex!", 6, 0, 0,
00124             (SCM complex_s, SCM x_s, SCM y_s, SCM angle_s, SCM mirror_s,
00125              SCM locked_s), "Set complex object parameters")
00126 {
00127   SCM_ASSERT (edascm_is_object_type (complex_s, OBJ_COMPLEX), complex_s,
00128               SCM_ARG1, s_set_complex_x);
00129   SCM_ASSERT (scm_is_integer (x_s),     x_s,     SCM_ARG2, s_set_complex_x);
00130   SCM_ASSERT (scm_is_integer (y_s),     y_s,     SCM_ARG3, s_set_complex_x);
00131   SCM_ASSERT (scm_is_integer (angle_s), angle_s, SCM_ARG4, s_set_complex_x);
00132 
00133   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
00134   OBJECT *obj = edascm_to_object (complex_s);
00135 
00136   /* Angle */
00137   int angle = scm_to_int (angle_s);
00138   switch (angle) {
00139   case 0:
00140   case 90:
00141   case 180:
00142   case 270:
00143     /* These are all fine. */
00144     break;
00145   default:
00146     /* Otherwise, not fine. */
00147     scm_misc_error (s_set_complex_x,
00148                     _("Invalid complex angle ~A. Must be 0, 90, 180, or 270 degrees"),
00149                     scm_list_1 (angle_s));
00150   }
00151 
00152   o_emit_pre_change_notify (toplevel, obj);
00153 
00154   int x = scm_to_int (x_s);
00155   int y = scm_to_int (y_s);
00156   o_translate_world (toplevel,
00157                      x - obj->complex->x,
00158                      y - obj->complex->y,
00159                      obj);
00160   obj->complex->angle = angle;
00161   obj->complex->mirror = scm_is_true (mirror_s);
00162   obj->selectable = scm_is_false (locked_s);
00163 
00164   o_complex_recalc (toplevel, obj); /* We need to do this explicitly... */
00165 
00166   o_emit_change_notify (toplevel, obj);
00167 
00168   o_page_changed (toplevel, obj);
00169 
00170   return complex_s;
00171 }
00172 
00191 SCM_DEFINE (complex_info, "%complex-info", 1, 0, 0,
00192             (SCM complex_s), "Get complex object parameters.")
00193 {
00194   SCM_ASSERT (edascm_is_object_type (complex_s, OBJ_COMPLEX), complex_s,
00195               SCM_ARG1, s_complex_info);
00196 
00197   OBJECT *obj = edascm_to_object (complex_s);
00198 
00199   return scm_list_n (scm_from_utf8_string (obj->complex_basename),
00200                      scm_from_int (obj->complex->x),
00201                      scm_from_int (obj->complex->y),
00202                      scm_from_int (obj->complex->angle),
00203                      obj->complex->mirror ? SCM_BOOL_T : SCM_BOOL_F,
00204                      obj->selectable ? SCM_BOOL_F : SCM_BOOL_T,
00205                      SCM_UNDEFINED);
00206 }
00207 
00218 SCM_DEFINE (complex_contents, "%complex-contents", 1, 0, 0,
00219             (SCM complex_s), "Get complex object contents.")
00220 {
00221   SCM_ASSERT (edascm_is_object_type (complex_s, OBJ_COMPLEX), complex_s,
00222               SCM_ARG1, s_complex_contents);
00223 
00224   OBJECT *obj = edascm_to_object (complex_s);
00225 
00226   return edascm_from_object_glist (obj->complex->prim_objs);
00227 }
00228 
00243 SCM_DEFINE (complex_append_x, "%complex-append!", 2, 0, 0,
00244             (SCM complex_s, SCM obj_s),
00245             "Add a primitive object to a complex object")
00246 {
00247   /* Ensure that the arguments have the correct types. */
00248   SCM_ASSERT (edascm_is_object_type (complex_s, OBJ_COMPLEX), complex_s,
00249               SCM_ARG1, s_complex_append_x);
00250   SCM_ASSERT ((EDASCM_OBJECTP (obj_s)
00251                && !edascm_is_object_type (obj_s, OBJ_COMPLEX)
00252                && !edascm_is_object_type (obj_s, OBJ_PLACEHOLDER)),
00253               obj_s, SCM_ARG2, s_complex_append_x);
00254 
00255   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
00256   OBJECT *parent = edascm_to_object (complex_s);
00257   OBJECT *child = edascm_to_object (obj_s);
00258 
00259   /* Check that object is not already attached to a page or a
00260      different complex. */
00261   if ((o_get_page (toplevel, child) != NULL)
00262       || ((child->parent != NULL) && (child->parent != parent))) {
00263     scm_error (edascm_object_state_sym,
00264                s_complex_append_x,
00265                _("Object ~A is already attached to something"),
00266                scm_list_1 (obj_s), SCM_EOL);
00267   }
00268 
00269   if (child->parent == parent) return obj_s;
00270 
00271   /* Object cleanup now managed by C code. */
00272   edascm_c_set_gc (obj_s, 0);
00273 
00274   /* Don't need to emit change notifications for the child because
00275    * it's guaranteed not to be present in a page at this point. */
00276   o_emit_pre_change_notify (toplevel, parent);
00277 
00278   parent->complex->prim_objs =
00279     g_list_append (parent->complex->prim_objs, child);
00280   child->parent = parent;
00281 
00282   o_complex_recalc (toplevel, parent);
00283 
00284   /* We may need to update connections */
00285   s_tile_update_object (toplevel, child);
00286   s_conn_update_object (toplevel, child);
00287 
00288   o_emit_change_notify (toplevel, parent);
00289 
00290   o_page_changed (toplevel, parent);
00291 
00292   return complex_s;
00293 }
00294 
00308 SCM_DEFINE (complex_remove_x, "%complex-remove!", 2, 0, 0,
00309             (SCM complex_s, SCM obj_s),
00310             "Remove a primitive object from a complex object")
00311 {
00312   /* Ensure that the arguments have the correct types. */
00313   SCM_ASSERT (edascm_is_object_type (complex_s, OBJ_COMPLEX), complex_s,
00314               SCM_ARG1, s_complex_remove_x);
00315   SCM_ASSERT (EDASCM_OBJECTP (obj_s), obj_s, SCM_ARG2, s_complex_remove_x);
00316 
00317   TOPLEVEL *toplevel = edascm_c_current_toplevel ();
00318   OBJECT *parent = edascm_to_object (complex_s);
00319   OBJECT *child = edascm_to_object (obj_s);
00320   PAGE *child_page = o_get_page (toplevel, child);
00321 
00322   /* Check that object is not attached to a different complex. */
00323   if ((child->parent != NULL) && (child->parent != parent)) {
00324     scm_error (edascm_object_state_sym, s_complex_remove_x,
00325                _("Object ~A is attached to a different complex"),
00326                scm_list_1 (obj_s), SCM_EOL);
00327   }
00328 
00329   /* Check that object is not attached to a page. */
00330   if ((child->parent == NULL) && (child_page != NULL)) {
00331     scm_error (edascm_object_state_sym, s_complex_remove_x,
00332                _("Object ~A is attached to a page"),
00333                scm_list_1 (obj_s), SCM_EOL);
00334   }
00335 
00336   /* Check that object is not attached as an attribute. */
00337   if (child->attached_to != NULL) {
00338     scm_error (edascm_object_state_sym, s_complex_remove_x,
00339                _("Object ~A is attached as an attribute"),
00340                scm_list_1 (obj_s), SCM_EOL);
00341   }
00342 
00343   /* Check that object doesn't have attributes. */
00344   if (child->attribs != NULL) {
00345     scm_error (edascm_object_state_sym, s_complex_remove_x,
00346                _("Object ~A has attributes"),
00347                scm_list_1 (obj_s), SCM_EOL);
00348   }
00349 
00350   if (child->parent == NULL) return obj_s;
00351 
00352   /* Don't need to emit change notifications for the child because
00353    * only the parent will remain in the page. */
00354   o_emit_pre_change_notify (toplevel, parent);
00355 
00356   parent->complex->prim_objs =
00357     g_list_remove_all (parent->complex->prim_objs, child);
00358   child->parent = NULL;
00359 
00360   /* We may need to update connections */
00361   s_tile_remove_object (child);
00362   s_conn_remove_object (toplevel, child);
00363 
00364   o_emit_change_notify (toplevel, parent);
00365 
00366   o_page_changed (toplevel, parent);
00367 
00368   /* Object cleanup now managed by Guile. */
00369   edascm_c_set_gc (obj_s, 1);
00370   return complex_s;
00371 }
00372 
00379 static void
00380 init_module_geda_core_complex ()
00381 {
00382   /* Register the functions and symbols */
00383   #include "scheme_complex.x"
00384 
00385   /* Add them to the module's public definitions. */
00386   scm_c_export (s_make_complex, s_make_complex_library, s_set_complex_x,
00387                 s_complex_info, s_complex_contents, s_complex_append_x,
00388                 s_complex_remove_x, NULL);
00389 }
00390 
00397 void
00398 edascm_init_complex ()
00399 {
00400   /* Define the (geda core object) module */
00401   scm_c_define_module ("geda core complex",
00402                        init_module_geda_core_complex,
00403                        NULL);
00404 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines