Bumped versions to 1.1.2/20070818/30:2:0 for the next development snapshot
[geda-gaf/whiteaudio.git] / gschem / src / o_misc.c
blob012cf4fb276ba2cd7c27a5cab5d17cf31f331875
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #include <libgen.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
33 #include <libgeda/libgeda.h>
35 #include "../include/globals.h"
36 #include "../include/prototype.h"
38 #ifdef HAVE_LIBDMALLOC
39 #include <dmalloc.h>
40 #endif
42 /* break with the tradition here and input a list */
43 /*! \todo probably should go back and do the same for o_copy o_move
44 * o_delete...
46 /*! \todo Finish function documentation!!!
47 * \brief
48 * \par Function Description
51 void o_edit(TOPLEVEL *w_current, GList *list)
53 char *equal_ptr;
54 OBJECT *o_current;
55 int num_lines = 0;
57 if (list == NULL) {
58 w_current->inside_action = 0;
59 i_set_state(w_current, SELECT);
60 return;
63 o_current = (OBJECT *) list->data;
64 if (o_current == NULL) {
65 fprintf(stderr, _("Got an unexpected NULL in o_edit\n"));
66 exit(-1);
69 /* for now deal with only the first item */
70 switch(o_current->type) {
72 /* also add the ability to multi attrib edit: nets, busses, pins */
73 case(OBJ_COMPLEX):
74 case(OBJ_PLACEHOLDER):
75 case(OBJ_NET):
76 case(OBJ_PIN):
77 case(OBJ_BUS):
78 x_multiattrib_open (w_current);
79 break;
81 case(OBJ_PICTURE):
82 picture_change_filename_dialog(w_current);
83 break;
84 case(OBJ_TEXT):
85 if(strchr(o_current->text->string,'=')) {
87 /* now really make sure it's an attribute by
88 * checking that there are NO spaces around the ='s
90 equal_ptr = strchr(o_current->text->string, '=');
92 /* and also make sure it is only a single line */
93 num_lines = o_text_num_lines(o_current->text->string);
95 /* there is a possiblity for core dump yes? */
96 /* by exceeding the size of the text_string? */
97 /* or maybe not, since if the ='s is at the end of */
98 /* the string, there better be a null after it! */
99 if ( (*(equal_ptr + 1) != ' ') &&
100 (*(equal_ptr - 1) != ' ') &&
101 (num_lines == 1) ) {
102 attrib_edit_dialog(w_current,o_current, FROM_MENU);
103 /* multi_attrib_edit(w_current, o_current); */
105 } else {
106 o_text_edit(w_current, o_current);
108 } else {
109 o_text_edit(w_current, o_current);
111 break;
114 /* has to be more extensive in the future */
115 /* some sort of redrawing? */
118 /*! \todo Finish function documentation!!!
119 * \brief
120 * \par Function Description
123 /* This locks the entire selected list. It does lock components, but does NOT
124 * change the color (of primatives of the components) though
125 * this cannot be called recursively */
126 void o_lock(TOPLEVEL *w_current)
128 OBJECT *object = NULL;
129 GList *s_current = NULL;
131 /* skip over head */
132 s_current = geda_list_get_glist( w_current->page_current->selection_list );
134 while(s_current != NULL) {
135 object = (OBJECT *) s_current->data;
136 if (object) {
137 /* check to see if locked_color is already being used */
138 if (object->locked_color == -1) {
139 object->sel_func = NULL;
140 object->locked_color = object->color;
141 object->color = w_current->lock_color;
142 w_current->page_current->CHANGED=1;
143 } else {
144 s_log_message(_("Object already locked\n"));
148 s_current=s_current->next;
151 o_unselect_all(w_current);
152 o_undo_savestate(w_current, UNDO_ALL);
153 i_update_menus(w_current);
156 /*! \todo Finish function documentation!!!
157 * \brief
158 * \par Function Description
161 /* You can unlock something by selecting it with a bounding box... */
162 /* this will probably change in the future, but for now it's a
163 something.. :-) */
164 /* this cannot be called recursively */
165 void o_unlock(TOPLEVEL *w_current)
167 OBJECT *object = NULL;
168 GList *s_current = NULL;
170 s_current = geda_list_get_glist( w_current->page_current->selection_list );
172 while(s_current != NULL) {
173 object = (OBJECT *) s_current->data;
174 if (object) {
175 /* only unlock if sel_func is not set to something */
176 if (object->sel_func == NULL) {
177 object->sel_func = select_func;
178 object->color = object->locked_color;
179 object->locked_color = -1;
180 w_current->page_current->CHANGED = 1;
181 } else {
182 s_log_message(_("Object already unlocked\n"));
186 s_current=s_current->next;
188 o_undo_savestate(w_current, UNDO_ALL);
191 /*! \brief Rotate all objects in list.
192 * \par Function Description
193 * Given the selection <B>list</B>, and the center of rotation
194 * (<B>centerx</B>,<B>centery</B>, this function traverses all the selection
195 * list, rotating each object.
196 * The selection list contains a given object and all its attributes
197 * (refdes, pinname, pinlabel, ...).
198 * There is a second pass to run the rotate hooks of non-simple objects,
199 * like pin or complex objects, for example.
201 * \param [in] w_current The TOPLEVEL object.
202 * \param [in] list The list of objects to rotate.
203 * \param [in] centerx Center x coordinate of rotation.
204 * \param [in] centery Center y coordinate of rotation.
206 void o_rotate_90_world(TOPLEVEL *w_current, GList *list,
207 int centerx, int centery)
209 OBJECT *object;
210 GList *s_current;
211 int new_angle;
212 GList *other_objects=NULL;
213 GList *connected_objects=NULL;
214 OBJECT *o_current=NULL;
216 /* this is okay if you just hit rotate and have nothing selected */
217 if (list == NULL) {
218 w_current->inside_action = 0;
219 i_set_state(w_current, SELECT);
220 return;
223 s_current = list;
225 while (s_current != NULL) {
226 object = (OBJECT *) s_current->data;
228 if (!object) {
229 fprintf(stderr, _("ERROR: NULL object in o_rotate_90!\n"));
230 return;
233 g_list_free(other_objects);
234 other_objects = NULL;
235 g_list_free(connected_objects);
236 connected_objects = NULL;
238 switch(object->type) {
241 case(OBJ_NET):
242 if (!w_current->DONT_REDRAW) {
243 o_cue_undraw(w_current, object);
244 o_net_erase(w_current, object);
245 o_line_erase_grips(w_current, object);
248 /* save the other objects */
249 other_objects = s_conn_return_others(other_objects, object);
250 s_conn_remove(w_current, object);
252 o_net_rotate_world(w_current, centerx, centery, 90, object);
253 s_conn_update_object(w_current, object);
254 if (!w_current->DONT_REDRAW) {
255 o_net_draw(w_current, object);
257 /* draw the other objects */
258 o_cue_undraw_list(w_current, other_objects);
259 o_cue_draw_list(w_current, other_objects);
262 /* get other connected objects and redraw */
263 connected_objects = s_conn_return_others(connected_objects, object);
264 if (!w_current->DONT_REDRAW) {
265 o_cue_undraw_list(w_current, connected_objects);
266 o_cue_draw_list(w_current, connected_objects);
268 /* finally redraw the cues on the current object */
269 o_cue_draw_single(w_current, object);
271 break;
273 case(OBJ_BUS):
274 if (!w_current->DONT_REDRAW) {
275 o_cue_undraw(w_current, object);
276 o_bus_erase(w_current, object);
277 o_line_erase_grips(w_current, object);
280 other_objects = s_conn_return_others(other_objects, object);
281 s_conn_remove(w_current, object);
283 o_bus_rotate_world(w_current, centerx, centery, 90, object);
284 s_conn_update_object(w_current, object);
285 if (!w_current->DONT_REDRAW) {
286 o_bus_draw(w_current, object);
288 /* draw the other objects */
289 o_cue_undraw_list(w_current, other_objects);
290 o_cue_draw_list(w_current, other_objects);
293 /* get other connected objects and redraw */
294 connected_objects = s_conn_return_others(connected_objects, object);
295 if (!w_current->DONT_REDRAW) {
296 o_cue_undraw_list(w_current, connected_objects);
297 o_cue_draw_list(w_current, connected_objects);
299 /* finally redraw the cues on the current object */
300 o_cue_draw_single(w_current, object);
302 break;
304 case(OBJ_PIN):
305 if (!w_current->DONT_REDRAW) {
306 o_cue_undraw(w_current, object);
307 o_pin_erase(w_current, object);
308 o_line_erase_grips(w_current, object);
311 other_objects = s_conn_return_others(other_objects, object);
312 s_conn_remove(w_current, object);
314 o_pin_rotate_world(w_current, centerx, centery,
315 90, object);
316 s_conn_update_object(w_current, object);
317 if (!w_current->DONT_REDRAW) {
318 o_pin_draw(w_current, object);
320 /* draw the other objects */
321 o_cue_undraw_list(w_current, other_objects);
322 o_cue_draw_list(w_current, other_objects);
325 /* get other connected objects and redraw */
326 connected_objects = s_conn_return_others(connected_objects, object);
327 if (!w_current->DONT_REDRAW) {
328 o_cue_undraw_list(w_current, connected_objects);
329 o_cue_draw_list(w_current, connected_objects);
331 /* finally redraw the cues on the current object */
332 o_cue_draw_single(w_current, object);
334 break;
336 case(OBJ_COMPLEX):
337 if (!w_current->DONT_REDRAW) {
338 o_cue_undraw_objects(w_current, object->complex->prim_objs);
339 /* erase the current selection */
340 o_complex_erase(w_current, object);
343 other_objects = s_conn_return_complex_others(other_objects, object);
345 /* remove all conn references */
346 o_current = object->complex->prim_objs;
347 while(o_current != NULL) {
348 s_conn_remove(w_current, o_current);
349 o_current = o_current->next;
352 /* do the rotate */
353 /*w_current->ADDING_SEL=1; NEWSEL: needed? */
354 new_angle = (object->complex->angle + 90) % 360;
355 o_complex_rotate_world(w_current, centerx, centery,
356 new_angle, 90, object);
357 /*w_current->ADDING_SEL = 0; NEWSEL: needed? */
358 s_conn_update_complex(w_current, object->complex->prim_objs);
359 if (!w_current->DONT_REDRAW) {
360 o_complex_draw(w_current, object);
362 o_cue_undraw_list(w_current, other_objects);
363 o_cue_draw_list(w_current, other_objects);
366 /* now draw the newly connected objects */
367 connected_objects = s_conn_return_complex_others(connected_objects,
368 object);
369 if (!w_current->DONT_REDRAW) {
370 o_cue_undraw_list(w_current, connected_objects);
371 o_cue_draw_list(w_current, connected_objects);
373 break;
375 case(OBJ_LINE):
376 if (!w_current->DONT_REDRAW) {
377 o_line_erase_grips(w_current, object);
378 o_line_erase(w_current, object);
381 o_line_rotate_world(w_current, centerx, centery,
382 90, object);
384 if (!w_current->DONT_REDRAW) {
385 o_line_draw(w_current, object);
387 break;
389 case(OBJ_BOX):
390 /* erase the current selection */
391 if (!w_current->DONT_REDRAW) {
392 o_box_erase_grips(w_current, object);
393 o_box_erase(w_current, object);
396 o_box_rotate_world(w_current, centerx, centery,
397 90, object);
399 if (!w_current->DONT_REDRAW) {
400 o_box_draw(w_current, object);
402 break;
404 case(OBJ_PICTURE):
405 /* erase the current selection */
407 if (!w_current->DONT_REDRAW) {
408 o_picture_erase_grips(w_current, object);
409 o_picture_erase(w_current, object);
412 o_picture_rotate_world(w_current, centerx, centery,
413 90, object);
415 if (!w_current->DONT_REDRAW) {
416 o_picture_draw(w_current, object);
418 break;
420 case(OBJ_CIRCLE):
421 if (!w_current->DONT_REDRAW) {
422 o_circle_erase_grips(w_current, object);
423 o_circle_erase(w_current, object);
426 o_circle_rotate_world(w_current, centerx, centery,
427 90, object);
429 if (!w_current->DONT_REDRAW) {
430 o_circle_draw(w_current, object);
432 break;
434 case(OBJ_ARC):
435 if (!w_current->DONT_REDRAW) {
436 o_arc_erase(w_current, object);
439 o_arc_rotate_world(w_current, centerx, centery, 90, object);
440 if (!w_current->DONT_REDRAW) {
441 o_arc_draw(w_current, object);
443 break;
445 case(OBJ_TEXT):
446 /* erase the current selection */
447 if (!w_current->DONT_REDRAW) {
448 o_text_erase(w_current, object);
451 new_angle = (object->text->angle + 90) % 360;
452 o_text_rotate_world(w_current, centerx, centery,
453 new_angle, 90, object);
455 if (!w_current->DONT_REDRAW) {
456 o_text_draw(w_current, object);
458 break;
460 s_current = s_current->next;
463 /* All objects were rotated. Do a 2nd pass to run the rotate hooks */
464 /* Do not run any hooks for simple objects here, like text, since they
465 were rotated in the previous pass, and the selection list can contain
466 an object and all its attributes (text) */
467 s_current = list;
468 while (s_current != NULL) {
469 object = (OBJECT *) s_current->data;
471 if (!object) {
472 fprintf(stderr, _("ERROR: NULL object in o_rotate_90!\n"));
473 return;
476 switch(object->type) {
477 case(OBJ_PIN):
478 /* Run the rotate pin hook */
479 if (scm_hook_empty_p(rotate_pin_hook) == SCM_BOOL_F &&
480 object != NULL) {
481 scm_run_hook(rotate_pin_hook,
482 scm_cons(g_make_object_smob(w_current, object),
483 SCM_EOL));
485 break;
487 case (OBJ_COMPLEX):
488 /* Run the rotate hook */
489 if (scm_hook_empty_p(rotate_component_object_hook) == SCM_BOOL_F &&
490 object != NULL) {
491 scm_run_hook(rotate_component_object_hook,
492 scm_cons(g_make_object_smob(w_current, object),
493 SCM_EOL));
495 break;
496 default:
497 break;
500 s_current = s_current->next;
503 /* Don't save the undo state if we are inside an action */
504 /* This is useful when rotating the selection while moving, for example */
505 w_current->page_current->CHANGED = 1;
506 if (!w_current->inside_action) {
507 o_undo_savestate(w_current, UNDO_ALL);
512 /*! \todo Finish function documentation!!!
513 * \brief
514 * \par Function Description
517 void o_mirror_world(TOPLEVEL *w_current, GList *list, int centerx, int centery)
519 OBJECT *object;
520 GList *s_current;
521 OBJECT *o_current = NULL;
522 GList *other_objects=NULL;
523 GList *connected_objects=NULL;
525 if (list == NULL) {
526 w_current->inside_action = 0;
527 i_set_state(w_current, SELECT);
528 return;
531 s_current = list;
533 while (s_current != NULL) {
535 object = (OBJECT *) s_current->data;
537 if (!object) {
538 fprintf(stderr, _("ERROR: NULL object in o_mirror!\n"));
539 return;
542 g_list_free(other_objects);
543 other_objects = NULL;
544 g_list_free(connected_objects);
545 connected_objects = NULL;
547 switch(object->type) {
550 case(OBJ_NET):
551 o_cue_undraw(w_current, object);
552 o_net_erase(w_current, object);
553 o_line_erase_grips(w_current, object);
555 other_objects = s_conn_return_others(other_objects, object);
556 s_conn_remove(w_current, object);
558 o_net_mirror_world(w_current, centerx, centery, object);
559 s_conn_update_object(w_current, object);
560 o_net_draw(w_current, object);
562 /* draw the other objects */
563 o_cue_undraw_list(w_current, other_objects);
564 o_cue_draw_list(w_current, other_objects);
566 /* get other connected objects and redraw */
567 connected_objects = s_conn_return_others(connected_objects, object);
568 o_cue_undraw_list(w_current, connected_objects);
569 o_cue_draw_list(w_current, connected_objects);
571 /* finally redraw the cues on the current object */
572 o_cue_draw_single(w_current, object);
573 break;
575 case(OBJ_PIN):
576 o_cue_undraw(w_current, object);
577 o_pin_erase(w_current, object);
578 o_line_erase_grips(w_current, object);
580 other_objects = s_conn_return_others(other_objects, object);
581 s_conn_remove(w_current, object);
583 o_pin_mirror_world(w_current, centerx, centery, object);
584 s_conn_update_object(w_current, object);
585 o_pin_draw(w_current, object);
587 /* draw the other objects */
588 o_cue_undraw_list(w_current, other_objects);
589 o_cue_draw_list(w_current, other_objects);
591 /* get other connected objects and redraw */
592 connected_objects = s_conn_return_others(connected_objects, object);
593 o_cue_undraw_list(w_current, connected_objects);
594 o_cue_draw_list(w_current, connected_objects);
596 /* finally redraw the cues on the current object */
597 o_cue_draw_single(w_current, object);
598 break;
600 case(OBJ_BUS):
601 o_bus_erase(w_current, object);
602 o_line_erase_grips(w_current, object);
604 other_objects = s_conn_return_others(other_objects, object);
605 s_conn_remove(w_current, object);
607 o_bus_mirror_world(w_current, centerx, centery, object);
608 s_conn_update_object(w_current, object);
609 o_bus_draw(w_current, object);
611 /* draw the other objects */
612 o_cue_undraw_list(w_current, other_objects);
613 o_cue_draw_list(w_current, other_objects);
615 /* get other connected objects and redraw */
616 connected_objects = s_conn_return_others(connected_objects, object);
617 o_cue_undraw_list(w_current, connected_objects);
618 o_cue_draw_list(w_current, connected_objects);
620 /* finally redraw the cues on the current object */
621 o_cue_draw_single(w_current, object);
622 break;
624 case(OBJ_COMPLEX):
625 o_cue_undraw_objects(w_current, object->complex->prim_objs);
626 /* erase the current selection */
627 o_complex_erase(w_current, object);
629 other_objects = s_conn_return_complex_others(other_objects, object);
631 /* remove all conn references */
632 o_current = object->complex->prim_objs;
633 while(o_current != NULL) {
634 s_conn_remove(w_current, o_current);
635 o_current = o_current->next;
638 o_complex_mirror_world(w_current, centerx, centery, object);
639 s_conn_update_complex(w_current, object->complex->prim_objs);
640 o_complex_draw(w_current, object);
642 o_cue_undraw_list(w_current, other_objects);
643 o_cue_draw_list(w_current, other_objects);
645 /* now draw the newly connected objects */
646 connected_objects = s_conn_return_complex_others(connected_objects,
647 object);
648 o_cue_undraw_list(w_current, connected_objects);
649 o_cue_draw_list(w_current, connected_objects);
650 break;
652 case(OBJ_LINE):
653 o_line_erase_grips(w_current, object);
654 o_line_erase(w_current, object);
655 o_line_mirror_world(w_current,
656 centerx, centery, object);
657 o_line_draw(w_current, object);
658 break;
660 case(OBJ_BOX):
661 o_box_erase_grips(w_current, object);
662 o_box_erase(w_current, object);
663 o_box_mirror_world(w_current,
664 centerx, centery, object);
665 o_box_draw(w_current, object);
666 break;
668 case(OBJ_PICTURE):
669 o_picture_erase_grips(w_current, object);
670 o_picture_erase(w_current, object);
671 o_picture_mirror_world(w_current,
672 centerx, centery, object);
673 o_picture_draw(w_current, object);
674 break;
676 case(OBJ_CIRCLE):
677 o_circle_erase_grips(w_current, object);
678 o_circle_erase(w_current, object);
679 o_circle_mirror_world(w_current,
680 centerx, centery, object);
681 o_circle_draw(w_current, object);
682 break;
684 case(OBJ_ARC):
685 o_arc_erase(w_current, object);
686 o_arc_mirror_world(w_current, centerx, centery, object);
687 o_arc_draw(w_current, object);
688 break;
690 case(OBJ_TEXT):
691 o_text_erase(w_current, object);
692 o_text_mirror_world(w_current,
693 centerx, centery, object);
694 o_text_draw(w_current, object);
695 break;
699 s_current = s_current->next;
703 /* All objects were rotated. Do a 2nd pass to run the rotate hooks */
704 /* Do not run any hooks for simple objects here, like text, since they
705 were rotated in the previous pass, and the selection list can contain
706 an object and all its attributes (text) */
707 s_current = list;
708 while (s_current != NULL) {
709 object = (OBJECT *) s_current->data;
711 if (!object) {
712 fprintf(stderr, _("ERROR: NULL object in o_rotate_90!\n"));
713 return;
716 switch(object->type) {
717 case(OBJ_PIN):
718 /* Run the rotate pin hook */
719 if (scm_hook_empty_p(mirror_pin_hook) == SCM_BOOL_F &&
720 object != NULL) {
721 scm_run_hook(rotate_pin_hook,
722 scm_cons(g_make_object_smob(w_current, object),
723 SCM_EOL));
725 break;
727 case (OBJ_COMPLEX):
728 /* Run the rotate pin hook */
729 if (scm_hook_empty_p(rotate_component_object_hook) == SCM_BOOL_F &&
730 object != NULL) {
731 scm_run_hook(mirror_component_object_hook,
732 scm_cons(g_make_object_smob(w_current, object),
733 SCM_EOL));
735 break;
736 default:
737 break;
740 s_current = s_current->next;
744 w_current->page_current->CHANGED=1;
745 o_undo_savestate(w_current, UNDO_ALL);
748 /*! \todo Finish function documentation!!!
749 * \brief
750 * \par Function Description
753 void o_edit_show_hidden_lowlevel(TOPLEVEL *w_current, OBJECT *o_list)
755 OBJECT *o_current = o_list;
757 if (o_current == NULL) {
758 return;
761 while(o_current != NULL) {
762 if (o_current->type == OBJ_TEXT && o_current->visibility == INVISIBLE) {
764 /* don't toggle the visibility flag */
766 if (w_current->show_hidden_text) {
767 /* draw the text object if it hidden */
768 if (o_current->text->prim_objs == NULL) {
769 o_text_recreate(w_current, o_current);
771 o_text_recalc(w_current, o_current);
772 o_text_draw(w_current, o_current);
773 } else {
774 /* object is hidden and we are now NOT drawing it, so */
775 /* get rid of the extra primitive data */
776 o_text_recreate(w_current, o_current);
777 o_text_recalc(w_current, o_current);
778 /* unfortunately, you cannot erase the old visible text here */
779 /* because o_text_draw will just return */
783 if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
784 o_edit_show_hidden_lowlevel(w_current, o_current->complex->prim_objs);
785 o_complex_recalc(w_current, o_current);
788 o_current = o_current->next;
792 /*! \todo Finish function documentation!!!
793 * \brief
794 * \par Function Description
797 void o_edit_show_hidden(TOPLEVEL *w_current, OBJECT *o_list)
799 /* this function just shows the hidden text, but doesn't toggle it */
800 /* this function does not change the CHANGED bit, no real changes are */
801 /* made to the schematic */
803 /* toggle show_hidden_text variable, which when it is true */
804 /* means that hidden text IS drawn */
805 w_current->show_hidden_text = !w_current->show_hidden_text;
806 i_show_state(w_current, NULL); /* update screen status */
808 o_edit_show_hidden_lowlevel(w_current, o_list);
809 o_redraw_all_fast(w_current);
811 if (w_current->show_hidden_text) {
812 s_log_message(_("Hidden text is now visible\n"));
813 } else {
814 s_log_message(_("Hidden text is now invisible\n"));
818 /*! \todo Finish function documentation!!!
819 * \brief
820 * \par Function Description
823 void o_edit_make_visible(TOPLEVEL *w_current, OBJECT *o_list)
825 /* this function actually changes the visibility flag */
826 OBJECT *o_current = NULL;
828 if (o_list == NULL)
829 return;
830 o_current = o_list;
832 while(o_current != NULL) {
834 if (o_current->type == OBJ_TEXT) {
835 if (o_current->visibility == INVISIBLE) {
836 o_current->visibility = VISIBLE;
838 if (o_current->text->prim_objs == NULL) {
839 o_text_recreate(w_current, o_current);
842 o_text_draw(w_current, o_current);
844 w_current->page_current->CHANGED = 1;
847 o_current = o_current->next;
849 o_undo_savestate(w_current, UNDO_ALL);
853 #define FIND_WINDOW_HALF_SIZE (5000)
855 OBJECT *last_o = NULL;
856 int skiplast;
858 /*! \todo Finish function documentation!!!
859 * \brief
860 * \par Function Description
863 int o_edit_find_text(TOPLEVEL * w_current, OBJECT * o_list, char *stext,
864 int descend, int skip)
867 char *attrib = NULL;
868 int count = 0;
869 PAGE *parent = NULL;
870 char *current_filename = NULL;
871 int page_control = 0;
872 int pcount = 0;
873 int rv;
874 int text_screen_height;
876 OBJECT *o_current = NULL;
878 skiplast = skip;
879 o_current = o_list;
881 if (o_current == NULL) {
882 return 1;
885 while (o_current != NULL) {
887 if (descend) {
888 if (o_current->type == OBJ_COMPLEX) {
889 parent = w_current->page_current;
890 attrib = o_attrib_search_name_single_count(o_current,
891 "source", count);
893 /* if above is null, then look inside symbol */
894 if (attrib == NULL) {
895 attrib = o_attrib_search_name(o_current->
896 complex->
897 prim_objs, "source", count);
898 /* looking_inside = TRUE; */
901 if (attrib) {
902 pcount = 0;
903 current_filename = u_basic_breakup_string(attrib, ',', pcount);
904 if (current_filename != NULL) {
905 page_control =
906 s_hierarchy_down_schematic_single(w_current,
907 current_filename,
908 parent,
909 page_control,
910 HIERARCHY_NORMAL_LOAD);
911 /* o_redraw_all(w_current); */
913 rv = o_edit_find_text(w_current,
914 w_current->page_current->object_head,
915 stext, descend, skiplast);
916 if (!rv) {
917 return 0;
919 s_hierarchy_up(w_current, w_current->page_current->up);
925 if (o_current->type == OBJ_TEXT) {
926 /* replaced strcmp with strstr to simplify the search */
927 if (strstr(o_current->text->string,stext)) {
928 if (!skiplast) {
929 a_zoom(w_current, ZOOM_FULL, DONTCARE, A_PAN_DONT_REDRAW);
930 text_screen_height = SCREENabs(w_current,
931 o_text_height(o_current->
932 text->string,
933 o_current->
934 text->size));
935 /* this code will zoom/pan till the text screen height is about */
936 /* 50 pixels high, perhaps a future enhancement will be to make */
937 /* this number configurable */
938 while (text_screen_height < 50) {
939 a_zoom(w_current, ZOOM_IN, DONTCARE, A_PAN_DONT_REDRAW);
940 text_screen_height = SCREENabs(w_current,
941 o_text_height(o_current->
942 text->string,
943 o_current->
944 text->size));
946 a_pan_general(w_current, o_current->text->x, o_current->text->y,
947 1, 0);
949 last_o = o_current;
950 break;
952 if (last_o == o_current) {
953 skiplast = 0;
958 o_current = o_current->next;
960 if (o_current == NULL) {
961 return 1;
964 return (o_current == NULL);
968 /*! \todo Finish function documentation!!!
969 * \brief
970 * \par Function Description
973 void o_edit_hide_specific_text(TOPLEVEL * w_current, OBJECT * o_list,
974 char *stext)
976 OBJECT *o_current = NULL;
978 if (o_list == NULL)
979 return;
981 o_current = o_list;
983 while (o_current != NULL) {
985 if (o_current->type == OBJ_TEXT) {
986 if (!strncmp(stext, o_current->text->string, strlen(stext))) {
987 if (o_current->visibility == VISIBLE) {
988 o_current->visibility = INVISIBLE;
990 if (o_current->text->prim_objs == NULL) {
991 o_text_recreate(w_current, o_current);
993 w_current->page_current->CHANGED = 1;
997 o_current = o_current->next;
999 o_undo_savestate(w_current, UNDO_ALL);
1000 o_redraw_all(w_current);
1003 /*! \todo Finish function documentation!!!
1004 * \brief
1005 * \par Function Description
1008 void o_edit_show_specific_text(TOPLEVEL * w_current, OBJECT * o_list,
1009 char *stext)
1011 OBJECT *o_current = NULL;
1013 if (o_list == NULL)
1014 return;
1016 o_current = o_list;
1018 while (o_current != NULL) {
1020 if (o_current->type == OBJ_TEXT) {
1021 if (!strncmp(stext, o_current->text->string, strlen(stext))) {
1022 if (o_current->visibility == INVISIBLE) {
1023 o_current->visibility = VISIBLE;
1025 if (o_current->text->prim_objs == NULL) {
1026 o_text_recreate(w_current, o_current);
1028 o_text_draw(w_current, o_current);
1029 w_current->page_current->CHANGED = 1;
1033 o_current = o_current->next;
1035 o_undo_savestate(w_current, UNDO_ALL);
1038 /*! \todo Finish function documentation!!!
1039 * \brief
1040 * \par Function Description
1043 void o_update_component(TOPLEVEL *w_current, OBJECT *o_current)
1045 OBJECT *tmp_list, *new_complex;
1046 ATTRIB *new_attribs, *a_current;
1047 gboolean is_embedded;
1048 const CLibSymbol *clib;
1050 g_return_if_fail (o_current != NULL);
1052 is_embedded = o_complex_is_embedded (o_current);
1054 g_assert (o_current->complex_basename != NULL);
1055 clib = s_clib_get_symbol_by_name (o_current->complex_basename);
1057 if (clib == NULL) {
1058 s_log_message (_("Could not find symbol [%s] in library. Update failed.\n"),
1059 o_current->complex_basename);
1060 return;
1063 /* erase the complex object */
1064 o_erase_single (w_current, o_current);
1065 /* delete its connections */
1066 s_conn_remove_complex (w_current, o_current);
1067 /* and unselect it */
1068 o_selection_remove( w_current->page_current->selection_list, o_current);
1070 /* build a temporary list and add a complex to this list */
1071 tmp_list = s_basic_init_object ("update component");
1072 new_complex = o_complex_add (w_current,
1073 tmp_list, NULL,
1074 OBJ_COMPLEX,
1075 WHITE,
1076 o_current->complex->x,
1077 o_current->complex->y,
1078 o_current->complex->angle,
1079 o_current->complex->mirror,
1080 clib, o_current->complex_basename,
1081 1, TRUE);
1083 /* updating the old complex with data from the new one */
1084 /* first process the prim_objs: */
1085 /* - delete the prim_objs of the old component */
1086 s_delete_list_fromstart (w_current,
1087 o_current->complex->prim_objs);
1088 /* - put the prim_objs of the new component in the old one */
1089 o_current->complex->prim_objs = new_complex->complex->prim_objs;
1090 /* - reset the new complex prim_objs */
1091 new_complex->complex->prim_objs = NULL;
1093 /* then process the attributes: */
1094 new_attribs = new_complex->attribs;
1095 /* - check each attrib of the new complex */
1096 a_current = new_attribs ? new_attribs->next : NULL;
1097 while (a_current != NULL) {
1098 OBJECT *o_attrib;
1099 gchar *name, *value;
1100 char *attrfound;
1101 g_assert (a_current->object->type == OBJ_TEXT);
1102 o_attrib_get_name_value (a_current->object->text->string,
1103 &name, &value);
1105 attrfound = o_attrib_search_name_single(o_current, name, NULL);
1107 /* free these now since they are no longer being used */
1108 if (name) { g_free(name); }
1109 if (value) { g_free(value); }
1111 if (attrfound == NULL) {
1112 /* attribute with same name not found in old component: */
1113 /* add new attribute to old component */
1115 /* make a copy of the attribute object */
1116 o_list_copy_to (w_current, o_current,
1117 a_current->object, NORMAL_FLAG, &o_attrib);
1118 if (o_current->attribs == NULL) {
1119 /* object has no attribute list: create it */
1120 o_current->attribs = add_attrib_head(o_current);
1122 /* add the attribute to old */
1123 o_attrib_add (w_current, o_current->attribs, o_attrib);
1124 /* redraw the attribute object */
1125 o_redraw_single (w_current, o_attrib);
1126 /* note: this object is unselected (not added to selection). */
1128 else
1130 g_free(attrfound);
1134 a_current = a_current->next;
1137 /* finally delete the temp list with the updated complex */
1138 s_delete_list_fromstart (w_current, tmp_list);
1140 /* Recalculate the bounds of the object */
1141 o_complex_recalc(w_current, o_current);
1143 /* reconnect, re-select and redraw */
1144 s_conn_update_complex (w_current, o_current->complex->prim_objs);
1145 o_selection_add( w_current->page_current->selection_list, o_current );
1146 o_redraw_single (w_current, o_current);
1148 /* Re-flag as embedded if necessary */
1149 o_current->complex_embedded = is_embedded;
1151 /* mark the page as modified */
1152 w_current->page_current->CHANGED = 1;
1153 o_undo_savestate (w_current, UNDO_ALL);
1157 /*! \brief Do autosave on all pages that are marked.
1158 * \par Function Description
1159 * Looks for pages with the do_autosave_backup flag activated and
1160 * autosaves them.
1162 * \param [in] toplevel The TOPLEVEL object to search for autosave's.
1164 void o_autosave_backups(TOPLEVEL *toplevel)
1166 PAGE *p_save, *p_current;
1167 gchar *backup_filename;
1168 gchar *real_filename;
1169 gchar *only_filename;
1170 gchar *dirname;
1171 mode_t saved_umask;
1172 mode_t mask;
1173 struct stat st;
1175 g_assert (toplevel->page_head != NULL &&
1176 toplevel->page_head->pid == -1);
1178 /* save current page */
1179 p_save = toplevel->page_current;
1181 for (p_current = toplevel->page_head->next;
1182 p_current != NULL;
1183 p_current = p_current->next) {
1185 if (p_current->do_autosave_backup == 0) {
1186 continue;
1188 if (p_current->ops_since_last_backup != 0) {
1189 /* make p_current the current page of toplevel */
1190 s_page_goto (toplevel, p_current);
1192 /* Get the real filename and file permissions */
1193 real_filename = follow_symlinks (p_current->page_filename, NULL);
1195 if (real_filename == NULL) {
1196 s_log_message (_("o_autosave_backups: Can't get the real filename of %s."), p_current->page_filename);
1197 fprintf (stderr, "o_autosave_backups: Can't get the real filename of %s.\n", p_current->page_filename);
1199 else {
1200 /* Get the directory in which the real filename lives */
1201 dirname = g_path_get_dirname (real_filename);
1202 only_filename = g_path_get_basename(real_filename);
1205 backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING,
1206 dirname, G_DIR_SEPARATOR, only_filename);
1208 /* If there is not an existing file with that name, compute the
1209 * permissions and uid/gid that we will use for the newly-created file.
1212 if (stat (real_filename, &st) != 0)
1214 struct stat dir_st;
1215 int result;
1217 /* Use default permissions */
1218 saved_umask = umask(0);
1219 st.st_mode = 0666 & ~saved_umask;
1220 umask(saved_umask);
1221 st.st_uid = getuid ();
1223 result = stat (dirname, &dir_st);
1225 if (result == 0 && (dir_st.st_mode & S_ISGID))
1226 st.st_gid = dir_st.st_gid;
1227 else
1228 st.st_gid = getgid ();
1230 g_free (dirname);
1231 g_free (only_filename);
1232 g_free (real_filename);
1234 /* Make the backup file writable before saving a new one */
1235 if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) &&
1236 (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
1237 saved_umask = umask(0);
1238 if (chmod(backup_filename, (S_IWRITE|S_IWGRP|S_IWOTH) &
1239 ((~saved_umask) & 0777)) != 0) {
1240 s_log_message (_("Could NOT set previous backup file [%s] read-write\n"),
1241 backup_filename);
1243 umask(saved_umask);
1246 if (o_save (toplevel, backup_filename)) {
1248 p_current->ops_since_last_backup = 0;
1249 p_current->do_autosave_backup = 0;
1251 /* Make the backup file readonly so a 'rm *' command will ask
1252 the user before deleting it */
1253 saved_umask = umask(0);
1254 mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH);
1255 mask = (~mask)&0777;
1256 mask &= ((~saved_umask) & 0777);
1257 if (chmod(backup_filename,mask) != 0) {
1258 s_log_message (_("Could NOT set backup file [%s] readonly\n"),
1259 backup_filename);
1261 umask(saved_umask);
1262 } else {
1263 s_log_message (_("Could NOT save backup file [%s]\n"),
1264 backup_filename);
1266 g_free (backup_filename);
1270 /* restore current page */
1271 s_page_goto (toplevel, p_save);