libgeda
|
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 }