1 /*-------------------------------------------------------------------------*/
2 /* events.c --- xcircuit routines handling Xevents and Callbacks */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
6 /*-------------------------------------------------------------------------*/
7 /* written by Tim Edwards, 8/13/93 */
8 /*-------------------------------------------------------------------------*/
17 #include <X11/Intrinsic.h>
18 #include <X11/StringDefs.h>
21 #include <X11/keysymdef.h>
26 #include <X11/keysymdef.h>
31 #include <cairo/cairo-xlib.h>
34 /*-------------------------------------------------------------------------*/
36 /*-------------------------------------------------------------------------*/
43 #include "colordefs.h"
45 #define HOLD_MASK (Mod4Mask << 16)
47 /*----------------------------------------------------------------------*/
48 /* Function prototype declarations */
49 /*----------------------------------------------------------------------*/
50 #include "prototypes.h"
52 /*-------------------------------------------------------------------------*/
53 /* Global Variable definitions */
54 /*-------------------------------------------------------------------------*/
56 extern XtAppContext app
;
58 extern Cursor appcursors
[NUM_CURSORS
];
59 extern Globaldata xobjs
;
60 extern XCWindowData
*areawin
;
61 extern ApplicationData appdata
;
62 extern colorindex
*colorlist
;
65 extern xcWidget message2
, top
;
66 extern char _STR
[150], _STR2
[250];
68 extern double saveratio
;
69 extern u_char texttype
;
70 extern aliasptr aliastop
;
73 extern Tcl_Interp
*xcinterp
;
79 #if !defined(HAVE_CAIRO)
80 Pixmap dbuf
= (Pixmap
)NULL
;
83 Boolean was_preselected
;
85 /*----------------------------------------------------------------------------*/
86 /* Edit Object pushing and popping. */
87 /*----------------------------------------------------------------------------*/
89 Boolean
recursefind(objectptr parent
, objectptr suspect
)
93 if (parent
== suspect
) return True
;
95 for (shell
= parent
->plist
; shell
< parent
->plist
+ parent
->parts
; shell
++)
96 if (IS_OBJINST(*shell
))
97 if (recursefind(TOOBJINST(shell
)->thisobject
, suspect
)) return True
;
102 /*--------------------------------------------------------------*/
103 /* Transfer objects in the select list to the current object */
104 /* (but disallow infinitely recursive loops!) */
105 /*--------------------------------------------------------------*/
106 /* IMPORTANT: delete_for_xfer() MUST be executed prior to */
107 /* calling transferselects(), so that the deleted elements are */
108 /* in an object saved in areawin->editstack. */
109 /*--------------------------------------------------------------*/
111 void transferselects()
117 if (areawin
->editstack
->parts
== 0) return;
119 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
120 eventmode
== UNDO_MODE
|| eventmode
== CATMOVE_MODE
) {
121 short ps
= topobject
->parts
;
125 locselects
= areawin
->editstack
->parts
;
126 areawin
->selectlist
= xc_undelete(areawin
->topinstance
,
127 areawin
->editstack
, (short)NORMAL
, (short *)NULL
);
128 areawin
->selects
= locselects
;
130 /* Move all selected items to the cursor position */
131 newpos
= UGetCursor();
132 drag((int)newpos
.x
, (int)newpos
.y
);
134 /* check to make sure this object is not the current object */
135 /* or one of its direct ancestors, else an infinite loop results. */
137 for (ps
= 0; ps
< topobject
->parts
; ps
++) {
138 if (IS_OBJINST(*(topobject
->plist
+ ps
))) {
139 tobj
= TOOBJINST(topobject
->plist
+ ps
);
140 if (recursefind(tobj
->thisobject
, topobject
)) {
141 Wprintf("Attempt to place object inside of itself");
142 delete_noundo(NORMAL
);
150 /*-------------------------------------------------------------------*/
151 /* Make a new matrix corresponding to the current position and scale */
152 /*-------------------------------------------------------------------*/
157 DCTM
= (Matrixptr
)malloc(sizeof(Matrix
));
158 DCTM
->nextmatrix
= NULL
;
164 /*-------------------------------------------------------*/
165 /* set the viewscale variable to the proper address */
166 /*-------------------------------------------------------*/
168 void setpage(Boolean killselects
)
170 areawin
->vscale
= topobject
->viewscale
;
171 areawin
->pcorner
= topobject
->pcorner
;
174 if (killselects
) clearselects();
177 if (xobjs
.suspend
< 0)
178 XcInternalTagCall(xcinterp
, 2, "page", "goto");
182 /*-------------------------------------------------------*/
183 /* switch to a new page */
184 /*-------------------------------------------------------*/
186 int changepage(short pagenumber
)
192 /* to add to existing number of top level pages. . . */
194 if (pagenumber
== 255) {
195 if (xobjs
.pages
== 255) {
196 Wprintf("Out of available pages!");
199 else pagenumber
= xobjs
.pages
;
202 if (pagenumber
>= xobjs
.pages
) {
204 xobjs
.pagelist
= (Pagedata
**)realloc(xobjs
.pagelist
, (pagenumber
+ 1)
205 * sizeof(Pagedata
*));
206 xobjs
.pagelist
[pagenumber
] = (Pagedata
*)malloc(sizeof(Pagedata
));
207 xobjs
.pagelist
[pagenumber
]->filename
= NULL
;
208 xobjs
.pagelist
[pagenumber
]->background
.name
= NULL
;
209 xobjs
.pagelist
[pagenumber
]->pageinst
= NULL
;
211 /* If we skipped ahead to pagenumber, fill in the pages in between */
212 for (npage
= xobjs
.pages
; npage
< pagenumber
; npage
++) {
213 xobjs
.pagelist
[npage
] = (Pagedata
*)malloc(sizeof(Pagedata
));
214 xobjs
.pagelist
[npage
]->pageinst
= NULL
;
217 xobjs
.pages
= pagenumber
+ 1;
221 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
|| eventmode
== UNDO_MODE
) {
222 delete_for_xfer(NORMAL
, areawin
->selectlist
, areawin
->selects
);
223 undo_type
= UNDO_MORE
;
227 undo_type
= UNDO_DONE
;
229 if (areawin
->page
!= pagenumber
)
230 register_for_undo(XCF_Page
, undo_type
, areawin
->topinstance
,
231 areawin
->page
, pagenumber
);
233 if (eventmode
!= ASSOC_MODE
) {
234 areawin
->page
= pagenumber
;
235 free_stack(&areawin
->stack
);
237 if (xobjs
.pagelist
[pagenumber
]->pageinst
== NULL
) {
239 /* initialize a new page */
241 pageobj
= (objectptr
) malloc (sizeof(object
));
243 sprintf(pageobj
->name
, "Page %d", pagenumber
+ 1);
245 xobjs
.pagelist
[pagenumber
]->pageinst
= newpageinst(pageobj
);
246 xobjs
.pagelist
[pagenumber
]->filename
= NULL
;
247 xobjs
.pagelist
[pagenumber
]->background
.name
= NULL
;
249 pagereset(pagenumber
);
252 /* Write back the current view parameters */
253 if (areawin
->topinstance
!= NULL
) {
254 topobject
->viewscale
= areawin
->vscale
;
255 topobject
->pcorner
= areawin
->pcorner
;
258 areawin
->topinstance
= xobjs
.pagelist
[pagenumber
]->pageinst
;
265 /*-------------------------------------------------------*/
266 /* switch to a new page and redisplay */
267 /*-------------------------------------------------------*/
269 void newpage(short pagenumber
)
273 eventmode
= NORMAL_MODE
;
277 case NORMAL_MODE
: case COPY_MODE
: case MOVE_MODE
: case UNDO_MODE
:
278 if (changepage(pagenumber
) >= 0) {
281 refresh(NULL
, NULL
, NULL
);
283 togglegrid((u_short
)xobjs
.pagelist
[areawin
->page
]->coordstyle
);
289 Wprintf("Cannot switch pages from this mode");
294 /*---------------------------------------*/
295 /* Stack structure push and pop routines */
296 /*---------------------------------------*/
298 void push_stack(pushlistptr
*stackroot
, objinstptr thisinst
, char *clientdata
)
302 newpush
= (pushlistptr
)malloc(sizeof(pushlist
));
303 newpush
->next
= *stackroot
;
304 newpush
->clientdata
= clientdata
;
305 newpush
->thisinst
= thisinst
;
306 *stackroot
= newpush
;
309 /*----------------------------------------------------------*/
311 void pop_stack(pushlistptr
*stackroot
)
313 pushlistptr lastpush
;
316 Fprintf(stderr
, "pop_genstack() Error: NULL instance stack!\n");
320 lastpush
= (*stackroot
)->next
;
322 *stackroot
= lastpush
;
325 /*----------------------------------------------------------*/
327 void free_stack(pushlistptr
*stackroot
)
329 while ((*stackroot
) != NULL
)
330 pop_stack(stackroot
);
333 /*------------------------------------------*/
334 /* Push object onto hierarchy stack to edit */
335 /*------------------------------------------*/
337 void pushobject(objinstptr thisinst
)
339 short *selectobj
, *savelist
;
341 u_char undo_type
= UNDO_DONE
;
342 objinstptr pushinst
= thisinst
;
346 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
) {
347 savelist
= areawin
->selectlist
;
348 saves
= areawin
->selects
;
349 areawin
->selectlist
= NULL
;
350 areawin
->selects
= 0;
351 undo_type
= UNDO_MORE
;
354 if (pushinst
== NULL
) {
355 selectobj
= areawin
->selectlist
;
356 if (areawin
->selects
== 0) {
357 disable_selects(topobject
, savelist
, saves
);
358 selectobj
= select_element(OBJINST
);
359 enable_selects(topobject
, savelist
, saves
);
361 if (areawin
->selects
== 0) {
362 Wprintf("No objects selected.");
365 else if (areawin
->selects
> 1) {
366 Wprintf("Choose only one object.");
369 else if (SELECTTYPE(selectobj
) != OBJINST
) {
370 Wprintf("Element to push must be an object.");
373 else pushinst
= SELTOOBJINST(selectobj
);
376 if (savelist
!= NULL
) {
377 delete_for_xfer(NORMAL
, savelist
, saves
);
381 register_for_undo(XCF_Push
, undo_type
, areawin
->topinstance
, pushinst
);
383 /* save the address of the current object to the push stack */
385 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
387 topobject
->viewscale
= areawin
->vscale
;
388 topobject
->pcorner
= areawin
->pcorner
;
389 areawin
->topinstance
= pushinst
;
391 /* move selected items to the new object */
395 refresh(NULL
, NULL
, NULL
);
399 /*--------------------------*/
400 /* Pop edit hierarchy stack */
401 /*--------------------------*/
403 void popobject(xcWidget w
, pointertype no_undo
, caddr_t calldata
)
405 u_char undo_type
= UNDO_DONE
;
406 UNUSED(w
); UNUSED(calldata
);
408 if (areawin
->stack
== NULL
|| (eventmode
!= NORMAL_MODE
&& eventmode
!= MOVE_MODE
409 && eventmode
!= COPY_MODE
&& eventmode
!= FONTCAT_MODE
&&
410 eventmode
!= ASSOC_MODE
&& eventmode
!= UNDO_MODE
&&
411 eventmode
!= EFONTCAT_MODE
)) return;
413 if ((eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
|| eventmode
== UNDO_MODE
)
414 && ((areawin
->stack
->thisinst
== xobjs
.libtop
[LIBRARY
]) ||
415 (areawin
->stack
->thisinst
== xobjs
.libtop
[USERLIB
]))) return;
417 /* remove any selected items from the current object */
419 if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
|| eventmode
== UNDO_MODE
) {
420 undo_type
= UNDO_MORE
;
421 delete_for_xfer(NORMAL
, areawin
->selectlist
, areawin
->selects
);
423 else if (eventmode
!= FONTCAT_MODE
&& eventmode
!= EFONTCAT_MODE
)
426 /* If coming from the library, don't register an undo action, because */
427 /* it has already been registered as type XCF_Library_Pop. */
429 if (no_undo
== (pointertype
)0)
430 register_for_undo(XCF_Pop
, undo_type
, areawin
->topinstance
);
432 topobject
->viewscale
= areawin
->vscale
;
433 topobject
->pcorner
= areawin
->pcorner
;
434 areawin
->topinstance
= areawin
->stack
->thisinst
;
435 pop_stack(&areawin
->stack
);
437 /* if new object is a library or PAGELIB, put back into CATALOG_MODE */
439 if (is_library(topobject
) >= 0) eventmode
= CATALOG_MODE
;
441 /* move selected items to the new object */
443 if (eventmode
== FONTCAT_MODE
|| eventmode
== EFONTCAT_MODE
)
448 if (eventmode
!= ASSOC_MODE
)
451 refresh(NULL
, NULL
, NULL
);
454 /*-------------------------------------------------------------------------*/
455 /* Destructive reset of entire object */
456 /*-------------------------------------------------------------------------*/
458 void resetbutton(xcWidget button
, pointertype pageno
, caddr_t calldata
)
463 UNUSED(button
); UNUSED(calldata
);
465 if (eventmode
!= NORMAL_MODE
) return;
467 page
= (pageno
== (pointertype
)0) ? areawin
->page
: (short)(pageno
- 1);
469 pageinst
= xobjs
.pagelist
[page
]->pageinst
;
471 if (pageinst
== NULL
) return; /* page already cleared */
473 pageobj
= pageinst
->thisobject
;
475 /* Make sure this is a real top-level page */
477 if (is_page(topobject
) < 0) {
478 if (pageno
== (pointertype
)0) {
479 Wprintf("Can only clear top-level pages!");
483 /* Make sure that we're not in the hierarchy of the page being deleted */
485 for (slist
= areawin
->stack
; slist
!= NULL
; slist
= slist
->next
)
486 if (slist
->thisinst
->thisobject
== pageobj
) {
487 Wprintf("Can't delete the page while you're in its hierarchy!");
493 /* Watch for pages which are linked by schematic/symbol. */
495 if (pageobj
->symschem
!= NULL
) {
496 Wprintf("Schematic association to object %s", pageobj
->symschem
->name
);
500 sprintf(pageobj
->name
, "Page %d", page
+ 1);
501 xobjs
.pagelist
[page
]->filename
= (char *)realloc(xobjs
.pagelist
[page
]->filename
,
502 (strlen(pageobj
->name
) + 1) * sizeof(char));
503 strcpy(xobjs
.pagelist
[page
]->filename
, pageobj
->name
);
504 reset(pageobj
, NORMAL
);
507 if (page
== areawin
->page
) {
508 areawin
->redraw_needed
= True
;
509 drawarea(areawin
->area
, NULL
, NULL
);
512 Wprintf("Page cleared.");
516 /*------------------------------------------------------*/
517 /* Redraw the horizontal scrollbar */
518 /*------------------------------------------------------*/
520 void drawhbar(xcWidget bar
, caddr_t clientdata
, caddr_t calldata
)
524 long rleft
, rright
, rmid
;
525 UNUSED(clientdata
); UNUSED(calldata
);
527 if (!xcIsRealized(bar
)) return;
528 if (xobjs
.suspend
>= 0) return;
530 bwin
= xcWindow(bar
);
532 if (topobject
->bbox
.width
> 0) {
533 frac
= (float) areawin
->width
/ (float) topobject
->bbox
.width
;
534 rleft
= (long)(frac
* (float)(areawin
->pcorner
.x
535 - topobject
->bbox
.lowerleft
.x
));
536 rright
= rleft
+ (long)(frac
* (float)areawin
->width
/ areawin
->vscale
);
540 rright
= (long)areawin
->width
;
542 rmid
= (rright
+ rleft
) >> 1;
544 if (rleft
< 0) rleft
= 0;
545 if (rright
> areawin
->width
) rright
= areawin
->width
;
547 XSetFunction(dpy
, areawin
->gc
, GXcopy
);
548 XSetForeground(dpy
, areawin
->gc
, colorlist
[BARCOLOR
].color
.pixel
);
549 if (rmid
> 0 && rleft
> 0)
550 XClearArea(dpy
, bwin
, 0, 0, (int)rleft
, SBARSIZE
, FALSE
);
551 XFillRectangle(dpy
, bwin
, areawin
->gc
, (int)rleft
+ 1, 1,
552 (int)(rright
- rleft
), SBARSIZE
- 1);
554 XClearArea(dpy
, bwin
, (int)rright
+ 1, 0, areawin
->width
555 - (int)rright
, SBARSIZE
, FALSE
);
556 XClearArea(dpy
, bwin
, (int)rmid
- 1, 1, 3, SBARSIZE
, FALSE
);
558 XSetForeground(dpy
, areawin
->gc
, colorlist
[areawin
->gccolor
].color
.pixel
);
561 /*------------------------------------------------------*/
562 /* Redraw the vertical scrollbar */
563 /*------------------------------------------------------*/
565 void drawvbar(xcWidget bar
, caddr_t clientdata
, caddr_t calldata
)
567 Window bwin
= xcWindow(bar
);
569 long rtop
, rbot
, rmid
;
570 UNUSED(clientdata
); UNUSED(calldata
);
572 if (!xcIsRealized(bar
)) return;
573 if (xobjs
.suspend
>= 0) return;
575 if (topobject
->bbox
.height
> 0) {
576 frac
= (float)areawin
->height
/ (float)topobject
->bbox
.height
;
577 rbot
= (long)(frac
* (float)(topobject
->bbox
.lowerleft
.y
578 - areawin
->pcorner
.y
+ topobject
->bbox
.height
));
579 rtop
= rbot
- (long)(frac
* (float)areawin
->height
/ areawin
->vscale
);
582 rbot
= areawin
->height
;
585 rmid
= (rtop
+ rbot
) >> 1;
587 if (rtop
< 0) rtop
= 0;
588 if (rbot
> areawin
->height
) rbot
= areawin
->height
;
590 XSetFunction(dpy
, areawin
->gc
, GXcopy
);
591 XSetForeground(dpy
, areawin
->gc
, colorlist
[BARCOLOR
].color
.pixel
);
592 if (rmid
> 0 && rtop
> 0)
593 XClearArea(dpy
, bwin
, 0, 0, SBARSIZE
, (int)rtop
, FALSE
);
594 XFillRectangle(dpy
, bwin
, areawin
->gc
, 0, (int)rtop
+ 2, SBARSIZE
,
597 XClearArea(dpy
, bwin
, 0, (int)rbot
+ 1, SBARSIZE
, areawin
->height
599 XClearArea(dpy
, bwin
, 0, (int)rmid
- 1, SBARSIZE
, 3, FALSE
);
601 XSetForeground(dpy
, areawin
->gc
, colorlist
[areawin
->gccolor
].color
.pixel
);
604 /*------------------------------------------------------*/
605 /* Simultaneously scroll the screen and horizontal */
606 /* bar when dragging the mouse in the scrollbar area */
607 /*------------------------------------------------------*/
609 void panhbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
612 short savex
= areawin
->pcorner
.x
;
615 if (eventmode
== SELAREA_MODE
) return;
617 newx
= (long)(event
->x
* ((float)topobject
->bbox
.width
/
618 areawin
->width
) + topobject
->bbox
.lowerleft
.x
- 0.5 *
619 ((float)areawin
->width
/ areawin
->vscale
));
620 areawin
->pcorner
.x
= (short)newx
;
621 drawhbar(bar
, NULL
, NULL
);
622 areawin
->pcorner
.x
= savex
;
624 if ((newpx
= (long)(newx
- savex
) * areawin
->vscale
) == 0)
627 areawin
->panx
= -newpx
;
628 drawarea(NULL
, NULL
, NULL
);
631 /*------------------------------------------------------*/
632 /* End the horizontal scroll and refresh entire screen */
633 /*------------------------------------------------------*/
635 void endhbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
638 short savex
= areawin
->pcorner
.x
;
643 newx
= (long)(event
->x
* ((float)topobject
->bbox
.width
/
644 areawin
->width
) + topobject
->bbox
.lowerleft
.x
- 0.5 *
645 ((float)areawin
->width
/ areawin
->vscale
));
647 areawin
->pcorner
.x
= (short)newx
;
649 if ((newx
<< 1) != (long)((short)(newx
<< 1)) || checkbounds() == -1) {
650 areawin
->pcorner
.x
= savex
;
651 Wprintf("Reached boundary: cannot pan further");
656 areawin
->redraw_needed
= True
;
657 areawin
->lastbackground
= NULL
;
659 drawhbar(bar
, NULL
, NULL
);
660 drawarea(bar
, NULL
, NULL
);
663 /*------------------------------------------------------*/
664 /* Simultaneously scroll the screen and vertical */
665 /* bar when dragging the mouse in the scrollbar area */
666 /*------------------------------------------------------*/
668 void panvbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
671 short savey
= areawin
->pcorner
.y
;
674 if (eventmode
== SELAREA_MODE
) return;
676 newy
= (int)((areawin
->height
- event
->y
) *
677 ((float)topobject
->bbox
.height
/ areawin
->height
) +
678 topobject
->bbox
.lowerleft
.y
- 0.5 * ((float)areawin
->height
/
680 areawin
->pcorner
.y
= (short)newy
;
681 drawvbar(bar
, NULL
, NULL
);
682 areawin
->pcorner
.y
= savey
;
684 if ((newpy
= (long)(newy
- savey
) * areawin
->vscale
) == 0)
687 areawin
->pany
= newpy
;
688 drawarea(NULL
, NULL
, NULL
);
691 /*------------------------------------------------------*/
692 /* Pan the screen to follow the cursor position */
693 /*------------------------------------------------------*/
695 void trackpan(int x
, int y
)
698 short savey
= areawin
->pcorner
.y
;
699 short savex
= areawin
->pcorner
.x
;
701 newpos
.x
= areawin
->origin
.x
- x
;
702 newpos
.y
= y
- areawin
->origin
.y
;
704 areawin
->pcorner
.x
+= newpos
.x
/ areawin
->vscale
;
705 areawin
->pcorner
.y
+= newpos
.y
/ areawin
->vscale
;
707 drawhbar(areawin
->scrollbarh
, NULL
, NULL
);
708 drawvbar(areawin
->scrollbarv
, NULL
, NULL
);
710 areawin
->panx
= -newpos
.x
;
711 areawin
->pany
= newpos
.y
;
713 drawarea(NULL
, NULL
, NULL
);
715 areawin
->pcorner
.x
= savex
;
716 areawin
->pcorner
.y
= savey
;
720 /*------------------------------------------------------*/
721 /* End the vertical scroll and refresh entire screen */
722 /*------------------------------------------------------*/
724 void endvbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
727 short savey
= areawin
->pcorner
.y
;
732 newy
= (int)((areawin
->height
- event
->y
) *
733 ((float)topobject
->bbox
.height
/ areawin
->height
) +
734 topobject
->bbox
.lowerleft
.y
- 0.5 * ((float)areawin
->height
/
737 areawin
->pcorner
.y
= (short)newy
;
739 if ((newy
<< 1) != (long)((short)(newy
<< 1)) || checkbounds() == -1) {
740 areawin
->pcorner
.y
= savey
;
741 Wprintf("Reached boundary: cannot pan further");
746 areawin
->redraw_needed
= True
;
747 areawin
->lastbackground
= NULL
;
749 drawvbar(bar
, NULL
, NULL
);
750 drawarea(bar
, NULL
, NULL
);
753 /*--------------------------------------------------------------------*/
754 /* Zoom functions-- zoom box, zoom in, zoom out, and pan. */
755 /*--------------------------------------------------------------------*/
760 areawin
->lastbackground
= NULL
;
765 /*--------------------------------------------------------------------*/
767 void zoominbox(int x
, int y
)
770 float delxscale
, delyscale
;
771 XPoint savell
; /* ucenter, ncenter, (jdk)*/
772 UNUSED(x
); UNUSED(y
);
774 savescale
= areawin
->vscale
;
775 savell
.x
= areawin
->pcorner
.x
;
776 savell
.y
= areawin
->pcorner
.y
;
778 /* zoom-box function: corners are in areawin->save and areawin->origin */
779 /* select box has lower-left corner in .origin, upper-right in .save */
780 /* ignore if zoom box is size zero */
782 if (areawin
->save
.x
== areawin
->origin
.x
|| areawin
->save
.y
== areawin
->origin
.y
) {
783 Wprintf("Zoom box of size zero: Ignoring.");
784 eventmode
= NORMAL_MODE
;
788 /* determine whether x or y is limiting factor in zoom */
789 delxscale
= (areawin
->width
/ areawin
->vscale
) /
790 abs(areawin
->save
.x
- areawin
->origin
.x
);
791 delyscale
= (areawin
->height
/ areawin
->vscale
) /
792 abs(areawin
->save
.y
- areawin
->origin
.y
);
793 areawin
->vscale
*= min(delxscale
, delyscale
);
795 areawin
->pcorner
.x
= min(areawin
->origin
.x
, areawin
->save
.x
) -
796 (areawin
->width
/ areawin
->vscale
-
797 abs(areawin
->save
.x
- areawin
->origin
.x
)) / 2;
798 areawin
->pcorner
.y
= min(areawin
->origin
.y
, areawin
->save
.y
) -
799 (areawin
->height
/ areawin
->vscale
-
800 abs(areawin
->save
.y
- areawin
->origin
.y
)) / 2;
801 eventmode
= NORMAL_MODE
;
803 /* check for minimum scale */
805 if (checkbounds() == -1) {
806 areawin
->pcorner
.x
= savell
.x
;
807 areawin
->pcorner
.y
= savell
.y
;
808 areawin
->vscale
= savescale
;
809 Wprintf("At minimum scale: cannot scale further");
811 /* this is a rare case where an object gets out-of-bounds */
813 if (checkbounds() == -1) {
814 if (beeper
) XBell(dpy
, 100);
815 Wprintf("Unable to scale: Delete out-of-bounds object!");
822 /*--------------------------------------------------------------------*/
824 void zoomin(int x
, int y
)
827 XPoint ucenter
, ncenter
, savell
;
829 savescale
= areawin
->vscale
;
830 savell
.x
= areawin
->pcorner
.x
;
831 savell
.y
= areawin
->pcorner
.y
;
833 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ucenter
);
834 areawin
->vscale
*= areawin
->zoomfactor
;
835 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ncenter
);
836 areawin
->pcorner
.x
+= (ucenter
.x
- ncenter
.x
);
837 areawin
->pcorner
.y
+= (ucenter
.y
- ncenter
.y
);
839 /* check for minimum scale */
841 if (checkbounds() == -1) {
842 areawin
->pcorner
.x
= savell
.x
;
843 areawin
->pcorner
.y
= savell
.y
;
844 areawin
->vscale
= savescale
;
845 Wprintf("At minimum scale: cannot scale further");
847 /* this is a rare case where an object gets out-of-bounds */
849 if (checkbounds() == -1) {
850 if (beeper
) XBell(dpy
, 100);
851 Wprintf("Unable to scale: Delete out-of-bounds object!");
855 else if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
856 eventmode
== CATMOVE_MODE
)
862 /*--------------------------------------------------------------------*/
864 void zoominrefresh(int x
, int y
)
866 if (eventmode
== SELAREA_MODE
)
870 refresh(NULL
, NULL
, NULL
);
873 /*--------------------------------------------------------------------*/
875 void zoomoutbox(int x
, int y
)
878 float delxscale
, delyscale
, scalefac
;
879 XPoint savell
; /* ucenter, ncenter, (jdk)*/
881 UNUSED(x
); UNUSED(y
);
883 savescale
= areawin
->vscale
;
884 savell
.x
= areawin
->pcorner
.x
;
885 savell
.y
= areawin
->pcorner
.y
;
887 /* zoom-box function, analogous to that for zoom-in */
888 /* ignore if zoom box is size zero */
890 if (areawin
->save
.x
== areawin
->origin
.x
|| areawin
->save
.y
== areawin
->origin
.y
) {
891 Wprintf("Zoom box of size zero: Ignoring.");
892 eventmode
= NORMAL_MODE
;
896 /* determine whether x or y is limiting factor in zoom */
897 delxscale
= abs(areawin
->save
.x
- areawin
->origin
.x
) /
898 (areawin
->width
/ areawin
->vscale
);
899 delyscale
= abs(areawin
->save
.y
- areawin
->origin
.y
) /
900 (areawin
->height
/ areawin
->vscale
);
901 scalefac
= min(delxscale
, delyscale
);
902 areawin
->vscale
*= scalefac
;
904 /* compute lower-left corner of (reshaped) select box */
905 if (delxscale
< delyscale
) {
906 newll
.y
= min(areawin
->save
.y
, areawin
->origin
.y
);
907 newll
.x
= (areawin
->save
.x
+ areawin
->origin
.x
908 - (abs(areawin
->save
.y
- areawin
->origin
.y
) *
909 areawin
->width
/ areawin
->height
)) / 2;
912 newll
.x
= min(areawin
->save
.x
, areawin
->origin
.x
);
913 newll
.y
= (areawin
->save
.y
+ areawin
->origin
.y
914 - (abs(areawin
->save
.x
- areawin
->origin
.x
) *
915 areawin
->height
/ areawin
->width
)) / 2;
918 /* extrapolate to find new lower-left corner of screen */
919 newll
.x
= areawin
->pcorner
.x
- (int)((float)(newll
.x
-
920 areawin
->pcorner
.x
) / scalefac
);
921 newll
.y
= areawin
->pcorner
.y
- (int)((float)(newll
.y
-
922 areawin
->pcorner
.y
) / scalefac
);
924 eventmode
= NORMAL_MODE
;
925 areawin
->pcorner
.x
= (short)newll
.x
;
926 areawin
->pcorner
.y
= (short)newll
.y
;
928 if ((newll
.x
<< 1) != (long)(areawin
->pcorner
.x
<< 1) || (newll
.y
<< 1)
929 != (long)(areawin
->pcorner
.y
<< 1) || checkbounds() == -1) {
930 areawin
->vscale
= savescale
;
931 areawin
->pcorner
.x
= savell
.x
;
932 areawin
->pcorner
.y
= savell
.y
;
933 Wprintf("At maximum scale: cannot scale further.");
939 /*--------------------------------------------------------------------*/
941 void zoomout(int x
, int y
)
944 XPoint ucenter
, ncenter
, savell
;
947 savescale
= areawin
->vscale
;
948 savell
.x
= areawin
->pcorner
.x
;
949 savell
.y
= areawin
->pcorner
.y
;
951 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ucenter
);
952 areawin
->vscale
/= areawin
->zoomfactor
;
953 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ncenter
);
954 newll
.x
= (long)areawin
->pcorner
.x
+ (long)(ucenter
.x
- ncenter
.x
);
955 newll
.y
= (long)areawin
->pcorner
.y
+ (long)(ucenter
.y
- ncenter
.y
);
956 areawin
->pcorner
.x
= (short)newll
.x
;
957 areawin
->pcorner
.y
= (short)newll
.y
;
959 if ((newll
.x
<< 1) != (long)(areawin
->pcorner
.x
<< 1) || (newll
.y
<< 1)
960 != (long)(areawin
->pcorner
.y
<< 1) || checkbounds() == -1) {
961 areawin
->vscale
= savescale
;
962 areawin
->pcorner
.x
= savell
.x
;
963 areawin
->pcorner
.y
= savell
.y
;
964 Wprintf("At maximum scale: cannot scale further.");
967 else if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
968 eventmode
== CATMOVE_MODE
)
974 /*--------------------------------------------------------------------*/
976 void zoomoutrefresh(int x
, int y
)
978 if (eventmode
== SELAREA_MODE
)
982 refresh(NULL
, NULL
, NULL
);
985 /*--------------------------------------*/
986 /* Call to XWarpPointer */
987 /*--------------------------------------*/
989 void warppointer(int x
, int y
)
991 XWarpPointer(dpy
, None
, areawin
->window
, 0, 0, 0, 0, x
, y
);
994 /*--------------------------------------------------------------*/
995 /* ButtonPress handler during center pan */
996 /* x and y are cursor coordinates. */
997 /* If ptype is 1-4 (directional), then "value" is a fraction of */
998 /* the screen to scroll. */
999 /*--------------------------------------------------------------*/
1001 void panbutton(u_int ptype
, int x
, int y
, float value
)
1003 /* Window pwin; (jdk) */
1004 int xpos
, ypos
, newllx
, newlly
;
1005 XPoint savell
; /* , newpos; (jdk)*/
1006 Dimension hwidth
= areawin
->width
>> 1, hheight
= areawin
->height
>> 1;
1008 savell
.x
= areawin
->pcorner
.x
;
1009 savell
.y
= areawin
->pcorner
.y
;
1013 xpos
= hwidth
- (hwidth
* 2 * value
);
1017 xpos
= hwidth
+ (hwidth
* 2 * value
);
1022 ypos
= hheight
- (hheight
* 2 * value
);
1026 ypos
= hheight
+ (hheight
* 2 * value
);
1032 case 6: /* "pan follow" */
1033 if (eventmode
== PAN_MODE
)
1034 finish_op(XCF_Finish
, x
, y
);
1035 else if (eventmode
== NORMAL_MODE
) {
1036 eventmode
= PAN_MODE
;
1037 areawin
->save
.x
= x
;
1038 areawin
->save
.y
= y
;
1039 u2u_snap(&areawin
->save
);
1040 areawin
->origin
= areawin
->save
;
1042 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
1043 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
1045 xcAddEventHandler(areawin
->area
, PointerMotionMask
|
1046 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
1052 default: /* "pan here" */
1055 warppointer(hwidth
, hheight
);
1060 ypos
= hheight
- ypos
;
1062 newllx
= (int)areawin
->pcorner
.x
+ (int)((float)xpos
/ areawin
->vscale
);
1063 newlly
= (int)areawin
->pcorner
.y
+ (int)((float)ypos
/ areawin
->vscale
);
1065 areawin
->pcorner
.x
= (short) newllx
;
1066 areawin
->pcorner
.y
= (short) newlly
;
1068 if ((newllx
<< 1) != (long)(areawin
->pcorner
.x
<< 1) || (newlly
<< 1)
1069 != (long)(areawin
->pcorner
.y
<< 1) || checkbounds() == -1) {
1070 areawin
->pcorner
.x
= savell
.x
;
1071 areawin
->pcorner
.x
= savell
.y
;
1072 Wprintf("Reached bounds: cannot pan further.");
1075 else if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1076 eventmode
== CATMOVE_MODE
)
1082 /*--------------------------------------------------------------*/
1084 void panrefresh(u_int ptype
, int x
, int y
, float value
)
1086 panbutton(ptype
, x
, y
, value
);
1087 refresh(NULL
, NULL
, NULL
);
1090 /*----------------------------------------------------------------*/
1091 /* Check for out-of-bounds before warping pointer, and pan window */
1093 /*----------------------------------------------------------------*/
1095 void checkwarp(XPoint
*userpt
)
1099 user_to_window(*userpt
, &wpoint
);
1101 if (wpoint
.x
< 0 || wpoint
.y
< 0 || wpoint
.x
> areawin
->width
||
1102 wpoint
.y
> areawin
->height
) {
1103 panrefresh(5, wpoint
.x
, wpoint
.y
, 0);
1104 wpoint
.x
= areawin
->width
>> 1;
1105 wpoint
.y
= areawin
->height
>> 1;
1106 /* snap(wpoint.x, wpoint.y, userpt); */
1108 warppointer(wpoint
.x
, wpoint
.y
);
1111 /*--------------------------------------------------------------*/
1112 /* Return a pointer to the element containing a reference point */
1113 /*--------------------------------------------------------------*/
1115 genericptr
getsubpart(pathptr editpath
, int *idx
)
1117 pointselect
*tmpptr
= NULL
;
1122 for (pgen
= editpath
->plist
; pgen
< editpath
->plist
+ editpath
->parts
; pgen
++) {
1123 switch (ELEMENTTYPE(*pgen
)) {
1125 if (TOPOLY(pgen
)->cycle
!= NULL
) {
1126 for (tmpptr
= TOPOLY(pgen
)->cycle
;; tmpptr
++) {
1127 if (tmpptr
->flags
& REFERENCE
) break;
1128 if (tmpptr
->flags
& LASTENTRY
) break;
1130 if (tmpptr
->flags
& REFERENCE
) return *pgen
;
1134 if (TOSPLINE(pgen
)->cycle
!= NULL
) {
1135 for (tmpptr
= TOSPLINE(pgen
)->cycle
;; tmpptr
++) {
1136 if (tmpptr
->flags
& REFERENCE
) break;
1137 if (tmpptr
->flags
& LASTENTRY
) break;
1139 if (tmpptr
->flags
& REFERENCE
) return *pgen
;
1148 /*--------------------------------------------------------------*/
1149 /* Return a pointer to the current reference point of an */
1150 /* edited element (polygon, spline, or path) */
1151 /*--------------------------------------------------------------*/
1153 pointselect
*getrefpoint(genericptr genptr
, XPoint
**refpt
)
1155 pointselect
*tmpptr
= NULL
;
1158 if (refpt
) *refpt
= NULL
;
1159 switch (genptr
->type
) {
1161 if (((polyptr
)genptr
)->cycle
!= NULL
) {
1162 for (tmpptr
= ((polyptr
)genptr
)->cycle
;; tmpptr
++) {
1163 if (tmpptr
->flags
& REFERENCE
) break;
1164 if (tmpptr
->flags
& LASTENTRY
) break;
1166 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= NULL
;
1167 else if (refpt
) *refpt
= ((polyptr
)genptr
)->points
+ tmpptr
->number
;
1171 if (((splineptr
)genptr
)->cycle
!= NULL
) {
1172 for (tmpptr
= ((splineptr
)genptr
)->cycle
;; tmpptr
++) {
1173 if (tmpptr
->flags
& REFERENCE
) break;
1174 if (tmpptr
->flags
& LASTENTRY
) break;
1176 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= NULL
;
1177 else if (refpt
) *refpt
= &((splineptr
)genptr
)->ctrl
[tmpptr
->number
];
1181 for (pgen
= ((pathptr
)genptr
)->plist
; pgen
< ((pathptr
)genptr
)->plist
+
1182 ((pathptr
)genptr
)->parts
; pgen
++) {
1183 if ((tmpptr
= getrefpoint(*pgen
, refpt
)) != NULL
)
1194 /*--------------------------------------------------------------*/
1195 /* Return next edit point on a polygon, arc, or spline. Do not */
1196 /* update the cycle of the element. */
1197 /*--------------------------------------------------------------*/
1199 int checkcycle(genericptr genptr
, short dir
)
1201 pointselect
*tmpptr
;
1202 short tmppt
, points
;
1205 switch (genptr
->type
) {
1207 if (((polyptr
)genptr
)->cycle
== NULL
)
1210 for (tmpptr
= ((polyptr
)genptr
)->cycle
;; tmpptr
++) {
1211 if (tmpptr
->flags
& REFERENCE
) break;
1212 if (tmpptr
->flags
& LASTENTRY
) break;
1214 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= ((polyptr
)genptr
)->cycle
;
1216 tmppt
= (tmpptr
== NULL
) ? -1 : tmpptr
->number
;
1217 points
= ((polyptr
)genptr
)->number
;
1220 if (((splineptr
)genptr
)->cycle
== NULL
)
1223 for (tmpptr
= ((splineptr
)genptr
)->cycle
;; tmpptr
++) {
1224 if (tmpptr
->flags
& REFERENCE
) break;
1225 if (tmpptr
->flags
& LASTENTRY
) break;
1227 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= ((splineptr
)genptr
)->cycle
;
1229 tmppt
= (tmpptr
== NULL
) ? -1 : tmpptr
->number
;
1233 tmpptr
= ((arcptr
)genptr
)->cycle
;
1234 tmppt
= (tmpptr
== NULL
) ? -1 : tmpptr
->number
;
1238 for (pgen
= ((pathptr
)genptr
)->plist
; pgen
< ((pathptr
)genptr
)->plist
+
1239 ((pathptr
)genptr
)->parts
; pgen
++) {
1240 if ((tmppt
= checkcycle(*pgen
, dir
)) >= 0)
1248 if (tmppt
>= 0) { /* Ignore nonexistent cycles */
1250 if (tmppt
< 0) tmppt
+= points
;
1256 /*--------------------------------------------------------------*/
1257 /* Change to the next part of a path for editing */
1258 /* For now, |dir| is treated as 1 regardless of its value. */
1259 /*--------------------------------------------------------------*/
1261 void nextpathcycle(pathptr nextpath
, short dir
)
1263 genericptr ppart
= getsubpart(nextpath
, NULL
);
1267 splineptr thisspline
;
1269 short cycle
, newcycle
;
1271 /* Simple cases---don't need to switch elements */
1273 switch (ELEMENTTYPE(ppart
)) {
1275 thispoly
= (polyptr
)ppart
;
1276 cptr
= thispoly
->cycle
;
1277 if (cptr
== NULL
) return;
1278 curpt
= thispoly
->points
+ cptr
->number
;
1279 newcycle
= checkcycle(ppart
, dir
);
1280 advancecycle(&ppart
, newcycle
);
1281 if (cptr
->number
< thispoly
->number
&& cptr
->number
> 0) {
1282 checkwarp(thispoly
->points
+ cptr
->number
);
1283 removeothercycles(nextpath
, ppart
);
1284 updatepath(nextpath
);
1289 thisspline
= (splineptr
)ppart
;
1290 cptr
= ((splineptr
)ppart
)->cycle
;
1291 if (cptr
== NULL
) return;
1292 curpt
= &thisspline
->ctrl
[cptr
->number
];
1293 newcycle
= checkcycle(ppart
, dir
);
1294 advancecycle(&ppart
, newcycle
);
1295 if (cptr
->number
< 4 && cptr
->number
> 0) {
1296 checkwarp(&thisspline
->ctrl
[cptr
->number
]);
1297 removeothercycles(nextpath
, ppart
);
1298 updatepath(nextpath
);
1299 if (newcycle
== 1 || newcycle
== 2)
1300 addanticycle(nextpath
, thisspline
, newcycle
);
1306 /* Moving on to the next element. . . */
1308 /* If dir < 0, go to the penultimate cycle of the last part */
1309 /* If dir > 0, go to the second cycle of the next part */
1311 for (ggen
= nextpath
->plist
; (*ggen
!= ppart
) &&
1312 (ggen
< nextpath
->plist
+ nextpath
->parts
); ggen
++);
1314 if (ggen
== nextpath
->plist
+ nextpath
->parts
) return; /* shouldn't happen! */
1321 if (ggen
< nextpath
->plist
)
1322 ggen
= nextpath
->plist
+ nextpath
->parts
- 1;
1323 else if (ggen
== nextpath
->plist
+ nextpath
->parts
)
1324 ggen
= nextpath
->plist
;
1326 removecycle((genericptr
*)(&nextpath
));
1328 /* The next point to edit is the first point in the next segment */
1329 /* that is not at the same position as the one we were last editing. */
1331 switch (ELEMENTTYPE(*ggen
)) {
1333 thispoly
= TOPOLY(ggen
);
1334 cycle
= (dir
> 0) ? 0 : thispoly
->number
- 1;
1335 addcycle(ggen
, cycle
, 0);
1336 makerefcycle(thispoly
->cycle
, cycle
);
1337 if ((thispoly
->points
+ cycle
)->x
== curpt
->x
&&
1338 (thispoly
->points
+ cycle
)->y
== curpt
->y
) {
1339 newcycle
= checkcycle((genericptr
)thispoly
, 1);
1340 advancecycle(ggen
, newcycle
);
1343 checkwarp(thispoly
->points
+ cycle
);
1346 thisspline
= TOSPLINE(ggen
);
1347 cycle
= (dir
> 0) ? 0 : 3;
1348 addcycle(ggen
, cycle
, 0);
1349 makerefcycle(thisspline
->cycle
, cycle
);
1350 if (thisspline
->ctrl
[cycle
].x
== curpt
->x
&&
1351 thisspline
->ctrl
[cycle
].y
== curpt
->y
) {
1352 newcycle
= checkcycle((genericptr
)thisspline
, 1);
1353 advancecycle(ggen
, newcycle
);
1355 if (cycle
== 1 || cycle
== 2)
1356 addanticycle(nextpath
, thisspline
, cycle
);
1358 checkwarp(&(thisspline
->ctrl
[cycle
]));
1361 updatepath(nextpath
);
1364 /*--------------------------------------------------------------*/
1365 /* Change to next edit point on a polygon */
1366 /*--------------------------------------------------------------*/
1368 void nextpolycycle(polyptr
*nextpoly
, short dir
)
1372 newcycle
= checkcycle((genericptr
)(*nextpoly
), dir
);
1373 advancecycle((genericptr
*)nextpoly
, newcycle
);
1374 findconstrained(*nextpoly
);
1375 printeditbindings();
1377 newcycle
= (*nextpoly
)->cycle
->number
;
1378 checkwarp((*nextpoly
)->points
+ newcycle
);
1381 /*--------------------------------------------------------------*/
1382 /* Change to next edit cycle on a spline */
1383 /*--------------------------------------------------------------*/
1385 void nextsplinecycle(splineptr
*nextspline
, short dir
)
1388 newcycle
= checkcycle((genericptr
)(*nextspline
), dir
);
1389 advancecycle((genericptr
*)nextspline
, newcycle
);
1391 if (newcycle
== 1 || newcycle
== 2)
1392 Wprintf("Adjust control point");
1394 Wprintf("Adjust endpoint position");
1396 checkwarp(&(*nextspline
)->ctrl
[newcycle
]);
1399 /*--------------------------------------------------------------*/
1400 /* Warp pointer to the edit point on an arc. */
1401 /*--------------------------------------------------------------*/
1403 void warparccycle(arcptr nextarc
, short cycle
)
1410 curang
.x
= nextarc
->position
.x
+ abs(nextarc
->radius
);
1411 curang
.y
= nextarc
->position
.y
;
1412 if (abs(nextarc
->radius
) != nextarc
->yaxis
)
1413 Wprintf("Adjust ellipse size");
1415 Wprintf("Adjust arc radius");
1418 rad
= (double)(nextarc
->angle1
* RADFAC
);
1419 curang
.x
= nextarc
->position
.x
+ abs(nextarc
->radius
) * cos(rad
);
1420 curang
.y
= nextarc
->position
.y
+ nextarc
->yaxis
* sin(rad
);
1421 Wprintf("Adjust arc endpoint");
1424 rad
= (double)(nextarc
->angle2
* RADFAC
);
1425 curang
.x
= nextarc
->position
.x
+ abs(nextarc
->radius
) * cos(rad
);
1426 curang
.y
= nextarc
->position
.y
+ nextarc
->yaxis
* sin(rad
);
1427 Wprintf("Adjust arc endpoint");
1430 curang
.x
= nextarc
->position
.x
;
1431 curang
.y
= nextarc
->position
.y
+ nextarc
->yaxis
;
1432 Wprintf("Adjust ellipse minor axis");
1438 /*--------------------------------------------------------------*/
1439 /* Change to next edit cycle on an arc */
1440 /*--------------------------------------------------------------*/
1442 void nextarccycle(arcptr
*nextarc
, short dir
)
1446 newcycle
= checkcycle((genericptr
)(*nextarc
), dir
);
1447 advancecycle((genericptr
*)nextarc
, newcycle
);
1448 warparccycle(*nextarc
, newcycle
);
1451 /*------------------------------------------------------*/
1452 /* Get a numerical response from the keyboard (0-9) */
1453 /*------------------------------------------------------*/
1460 XKeyEvent
*keyevent
= (XKeyEvent
*)(&event
);
1464 XNextEvent(dpy
, &event
);
1465 if (event
.type
== KeyPress
) break;
1466 else xcDispatchEvent(&event
);
1468 XLookupString(keyevent
, _STR
, 150, &keypressed
, NULL
);
1469 if (keypressed
> XK_0
&& keypressed
<= XK_9
)
1470 return (short)(keypressed
- XK_1
);
1477 /*--------------------------*/
1478 /* Register a "press" event */
1479 /*--------------------------*/
1482 void makepress(ClientData clientdata
)
1484 void makepress(XtPointer clientdata
, xcIntervalId
*id
)
1487 int keywstate
= (int)((pointertype
)clientdata
);
1492 /* Button/Key was pressed long enough to make a "press", not a "tap" */
1494 areawin
->time_id
= 0;
1495 pressmode
= keywstate
;
1496 eventdispatch(keywstate
| HOLD_MASK
, areawin
->save
.x
, areawin
->save
.y
);
1499 /*------------------------------------------------------*/
1500 /* Handle button events as if they were keyboard events */
1501 /*------------------------------------------------------*/
1503 void buttonhandler(xcWidget w
, caddr_t clientdata
, XButtonEvent
*event
)
1505 XKeyEvent
*kevent
= (XKeyEvent
*)event
;
1507 if (event
->type
== ButtonPress
)
1508 kevent
->type
= KeyPress
;
1510 kevent
->type
= KeyRelease
;
1512 switch (event
->button
) {
1514 kevent
->state
|= Button1Mask
;
1517 kevent
->state
|= Button2Mask
;
1520 kevent
->state
|= Button3Mask
;
1523 kevent
->state
|= Button4Mask
;
1526 kevent
->state
|= Button5Mask
;
1529 keyhandler(w
, clientdata
, kevent
);
1532 /*--------------------------------------------------------------*/
1533 /* Edit operations specific to polygons (point manipulation) */
1534 /*--------------------------------------------------------------*/
1536 void poly_edit_op(int op
)
1538 genericptr keygen
= *(EDITPART
);
1543 if (IS_PATH(keygen
))
1544 keygen
= getsubpart((pathptr
)keygen
, NULL
);
1546 switch(ELEMENTTYPE(keygen
)) {
1548 lwire
= (polyptr
)keygen
;
1550 /* Remove a point from the polygon */
1551 if (op
== XCF_Edit_Delete
) {
1552 if (lwire
->number
< 3) return;
1553 if (lwire
->number
== 3 && !(lwire
->style
& UNCLOSED
))
1554 lwire
->style
|= UNCLOSED
;
1555 cycle
= checkcycle((genericptr
)lwire
, 0);
1557 for (lpoint
= lwire
->points
+ cycle
; lpoint
<
1558 lwire
->points
+ lwire
->number
; lpoint
++)
1559 *lpoint
= *(lpoint
+ 1);
1560 if (eventmode
== EPOLY_MODE
)
1561 poly_mode_draw(xcDRAW_EDIT
, TOPOLY(EDITPART
));
1563 path_mode_draw(xcDRAW_EDIT
, TOPATH(EDITPART
));
1564 nextpolycycle(&lwire
, -1);
1567 /* Add a point to the polygon */
1568 else if (op
== XCF_Edit_Insert
|| op
== XCF_Edit_Append
) {
1570 lwire
->points
= (XPoint
*)realloc(lwire
->points
, lwire
->number
1572 cycle
= checkcycle((genericptr
)lwire
, 0);
1573 for (lpoint
= lwire
->points
+ lwire
->number
- 1; lpoint
> lwire
->
1574 points
+ cycle
; lpoint
--)
1575 *lpoint
= *(lpoint
- 1);
1576 if (eventmode
== EPOLY_MODE
)
1577 poly_mode_draw(xcDRAW_EDIT
, TOPOLY(EDITPART
));
1579 path_mode_draw(xcDRAW_EDIT
, TOPATH(EDITPART
));
1580 if (op
== XCF_Edit_Append
)
1581 nextpolycycle(&lwire
, 1);
1584 /* Parameterize the position of a polygon point */
1585 else if (op
== XCF_Edit_Param
) {
1586 cycle
= checkcycle((genericptr
)lwire
, 0);
1587 makenumericalp(&keygen
, P_POSITION_X
, NULL
, cycle
);
1588 makenumericalp(&keygen
, P_POSITION_Y
, NULL
, cycle
);
1594 /*----------------------------------------------------------------------*/
1595 /* Handle attachment of edited elements to nearby elements */
1596 /*----------------------------------------------------------------------*/
1600 /* Conditions: One element is selected, key "A" is pressed. */
1601 /* Then there must exist a spline, polygon, arc, or label */
1604 if (areawin
->selects
<= 1) {
1607 if (areawin
->attachto
>= 0) {
1608 areawin
->attachto
= -1; /* default value---no attachments */
1609 Wprintf("Unconstrained moving");
1614 select_prev
= areawin
->selects
;
1615 refsel
= select_add_element(SPLINE
|ARC
|POLYGON
|LABEL
|OBJINST
);
1616 if ((refsel
!= NULL
) && (areawin
->selects
> select_prev
)) {
1618 /* transfer refsel over to attachto */
1620 areawin
->attachto
= *(refsel
+ areawin
->selects
- 1);
1622 if (areawin
->selects
== 0) freeselects();
1623 XTopSetForeground(SELTOCOLOR(refsel
));
1624 easydraw(areawin
->attachto
, DEFAULTCOLOR
);
1626 /* restore graphics state */
1627 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
1629 Wprintf("Constrained attach");
1631 /* Starting a new wire? */
1632 if (eventmode
== NORMAL_MODE
) {
1633 XPoint newpos
, userpt
;
1634 userpt
= UGetCursorPos();
1635 findattach(&newpos
, NULL
, &userpt
);
1637 eventmode
= WIRE_MODE
;
1638 areawin
->attachto
= -1;
1642 Wprintf("Nothing found to attach to");
1648 /*--------------------------------------------------------------*/
1649 /* This function returns TRUE if the indicated function is */
1650 /* compatible with the current eventmode; that is, whether */
1651 /* the function could ever be called from eventdispatch() */
1652 /* given the existing eventmode. */
1654 /* Note that this function has to be carefully written or the */
1655 /* function dispatch mechanism can put xcircuit into a bad */
1657 /*--------------------------------------------------------------*/
1659 Boolean
compatible_function(int function
)
1665 case XCF_Text_Left
: case XCF_Text_Right
:
1666 case XCF_Text_Home
: case XCF_Text_End
:
1667 case XCF_Text_Return
: case XCF_Text_Delete
:
1668 case XCF_Text_Delete_Param
:
1669 r
= (eventmode
== CATTEXT_MODE
|| eventmode
== TEXT_MODE
||
1670 eventmode
== ETEXT_MODE
) ?
1674 case XCF_Linebreak
: case XCF_Halfspace
:
1675 case XCF_Quarterspace
: case XCF_TabStop
:
1676 case XCF_TabForward
: case XCF_TabBackward
:
1677 case XCF_Superscript
: case XCF_Subscript
:
1678 case XCF_Normalscript
: case XCF_Underline
:
1679 case XCF_Overline
: case XCF_Font
:
1680 case XCF_Boldfont
: case XCF_Italicfont
:
1681 case XCF_Normalfont
: case XCF_ISO_Encoding
:
1682 case XCF_Special
: case XCF_Text_Split
:
1683 case XCF_Text_Up
: case XCF_Text_Down
:
1685 r
= (eventmode
== TEXT_MODE
|| eventmode
== ETEXT_MODE
) ?
1690 r
= (eventmode
== TEXT_MODE
|| eventmode
== ETEXT_MODE
||
1691 eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1692 eventmode
== NORMAL_MODE
) ?
1696 case XCF_Edit_Delete
: case XCF_Edit_Insert
: case XCF_Edit_Append
:
1697 case XCF_Edit_Param
:
1698 r
= (eventmode
== EPOLY_MODE
|| eventmode
== EPATH_MODE
) ?
1703 r
= (eventmode
== EPOLY_MODE
|| eventmode
== EPATH_MODE
||
1704 eventmode
== EINST_MODE
|| eventmode
== EARC_MODE
||
1705 eventmode
== ESPLINE_MODE
) ?
1710 r
= (eventmode
== EPOLY_MODE
|| eventmode
== EPATH_MODE
||
1711 eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1712 eventmode
== WIRE_MODE
|| eventmode
== NORMAL_MODE
) ?
1716 case XCF_Rotate
: case XCF_Flip_X
:
1718 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1719 eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
) ?
1723 case XCF_Snap
: case XCF_Swap
:
1724 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1725 eventmode
== NORMAL_MODE
) ?
1729 case XCF_Double_Snap
: case XCF_Halve_Snap
:
1731 r
= (eventmode
== CATALOG_MODE
|| eventmode
== CATTEXT_MODE
||
1732 eventmode
== ASSOC_MODE
|| eventmode
== CATMOVE_MODE
) ?
1736 case XCF_Library_Pop
:
1737 r
= (eventmode
== CATALOG_MODE
|| eventmode
== ASSOC_MODE
) ?
1741 case XCF_Library_Edit
: case XCF_Library_Delete
:
1742 case XCF_Library_Duplicate
: case XCF_Library_Hide
:
1743 case XCF_Library_Virtual
: case XCF_Library_Move
:
1744 case XCF_Library_Copy
:
1745 r
= (eventmode
== CATALOG_MODE
) ?
1749 case XCF_Library_Directory
:
1750 r
= (eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
||
1751 eventmode
== ASSOC_MODE
) ?
1755 case XCF_Next_Library
:
1756 r
= (eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
||
1757 eventmode
== ASSOC_MODE
|| eventmode
== CATMOVE_MODE
) ?
1761 case XCF_Select
: case XCF_Exit
:
1762 r
= (eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
) ?
1767 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1768 eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
||
1769 eventmode
== ASSOC_MODE
) ?
1774 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1775 eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
) ?
1779 case XCF_SelectBox
: case XCF_Wire
:
1780 case XCF_Delete
: case XCF_Rescale
:
1781 case XCF_Pin_Label
: case XCF_Pin_Global
:
1782 case XCF_Info_Label
: case XCF_Connectivity
:
1783 case XCF_Box
: case XCF_Arc
:
1784 case XCF_Text
: case XCF_Exchange
:
1785 case XCF_Copy
: case XCF_Virtual
:
1786 case XCF_Page_Directory
: case XCF_Join
:
1787 case XCF_Unjoin
: case XCF_Spline
:
1788 case XCF_Edit
: case XCF_Undo
:
1789 case XCF_Redo
: case XCF_Select_Save
:
1790 case XCF_Unselect
: case XCF_Dashed
:
1791 case XCF_Dotted
: case XCF_Solid
:
1792 case XCF_Dot
: case XCF_Write
:
1793 case XCF_Netlist
: case XCF_Sim
:
1794 case XCF_SPICE
: case XCF_SPICEflat
:
1795 case XCF_PCB
: case XCF_Move
:
1796 r
= (eventmode
== NORMAL_MODE
) ?
1800 case XCF_Nothing
: case XCF_View
:
1801 case XCF_Redraw
: case XCF_Zoom_In
:
1802 case XCF_Zoom_Out
: case XCF_Pan
:
1803 case XCF_Page
: case XCF_Help
:
1804 case XCF_Cancel
: case XCF_Prompt
:
1808 case XCF_Continue_Copy
:
1809 case XCF_Finish_Copy
:
1810 r
= (eventmode
== COPY_MODE
) ?
1814 case XCF_Continue_Element
:
1815 case XCF_Finish_Element
:
1816 r
= (eventmode
== WIRE_MODE
|| eventmode
== BOX_MODE
||
1817 eventmode
== ARC_MODE
|| eventmode
== SPLINE_MODE
||
1818 eventmode
== EPATH_MODE
|| eventmode
== EPOLY_MODE
||
1819 eventmode
== EARC_MODE
|| eventmode
== ESPLINE_MODE
||
1820 eventmode
== MOVE_MODE
|| eventmode
== CATMOVE_MODE
||
1821 eventmode
== EINST_MODE
|| eventmode
== RESCALE_MODE
) ?
1825 case XCF_Cancel_Last
:
1826 r
= (eventmode
== WIRE_MODE
|| eventmode
== ARC_MODE
||
1827 eventmode
== SPLINE_MODE
|| eventmode
== EPATH_MODE
||
1828 eventmode
== EPOLY_MODE
|| eventmode
== EARC_MODE
||
1829 eventmode
== EINST_MODE
|| eventmode
== ESPLINE_MODE
) ?
1834 r
= (eventmode
== FONTCAT_MODE
|| eventmode
== EFONTCAT_MODE
||
1835 eventmode
== ASSOC_MODE
|| eventmode
== CATALOG_MODE
||
1836 eventmode
== CATTEXT_MODE
|| eventmode
== MOVE_MODE
||
1837 eventmode
== RESCALE_MODE
|| eventmode
== SELAREA_MODE
||
1838 eventmode
== PAN_MODE
|| eventmode
== NORMAL_MODE
||
1839 eventmode
== CATMOVE_MODE
) ?
1843 default: /* Function type was not handled. */
1844 funcname
= func_to_string(function
);
1845 if (funcname
== NULL
)
1846 Wprintf("Error: \"%s\" is not a known function!");
1848 Wprintf("Error: Function type \"%s\" (%d) not handled by "
1849 "compatible_function()", func_to_string(function
),
1856 /*----------------------------------------------------------------------*/
1857 /* Main event dispatch routine. Call one of the known routines based */
1858 /* on the key binding. Some handling is done by secondary dispatch */
1859 /* routines in other files; when this is done, the key binding is */
1860 /* determined here and the bound operation type passed to the secondary */
1861 /* dispatch routine. */
1863 /* Return value: 0 if event was handled, -1 if not. */
1864 /*----------------------------------------------------------------------*/
1866 int eventdispatch(int keywstate
, int x
, int y
)
1868 short value
; /* For return values from boundfunction() */
1869 int function
; /* What function should be invoked */
1870 int handled
= -1; /* event was handled */
1872 /* Invalid key state returned from getkeysignature(); usually this */
1873 /* means a modifier key pressed by itself. */
1875 if (keywstate
== -1) return -1;
1876 function
= boundfunction(areawin
->area
, keywstate
, &value
);
1878 /* Check for ASCII or ISO-Latin1-9 characters in keywstate while in */
1879 /* a text-entry state. Only the function XCF_Special is allowed in */
1880 /* text-entry mode, because XCF_Special can be used to enter the */
1881 /* character bound to the XCF_Special function. */
1883 if (keywstate
>= 32 && keywstate
< 256) {
1884 if (eventmode
== CATTEXT_MODE
|| eventmode
== TEXT_MODE
||
1885 eventmode
== ETEXT_MODE
) {
1886 if (function
!= XCF_Special
)
1887 handled
= labeltext(keywstate
, NULL
);
1888 else if (eventmode
!= CATTEXT_MODE
) {
1889 labelptr elabel
= TOLABEL(EDITPART
);
1890 if (elabel
->anchor
& LATEXLABEL
)
1891 handled
= labeltext(keywstate
, NULL
);
1896 if (handled
== -1) {
1898 handled
= functiondispatch(function
, value
, x
, y
);
1900 char *keystring
= key_to_string(keywstate
);
1902 if (python_key_command(keywstate
) < 0)
1904 Wprintf("Key \'%s\' is not bound to a macro", keystring
);
1909 if (areawin
->redraw_needed
)
1910 drawarea(NULL
, NULL
, NULL
);
1915 /*----------------------------------------------------------------------*/
1916 /* Dispatch actions by function number. Note that the structure of */
1917 /* this function is closely tied to the routine compatible_function(). */
1918 /*----------------------------------------------------------------------*/
1920 int functiondispatch(int function
, short value
, int x
, int y
)
1924 switch (eventmode
) {
1927 snap(x
, y
, &areawin
->save
);
1930 window_to_user(x
, y
, &areawin
->save
);
1938 if (value
< 0 || value
> xobjs
.pages
)
1939 Wprintf("Page %d out of range.", (int)value
);
1946 case XCF_Superscript
:
1947 labeltext(SUPERSCRIPT
, (char *)1);
1950 labeltext(SUBSCRIPT
, (char *)1);
1952 case XCF_Normalscript
:
1953 labeltext(NORMALSCRIPT
, (char *)1);
1956 setfont(NULL
, 1000, NULL
);
1959 fontstyle(NULL
, 1, NULL
);
1961 case XCF_Italicfont
:
1962 fontstyle(NULL
, 2, NULL
);
1964 case XCF_Normalfont
:
1965 fontstyle(NULL
, 0, NULL
);
1968 labeltext(UNDERLINE
, (char *)1);
1971 labeltext(OVERLINE
, (char *)1);
1973 case XCF_ISO_Encoding
:
1974 fontencoding(NULL
, 2, NULL
);
1977 labeltext(HALFSPACE
, (char *)1);
1979 case XCF_Quarterspace
:
1980 labeltext(QTRSPACE
, (char *)1);
1983 result
= dospecial();
1991 labeltext(TABSTOP
, (char *)1);
1993 case XCF_TabForward
:
1994 labeltext(TABFORWARD
, (char *)1);
1996 case XCF_TabBackward
:
1997 labeltext(TABBACKWARD
, (char *)1);
1999 case XCF_Text_Return
:
2000 labeltext(TEXT_RETURN
, (char *)1);
2002 case XCF_Text_Delete
:
2003 labeltext(TEXT_DELETE
, (char *)1);
2005 case XCF_Text_Delete_Param
:
2006 labeltext(TEXT_DEL_PARAM
, (char *)1);
2008 case XCF_Text_Right
:
2009 labeltext(TEXT_RIGHT
, (char *)1);
2012 labeltext(TEXT_LEFT
, (char *)1);
2015 labeltext(TEXT_UP
, (char *)1);
2018 labeltext(TEXT_DOWN
, (char *)1);
2020 case XCF_Text_Split
:
2021 labeltext(TEXT_SPLIT
, (char *)1);
2024 labeltext(TEXT_HOME
, (char *)1);
2027 labeltext(TEXT_END
, (char *)1);
2030 labeltext(RETURN
, (char *)1);
2032 case XCF_Edit_Param
:
2033 case XCF_Edit_Delete
:
2034 case XCF_Edit_Insert
:
2035 case XCF_Edit_Append
:
2036 poly_edit_op(function
);
2039 path_op(*(EDITPART
), XCF_Continue_Element
, x
, y
);
2044 case XCF_Next_Library
:
2047 case XCF_Library_Directory
:
2048 startcatalog(NULL
, LIBLIB
, NULL
);
2050 case XCF_Library_Edit
:
2051 window_to_user(x
, y
, &areawin
->save
);
2053 select_element(LABEL
);
2054 if (areawin
->selects
== 1)
2057 case XCF_Library_Delete
:
2058 catalog_op(XCF_Select
, x
, y
);
2061 case XCF_Library_Duplicate
:
2062 catalog_op(XCF_Select
, x
, y
);
2065 case XCF_Library_Hide
:
2066 catalog_op(XCF_Select
, x
, y
);
2069 case XCF_Library_Virtual
:
2070 catalog_op(XCF_Select
, x
, y
);
2073 case XCF_Page_Directory
:
2074 startcatalog(NULL
, PAGELIB
, NULL
);
2076 case XCF_Library_Copy
:
2077 case XCF_Library_Pop
:
2078 catalog_op(function
, x
, y
);
2084 starthelp(NULL
, NULL
, NULL
);
2087 areawin
->redraw_needed
= True
;
2090 zoomview(NULL
, NULL
, NULL
);
2093 zoominrefresh(x
, y
);
2096 zoomoutrefresh(x
, y
);
2099 panrefresh(value
, x
, y
, 0.3);
2101 case XCF_Double_Snap
:
2104 case XCF_Halve_Snap
:
2109 Tcl_Eval(xcinterp
, "xcircuit::promptsavepage");
2111 outputpopup(NULL
, NULL
, NULL
);
2115 elementrotate(value
, &areawin
->save
);
2118 elementflip(&areawin
->save
);
2121 elementvflip(&areawin
->save
);
2127 if (areawin
->snapto
) {
2128 areawin
->snapto
= False
;
2129 Wprintf("Snap-to off");
2132 areawin
->snapto
= True
;
2133 Wprintf("Snap-to on");
2137 if (eventmode
== CATALOG_MODE
|| eventmode
== ASSOC_MODE
) {
2138 eventmode
= NORMAL_MODE
;
2142 popobject(NULL
, 0, NULL
);
2145 if (eventmode
== CATALOG_MODE
) {
2146 /* Don't allow push from library directory */
2147 if ((areawin
->topinstance
!= xobjs
.libtop
[LIBLIB
])
2148 && (areawin
->topinstance
!= xobjs
.libtop
[PAGELIB
])) {
2149 window_to_user(x
, y
, &areawin
->save
);
2150 eventmode
= NORMAL_MODE
;
2161 if (eventmode
== CATALOG_MODE
)
2162 catalog_op(function
, x
, y
);
2164 select_add_element(ALL_TYPES
);
2173 eventmode
= TEXT_MODE
;
2174 textbutton(NORMAL
, x
, y
);
2179 case XCF_Library_Move
:
2180 /* Don't allow from library directory. Then fall through to XCF_Move */
2181 if (areawin
->topinstance
== xobjs
.libtop
[LIBLIB
]) break;
2183 if (areawin
->selects
== 0) {
2184 was_preselected
= FALSE
;
2185 if (eventmode
== CATALOG_MODE
)
2186 catalog_op(XCF_Select
, x
, y
);
2188 select_element(ALL_TYPES
);
2190 else was_preselected
= TRUE
;
2192 if (areawin
->selects
> 0) {
2193 eventmode
= (eventmode
== CATALOG_MODE
) ? CATMOVE_MODE
: MOVE_MODE
;
2194 u2u_snap(&areawin
->save
);
2195 areawin
->origin
= areawin
->save
;
2197 select_connected_pins();
2198 XDefineCursor(dpy
, areawin
->window
, ARROW
);
2199 move_mode_draw(xcDRAW_INIT
, NULL
);
2201 Tk_CreateEventHandler(areawin
->area
, ButtonMotionMask
|
2202 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
,
2225 case XCF_Select_Save
:
2227 Tcl_Eval(xcinterp
, "xcircuit::promptmakeobject");
2229 selectsave(NULL
, NULL
, NULL
);
2233 select_add_element(-ALL_TYPES
);
2236 setelementstyle(NULL
, DASHED
, NOBORDER
| DOTTED
| DASHED
);
2239 setelementstyle(NULL
, DOTTED
, NOBORDER
| DOTTED
| DASHED
);
2242 setelementstyle(NULL
, NORMAL
, NOBORDER
| DOTTED
| DASHED
);
2248 snap(x
, y
, &areawin
->save
);
2249 drawdot(areawin
->save
.x
, areawin
->save
.y
);
2250 areawin
->redraw_needed
= True
;
2251 drawarea(NULL
, NULL
, NULL
);
2254 u2u_snap(&areawin
->save
);
2255 startwire(&areawin
->save
);
2256 eventmode
= WIRE_MODE
;
2259 DoNothing(NULL
, NULL
, NULL
);
2262 quitcheck(areawin
->area
, NULL
, NULL
);
2265 callwritenet(NULL
, 0, NULL
);
2268 swapschem(0, -1, NULL
);
2271 eventmode
= TEXT_MODE
;
2272 textbutton(LOCAL
, x
, y
);
2274 case XCF_Pin_Global
:
2275 eventmode
= TEXT_MODE
;
2276 textbutton(GLOBAL
, x
, y
);
2278 case XCF_Info_Label
:
2279 eventmode
= TEXT_MODE
;
2280 textbutton(INFO
, x
, y
);
2283 if (checkselect(LABEL
| OBJINST
| GRAPHIC
) == TRUE
) {
2284 eventmode
= RESCALE_MODE
;
2285 rescale_mode_draw(xcDRAW_INIT
, NULL
);
2287 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
2288 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
2290 xcAddEventHandler(areawin
->area
, PointerMotionMask
|
2291 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
2299 case XCF_Connectivity
:
2300 connectivity(NULL
, NULL
, NULL
);
2303 case XCF_Continue_Copy
:
2304 case XCF_Finish_Copy
:
2305 copy_op(function
, x
, y
);
2307 case XCF_Continue_Element
:
2308 if (eventmode
== CATMOVE_MODE
|| eventmode
== MOVE_MODE
||
2309 eventmode
== RESCALE_MODE
)
2310 finish_op(XCF_Finish
, x
, y
);
2312 continue_op(function
, x
, y
);
2314 case XCF_Finish_Element
:
2315 case XCF_Cancel_Last
:
2317 finish_op(function
, x
, y
);
2320 if (eventmode
== CATALOG_MODE
|| eventmode
== ASSOC_MODE
)
2321 catalog_op(XCF_Library_Pop
, x
, y
);
2323 finish_op(function
, x
, y
);
2326 writenet(topobject
, "flatsim", "sim");
2329 writenet(topobject
, "spice", "spc");
2332 writenet(topobject
, "pcb", "pcbnet");
2335 writenet(topobject
, "flatspice", "fspc");
2338 Wprintf("Action not handled");
2341 case XCF_ChangeStyle
:
2342 Wprintf("Action not handled");
2347 /* Ensure that we do not get stuck in suspend mode */
2348 /* by removing the suspend state whenever a key is */
2351 if (xobjs
.suspend
== 1) {
2353 refresh(NULL
, NULL
, NULL
);
2355 else if (xobjs
.suspend
!= 2)
2361 /*------------------------------------------------------*/
2362 /* Get a canonical signature for a button/key event */
2363 /*------------------------------------------------------*/
2365 int getkeysignature(XKeyEvent
*event
)
2368 int keywstate
; /* KeySym with prepended state information */
2371 if (event
->keycode
== 0 && event
->state
== 0)
2374 XLookupString(event
, _STR
, 150, &keypressed
, NULL
);
2376 /* Ignore Shift, Control, Caps Lock, and Meta (Alt) keys */
2377 /* when pressed alone. */
2379 if (keypressed
== XK_Control_L
|| keypressed
== XK_Control_R
||
2380 keypressed
== XK_Alt_L
|| keypressed
== XK_Alt_R
||
2381 keypressed
== XK_Caps_Lock
|| keypressed
== XK_Shift_L
||
2382 keypressed
== XK_Shift_R
)
2385 /* Only keep key state information pertaining to Shift, Caps Lock, */
2386 /* Control, and Alt (Meta) */
2388 keywstate
= (keypressed
& 0xffff);
2390 /* Convert codes outside the character (0 - 255) range but within */
2391 /* the ISO-Latin1,...,9 encoding scheme (256-5120). X11 has unique */
2392 /* keysyms for each character, but the ISO-Latin encodings define */
2393 /* mappings to the 8-bit (256) character set. */
2395 if (keywstate
>= 256 && keywstate
< 5120)
2396 keywstate
= XKeysymToKeycode(dpy
, (KeySym
)keywstate
);
2398 /* ASCII values already come upper/lowercase; we only want to register */
2399 /* a Shift key if it's a non-ASCII key or another modifier is in effect */
2401 keywstate
|= (((LockMask
| ControlMask
| Mod1Mask
) & event
->state
) << 16);
2402 if (keywstate
> 255) keywstate
|= ((ShiftMask
& event
->state
) << 16);
2404 /* Treat button events and key events in the same way by setting */
2405 /* a key state for buttons */
2407 if (keypressed
== 0)
2408 keywstate
|= (((Button1Mask
| Button2Mask
| Button3Mask
| Button4Mask
|
2409 Button5Mask
| ShiftMask
)
2410 & event
->state
) << 16);
2415 /*------------------------*/
2416 /* Handle keyboard inputs */
2417 /*------------------------*/
2419 void keyhandler(xcWidget w
, caddr_t clientdata
, XKeyEvent
*event
)
2421 int keywstate
; /* KeySym with prepended state information */
2423 UNUSED(w
); UNUSED(clientdata
);
2426 if (popups
> 0) return;
2428 if (popups
> 0 && help_up
== 0) return;
2431 if ((event
->type
== KeyRelease
) || (event
->type
== ButtonRelease
)) {
2433 /* Register a "tap" event if a key or button was released */
2434 /* while a timeout event is pending. */
2436 if (areawin
->time_id
!= 0) {
2437 xcRemoveTimeOut(areawin
->time_id
);
2438 areawin
->time_id
= 0;
2439 keywstate
= getkeysignature(event
);
2440 eventdispatch(keywstate
, areawin
->save
.x
, areawin
->save
.y
);
2443 keywstate
= getkeysignature(event
);
2444 if ((pressmode
!= 0) && (keywstate
== pressmode
)) {
2445 /* Events that require hold & drag (namely, MOVE_MODE) */
2446 /* must be resolved here. Call finish_op() to ensure */
2447 /* that we restore xcircuit to a state of sanity. */
2449 finish_op(XCF_Finish
, event
->x
, event
->y
);
2451 if (areawin
->redraw_needed
)
2452 drawarea(NULL
, NULL
, NULL
);
2454 return; /* Ignore all other release events */
2458 /* Check if any bindings match key/button "hold". If so, then start */
2459 /* the timer and wait for key release or timeout. */
2462 keywstate
= getkeysignature(event
);
2463 if ((keywstate
!= -1) && (xobjs
.hold
== TRUE
)) {
2465 /* Establish whether a HOLD modifier binding would apply in */
2466 /* the current eventmode. If so, set the HOLD timer. */
2468 func
= boundfunction(areawin
->area
, keywstate
| HOLD_MASK
, NULL
);
2470 areawin
->save
.x
= event
->x
;
2471 areawin
->save
.y
= event
->y
;
2472 areawin
->time_id
= xcAddTimeOut(app
, PRESSTIME
,
2473 makepress
, (ClientData
)((pointertype
)keywstate
));
2478 eventdispatch(keywstate
, event
->x
, event
->y
);
2482 /*--------------------------------*/
2483 /* Set snap spacing from keyboard */
2484 /*--------------------------------*/
2486 void setsnap(short direction
)
2488 float oldsnap
= xobjs
.pagelist
[areawin
->page
]->snapspace
;
2491 if (direction
> 0) xobjs
.pagelist
[areawin
->page
]->snapspace
*= 2;
2494 xobjs
.pagelist
[areawin
->page
]->snapspace
/= 2;
2496 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2497 Wprintf("Snap space at minimum value of %s", buffer
);
2500 if (xobjs
.pagelist
[areawin
->page
]->snapspace
!= oldsnap
) {
2501 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2502 Wprintf("Snap spacing set to %s", buffer
);
2503 areawin
->redraw_needed
= True
;
2504 drawarea(NULL
, NULL
, NULL
);
2508 /*-----------------------------------------*/
2509 /* Reposition an object onto the snap grid */
2510 /*-----------------------------------------*/
2515 Boolean preselected
;
2517 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
2518 if (!checkselect(ALL_TYPES
)) return;
2519 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
2520 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
2521 + areawin
->selects
; selectobj
++) {
2522 easydraw(*selectobj
, DOFORALL
);
2523 switch(SELECTTYPE(selectobj
)) {
2525 objinstptr snapobj
= SELTOOBJINST(selectobj
);
2527 u2u_snap(&snapobj
->position
);
2530 graphicptr snapg
= SELTOGRAPHIC(selectobj
);
2532 u2u_snap(&snapg
->position
);
2535 labelptr snaplabel
= SELTOLABEL(selectobj
);
2537 u2u_snap(&snaplabel
->position
);
2540 polyptr snappoly
= SELTOPOLY(selectobj
);
2541 pointlist snappoint
;
2543 for (snappoint
= snappoly
->points
; snappoint
< snappoly
->points
+
2544 snappoly
->number
; snappoint
++)
2545 u2u_snap(snappoint
);
2548 arcptr snaparc
= SELTOARC(selectobj
);
2550 u2u_snap(&snaparc
->position
);
2551 if (areawin
->snapto
) {
2552 snaparc
->radius
= (snaparc
->radius
/
2553 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2554 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2555 snaparc
->yaxis
= (snaparc
->yaxis
/
2556 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2557 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2562 splineptr snapspline
= SELTOSPLINE(selectobj
);
2565 for (i
= 0; i
< 4; i
++)
2566 u2u_snap(&snapspline
->ctrl
[i
]);
2567 calcspline(snapspline
);
2570 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
2571 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
2572 easydraw(*selectobj
, DOFORALL
);
2575 select_invalidate_netlist();
2576 if (eventmode
== NORMAL_MODE
)
2581 /*----------------------------------------------*/
2582 /* Routines to print the cursor position */
2583 /*----------------------------------------------*/
2585 /*----------------------------------------------*/
2586 /* fast integer power-of-10 routine */
2587 /*----------------------------------------------*/
2595 case 0: return 1; break;
2596 case 1: return 10; break;
2597 case 2: return 100; break;
2598 case 3: return 1000; break;
2601 for (i
= 1; i
< a
+ 1; i
++) istr
[i
] = '0';
2608 /*--------------------------------------------------*/
2609 /* find greatest common factor between two integers */
2610 /*--------------------------------------------------*/
2612 int calcgcf(int a
, int b
)
2616 if ((mod
= a
% b
) == 0) return (b
);
2617 else return (calcgcf(b
, mod
));
2620 /*--------------------------------------------------------------*/
2621 /* generate a fraction from a float, if possible */
2622 /* fraction returned as a string (must be allocated beforehand) */
2623 /*--------------------------------------------------------------*/
2625 void fraccalc(float xyval
, char *fstr
)
2628 int ip
, mant
, divisor
, denom
, numer
, rpart
;
2630 char num
[10], *nptr
= &num
[2], *sptr
;
2633 fp
= fabs(xyval
- ip
);
2635 /* write fractional part and grab mantissa as integer */
2637 sprintf(num
, "%1.7f", fp
);
2638 num
[8] = '\0'; /* no rounding up! */
2639 sscanf(nptr
, "%d", &mant
);
2641 if (mant
!= 0) { /* search for repeating substrings */
2642 for (i
= 1; i
<= 3; i
++) {
2645 while ((sptr
= nptr
- rept
* i
) >= &num
[2]) {
2646 for (t
= 0; t
< i
; t
++)
2647 if (*(sptr
+ t
) != *(nptr
+ t
)) break;
2651 if (rept
> 1) break;
2654 sscanf(nptr
, "%d", &rpart
); /* rpart is repeating part of mantissa */
2655 if (i
> 3 || rpart
== 0) { /* no repeat */
2656 divisor
= calcgcf(1000000, mant
);
2657 denom
= 1000000 / divisor
;
2663 sscanf(&num
[2], "%d", &z
);
2665 mant
= z
* p
+ rpart
;
2666 fd
= ipow10(nptr
- &num
[2]) * p
;
2668 divisor
= calcgcf(fd
, mant
);
2669 denom
= fd
/ divisor
;
2671 numer
= mant
/ divisor
;
2673 sprintf(fstr
, "%5.3f", xyval
);
2675 sprintf(fstr
, "%hd/%hd", (xyval
> 0) ? numer
: -numer
, denom
);
2677 sprintf(fstr
, "%hd %hd/%hd", ip
, numer
, denom
);
2679 else sprintf(fstr
, "%hd", ip
);
2682 /*------------------------------------------------------------------------------*/
2683 /* Print the position of the cursor in the upper right-hand message window */
2684 /*------------------------------------------------------------------------------*/
2686 void printpos(short xval
, short yval
)
2689 float oscale
, iscale
= (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
/
2690 (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
;
2693 XPoint
*tpoint
, *npoint
;
2697 /* For polygons, print the length (last line of a wire or polygon) or */
2698 /* length and width (box only) */
2700 if (eventmode
== BOX_MODE
|| eventmode
== EPOLY_MODE
|| eventmode
== WIRE_MODE
) {
2701 polyptr lwire
= (eventmode
== BOX_MODE
) ? TOPOLY(ENDPART
) : TOPOLY(EDITPART
);
2702 if ((eventmode
== EPOLY_MODE
) && (lwire
->number
> 2)) {
2703 /* sanity check on edit cycle */
2704 cycle
= (lwire
->cycle
) ? lwire
->cycle
->number
: -1;
2705 if (cycle
< 0 || cycle
>= lwire
->number
) {
2706 advancecycle((genericptr
*)(&lwire
), 0);
2709 tpoint
= lwire
->points
+ cycle
;
2710 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, 1);
2711 llen
= wirelength(tpoint
, npoint
);
2712 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, -1);
2713 lwid
= wirelength(tpoint
, npoint
);
2715 if (lwire
->style
& UNCLOSED
) { /* unclosed polys */
2718 else if (cycle
== lwire
->number
- 1) {
2723 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2729 else if (eventmode
== BOX_MODE
) {
2730 tpoint
= lwire
->points
;
2731 npoint
= lwire
->points
+ 1;
2732 llen
= wirelength(tpoint
, npoint
);
2733 npoint
= lwire
->points
+ 3;
2734 lwid
= wirelength(tpoint
, npoint
);
2735 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2743 tpoint
= lwire
->points
+ lwire
->number
- 1;
2744 llen
= wirelength(tpoint
- 1, tpoint
);
2748 else if (eventmode
== ARC_MODE
|| eventmode
== EARC_MODE
) {
2749 arcptr larc
= (eventmode
== ARC_MODE
) ? TOARC(ENDPART
) : TOARC(EDITPART
);
2750 llen
= larc
->radius
;
2751 if (abs(larc
->radius
) != larc
->yaxis
) {
2759 switch (xobjs
.pagelist
[areawin
->page
]->coordstyle
) {
2761 sprintf(_STR
, "%g, %g", xval
* iscale
, yval
* iscale
);
2762 sptr
= _STR
+ strlen(_STR
);
2765 sprintf(sptr
, " (%g x %g)", llen
* iscale
, lwid
* iscale
);
2767 sprintf(sptr
, " (length %g)", llen
* iscale
);
2771 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2772 f1
= ((float)(xval
) * iscale
* oscale
) / 72.0;
2773 f2
= ((float)(yval
) * iscale
* oscale
) / 72.0;
2774 sprintf(_STR
, "%5.3f, %5.3f in", f1
, f2
);
2775 sptr
= _STR
+ strlen(_STR
);
2777 f1
= ((float)(llen
) * iscale
* oscale
) / 72.0;
2779 f2
= ((float)(lwid
) * iscale
* oscale
) / 72.0;
2780 sprintf(sptr
, " (%5.3f x %5.3f in)", f1
, f2
);
2783 sprintf(sptr
, " (length %5.3f in)", f1
);
2787 char fstr1
[30], fstr2
[30];
2789 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2790 fraccalc((((float)(xval
) * iscale
* oscale
) / 72.0), fstr1
);
2791 fraccalc((((float)(yval
) * iscale
* oscale
) / 72.0), fstr2
);
2792 sprintf(_STR
, "%s, %s in", fstr1
, fstr2
);
2793 sptr
= _STR
+ strlen(_STR
);
2795 fraccalc((((float)(llen
) * iscale
* oscale
) / 72.0), fstr1
);
2797 fraccalc((((float)(lwid
) * iscale
* oscale
) / 72.0), fstr2
);
2798 sprintf(sptr
, " (%s x %s in)", fstr1
, fstr2
);
2801 sprintf(sptr
, " (length %s in)", fstr1
);
2805 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* CMSCALE
;
2806 f1
= ((float)(xval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2807 f2
= ((float)(yval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2808 sprintf(_STR
, "%5.3f, %5.3f cm", f1
, f2
);
2809 sptr
= _STR
+ strlen(_STR
);
2811 f1
= ((float)(llen
) * iscale
* oscale
) / IN_CM_CONVERT
;
2813 f2
= ((float)(lwid
) * iscale
* oscale
) / IN_CM_CONVERT
;
2814 sprintf(sptr
, " (%5.3f x %5.3f cm)", f1
, f2
);
2817 sprintf(sptr
, " (length %5.3f cm)", f1
);
2824 /*---------------------------------------------------*/
2825 /* Find nearest point of intersection of the cursor */
2826 /* position to a wire and move there. */
2827 /*---------------------------------------------------*/
2829 void findwirex(XPoint
*endpt1
, XPoint
*endpt2
, XPoint
*userpt
,
2830 XPoint
*newpos
, float *rot
)
2835 xsq
= sqwirelen(endpt1
, endpt2
);
2836 ysq
= sqwirelen(endpt1
, userpt
);
2837 zsq
= sqwirelen(endpt2
, userpt
);
2838 frac
= 0.5 + (float)(ysq
- zsq
) / (float)(xsq
<< 1);
2839 if (frac
> 1) frac
= 1;
2840 else if (frac
< 0) frac
= 0;
2841 newpos
->x
= endpt1
->x
+ (int)((endpt2
->x
- endpt1
->x
) * frac
);
2842 newpos
->y
= endpt1
->y
+ (int)((endpt2
->y
- endpt1
->y
) * frac
);
2844 *rot
= 180.0 + INVRFAC
* atan2((double)(endpt1
->x
-
2845 endpt2
->x
), (double)(endpt1
->y
- endpt2
->y
));
2848 /*----------------------------------------------------------------*/
2849 /* Find the closest point of attachment from the pointer position */
2850 /* to the "attachto" element. */
2851 /*----------------------------------------------------------------*/
2853 void findattach(XPoint
*newpos
, float *rot
, XPoint
*userpt
)
2855 XPoint
*endpt1
, *endpt2
;
2860 if (rot
) locrot
= *rot
;
2862 /* find point of intersection and slope */
2864 if (SELECTTYPE(&areawin
->attachto
) == ARC
) {
2865 arcptr aarc
= SELTOARC(&areawin
->attachto
);
2867 tmpang
= atan2((double)(userpt
->y
- aarc
->position
.y
) * (double)
2868 (abs(aarc
->radius
)), (double)(userpt
->x
- aarc
->position
.x
) *
2869 (double)aarc
->yaxis
);
2871 /* don't follow the arc beyond its endpoints */
2873 tmpdeg
= (float)(tmpang
* INVRFAC
);
2874 if (tmpdeg
< 0) tmpdeg
+= 360;
2875 if (((aarc
->angle2
> 360) && (tmpdeg
> aarc
->angle2
- 360) &&
2876 (tmpdeg
< aarc
->angle1
)) ||
2877 ((aarc
->angle1
< 0) && (tmpdeg
> aarc
->angle2
) &&
2878 (tmpdeg
< aarc
->angle1
+ 360)) ||
2879 ((aarc
->angle1
>= 0) && (aarc
->angle2
<= 360) && ((tmpdeg
2880 > aarc
->angle2
) || (tmpdeg
< aarc
->angle1
)))) {
2881 float testd1
= aarc
->angle1
- tmpdeg
;
2882 float testd2
= tmpdeg
- aarc
->angle2
;
2883 if (testd1
< 0) testd1
+= 360;
2884 if (testd2
< 0) testd2
+= 360;
2886 /* if arc is closed, attach to the line between the endpoints */
2888 if (!(aarc
->style
& UNCLOSED
)) {
2890 tmpang
= (double) aarc
->angle1
/ INVRFAC
;
2891 end1
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2892 end1
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2893 tmpang
= (double) aarc
->angle2
/ INVRFAC
;
2894 end2
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2895 end2
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2896 findwirex(&end1
, &end2
, userpt
, newpos
, &locrot
);
2897 if (rot
) *rot
= locrot
;
2901 tmpang
= (double)((testd1
< testd2
) ? aarc
->angle1
: aarc
->angle2
)
2905 /* get position in user coordinates nearest to the intersect pt */
2907 newpos
->x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2908 newpos
->y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2910 /* rotation of object is normal to the curve of the ellipse */
2913 *rot
= 90.0 - INVRFAC
* tmpang
;
2914 if (*rot
< 0.0) *rot
+= 360.0;
2917 else if (SELECTTYPE(&areawin
->attachto
) == SPLINE
) {
2918 splineptr aspline
= SELTOSPLINE(&areawin
->attachto
);
2919 frac
= findsplinemin(aspline
, userpt
);
2920 findsplinepos(aspline
, frac
, newpos
, &locrot
);
2921 if (rot
) *rot
= locrot
;
2923 else if (SELECTTYPE(&areawin
->attachto
) == OBJINST
) {
2925 objinstptr ainst
= SELTOOBJINST(&areawin
->attachto
);
2926 objectptr aobj
= ainst
->thisobject
;
2928 long testdist
, mindist
= 1e8
;
2931 /* In case instance has no pin labels, we will attach to */
2932 /* the instance's own origin. */
2934 mdpoint
.x
= mdpoint
.y
= 0;
2935 ReferencePosition(ainst
, &mdpoint
, newpos
);
2937 /* Find the nearest pin label in the object instance and attach to it */
2938 for (ggen
= aobj
->plist
; ggen
< aobj
->plist
+ aobj
->parts
; ggen
++) {
2939 if (ELEMENTTYPE(*ggen
) == LABEL
) {
2940 labelptr alab
= TOLABEL(ggen
);
2941 if (alab
->pin
== LOCAL
|| alab
->pin
== GLOBAL
) {
2942 ReferencePosition(ainst
, &alab
->position
, &mdpoint
);
2943 testdist
= sqwirelen(&mdpoint
, userpt
);
2944 if (testdist
< mindist
) {
2952 else if (SELECTTYPE(&areawin
->attachto
) == LABEL
) {
2953 /* Only one choice: Attach to the label position */
2954 labelptr alabel
= SELTOLABEL(&areawin
->attachto
);
2955 newpos
->x
= alabel
->position
.x
;
2956 newpos
->y
= alabel
->position
.y
;
2958 else if (SELECTTYPE(&areawin
->attachto
) == POLYGON
) {
2959 polyptr apoly
= SELTOPOLY(&areawin
->attachto
);
2960 XPoint
*testpt
, *minpt
, *nxtpt
;
2961 long mindist
= 1e8
, testdist
;
2962 minpt
= nxtpt
= apoly
->points
; /* so variables aren't uninitialized */
2963 for (testpt
= apoly
->points
; testpt
< apoly
->points
+
2964 apoly
->number
- 1; testpt
++) {
2965 testdist
= finddist(testpt
, testpt
+ 1, userpt
);
2966 if (testdist
< mindist
) {
2972 if (!(apoly
->style
& UNCLOSED
)) {
2973 testdist
= finddist(testpt
, apoly
->points
, userpt
);
2974 if (testdist
< mindist
) {
2977 nxtpt
= apoly
->points
;
2982 findwirex(endpt1
, endpt2
, userpt
, newpos
, &locrot
);
2983 if (rot
) *rot
= locrot
;
2987 /*--------------------------------------------*/
2988 /* Find closest point in a path to the cursor */
2989 /*--------------------------------------------*/
2991 XPoint
*pathclosepoint(pathptr dragpath
, XPoint
*newpos
)
2996 int mdist
= 1000000, tdist
;
2998 for (cpoint
= dragpath
->plist
; cpoint
< dragpath
->plist
+ dragpath
->parts
;
3000 switch(ELEMENTTYPE(*cpoint
)) {
3002 tdist
= wirelength(&(TOARC(cpoint
)->position
), newpos
);
3003 if (tdist
< mdist
) {
3005 rpoint
= &(TOARC(cpoint
)->position
);
3009 mpoint
= closepoint(TOPOLY(cpoint
), newpos
);
3010 tdist
= wirelength(TOPOLY(cpoint
)->points
+ mpoint
, newpos
);
3011 if (tdist
< mdist
) {
3013 rpoint
= TOPOLY(cpoint
)->points
+ mpoint
;
3017 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[0]), newpos
);
3018 if (tdist
< mdist
) {
3020 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[0]);
3022 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[3]), newpos
);
3023 if (tdist
< mdist
) {
3025 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[3]);
3033 /*-------------------------------------------*/
3034 /* Drag a selected element around the screen */
3035 /*-------------------------------------------*/
3037 void drag(int x
, int y
)
3040 Boolean eventcheck
= False
;
3042 short deltax
, deltay
;
3048 /* flush out multiple pointermotion events from the event queue */
3049 /* use only the last motion event */
3050 while (XCheckWindowEvent(dpy
, areawin
->window
, PointerMotionMask
|
3051 Button1MotionMask
, &again
) == True
) eventcheck
= True
;
3053 XButtonEvent
*event
= (XButtonEvent
*)(&again
);
3054 locx
= (int)event
->x
;
3055 locy
= (int)event
->y
;
3058 /* Determine if this event is supposed to be handled by */
3059 /* trackselarea(), or whether we should not be here at all */
3060 /* (button press and mouse movement in an unsupported mode) */
3062 if (eventmode
== SELAREA_MODE
) {
3066 else if (eventmode
== RESCALE_MODE
) {
3070 else if (eventmode
== PAN_MODE
) {
3071 trackpan(locx
, locy
);
3074 else if (eventmode
!= CATMOVE_MODE
&& eventmode
!= MOVE_MODE
3075 && eventmode
!= COPY_MODE
)
3078 snap(locx
, locy
, &userpt
);
3079 deltax
= userpt
.x
- areawin
->save
.x
;
3080 deltay
= userpt
.y
- areawin
->save
.y
;
3081 if (deltax
== 0 && deltay
== 0) return;
3083 areawin
->save
.x
= userpt
.x
;
3084 areawin
->save
.y
= userpt
.y
;
3086 /* set up the graphics state for moving a selected object */
3088 XTopSetForeground(SELECTCOLOR
);
3090 placeselects(deltax
, deltay
, &userpt
);
3092 /* restore graphics state */
3094 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
3096 /* print the position and other useful measurements */
3098 printpos(userpt
.x
, userpt
.y
);
3101 /*------------------------------------------------------*/
3102 /* Wrapper for drag() for xlib callback compatibility. */
3103 /*------------------------------------------------------*/
3105 void xlib_drag(xcWidget w
, caddr_t clientdata
, XEvent
*event
)
3107 XButtonEvent
*bevent
= (XButtonEvent
*)event
;
3108 UNUSED(w
); UNUSED(clientdata
);
3110 drag(bevent
->x
, bevent
->y
);
3111 if (areawin
->redraw_needed
)
3112 drawarea(NULL
, NULL
, NULL
);
3115 /*----------------------------------------------*/
3116 /* Rotate an element of a path */
3117 /*----------------------------------------------*/
3119 void elemrotate(genericptr
*genobj
, float direction
, XPoint
*position
)
3121 XPoint negpt
, *newpts
= (XPoint
*)NULL
;
3123 negpt
.x
= -position
->x
;
3124 negpt
.y
= -position
->y
;
3126 switch(ELEMENTTYPE(*genobj
)) {
3128 arcptr rotatearc
= TOARC(genobj
);
3129 rotatearc
->angle1
-= direction
;
3130 rotatearc
->angle2
-= direction
;
3131 if (rotatearc
->angle1
>= 360) {
3132 rotatearc
->angle1
-= 360;
3133 rotatearc
->angle2
-= 360;
3135 else if (rotatearc
->angle2
<= 0) {
3136 rotatearc
->angle1
+= 360;
3137 rotatearc
->angle2
+= 360;
3139 newpts
= (XPoint
*)malloc(sizeof(XPoint
));
3140 UTransformPoints(&rotatearc
->position
, newpts
, 1, negpt
, 1.0, 0);
3141 UTransformPoints(newpts
, &rotatearc
->position
, 1, *position
,
3147 splineptr rotatespline
= TOSPLINE(genobj
);
3148 newpts
= (XPoint
*)malloc(4 * sizeof(XPoint
));
3149 UTransformPoints(rotatespline
->ctrl
, newpts
, 4, negpt
, 1.0, 0);
3150 UTransformPoints(newpts
, rotatespline
->ctrl
, 4, *position
,
3152 calcspline(rotatespline
);
3156 polyptr rotatepoly
= TOPOLY(genobj
);
3157 newpts
= (XPoint
*)malloc(rotatepoly
->number
* sizeof(XPoint
));
3158 UTransformPoints(rotatepoly
->points
, newpts
, rotatepoly
->number
,
3160 UTransformPoints(newpts
, rotatepoly
->points
, rotatepoly
->number
,
3161 *position
, 1.0, direction
);
3164 if (newpts
) free(newpts
);
3167 /*------------------------------------------------------*/
3168 /* Rotate an element or group of elements */
3169 /* Objects and labels, if selected singly, rotate */
3170 /* about their position point. All other elements, */
3171 /* and groups, rotate about the cursor point. */
3172 /*------------------------------------------------------*/
3174 void elementrotate(float direction
, XPoint
*position
)
3176 short *selectobj
; /* , ld; (jdk) */
3177 Boolean single
= False
;
3178 Boolean need_refresh
= False
;
3179 Boolean preselected
;
3180 XPoint newpt
, negpt
;
3182 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3183 if (!checkselect(ALL_TYPES
)) return;
3184 if (areawin
->selects
== 1) single
= True
;
3186 negpt
.x
= -position
->x
;
3187 negpt
.y
= -position
->y
;
3189 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3190 + areawin
->selects
; selectobj
++) {
3192 /* erase the element */
3193 if (!need_refresh
) {
3194 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
3195 easydraw(*selectobj
, DOFORALL
);
3198 switch(SELECTTYPE(selectobj
)) {
3201 objinstptr rotateobj
= SELTOOBJINST(selectobj
);
3203 if (is_library(topobject
) >= 0 && !is_virtual(rotateobj
)) break;
3204 rotateobj
->rotation
+= direction
;
3205 while (rotateobj
->rotation
>= 360) rotateobj
->rotation
-= 360;
3206 while (rotateobj
->rotation
<= 0) rotateobj
->rotation
+= 360;
3208 UTransformPoints(&rotateobj
->position
, &newpt
, 1, negpt
, 1.0, 0);
3209 UTransformPoints(&newpt
, &rotateobj
->position
, 1, *position
,
3215 labelptr rotatetext
= SELTOLABEL(selectobj
);
3217 rotatetext
->rotation
+= direction
;
3218 while (rotatetext
->rotation
>= 360) rotatetext
->rotation
-= 360;
3219 while (rotatetext
->rotation
<= 0) rotatetext
->rotation
+= 360;
3221 UTransformPoints(&rotatetext
->position
, &newpt
, 1, negpt
, 1.0, 0);
3222 UTransformPoints(&newpt
, &rotatetext
->position
, 1, *position
,
3228 graphicptr rotateg
= SELTOGRAPHIC(selectobj
);
3230 rotateg
->rotation
+= direction
;
3231 while (rotateg
->rotation
>= 360) rotateg
->rotation
-= 360;
3232 while (rotateg
->rotation
<= 0) rotateg
->rotation
+= 360;
3234 rotateg
->valid
= FALSE
;
3235 #endif /* !HAVE_CAIRO */
3237 UTransformPoints(&rotateg
->position
, &newpt
, 1, negpt
, 1.0, 0);
3238 UTransformPoints(&newpt
, &rotateg
->position
, 1, *position
,
3241 need_refresh
= True
;
3244 case POLYGON
: case ARC
: case SPLINE
:{
3245 genericptr
*genpart
= topobject
->plist
+ *selectobj
;
3246 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3248 elemrotate(genpart
, direction
, position
);
3252 genericptr
*genpart
;
3253 pathptr rotatepath
= SELTOPATH(selectobj
);
3255 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3257 for (genpart
= rotatepath
->plist
; genpart
< rotatepath
->plist
3258 + rotatepath
->parts
; genpart
++)
3259 elemrotate(genpart
, direction
, position
);
3263 /* redisplay the element */
3264 if (preselected
|| ((eventmode
!= NORMAL_MODE
) && !need_refresh
)) {
3265 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
3266 easydraw(*selectobj
, DOFORALL
);
3270 /* This takes care of all selected instances and labels in one go, */
3271 /* because we only need to know the origin and amount of rotation. */
3273 if (eventmode
!= COPY_MODE
)
3274 register_for_undo(XCF_Rotate
, UNDO_MORE
, areawin
->topinstance
,
3275 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
,
3278 /* New rule (6/15/07) to be applied generally: If objects were */
3279 /* selected prior to calling elementrotate() and similar functions, */
3280 /* leave them selected upon exit. Otherwise, deselect them. */
3282 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
3286 if (eventmode
== CATALOG_MODE
) {
3288 if ((libnum
= is_library(topobject
)) >= 0) {
3289 composelib(libnum
+ LIBRARY
);
3290 need_refresh
= TRUE
;
3294 pwriteback(areawin
->topinstance
);
3295 calcbbox(areawin
->topinstance
);
3298 if (need_refresh
) drawarea(NULL
, NULL
, NULL
);
3301 /*----------------------------------------------*/
3302 /* Rescale the current edit element to the */
3303 /* dimensions of the rescale box. */
3304 /*----------------------------------------------*/
3306 void elementrescale(float newscale
)
3314 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3315 + areawin
->selects
; selectobj
++) {
3316 switch (SELECTTYPE(selectobj
)) {
3318 sclab
= SELTOLABEL(selectobj
);
3319 oldsize
= sclab
->scale
;
3320 sclab
->scale
= newscale
;
3323 scinst
= SELTOOBJINST(selectobj
);
3324 oldsize
= scinst
->scale
;
3325 scinst
->scale
= newscale
;
3328 scgraph
= SELTOGRAPHIC(selectobj
);
3329 oldsize
= scgraph
->scale
;
3330 scgraph
->scale
= newscale
;
3333 register_for_undo(XCF_Rescale
, UNDO_MORE
, areawin
->topinstance
,
3334 SELTOGENERIC(selectobj
), (double)oldsize
);
3336 calcbbox(areawin
->topinstance
);
3339 /*-------------------------------------------------*/
3340 /* Edit an element in an element-dependent fashion */
3341 /*-------------------------------------------------*/
3343 void edit(int x
, int y
)
3347 if (areawin
->selects
== 0) {
3348 Boolean saveredraw
= areawin
->redraw_needed
;
3349 selectobj
= select_element(ALL_TYPES
);
3350 areawin
->redraw_needed
= saveredraw
;
3353 selectobj
= areawin
->selectlist
;
3354 if (areawin
->selects
== 0)
3356 else if (areawin
->selects
!= 1) { /* Multiple object edit */
3358 short *selectlist
, selrefno
;
3359 Boolean save_redraw
= areawin
->redraw_needed
;
3361 /* Find the closest part to use as a reference */
3362 selnum
= areawin
->selects
;
3363 selectlist
= areawin
->selectlist
;
3364 areawin
->selects
= 0;
3365 areawin
->selectlist
= NULL
;
3366 selectobj
= select_element(ALL_TYPES
);
3367 if (selectobj
!= NULL
)
3368 selrefno
= *selectobj
;
3372 areawin
->selects
= selnum
;
3373 areawin
->selectlist
= selectlist
;
3374 areawin
->redraw_needed
= save_redraw
;
3375 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3376 + areawin
->selects
; selectobj
++) {
3377 if (*selectobj
== selrefno
) break;
3379 if (selectobj
== areawin
->selectlist
+ areawin
->selects
) {
3380 Wprintf("Put cursor close to the reference element.");
3384 /* Shuffle the reference element to the beginning of the select list */
3385 *selectobj
= *(areawin
->selectlist
);
3386 *(areawin
->selectlist
) = selrefno
;
3387 selectobj
= areawin
->selectlist
;
3390 switch(SELECTTYPE(selectobj
)) {
3392 labelptr
*lastlabel
= (labelptr
*)EDITPART
;
3397 /* save the old string, including parameters */
3398 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3401 /* fill any NULL instance parameters with the default value */
3402 copyparams(areawin
->topinstance
, areawin
->topinstance
);
3404 /* place text cursor line at point nearest the cursor */
3405 /* unless textend is set. . . */
3407 if (areawin
->textend
== 0) {
3408 TextLinesInfo tlinfo
;
3410 tlinfo
.tbreak
= NULL
;
3411 tlinfo
.padding
= NULL
;
3413 window_to_user(x
, y
, &areawin
->save
);
3414 InvTransformPoints(&areawin
->save
, &tmppt
, 1, (*lastlabel
)->position
,
3415 (*lastlabel
)->scale
, (*lastlabel
)->rotation
);
3416 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3417 tmppt
.x
+= ((*lastlabel
)->anchor
& NOTLEFT
?
3418 ((*lastlabel
)->anchor
& RIGHT
? tmpext
.maxwidth
3419 : tmpext
.maxwidth
>> 1) : 0);
3420 tmppt
.y
+= ((*lastlabel
)->anchor
& NOTBOTTOM
?
3421 ((*lastlabel
)->anchor
& TOP
? tmpext
.ascent
:
3422 (tmpext
.ascent
+ tmpext
.base
) >> 1) : tmpext
.base
);
3423 if ((*lastlabel
)->pin
)
3424 pinadjust((*lastlabel
)->anchor
, &tmppt
.x
, NULL
, -1);
3426 /* Where tbreak is passed to ULength, the character position */
3427 /* is returned in the TextLinesInfo dostop field. */
3428 tlinfo
.tbreak
= &tmppt
;
3429 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3430 areawin
->textpos
= tlinfo
.dostop
;
3432 if (tlinfo
.padding
!= NULL
) free(tlinfo
.padding
);
3435 /* find current font */
3437 curfont
= findcurfont(areawin
->textpos
, (*lastlabel
)->string
,
3438 areawin
->topinstance
);
3440 /* change menu buttons accordingly */
3442 setfontmarks(curfont
, (*lastlabel
)->anchor
);
3444 if (eventmode
== CATALOG_MODE
) {
3445 /* CATTEXT_MODE may show an otherwise hidden library namespace */
3446 undrawtext(*lastlabel
);
3447 eventmode
= CATTEXT_MODE
;
3448 redrawtext(*lastlabel
);
3449 areawin
->redraw_needed
= False
; /* ignore prev. redraw requests */
3450 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3453 eventmode
= ETEXT_MODE
;
3454 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3457 XDefineCursor(dpy
, areawin
->window
, TEXTPTR
);
3459 /* write the text at the bottom */
3461 charreport(*lastlabel
);
3465 case POLYGON
: case ARC
: case SPLINE
: case PATH
:
3466 window_to_user(x
, y
, &areawin
->save
);
3467 pathedit(*(EDITPART
));
3470 case OBJINST
: case GRAPHIC
:
3471 if (areawin
->selects
== 1)
3475 XDefineCursor (dpy
, areawin
->window
, EDCURSOR
);
3478 /*----------------------------------------------------------------------*/
3479 /* edit() routine for path-type elements (polygons, splines, arcs, and */
3481 /*----------------------------------------------------------------------*/
3483 void pathedit(genericptr editpart
)
3485 splineptr lastspline
= NULL
;
3487 polyptr lastpoly
= NULL
;
3494 /* Find and set constrained edit points on all elements. Register */
3495 /* each element with the undo mechanism. */
3497 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
3498 areawin
->selects
; eselect
++) {
3499 switch (SELECTTYPE(eselect
)) {
3501 findconstrained(SELTOPOLY(eselect
));
3504 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3505 SELTOGENERIC(eselect
));
3510 switch(ELEMENTTYPE(editpart
)) {
3512 genericptr
*ggen
, *savegen
= NULL
;
3513 int mincycle
, dist
, mindist
= 1e6
;
3515 lastpath
= (pathptr
)editpart
;
3516 havecycle
= (checkcycle(editpart
, 0) >= 0) ? True
: False
;
3518 /* determine which point of the path is closest to the cursor */
3519 for (ggen
= lastpath
->plist
; ggen
< lastpath
->plist
+ lastpath
->parts
;
3521 switch (ELEMENTTYPE(*ggen
)) {
3523 lastpoly
= TOPOLY(ggen
);
3524 cycle
= closepoint(lastpoly
, &areawin
->save
);
3525 dist
= wirelength(lastpoly
->points
+ cycle
, &areawin
->save
);
3528 lastspline
= TOSPLINE(ggen
);
3529 cycle
= (wirelength(&lastspline
->ctrl
[0],
3530 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3531 &areawin
->save
)) ? 0 : 3;
3532 dist
= wirelength(&lastspline
->ctrl
[cycle
], &areawin
->save
);
3535 if (dist
< mindist
) {
3541 if (savegen
== NULL
) return; /* something went terribly wrong */
3542 switch (ELEMENTTYPE(*savegen
)) {
3544 lastpoly
= TOPOLY(savegen
);
3545 addcycle(savegen
, mincycle
, 0);
3546 savept
= lastpoly
->points
+ mincycle
;
3547 makerefcycle(lastpoly
->cycle
, mincycle
);
3548 findconstrained(lastpoly
);
3551 lastspline
= TOSPLINE(savegen
);
3552 addcycle(savegen
, mincycle
, 0);
3553 savept
= &lastspline
->ctrl
[mincycle
];
3554 makerefcycle(lastspline
->cycle
, mincycle
);
3557 updatepath(lastpath
);
3559 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3560 (genericptr
)lastpath
);
3561 patheditpush(lastpath
);
3562 areawin
->origin
= areawin
->save
;
3565 path_mode_draw(xcDRAW_INIT
, lastpath
);
3567 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3568 (xcEventHandler
)trackelement
, NULL
);
3569 eventmode
= EPATH_MODE
;
3570 printpos(savept
->x
, savept
->y
);
3575 lastpoly
= (polyptr
)editpart
;
3577 /* Determine which point of polygon is closest to cursor */
3578 cycle
= closepoint(lastpoly
, &areawin
->save
);
3579 havecycle
= (lastpoly
->cycle
== NULL
) ? False
: True
;
3580 addcycle(&editpart
, cycle
, 0);
3581 savept
= lastpoly
->points
+ cycle
;
3582 makerefcycle(lastpoly
->cycle
, cycle
);
3584 findconstrained(lastpoly
);
3585 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3586 (genericptr
)lastpoly
);
3589 /* Push onto the editstack */
3590 polyeditpush(lastpoly
);
3592 /* remember our postion for pointer restore */
3593 areawin
->origin
= areawin
->save
;
3597 poly_mode_draw(xcDRAW_INIT
, lastpoly
);
3599 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3600 (xcEventHandler
)trackelement
, NULL
);
3601 eventmode
= EPOLY_MODE
;
3602 printeditbindings();
3603 printpos(savept
->x
, savept
->y
);
3608 lastspline
= (splineptr
)editpart
;
3610 /* find which point is closest to the cursor */
3612 cycle
= (wirelength(&lastspline
->ctrl
[0],
3613 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3614 &areawin
->save
)) ? 0 : 3;
3615 havecycle
= (lastspline
->cycle
== NULL
) ? False
: True
;
3616 addcycle(&editpart
, cycle
, 0);
3617 makerefcycle(lastspline
->cycle
, cycle
);
3618 curpt
= &lastspline
->ctrl
[cycle
];
3620 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3621 (genericptr
)lastspline
);
3623 /* Push onto the editstack */
3624 splineeditpush(lastspline
);
3626 /* remember our postion for pointer restore */
3627 areawin
->origin
= areawin
->save
;
3631 spline_mode_draw(xcDRAW_INIT
, lastspline
);
3632 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3633 (xcEventHandler
)trackelement
, NULL
);
3634 eventmode
= ESPLINE_MODE
;
3638 float tmpratio
, tlen
;
3640 lastarc
= (arcptr
)editpart
;
3642 /* find a part of the arc close to the pointer */
3644 tlen
= (float)wirelength(&areawin
->save
, &(lastarc
->position
));
3645 tmpratio
= (float)(abs(lastarc
->radius
)) / tlen
;
3646 curpt
.x
= lastarc
->position
.x
+ tmpratio
* (areawin
->save
.x
3647 - lastarc
->position
.x
);
3648 tmpratio
= (float)lastarc
->yaxis
/ tlen
;
3649 curpt
.y
= lastarc
->position
.y
+ tmpratio
* (areawin
->save
.y
3650 - lastarc
->position
.y
);
3651 addcycle(&editpart
, 0, 0);
3652 saveratio
= (double)(lastarc
->yaxis
) / (double)(abs(lastarc
->radius
));
3654 /* Push onto the editstack */
3655 arceditpush(lastarc
);
3656 areawin
->origin
= areawin
->save
;
3660 areawin
->save
.x
= curpt
.x
; /* for redrawing dotted edit line */
3661 areawin
->save
.y
= curpt
.y
;
3662 arc_mode_draw(xcDRAW_INIT
, lastarc
);
3663 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3664 (xcEventHandler
)trackarc
, NULL
);
3665 eventmode
= EARC_MODE
;
3666 printpos(curpt
.x
, curpt
.y
);
3671 /*------------------------------------------------------*/
3672 /* Raise an element to the top of the list */
3673 /*------------------------------------------------------*/
3675 void xc_top(short *selectno
, short *orderlist
)
3678 genericptr
*raiseobj
, *genobj
, temp
;
3680 raiseobj
= topobject
->plist
+ *selectno
;
3683 for (genobj
= topobject
->plist
+ *selectno
; genobj
<
3684 topobject
->plist
+ topobject
->parts
- 1; genobj
++) {
3685 *genobj
= *(genobj
+ 1);
3686 *(orderlist
+ i
) = *(orderlist
+ i
+ 1);
3689 *(topobject
->plist
+ topobject
->parts
- 1) = temp
;
3690 *(orderlist
+ topobject
->parts
- 1) = *selectno
;
3691 *selectno
= topobject
->parts
- 1;
3694 /*------------------------------------------------------*/
3695 /* Lower an element to the bottom of the list */
3696 /*------------------------------------------------------*/
3698 void xc_bottom(short *selectno
, short *orderlist
)
3701 genericptr
*lowerobj
, *genobj
, temp
;
3703 lowerobj
= topobject
->plist
+ *selectno
;
3706 for (genobj
= topobject
->plist
+ *selectno
;
3707 genobj
> topobject
->plist
; genobj
--) {
3708 *genobj
= *(genobj
- 1);
3709 *(orderlist
+ i
) = *(orderlist
+ i
- 1);
3713 *orderlist
= *selectno
;
3717 /*--------------------------------------------------------------*/
3718 /* Raise all selected elements by one position in the list */
3719 /*--------------------------------------------------------------*/
3723 short *sel
, topsel
, maxsel
, *topidx
, limit
, *orderlist
, i
;
3724 genericptr
*raiseobj
, temp
;
3726 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3727 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3729 /* Find topmost element in the select list */
3731 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3733 if (*sel
> maxsel
) {
3738 if (maxsel
== -1) return; /* Error condition */
3741 limit
= topobject
->parts
- 1;
3744 /* Exchange the topmost element with the one above it */
3745 if (topsel
< limit
) {
3746 raiseobj
= topobject
->plist
+ topsel
;
3748 *raiseobj
= *(raiseobj
+ 1);
3749 *(raiseobj
+ 1) = temp
;
3751 i
= *(orderlist
+ topsel
);
3752 *(orderlist
+ topsel
) = *(orderlist
+ topsel
+ 1);
3753 *(orderlist
+ topsel
+ 1) = i
;
3758 /* Find next topmost element */
3760 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3762 if (*sel
< maxsel
) {
3763 if (*sel
> topsel
) {
3769 if (topsel
== -1) break; /* No more elements to raise */
3772 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3776 /*--------------------------------------------------------------*/
3777 /* Lower all selected elements by one position in the list */
3778 /*--------------------------------------------------------------*/
3782 short *sel
, botsel
, minsel
, *botidx
, limit
, *orderlist
, i
;
3783 genericptr
*lowerobj
, temp
;
3785 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3786 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3788 /* Find bottommost element in the select list */
3789 minsel
= topobject
->parts
;
3790 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3792 if (*sel
< minsel
) {
3797 if (minsel
== topobject
->parts
) return; /* Error condition */
3803 /* Exchange the topmost element with the one below it */
3804 if (botsel
> limit
) {
3805 lowerobj
= topobject
->plist
+ botsel
;
3807 *lowerobj
= *(lowerobj
- 1);
3808 *(lowerobj
- 1) = temp
;
3810 i
= *(orderlist
+ botsel
);
3811 *(orderlist
+ botsel
) = *(orderlist
+ botsel
- 1);
3812 *(orderlist
+ botsel
- 1) = i
;
3817 /* Find next topmost element */
3818 botsel
= topobject
->parts
;
3819 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3821 if (*sel
> minsel
) {
3822 if (*sel
< botsel
) {
3828 if (botsel
== topobject
->parts
) break; /* No more elements to raise */
3831 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3835 /*------------------------------------------------------*/
3836 /* Generate a virtual copy of an object instance in the */
3837 /* user library. This is like the library virtual copy */
3838 /* except that it allows the user to generate a library */
3839 /* copy of an existing instance, without having to make */
3840 /* a copy of the master library instance and edit it. */
3841 /* copyvirtual() also allows the library virtual */
3842 /* instance to take on a specific rotation or flip */
3843 /* value, which cannot be done with the library virtual */
3844 /* copy function. */
3845 /*------------------------------------------------------*/
3849 short *selectno
, created
= 0;
3850 objinstptr vcpobj
, libinst
;
3852 for (selectno
= areawin
->selectlist
; selectno
< areawin
->selectlist
+
3853 areawin
->selects
; selectno
++) {
3854 if (SELECTTYPE(selectno
) == OBJINST
) {
3855 vcpobj
= SELTOOBJINST(selectno
);
3856 libinst
= addtoinstlist(USERLIB
- LIBRARY
, vcpobj
->thisobject
, TRUE
);
3857 instcopy(libinst
, vcpobj
);
3862 Wprintf("No object instances selected for virtual copy!");
3866 composelib(USERLIB
);
3870 /*------------------------------------------------------*/
3871 /* Exchange the list position (drawing order) of two */
3872 /* elements, or move the position of one element to the */
3873 /* top or bottom. */
3874 /*------------------------------------------------------*/
3878 short *selectno
, *orderlist
, i
;
3879 genericptr
*exchobj
, *exchobj2
, temp
;
3880 Boolean preselected
;
3882 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3883 if (!checkselect(ALL_TYPES
)) {
3884 Wprintf("Select 1 or 2 objects");
3888 selectno
= areawin
->selectlist
;
3889 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3890 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3892 if (areawin
->selects
== 1) { /* lower if on top; raise otherwise */
3893 if (*selectno
== topobject
->parts
- 1)
3894 xc_bottom(selectno
, orderlist
);
3896 xc_top(selectno
, orderlist
);
3898 else { /* exchange the two objects */
3899 exchobj
= topobject
->plist
+ *selectno
;
3900 exchobj2
= topobject
->plist
+ *(selectno
+ 1);
3903 *exchobj
= *exchobj2
;
3906 i
= *(orderlist
+ *selectno
);
3907 *(orderlist
+ *selectno
) = *(orderlist
+ *(selectno
+ 1));
3908 *(orderlist
+ *(selectno
+ 1)) = i
;
3910 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
3911 orderlist
, topobject
->parts
);
3913 incr_changes(topobject
);
3916 drawarea(NULL
, NULL
, NULL
);
3919 /*--------------------------------------------------------*/
3920 /* Flip an element horizontally (POLYGON, ARC, or SPLINE) */
3921 /*--------------------------------------------------------*/
3923 void elhflip(genericptr
*genobj
, short x
)
3925 switch(ELEMENTTYPE(*genobj
)) {
3927 polyptr flippoly
= TOPOLY(genobj
);
3929 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
3930 flippoly
->number
; ppoint
++)
3931 ppoint
->x
= (x
<< 1) - ppoint
->x
;
3935 arcptr fliparc
= TOARC(genobj
);
3936 float tmpang
= 180 - fliparc
->angle1
;
3937 fliparc
->angle1
= 180 - fliparc
->angle2
;
3938 fliparc
->angle2
= tmpang
;
3939 if (fliparc
->angle2
< 0) {
3940 fliparc
->angle1
+= 360;
3941 fliparc
->angle2
+= 360;
3943 fliparc
->radius
= -fliparc
->radius
;
3944 fliparc
->position
.x
= (x
<< 1) - fliparc
->position
.x
;
3949 splineptr flipspline
= TOSPLINE(genobj
);
3951 for (i
= 0; i
< 4; i
++)
3952 flipspline
->ctrl
[i
].x
= (x
<< 1) - flipspline
->ctrl
[i
].x
;
3953 calcspline(flipspline
);
3958 /*--------------------------------------------------------*/
3959 /* Flip an element vertically (POLYGON, ARC, or SPLINE) */
3960 /*--------------------------------------------------------*/
3962 void elvflip(genericptr
*genobj
, short y
)
3964 switch(ELEMENTTYPE(*genobj
)) {
3967 polyptr flippoly
= TOPOLY(genobj
);
3970 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
3971 flippoly
->number
; ppoint
++)
3972 ppoint
->y
= (y
<< 1) - ppoint
->y
;
3976 arcptr fliparc
= TOARC(genobj
);
3977 float tmpang
= 360 - fliparc
->angle1
;
3978 fliparc
->angle1
= 360 - fliparc
->angle2
;
3979 fliparc
->angle2
= tmpang
;
3980 if (fliparc
->angle1
>= 360) {
3981 fliparc
->angle1
-= 360;
3982 fliparc
->angle2
-= 360;
3984 fliparc
->radius
= -fliparc
->radius
;
3985 fliparc
->position
.y
= (y
<< 1) - fliparc
->position
.y
;
3990 splineptr flipspline
= TOSPLINE(genobj
);
3992 for (i
= 0; i
< 4; i
++)
3993 flipspline
->ctrl
[i
].y
= (y
<< 1) - flipspline
->ctrl
[i
].y
;
3994 calcspline(flipspline
);
3999 /*------------------------------------------------------*/
4000 /* Horizontally flip an element */
4001 /*------------------------------------------------------*/
4003 void elementflip(XPoint
*position
)
4006 Boolean single
= False
;
4007 Boolean preselected
;
4009 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4010 if (!checkselect(ALL_TYPES
)) return;
4011 if (areawin
->selects
== 1) single
= True
;
4013 if (eventmode
!= COPY_MODE
)
4014 register_for_undo(XCF_Flip_X
, UNDO_MORE
, areawin
->topinstance
,
4015 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4017 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4018 + areawin
->selects
; selectobj
++) {
4020 /* erase the object */
4021 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4022 easydraw(*selectobj
, DOFORALL
);
4024 switch(SELECTTYPE(selectobj
)) {
4026 labelptr fliplab
= SELTOLABEL(selectobj
);
4027 if ((fliplab
->anchor
& (RIGHT
| NOTLEFT
)) != NOTLEFT
)
4028 fliplab
->anchor
^= (RIGHT
| NOTLEFT
);
4030 fliplab
->position
.x
= (position
->x
<< 1) - fliplab
->position
.x
;
4033 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4034 flipg
->scale
= -flipg
->scale
;
4036 flipg
->valid
= FALSE
;
4037 #endif /* !HAVE_CAIRO */
4039 flipg
->position
.x
= (position
->x
<< 1) - flipg
->position
.x
;
4042 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4043 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4044 flipobj
->scale
= -flipobj
->scale
;
4046 flipobj
->position
.x
= (position
->x
<< 1) - flipobj
->position
.x
;
4048 case POLYGON
: case ARC
: case SPLINE
:
4049 elhflip(topobject
->plist
+ *selectobj
, position
->x
);
4052 genericptr
*genpart
;
4053 pathptr flippath
= SELTOPATH(selectobj
);
4055 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4056 + flippath
->parts
; genpart
++)
4057 elhflip(genpart
, position
->x
);
4061 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4062 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4063 easydraw(*selectobj
, DOFORALL
);
4066 select_invalidate_netlist();
4067 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4071 if (eventmode
== NORMAL_MODE
)
4072 incr_changes(topobject
);
4073 if (eventmode
== CATALOG_MODE
) {
4075 if ((libnum
= is_library(topobject
)) >= 0) {
4076 composelib(libnum
+ LIBRARY
);
4077 drawarea(NULL
, NULL
, NULL
);
4081 pwriteback(areawin
->topinstance
);
4082 calcbbox(areawin
->topinstance
);
4086 /*----------------------------------------------*/
4087 /* Vertically flip an element */
4088 /*----------------------------------------------*/
4090 void elementvflip(XPoint
*position
)
4093 /*short fsign; (jdk) */
4094 Boolean preselected
;
4095 Boolean single
= False
;
4097 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4098 if (!checkselect(ALL_TYPES
)) return;
4099 if (areawin
->selects
== 1) single
= True
;
4101 if (eventmode
!= COPY_MODE
)
4102 register_for_undo(XCF_Flip_Y
, UNDO_MORE
, areawin
->topinstance
,
4103 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4105 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4106 + areawin
->selects
; selectobj
++) {
4108 /* erase the object */
4109 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4110 easydraw(*selectobj
, DOFORALL
);
4112 switch(SELECTTYPE(selectobj
)) {
4114 labelptr fliplab
= SELTOLABEL(selectobj
);
4115 if ((fliplab
->anchor
& (TOP
| NOTBOTTOM
)) != NOTBOTTOM
)
4116 fliplab
->anchor
^= (TOP
| NOTBOTTOM
);
4118 fliplab
->position
.y
= (position
->y
<< 1) - fliplab
->position
.y
;
4121 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4123 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4124 flipobj
->scale
= -(flipobj
->scale
);
4125 flipobj
->rotation
+= 180;
4126 while (flipobj
->rotation
>= 360) flipobj
->rotation
-= 360;
4128 flipobj
->position
.y
= (position
->y
<< 1) - flipobj
->position
.y
;
4131 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4133 flipg
->scale
= -(flipg
->scale
);
4134 flipg
->rotation
+= 180;
4135 while (flipg
->rotation
>= 360) flipg
->rotation
-= 360;
4137 flipg
->position
.y
= (position
->y
<< 1) - flipg
->position
.y
;
4139 case POLYGON
: case ARC
: case SPLINE
:
4140 elvflip(topobject
->plist
+ *selectobj
, position
->y
);
4143 genericptr
*genpart
;
4144 pathptr flippath
= SELTOPATH(selectobj
);
4146 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4147 + flippath
->parts
; genpart
++)
4148 elvflip(genpart
, position
->y
);
4151 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4152 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4153 easydraw(*selectobj
, DOFORALL
);
4156 select_invalidate_netlist();
4157 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4160 if (eventmode
== NORMAL_MODE
) {
4161 incr_changes(topobject
);
4163 if (eventmode
== CATALOG_MODE
) {
4165 if ((libnum
= is_library(topobject
)) >= 0) {
4166 composelib(libnum
+ LIBRARY
);
4167 drawarea(NULL
, NULL
, NULL
);
4171 pwriteback(areawin
->topinstance
);
4172 calcbbox(areawin
->topinstance
);
4176 /*----------------------------------------*/
4177 /* ButtonPress handler during delete mode */
4178 /*----------------------------------------*/
4180 void deletebutton(int x
, int y
)
4182 UNUSED(x
); UNUSED(y
);
4184 if (checkselect(ALL_TYPES
)) {
4185 standard_element_delete(ERASE
);
4186 calcbbox(areawin
->topinstance
);
4188 setoptionmenu(); /* Return GUI check/radio boxes to default */
4191 /*----------------------------------------------------------------------*/
4192 /* Process of element deletion. Remove one element from the indicated */
4194 /*----------------------------------------------------------------------*/
4196 void delete_one_element(objinstptr thisinstance
, genericptr thiselement
)
4198 objectptr thisobject
;
4200 Boolean pinchange
= False
;
4202 thisobject
= thisinstance
->thisobject
;
4204 /* The netlist contains pointers to elements which no longer */
4205 /* exist on the page, so we should remove them from the netlist. */
4207 if (RemoveFromNetlist(thisobject
, thiselement
)) pinchange
= True
;
4208 for (genobj
= thisobject
->plist
; genobj
< thisobject
->plist
4209 + thisobject
->parts
; genobj
++)
4210 if (*genobj
== thiselement
)
4213 if (genobj
== thisobject
->plist
+ thisobject
->parts
) return;
4215 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4216 *(genobj
- 1) = *genobj
;
4217 thisobject
->parts
--;
4219 if (pinchange
) setobjecttype(thisobject
);
4220 incr_changes(thisobject
);
4221 calcbbox(thisinstance
);
4222 invalidate_netlist(thisobject
);
4223 /* freenetlist(thisobject); */
4226 /*----------------------------------------------------------------------*/
4227 /* Process of element deletion. Remove everything in the selection */
4228 /* list from the indicated object, and return a new object containing */
4229 /* only the deleted elements. */
4231 /* if drawmode is DRAW, we erase the objects as we remove them. */
4233 /* Note that if "slist" is areawin->selectlist, it is freed by this */
4234 /* routine (calls freeselects()), but not otherwise. */
4235 /*----------------------------------------------------------------------*/
4237 objectptr
delete_element(objinstptr thisinstance
, short *slist
, int selects
,
4241 objectptr delobj
, thisobject
;
4243 Boolean pinchange
= False
;
4245 if (slist
== NULL
|| selects
== 0) return NULL
;
4247 thisobject
= thisinstance
->thisobject
;
4249 delobj
= (objectptr
) malloc(sizeof(object
));
4253 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4256 for (selectobj
= slist
; selectobj
< slist
+ selects
; selectobj
++) {
4257 genobj
= thisobject
->plist
+ *selectobj
;
4258 if (drawmode
) easydraw(*selectobj
, DOFORALL
);
4260 *(delobj
->plist
+ delobj
->parts
) = *genobj
;
4263 /* The netlist contains pointers to elements which no longer */
4264 /* exist on the page, so we should remove them from the netlist. */
4266 if (RemoveFromNetlist(thisobject
, *genobj
)) pinchange
= True
;
4267 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4268 *(genobj
- 1) = *genobj
;
4269 thisobject
->parts
--;
4270 reviseselect(slist
, selects
, selectobj
);
4272 if (pinchange
) setobjecttype(thisobject
);
4274 if (slist
== areawin
->selectlist
)
4277 calcbbox(thisinstance
);
4278 /* freenetlist(thisobject); */
4281 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
4282 drawarea(NULL
, NULL
, NULL
);
4287 /*----------------------------------------------------------------------*/
4288 /* Wrapper for delete_element(). Remember this deletion for the undo */
4290 /*----------------------------------------------------------------------*/
4292 void standard_element_delete(short drawmode
)
4296 /* register_for_undo(XCF_Select, UNDO_MORE, areawin->topinstance, */
4297 /* areawin->selectlist, areawin->selects); */
4298 select_invalidate_netlist();
4299 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4300 areawin
->selects
, drawmode
);
4301 register_for_undo(XCF_Delete
, UNDO_DONE
, areawin
->topinstance
,
4302 delobj
, (int)drawmode
);
4303 incr_changes(topobject
); /* Treat as one change */
4306 /*----------------------------------------------------------------------*/
4307 /* Another wrapper for delete_element(), in which we do not save the */
4308 /* deletion as an undo event. However, the returned object is saved */
4309 /* on areawin->editstack, so that the objects can be grabbed. This */
4310 /* allows objects to be carried across pages and through the hierarchy. */
4311 /*----------------------------------------------------------------------*/
4313 void delete_for_xfer(short drawmode
, short *slist
, int selects
)
4316 reset(areawin
->editstack
, DESTROY
);
4317 areawin
->editstack
= delete_element(areawin
->topinstance
,
4318 slist
, selects
, drawmode
);
4322 /*----------------------------------------------------------------------*/
4323 /* Yet another wrapper for delete_element(), in which we destroy the */
4324 /* object returned and free all associated memory. */
4325 /*----------------------------------------------------------------------*/
4327 void delete_noundo(short drawmode
)
4331 select_invalidate_netlist();
4332 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4333 areawin
->selects
, drawmode
);
4335 if (delobj
!= NULL
) reset(delobj
, DESTROY
);
4338 /*----------------------------------------------------------------------*/
4339 /* Undelete last deleted elements and return a selectlist of the */
4340 /* elements. If "olist" is non-NULL, then the undeleted elements are */
4341 /* placed into the object of thisinstance in the order given by olist, */
4342 /* and a copy of olist is returned. If "olist" is NULL, then the */
4343 /* undeleted elements are placed at the end of thisinstance->thisobject */
4344 /* ->plist, and a new selection list is returned. If "olist" is non- */
4345 /* NULL, then the size of olist had better match the number of objects */
4346 /* in delobj! It is up to the calling routine to check this. */
4347 /*----------------------------------------------------------------------*/
4349 short *xc_undelete(objinstptr thisinstance
, objectptr delobj
, short mode
,
4352 objectptr thisobject
;
4354 short *slist
, count
, i
; /* position; (jdk) */
4356 thisobject
= thisinstance
->thisobject
;
4357 slist
= (short *)malloc(delobj
->parts
* sizeof(short));
4360 for (regen
= delobj
->plist
; regen
< delobj
->plist
+ delobj
->parts
; regen
++) {
4361 PLIST_INCR(thisobject
);
4362 if (olist
== NULL
) {
4363 *(slist
+ count
) = thisobject
->parts
;
4364 *(topobject
->plist
+ topobject
->parts
) = *regen
;
4367 *(slist
+ count
) = *(olist
+ count
);
4368 for (i
= thisobject
->parts
; i
> *(olist
+ count
); i
--)
4369 *(thisobject
->plist
+ i
) = *(thisobject
->plist
+ i
- 1);
4370 *(thisobject
->plist
+ i
) = *regen
;
4372 thisobject
->parts
++;
4374 XTopSetForeground((*regen
)->color
);
4375 easydraw(*(slist
+ count
), DEFAULTCOLOR
);
4379 /* If the element has passed parameters (eparam), then we have to */
4380 /* check if the key exists in the new parent object. If not, */
4381 /* delete the parameter. */
4383 if ((*regen
)->passed
) {
4384 eparamptr nextepp
, epp
= (*regen
)->passed
;
4385 while (epp
!= NULL
) {
4386 nextepp
= epp
->next
;
4387 if (!match_param(thisobject
, epp
->key
)) {
4388 if (epp
== (*regen
)->passed
) (*regen
)->passed
= nextepp
;
4389 free_element_param(*regen
, epp
);
4395 /* Likewise, string parameters must be checked in labels because */
4396 /* they act like element parameters. */
4398 if (IS_LABEL(*regen
)) {
4399 labelptr glab
= TOLABEL(regen
);
4400 stringpart
*gstr
, *lastpart
= NULL
;
4401 for (gstr
= glab
->string
; gstr
!= NULL
; gstr
= lastpart
->nextpart
) {
4402 if (gstr
->type
== PARAM_START
) {
4403 if (!match_param(thisobject
, gstr
->data
.string
)) {
4404 free(gstr
->data
.string
);
4406 lastpart
->nextpart
= gstr
->nextpart
;
4408 glab
->string
= gstr
->nextpart
;
4410 gstr
= (lastpart
) ? lastpart
: glab
->string
;
4417 incr_changes(thisobject
); /* treat as one change */
4418 calcbbox(thisinstance
);
4420 /* flush the delete buffer but don't delete the elements */
4421 reset(delobj
, SAVE
);
4423 if (delobj
!= areawin
->editstack
) free(delobj
);
4428 /*----------------------------*/
4429 /* select save object handler */
4430 /*----------------------------*/
4432 void printname(objectptr curobject
)
4434 char editstr
[10], pagestr
[10];
4439 Dimension swidth
, swidth2
, sarea
;
4441 char *sptr
= tmpname
;
4444 /* print full string to make message widget proper size */
4446 strcpy(editstr
, ((ispage
= is_page(curobject
)) >= 0) ? "Editing: " : "");
4447 strcpy(editstr
, (is_library(curobject
) >= 0) ? "Library: " : "");
4448 if (strstr(curobject
->name
, "Page") == NULL
&& (ispage
>= 0))
4449 sprintf(pagestr
, " (p. %d)", areawin
->page
+ 1);
4452 W2printf("%s%s%s", editstr
, curobject
->name
, pagestr
);
4454 /* Tcl doesn't update width changes immediately. . . what to do? */
4455 /* (i.e., Tk_Width(message2) gives the original width) */
4458 XtSetArg(wargs
[0], XtNwidth
, &sarea
);
4459 XtGetValues(message2
, wargs
, 1);
4461 /* in the remote case that the string is longer than message widget, */
4462 /* truncate the string and denote the truncation with an ellipsis (...) */
4464 strcpy(tmpname
, curobject
->name
);
4465 swidth2
= XTextWidth(appdata
.xcfont
, editstr
, strlen(editstr
));
4466 swidth
= XTextWidth(appdata
.xcfont
, tmpname
, strlen(tmpname
));
4468 if ((swidth
+ swidth2
) > sarea
) {
4470 while ((swidth
+ swidth2
) > sarea
) {
4472 swidth
= XTextWidth(appdata
.xcfont
, sptr
, strlen(sptr
));
4474 for(ip
= sptr
; ip
< sptr
+ 3 && *ip
!= '\0'; ip
++) *ip
= '.';
4476 W2printf("Editing: %s", sptr
);
4481 /*--------------------------------------------------------------*/
4482 /* Make sure that a string does not conflict with postscript */
4483 /* names (commands and definitions found in xcircps2.pro). */
4485 /* Return value is NULL if no change was made. Otherwise, the */
4486 /* return value is an allocated string. */
4487 /*--------------------------------------------------------------*/
4489 char *checkvalidname(char *teststring
, objectptr newobj
)
4492 short dupl
; /* flag a duplicate string */
4494 char *sptr
, *pptr
, *cptr
;
4498 /* Try not to allocate memory unless necessary */
4505 if (newobj
!= NULL
) {
4506 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4507 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4508 libobj
= xobjs
.userlibs
[i
].library
+ j
;
4510 if (*libobj
== newobj
) continue;
4511 if (!strcmp(pptr
, (*libobj
)->name
)) {
4513 /* Prepend an underscore to the object name. If the */
4514 /* object has no technology, create a null technology */
4515 /* name. Otherwise, the technology remains the same */
4516 /* but the object name gets the prepended underscore. */
4518 if ((cptr
= strstr(pptr
, "::")) == NULL
) {
4519 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 3);
4520 sprintf(pptr
, "::_%s", (*libobj
)->name
);
4523 int offset
= cptr
- pptr
+ 2;
4525 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 2);
4527 pptr
= (char *)realloc(pptr
, strlen((*libobj
)->name
) + 2);
4528 sprintf(pptr
, "%s", (*libobj
)->name
);
4529 sprintf(pptr
+ offset
, "_%s", (*libobj
)->name
+ offset
);
4536 /* If we're in the middle of a file load, the name cannot be */
4537 /* the same as an alias, either. */
4539 if (aliastop
!= NULL
) {
4540 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
4541 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
) {
4542 if (!strcmp(pptr
, sref
->alias
)) {
4544 pptr
= (char *)malloc(strlen(sref
->alias
) + 2);
4546 pptr
= (char *)realloc(pptr
, strlen(sref
->alias
) + 2);
4547 sprintf(pptr
, "_%s", sref
->alias
);
4555 } while (dupl
== 1);
4557 return (pptr
== sptr
) ? NULL
: pptr
;
4560 /*--------------------------------------------------------------*/
4561 /* Make sure that name for new object does not conflict with */
4562 /* existing object definitions */
4564 /* Return: True if name required change, False otherwise */
4565 /*--------------------------------------------------------------*/
4567 Boolean
checkname(objectptr newobj
)
4571 /* Check for empty string */
4572 if (strlen(newobj
->name
) == 0) {
4573 Wprintf("Blank object name changed to default");
4574 sprintf(newobj
->name
, "user_object");
4577 pptr
= checkvalidname(newobj
->name
, newobj
);
4579 /* Change name if necessary to avoid naming conflicts */
4581 Wprintf("Created new object %s", newobj
->name
);
4585 Wprintf("Changed name from %s to %s to avoid conflict with "
4586 "existing object", newobj
->name
, pptr
);
4587 strncpy(newobj
->name
, pptr
, 79);
4593 /*------------------------------------------------------------*/
4594 /* Find the object "dot" in the builtin library, if it exists */
4595 /*------------------------------------------------------------*/
4603 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4604 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4605 dotobj
= *(xobjs
.userlibs
[i
].library
+ j
);
4606 name
= dotobj
->name
;
4607 if ((pptr
= strstr(name
, "::")) != NULL
) name
= pptr
+ 2;
4608 if (!strcmp(name
, "dot")) {
4613 return (objectptr
)NULL
;
4616 /*--------------------------------------*/
4617 /* Add value origin to all points */
4618 /*--------------------------------------*/
4620 void movepoints(genericptr
*ssgen
, short deltax
, short deltay
)
4622 switch(ELEMENTTYPE(*ssgen
)) {
4624 fpointlist sspoints
;
4625 TOARC(ssgen
)->position
.x
+= deltax
;
4626 TOARC(ssgen
)->position
.y
+= deltay
;
4627 for (sspoints
= TOARC(ssgen
)->points
; sspoints
< TOARC(ssgen
)->points
+
4628 TOARC(ssgen
)->number
; sspoints
++) {
4629 sspoints
->x
+= deltax
;
4630 sspoints
->y
+= deltay
;
4636 for (sspoints
= TOPOLY(ssgen
)->points
; sspoints
< TOPOLY(ssgen
)->points
+
4637 TOPOLY(ssgen
)->number
; sspoints
++) {
4638 sspoints
->x
+= deltax
;
4639 sspoints
->y
+= deltay
;
4644 fpointlist sspoints
;
4646 for (sspoints
= TOSPLINE(ssgen
)->points
; sspoints
<
4647 TOSPLINE(ssgen
)->points
+ INTSEGS
; sspoints
++) {
4648 sspoints
->x
+= deltax
;
4649 sspoints
->y
+= deltay
;
4651 for (j
= 0; j
< 4; j
++) {
4652 TOSPLINE(ssgen
)->ctrl
[j
].x
+= deltax
;
4653 TOSPLINE(ssgen
)->ctrl
[j
].y
+= deltay
;
4657 TOOBJINST(ssgen
)->position
.x
+= deltax
;
4658 TOOBJINST(ssgen
)->position
.y
+= deltay
;
4661 TOGRAPHIC(ssgen
)->position
.x
+= deltax
;
4662 TOGRAPHIC(ssgen
)->position
.y
+= deltay
;
4665 TOLABEL(ssgen
)->position
.x
+= deltax
;
4666 TOLABEL(ssgen
)->position
.y
+= deltay
;
4671 /*----------------------------------------------------------------------*/
4672 /* Add value origin to all edited points, according to edit flags */
4673 /*----------------------------------------------------------------------*/
4675 void editpoints(genericptr
*ssgen
, short deltax
, short deltay
)
4679 splineptr editspline
;
4680 short cycle
, cpoint
;
4685 switch(ELEMENTTYPE(*ssgen
)) {
4687 editpoly
= TOPOLY(ssgen
);
4688 if (editpoly
->cycle
== NULL
)
4689 movepoints(ssgen
, deltax
, deltay
);
4691 for (cptr
= editpoly
->cycle
;; cptr
++) {
4692 cycle
= cptr
->number
;
4693 curpt
= editpoly
->points
+ cycle
;
4694 if (cptr
->flags
& EDITX
) curpt
->x
+= deltax
;
4695 if (cptr
->flags
& EDITY
) curpt
->y
+= deltay
;
4696 if (cptr
->flags
& LASTENTRY
) break;
4703 editspline
= TOSPLINE(ssgen
);
4704 if (editspline
->cycle
== NULL
)
4705 movepoints(ssgen
, deltax
, deltay
);
4707 for (cptr
= editspline
->cycle
;; cptr
++) {
4708 cycle
= cptr
->number
;
4709 if (cycle
== 0 || cycle
== 3) {
4710 cpoint
= (cycle
== 0) ? 1 : 2;
4711 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cpoint
].x
+= deltax
;
4712 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cpoint
].y
+= deltay
;
4714 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cycle
].x
+= deltax
;
4715 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cycle
].y
+= deltay
;
4716 if (cptr
->flags
& ANTIXY
) {
4717 editspline
->ctrl
[cycle
].x
-= deltax
;
4718 editspline
->ctrl
[cycle
].y
-= deltay
;
4720 if (cptr
->flags
& LASTENTRY
) break;
4724 calcspline(editspline
);
4728 editpath
= TOPATH(ssgen
);
4729 if (checkcycle(*ssgen
, 0) < 0) {
4730 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4732 movepoints(ggen
, deltax
, deltay
);
4735 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4737 if (checkcycle(*ggen
, 0) >= 0)
4738 editpoints(ggen
, deltax
, deltay
);
4744 movepoints(ssgen
, deltax
, deltay
);
4752 void xlib_makeobject(xcWidget w
, caddr_t nulldata
)
4754 UNUSED(w
); UNUSED(nulldata
);
4756 domakeobject(-1, (char *)_STR2
, FALSE
);
4759 #endif /* !TCL_WRAPPER */
4761 /*--------------------------------------------------------------*/
4762 /* Set the name for a new user-defined object and make the */
4763 /* object. If "forceempty" is true, we allow creation of a new */
4764 /* object with no elements (normally would be used only from a */
4765 /* script, where an object is being constructed automatically). */
4766 /*--------------------------------------------------------------*/
4768 objinstptr
domakeobject(int libnum
, char *name
, Boolean forceempty
)
4771 objinstptr
*newinst
;
4773 oparamptr ops
, newop
;
4774 eparamptr epp
, newepp
;
4777 short loclibnum
= libnum
;
4779 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
4781 /* make room for new entry in library list */
4783 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
4784 realloc(xobjs
.userlibs
[loclibnum
].library
,
4785 (xobjs
.userlibs
[loclibnum
].number
+ 1) * sizeof(objectptr
));
4787 newobj
= xobjs
.userlibs
[loclibnum
].library
+ xobjs
.userlibs
[loclibnum
].number
;
4789 *newobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4790 areawin
->selects
, NORMAL
);
4792 if (*newobj
== NULL
) {
4795 if (!forceempty
) return NULL
;
4797 /* Create a new (empty) object */
4799 initobj
= (objectptr
) malloc(sizeof(object
));
4804 invalidate_netlist(topobject
);
4805 xobjs
.userlibs
[loclibnum
].number
++;
4807 /* Create the instance of this object so we can compute a bounding box */
4809 NEW_OBJINST(newinst
, topobject
);
4810 instancedefaults(*newinst
, *newobj
, 0, 0);
4813 /* find closest snap point to bbox center and make this the obj. center */
4815 if (areawin
->center
) {
4816 origin
.x
= (*newobj
)->bbox
.lowerleft
.x
+ (*newobj
)->bbox
.width
/ 2;
4817 origin
.y
= (*newobj
)->bbox
.lowerleft
.y
+ (*newobj
)->bbox
.height
/ 2;
4820 origin
.x
= origin
.y
= 0;
4823 instancedefaults(*newinst
, *newobj
, origin
.x
, origin
.y
);
4825 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4827 switch(ELEMENTTYPE(*ssgen
)) {
4830 TOOBJINST(ssgen
)->position
.x
-= origin
.x
;
4831 TOOBJINST(ssgen
)->position
.y
-= origin
.y
;
4835 TOGRAPHIC(ssgen
)->position
.x
-= origin
.x
;
4836 TOGRAPHIC(ssgen
)->position
.y
-= origin
.y
;
4840 TOLABEL(ssgen
)->position
.x
-= origin
.x
;
4841 TOLABEL(ssgen
)->position
.y
-= origin
.y
;
4845 genericptr
*pathlist
;
4846 for (pathlist
= TOPATH(ssgen
)->plist
; pathlist
< TOPATH(ssgen
)->plist
4847 + TOPATH(ssgen
)->parts
; pathlist
++) {
4848 movepoints(pathlist
, -origin
.x
, -origin
.y
);
4853 movepoints(ssgen
, -origin
.x
, -origin
.y
);
4858 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4860 for (epp
= (*ssgen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
4861 ops
= match_param(topobject
, epp
->key
);
4862 newop
= copyparameter(ops
);
4863 newop
->next
= (*newobj
)->params
;
4864 (*newobj
)->params
= newop
;
4866 /* Generate an indirect parameter reference from child to parent */
4867 newepp
= make_new_eparam(epp
->key
);
4868 newepp
->flags
|= P_INDIRECT
;
4869 newepp
->pdata
.refkey
= strdup(epp
->key
);
4870 newepp
->next
= (*newinst
)->passed
;
4871 (*newinst
)->passed
= newepp
;
4873 if (IS_LABEL(*ssgen
)) {
4874 /* Also need to check for substring parameters in labels */
4875 for (sptr
= TOLABEL(ssgen
)->string
; sptr
!= NULL
; sptr
= sptr
->nextpart
) {
4876 if (sptr
->type
== PARAM_START
) {
4877 ops
= match_param(topobject
, sptr
->data
.string
);
4878 newop
= copyparameter(ops
);
4879 newop
->next
= (*newobj
)->params
;
4880 (*newobj
)->params
= newop
;
4882 /* Generate an indirect parameter reference from child to parent */
4883 newepp
= make_new_eparam(sptr
->data
.string
);
4884 newepp
->flags
|= P_INDIRECT
;
4885 newepp
->pdata
.refkey
= strdup(sptr
->data
.string
);
4886 newepp
->next
= (*newinst
)->passed
;
4887 (*newinst
)->passed
= newepp
;
4893 /* any parameters in the top-level object that used by the selected */
4894 /* elements must be copied into the new object. */
4896 /* put new object back into place */
4898 (*newobj
)->hidden
= False
;
4899 (*newobj
)->schemtype
= SYMBOL
;
4902 incr_changes(*newobj
);
4904 /* (netlist invalidation was taken care of by delete_element() */
4905 /* Also, incr_changes(topobject) was done by delete_element()) */
4907 XTopSetForeground((*newinst
)->color
);
4908 UDrawObject(*newinst
, SINGLE
, (*newinst
)->color
,
4909 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
4912 /* Copy name into object and check for conflicts */
4914 strcpy((*newobj
)->name
, name
);
4917 /* register the technology and mark the technology as not saved */
4918 AddObjectTechnology(*newobj
);
4920 /* generate library instance for this object (bounding box */
4921 /* should be default, so don't do calcbbox() on it) */
4923 addtoinstlist(loclibnum
, *newobj
, FALSE
);
4925 /* recompile the user catalog and reset view bounds */
4927 composelib(loclibnum
+ LIBRARY
);
4928 centerview(xobjs
.libtop
[loclibnum
+ LIBRARY
]);
4935 /*-------------------------------------------*/
4936 /* Make a user object from selected elements */
4937 /*-------------------------------------------*/
4939 void selectsave(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
4941 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
4942 UNUSED(clientdata
); UNUSED(calldata
);
4944 if (areawin
->selects
== 0) return; /* nothing was selected */
4946 /* Get a name for the new object */
4948 eventmode
= NORMAL_MODE
;
4949 popdata
->dataptr
= NULL
;
4950 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
4951 popupprompt(w
, "Enter name for new object:", "\0", xlib_makeobject
, popdata
, NULL
);
4956 /*-----------------------------*/
4957 /* Edit-stack support routines */
4958 /*-----------------------------*/
4960 void arceditpush(arcptr lastarc
)
4964 NEW_ARC(newarc
, areawin
->editstack
);
4965 arccopy(*newarc
, lastarc
);
4966 copycycles(&((*newarc
)->cycle
), &(lastarc
->cycle
));
4969 /*--------------------------------------*/
4971 void splineeditpush(splineptr lastspline
)
4973 splineptr
*newspline
;
4975 NEW_SPLINE(newspline
, areawin
->editstack
);
4976 splinecopy(*newspline
, lastspline
);
4979 /*--------------------------------------*/
4981 void polyeditpush(polyptr lastpoly
)
4985 NEW_POLY(newpoly
, areawin
->editstack
);
4986 polycopy(*newpoly
, lastpoly
);
4989 /*--------------------------------------*/
4991 void patheditpush(pathptr lastpath
)
4995 NEW_PATH(newpath
, areawin
->editstack
);
4996 pathcopy(*newpath
, lastpath
);
4999 /*-----------------------------*/
5000 /* Copying support routines */
5001 /*-----------------------------*/
5003 pointlist
copypoints(pointlist points
, int number
)
5005 pointlist rpoints
, cpoints
, newpoints
;
5007 rpoints
= (pointlist
) malloc(number
* sizeof(XPoint
));
5008 for (newpoints
= rpoints
, cpoints
= points
;
5009 newpoints
< rpoints
+ number
;
5010 newpoints
++, cpoints
++) {
5011 newpoints
->x
= cpoints
->x
;
5012 newpoints
->y
= cpoints
->y
;
5017 /*------------------------------------------*/
5019 void graphiccopy(graphicptr newg
, graphicptr copyg
)
5024 newg
->source
= copyg
->source
;
5025 newg
->position
.x
= copyg
->position
.x
;
5026 newg
->position
.y
= copyg
->position
.y
;
5027 newg
->rotation
= copyg
->rotation
;
5028 newg
->scale
= copyg
->scale
;
5029 newg
->color
= copyg
->color
;
5030 newg
->passed
= NULL
;
5031 copyalleparams((genericptr
)newg
, (genericptr
)copyg
);
5033 newg
->valid
= FALSE
;
5034 newg
->target
= NULL
;
5035 newg
->clipmask
= (Pixmap
)NULL
;
5036 #endif /* HAVE_CAIRO */
5038 /* Update the refcount of the source image */
5039 for (i
= 0; i
< xobjs
.images
; i
++) {
5040 iptr
= xobjs
.imagelist
+ i
;
5041 if (iptr
->image
== newg
->source
) {
5048 /*------------------------------------------*/
5050 void labelcopy(labelptr newtext
, labelptr copytext
)
5052 newtext
->string
= stringcopy(copytext
->string
);
5053 newtext
->position
.x
= copytext
->position
.x
;
5054 newtext
->position
.y
= copytext
->position
.y
;
5055 newtext
->rotation
= copytext
->rotation
;
5056 newtext
->scale
= copytext
->scale
;
5057 newtext
->anchor
= copytext
->anchor
;
5058 newtext
->color
= copytext
->color
;
5059 newtext
->passed
= NULL
;
5060 newtext
->cycle
= NULL
;
5061 copyalleparams((genericptr
)newtext
, (genericptr
)copytext
);
5062 newtext
->pin
= copytext
->pin
;
5065 /*------------------------------------------*/
5067 void arccopy(arcptr newarc
, arcptr copyarc
)
5069 newarc
->style
= copyarc
->style
;
5070 newarc
->color
= copyarc
->color
;
5071 newarc
->position
.x
= copyarc
->position
.x
;
5072 newarc
->position
.y
= copyarc
->position
.y
;
5073 newarc
->radius
= copyarc
->radius
;
5074 newarc
->yaxis
= copyarc
->yaxis
;
5075 newarc
->angle1
= copyarc
->angle1
;
5076 newarc
->angle2
= copyarc
->angle2
;
5077 newarc
->width
= copyarc
->width
;
5078 newarc
->passed
= NULL
;
5079 newarc
->cycle
= NULL
;
5080 copyalleparams((genericptr
)newarc
, (genericptr
)copyarc
);
5084 /*------------------------------------------*/
5086 void polycopy(polyptr newpoly
, polyptr copypoly
)
5088 newpoly
->style
= copypoly
->style
;
5089 newpoly
->color
= copypoly
->color
;
5090 newpoly
->width
= copypoly
->width
;
5091 newpoly
->number
= copypoly
->number
;
5092 copycycles(&(newpoly
->cycle
), &(copypoly
->cycle
));
5093 newpoly
->points
= copypoints(copypoly
->points
, copypoly
->number
);
5095 newpoly
->passed
= NULL
;
5096 copyalleparams((genericptr
)newpoly
, (genericptr
)copypoly
);
5099 /*------------------------------------------*/
5101 void splinecopy(splineptr newspline
, splineptr copyspline
)
5105 newspline
->style
= copyspline
->style
;
5106 newspline
->color
= copyspline
->color
;
5107 newspline
->width
= copyspline
->width
;
5108 copycycles(&(newspline
->cycle
), &(copyspline
->cycle
));
5109 for (i
= 0; i
< 4; i
++) {
5110 newspline
->ctrl
[i
].x
= copyspline
->ctrl
[i
].x
;
5111 newspline
->ctrl
[i
].y
= copyspline
->ctrl
[i
].y
;
5113 for (i
= 0; i
< INTSEGS
; i
++) {
5114 newspline
->points
[i
].x
= copyspline
->points
[i
].x
;
5115 newspline
->points
[i
].y
= copyspline
->points
[i
].y
;
5117 newspline
->passed
= NULL
;
5118 copyalleparams((genericptr
)newspline
, (genericptr
)copyspline
);
5121 /*----------------------------------------------*/
5123 /*----------------------------------------------*/
5125 void pathcopy(pathptr newpath
, pathptr copypath
)
5128 splineptr
*newspline
, copyspline
;
5129 polyptr
*newpoly
, copypoly
;
5131 newpath
->style
= copypath
->style
;
5132 newpath
->color
= copypath
->color
;
5133 newpath
->width
= copypath
->width
;
5135 newpath
->passed
= NULL
;
5136 copyalleparams((genericptr
)newpath
, (genericptr
)copypath
);
5137 newpath
->plist
= (genericptr
*)malloc(copypath
->parts
* sizeof(genericptr
));
5139 for (ggen
= copypath
->plist
; ggen
< copypath
->plist
+ copypath
->parts
; ggen
++) {
5140 switch (ELEMENTTYPE(*ggen
)) {
5142 copypoly
= TOPOLY(ggen
);
5143 NEW_POLY(newpoly
, newpath
);
5144 polycopy(*newpoly
, copypoly
);
5147 copyspline
= TOSPLINE(ggen
);
5148 NEW_SPLINE(newspline
, newpath
);
5149 splinecopy(*newspline
, copyspline
);
5155 /*--------------------------------------------------------------*/
5156 /* Copy an object instance */
5157 /*--------------------------------------------------------------*/
5159 void instcopy(objinstptr newobj
, objinstptr copyobj
)
5161 newobj
->position
.x
= copyobj
->position
.x
;
5162 newobj
->position
.y
= copyobj
->position
.y
;
5163 newobj
->rotation
= copyobj
->rotation
;
5164 newobj
->scale
= copyobj
->scale
;
5165 newobj
->style
= copyobj
->style
;
5166 newobj
->thisobject
= copyobj
->thisobject
;
5167 newobj
->color
= copyobj
->color
;
5168 newobj
->bbox
.lowerleft
.x
= copyobj
->bbox
.lowerleft
.x
;
5169 newobj
->bbox
.lowerleft
.y
= copyobj
->bbox
.lowerleft
.y
;
5170 newobj
->bbox
.width
= copyobj
->bbox
.width
;
5171 newobj
->bbox
.height
= copyobj
->bbox
.height
;
5173 newobj
->passed
= NULL
;
5174 copyalleparams((genericptr
)newobj
, (genericptr
)copyobj
);
5176 newobj
->params
= NULL
;
5177 copyparams(newobj
, copyobj
);
5179 /* If the parameters are the same, the bounding box should be, too. */
5180 if (copyobj
->schembbox
!= NULL
) {
5181 newobj
->schembbox
= (BBox
*)malloc(sizeof(BBox
));
5182 newobj
->schembbox
->lowerleft
.x
= copyobj
->schembbox
->lowerleft
.x
;
5183 newobj
->schembbox
->lowerleft
.y
= copyobj
->schembbox
->lowerleft
.y
;
5184 newobj
->schembbox
->width
= copyobj
->schembbox
->width
;
5185 newobj
->schembbox
->height
= copyobj
->schembbox
->height
;
5188 newobj
->schembbox
= NULL
;
5191 /*--------------------------------------------------------------*/
5192 /* The method for removing objects from a list is to add the */
5193 /* value REMOVE_TAG to the type of each object needing to be */
5194 /* removed, and then calling this routine. */
5195 /*--------------------------------------------------------------*/
5197 void delete_tagged(objinstptr thisinst
) {
5198 Boolean tagged
= True
;
5199 objectptr thisobject
, delobj
;
5203 thisobject
= thisinst
->thisobject
;
5207 for (stmp
= 0; stmp
< thisobject
->parts
; stmp
++) {
5208 pgen
= thisobject
->plist
+ stmp
;
5209 if ((*pgen
)->type
& REMOVE_TAG
) {
5210 (*pgen
)->type
&= (~REMOVE_TAG
);
5213 delobj
= delete_element(thisinst
, &stmp
, 1, 0);
5214 register_for_undo(XCF_Delete
, UNDO_MORE
, thisinst
, delobj
, 0);
5216 /* If we destroy elements in the current window, we need to */
5217 /* make sure that the selection list is updated appropriately. */
5219 if ((thisobject
== topobject
) && (areawin
->selects
> 0)) {
5220 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5221 areawin
->selects
; sobj
++)
5222 if (*sobj
> stmp
) (*sobj
)--;
5225 /* Also ensure that this element is not referenced in any */
5226 /* netlist. If it is, remove it and mark the netlist as */
5229 remove_netlist_element(thisobject
, *pgen
);
5233 undo_finish_series();
5236 /*-----------------------------------------------------------------*/
5237 /* For copying: Check if an object is about to be placed directly */
5238 /* on top of the same object. If so, delete the one underneath. */
5239 /*-----------------------------------------------------------------*/
5244 genericptr
*sgen
, *pgen
;
5245 Boolean tagged
= False
;
5247 /* Work through the select list */
5249 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5250 areawin
->selects
; sobj
++) {
5251 sgen
= topobject
->plist
+ (*sobj
);
5253 /* For each object being copied, compare it against every object */
5254 /* on the current page (except self). Flag if it's the same. */
5256 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+ topobject
->parts
;
5258 if (pgen
== sgen
) continue;
5259 if (compare_single(sgen
, pgen
)) {
5260 /* Make sure that this object is not part of the selection, */
5261 /* else chaos will reign. */
5262 for (cobj
= areawin
->selectlist
; cobj
< areawin
->selectlist
+
5263 areawin
->selects
; cobj
++) {
5264 if (pgen
== topobject
->plist
+ (*cobj
)) break;
5266 /* Tag it for future deletion and prevent further compares */
5267 if (cobj
== areawin
->selectlist
+ areawin
->selects
) {
5269 (*pgen
)->type
|= REMOVE_TAG
;
5275 /* Delete the tagged elements */
5276 Wprintf("Duplicate object deleted");
5277 delete_tagged(areawin
->topinstance
);
5278 incr_changes(topobject
);
5282 /*--------------------------------------------------------------*/
5283 /* Direct placement of elements. Assumes that the selectlist */
5284 /* contains all the elements to be positioned. "deltax" and */
5285 /* "deltay" are relative x and y positions to move the */
5287 /*--------------------------------------------------------------*/
5289 void placeselects(short deltax
, short deltay
, XPoint
*userpt
)
5292 XPoint newpos
, *ppt
;
5299 doattach
= ((userpt
== NULL
) || (areawin
->attachto
< 0)) ? FALSE
: TRUE
;
5301 /* under attachto condition, keep element attached to */
5302 /* the attachto element. */
5304 if (doattach
) findattach(&newpos
, &rot
, userpt
);
5308 areawin
->clipped
= -1; /* Prevent clipping */
5309 #endif /* HAVE_CAIRO */
5311 for (dragselect
= areawin
->selectlist
; dragselect
< areawin
->selectlist
5312 + areawin
->selects
; dragselect
++) {
5314 switch(SELECTTYPE(dragselect
)) {
5316 objinstptr draginst
= SELTOOBJINST(dragselect
);
5319 draginst
->position
.x
= newpos
.x
;
5320 draginst
->position
.y
= newpos
.y
;
5321 while (rot
>= 360.0) rot
-= 360.0;
5322 while (rot
< 0.0) rot
+= 360.0;
5323 draginst
->rotation
= rot
;
5326 draginst
->position
.x
+= deltax
;
5327 draginst
->position
.y
+= deltay
;
5332 graphicptr dragg
= SELTOGRAPHIC(dragselect
);
5333 dragg
->position
.x
+= deltax
;
5334 dragg
->position
.y
+= deltay
;
5337 labelptr draglabel
= SELTOLABEL(dragselect
);
5339 draglabel
->position
.x
= newpos
.x
;
5340 draglabel
->position
.y
= newpos
.y
;
5341 draglabel
->rotation
= rot
;
5344 draglabel
->position
.x
+= deltax
;
5345 draglabel
->position
.y
+= deltay
;
5349 pathptr dragpath
= SELTOPATH(dragselect
);
5350 genericptr
*pathlist
;
5353 XPoint
*pdelta
= pathclosepoint(dragpath
, &newpos
);
5354 deltax
= newpos
.x
- pdelta
->x
;
5355 deltay
= newpos
.y
- pdelta
->y
;
5357 for (pathlist
= dragpath
->plist
; pathlist
< dragpath
->plist
5358 + dragpath
->parts
; pathlist
++) {
5359 movepoints(pathlist
, deltax
, deltay
);
5363 polyptr dragpoly
= SELTOPOLY(dragselect
);
5364 pointlist dragpoints
;
5366 /* if (dragpoly->cycle != NULL) continue; */
5368 closest
= closepoint(dragpoly
, &newpos
);
5369 deltax
= newpos
.x
- dragpoly
->points
[closest
].x
;
5370 deltay
= newpos
.y
- dragpoly
->points
[closest
].y
;
5372 for (dragpoints
= dragpoly
->points
; dragpoints
< dragpoly
->points
5373 + dragpoly
->number
; dragpoints
++) {
5374 dragpoints
->x
+= deltax
;
5375 dragpoints
->y
+= deltay
;
5379 splineptr dragspline
= SELTOSPLINE(dragselect
);
5381 fpointlist dragpoints
;
5383 /* if (dragspline->cycle != NULL) continue; */
5385 closest
= (wirelength(&dragspline
->ctrl
[0], &newpos
)
5386 > wirelength(&dragspline
->ctrl
[3], &newpos
)) ? 3 : 0;
5387 deltax
= newpos
.x
- dragspline
->ctrl
[closest
].x
;
5388 deltay
= newpos
.y
- dragspline
->ctrl
[closest
].y
;
5390 for (dragpoints
= dragspline
->points
; dragpoints
< dragspline
->
5391 points
+ INTSEGS
; dragpoints
++) {
5392 dragpoints
->x
+= deltax
;
5393 dragpoints
->y
+= deltay
;
5395 for (j
= 0; j
< 4; j
++) {
5396 dragspline
->ctrl
[j
].x
+= deltax
;
5397 dragspline
->ctrl
[j
].y
+= deltay
;
5401 arcptr dragarc
= SELTOARC(dragselect
);
5402 fpointlist dragpoints
;
5405 deltax
= newpos
.x
- dragarc
->position
.x
;
5406 deltay
= newpos
.y
- dragarc
->position
.y
;
5408 dragarc
->position
.x
+= deltax
;
5409 dragarc
->position
.y
+= deltay
;
5410 for (dragpoints
= dragarc
->points
; dragpoints
< dragarc
->
5411 points
+ dragarc
->number
; dragpoints
++) {
5412 dragpoints
->x
+= deltax
;
5413 dragpoints
->y
+= deltay
;
5419 if (areawin
->pinattach
) {
5420 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
5421 topobject
->parts
; pgen
++) {
5422 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
5423 cpoly
= TOPOLY(pgen
);
5424 if (cpoly
->cycle
!= NULL
) {
5425 ppt
= cpoly
->points
+ cpoly
->cycle
->number
;
5426 newpos
.x
= ppt
->x
+ deltax
;
5427 newpos
.y
= ppt
->y
+ deltay
;
5428 if (areawin
->manhatn
)
5429 manhattanize(&newpos
, cpoly
, cpoly
->cycle
->number
, FALSE
);
5437 move_mode_draw(xcDRAW_EDIT
, NULL
);
5440 areawin
->clipped
= 0;
5441 #endif /* HAVE_CAIRO */
5444 /*----------------------------------------------------------------------*/
5445 /* Copy handler. Assumes that the selectlist contains the elements */
5446 /* to be copied, and that the initial position of the copy is held */
5447 /* in areawin->save. */
5448 /*----------------------------------------------------------------------*/
5454 if (!checkselect_draw(ALL_TYPES
, True
)) return;
5455 u2u_snap(&areawin
->save
);
5456 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
5457 + areawin
->selects
; selectobj
++) {
5459 /* Cycles will not be used for copy mode: remove them */
5460 removecycle(topobject
->plist
+ (*selectobj
));
5462 switch(SELECTTYPE(selectobj
)) {
5463 case LABEL
: { /* copy label */
5464 labelptr copytext
= SELTOLABEL(selectobj
);
5467 NEW_LABEL(newtext
, topobject
);
5468 labelcopy(*newtext
, copytext
);
5470 case OBJINST
: { /* copy object instance */
5471 objinstptr copyobj
= SELTOOBJINST(selectobj
);
5473 NEW_OBJINST(newobj
, topobject
);
5474 instcopy(*newobj
, copyobj
);
5476 case GRAPHIC
: { /* copy graphic instance */
5477 graphicptr copyg
= SELTOGRAPHIC(selectobj
);
5479 NEW_GRAPHIC(newg
, topobject
);
5480 graphiccopy(*newg
, copyg
);
5482 case PATH
: { /* copy path */
5483 pathptr copypath
= SELTOPATH(selectobj
);
5485 NEW_PATH(newpath
, topobject
);
5486 pathcopy(*newpath
, copypath
);
5488 case ARC
: { /* copy arc */
5489 arcptr copyarc
= SELTOARC(selectobj
);
5491 NEW_ARC(newarc
, topobject
);
5492 arccopy(*newarc
, copyarc
);
5494 case POLYGON
: { /* copy polygons */
5495 polyptr copypoly
= SELTOPOLY(selectobj
);
5497 NEW_POLY(newpoly
, topobject
);
5498 polycopy(*newpoly
, copypoly
);
5500 case SPLINE
: { /* copy spline */
5501 splineptr copyspline
= SELTOSPLINE(selectobj
);
5502 splineptr
*newspline
;
5503 NEW_SPLINE(newspline
, topobject
);
5504 splinecopy(*newspline
, copyspline
);
5508 /* change selection from the old to the new object */
5510 *selectobj
= topobject
->parts
- 1;
5514 /*--------------------------------------------------------------*/
5515 /* Function which initiates interactive placement of copied */
5517 /*--------------------------------------------------------------*/
5521 if (areawin
->selects
> 0) {
5522 move_mode_draw(xcDRAW_INIT
, NULL
);
5523 if (eventmode
== NORMAL_MODE
) {
5524 XDefineCursor(dpy
, areawin
->window
, COPYCURSOR
);
5525 eventmode
= COPY_MODE
;
5527 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
5528 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5530 XtAddEventHandler(areawin
->area
, PointerMotionMask
|
5531 ButtonMotionMask
, False
, (XtEventHandler
)xlib_drag
,
5535 select_invalidate_netlist();
5539 /*-----------------------------------------------------------*/
5540 /* Copy handler for copying from a button push or key event. */
5541 /*-----------------------------------------------------------*/
5543 void copy_op(int op
, int x
, int y
)
5545 if (op
== XCF_Copy
) {
5546 window_to_user(x
, y
, &areawin
->save
);
5547 createcopies(); /* This function does all the hard work */
5548 copydrag(); /* Start interactive placement */
5551 eventmode
= NORMAL_MODE
;
5552 areawin
->attachto
= -1;
5555 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5556 ButtonMotionMask
, False
, (xcEventHandler
)xctk_drag
,
5559 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5560 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5563 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5564 u2u_snap(&areawin
->save
);
5565 if (op
== XCF_Cancel
) {
5566 move_mode_draw(xcDRAW_EMPTY
, NULL
);
5567 delete_noundo(NORMAL
);
5569 else if (op
== XCF_Finish_Copy
) {
5570 move_mode_draw(xcDRAW_FINAL
, NULL
);
5571 /* If selected objects are the only ones on the page, */
5572 /* then do a full bbox calculation. */
5573 if (topobject
->parts
== areawin
->selects
)
5574 calcbbox(areawin
->topinstance
);
5578 register_for_undo(XCF_Copy
, UNDO_MORE
, areawin
->topinstance
,
5579 areawin
->selectlist
, areawin
->selects
);
5581 incr_changes(topobject
);
5583 else { /* XCF_Continue_Copy */
5584 move_mode_draw(xcDRAW_FINAL
, NULL
);
5585 if (topobject
->parts
== areawin
->selects
)
5586 calcbbox(areawin
->topinstance
);
5590 register_for_undo(XCF_Copy
, UNDO_DONE
, areawin
->topinstance
,
5591 areawin
->selectlist
, areawin
->selects
);
5593 copydrag(); /* Start interactive placement again */
5594 incr_changes(topobject
);
5599 /*----------------------------------------------*/
5600 /* Check for more than one button being pressed */
5601 /*----------------------------------------------*/
5603 Boolean
checkmultiple(XButtonEvent
*event
)
5605 int state
= Button1Mask
| Button2Mask
| Button3Mask
|
5606 Button4Mask
| Button5Mask
;
5607 state
&= event
->state
;
5608 /* ((x - 1) & x) is always non-zero if x has more than one bit set */
5609 return (((state
- 1) & state
) == 0) ? False
: True
;
5612 /*----------------------------------------------------------------------*/
5613 /* Operation continuation---dependent upon the ongoing operation. */
5614 /* This operation only pertains to a few event modes for which */
5615 /* continuation of action makes sense---drawing wires (polygons), and */
5616 /* editing polygons, arcs, splines, and paths. */
5617 /*----------------------------------------------------------------------*/
5619 void continue_op(int op
, int x
, int y
)
5623 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5624 window_to_user(x
, y
, &areawin
->save
);
5627 printpos(ppos
.x
, ppos
.y
);
5636 case(EPATH_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5637 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5638 path_op(*(EDITPART
), op
, x
, y
);
5641 inst_op(*(EDITPART
), op
, x
, y
);
5644 finish_op(XCF_Finish_Element
, x
, y
);
5651 /*--------------------------------------------------------------*/
5652 /* Finish or cancel an operation. This forces a return to */
5653 /* "normal" mode, with whatever other side effects are caused */
5654 /* by the operation. */
5655 /*--------------------------------------------------------------*/
5657 void finish_op(int op
, int x
, int y
)
5661 XPoint snappt
, boxpts
[4];
5664 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5665 window_to_user(x
, y
, &areawin
->save
);
5668 case(EPATH_MODE
): case(BOX_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5669 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5670 path_op(*(EDITPART
), op
, x
, y
);
5674 inst_op(*(EDITPART
), op
, x
, y
);
5677 case (FONTCAT_MODE
):
5678 case (EFONTCAT_MODE
):
5679 fontcat_op(op
, x
, y
);
5680 eventmode
= (eventmode
== FONTCAT_MODE
) ? TEXT_MODE
: ETEXT_MODE
;
5681 text_mode_draw(xcDRAW_INIT
, TOLABEL(EDITPART
));
5682 XDefineCursor (dpy
, areawin
->window
, TEXTPTR
);
5687 catalog_op(op
, x
, y
);
5699 curlabel
= TOLABEL(EDITPART
);
5700 if (op
== XCF_Cancel
) {
5701 redrawtext(curlabel
);
5702 areawin
->redraw_needed
= False
; /* ignore previous requests */
5703 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5704 freelabel(curlabel
->string
);
5710 singlebbox(EDITPART
);
5711 incr_changes(topobject
);
5712 select_invalidate_netlist();
5713 text_mode_draw(xcDRAW_FINAL
, curlabel
);
5715 setdefaultfontmarks();
5716 eventmode
= NORMAL_MODE
;
5719 case(ETEXT_MODE
): case(CATTEXT_MODE
):
5720 curlabel
= TOLABEL(EDITPART
);
5721 if (op
== XCF_Cancel
) {
5722 /* restore the original text */
5723 undrawtext(curlabel
);
5724 undo_finish_series();
5726 redrawtext(curlabel
);
5727 areawin
->redraw_needed
= False
; /* ignore previous requests */
5728 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5729 if (eventmode
== CATTEXT_MODE
) eventmode
= CATALOG_MODE
;
5731 setdefaultfontmarks();
5733 else textreturn(); /* Generate "return" key character */
5734 areawin
->textend
= 0;
5738 u2u_snap(&areawin
->save
);
5740 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5741 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5743 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5744 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5747 if (op
== XCF_Cancel
) {
5748 /* Just regenerate the library where we started */
5749 if (areawin
->selects
>= 1) {
5750 objinstptr selinst
= SELTOOBJINST(areawin
->selectlist
);
5751 libnum
= libfindobject(selinst
->thisobject
, NULL
);
5753 composelib(libnum
+ LIBRARY
);
5760 eventmode
= CATALOG_MODE
;
5761 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5765 u2u_snap(&areawin
->save
);
5767 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5768 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5770 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5771 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5774 if (op
== XCF_Cancel
) {
5775 /* If we came from the library with an object instance, in */
5776 /* MOVE_MODE, then "cancel" should delete the element. */
5777 /* Otherwise, put the position of the element back to what */
5778 /* it was before we started the move. The difference is */
5779 /* indicated by the value of areawin->editpart. */
5781 if ((areawin
->selects
> 0) && (*areawin
->selectlist
== topobject
->parts
))
5782 delete_noundo(NORMAL
);
5784 placeselects(areawin
->origin
.x
- areawin
->save
.x
,
5785 areawin
->origin
.y
- areawin
->save
.y
, NULL
);
5787 drawarea(NULL
, NULL
, NULL
);
5790 if (areawin
->selects
> 0) {
5791 register_for_undo(XCF_Move
,
5792 /* (was_preselected) ? UNDO_DONE : UNDO_MORE, */
5794 areawin
->topinstance
,
5795 (int)(areawin
->save
.x
- areawin
->origin
.x
),
5796 (int)(areawin
->save
.y
- areawin
->origin
.y
));
5797 pwriteback(areawin
->topinstance
);
5798 incr_changes(topobject
);
5799 select_invalidate_netlist();
5800 unselect_all(); /* The way it used to be. . . */
5803 /* full calc needed: move may shrink bbox */
5804 calcbbox(areawin
->topinstance
);
5806 /* if (!was_preselected) clearselects(); */
5808 areawin
->attachto
= -1;
5814 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5815 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5817 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5818 ButtonMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5821 rescale_mode_draw(xcDRAW_FINAL
, NULL
);
5822 if (op
!= XCF_Cancel
) {
5823 XPoint newpoints
[5];
5824 fscale
= UGetRescaleBox(&areawin
->save
, newpoints
);
5826 elementrescale(fscale
);
5827 areawin
->redraw_needed
= True
;
5830 eventmode
= NORMAL_MODE
;
5834 selarea_mode_draw(xcDRAW_FINAL
, NULL
);
5837 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5838 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5840 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5841 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5844 /* Zero-width boxes act like a normal selection. Otherwise, */
5845 /* proceed with the area select. */
5847 if ((areawin
->origin
.x
== areawin
->save
.x
) &&
5848 (areawin
->origin
.y
== areawin
->save
.y
))
5849 select_add_element(ALL_TYPES
);
5851 boxpts
[0] = areawin
->origin
;
5852 boxpts
[1].x
= areawin
->save
.x
;
5853 boxpts
[1].y
= areawin
->origin
.y
;
5854 boxpts
[2] = areawin
->save
;
5855 boxpts
[3].x
= areawin
->origin
.x
;
5856 boxpts
[3].y
= areawin
->save
.y
;
5857 selectarea(topobject
, boxpts
, 0);
5862 u2u_snap(&areawin
->save
);
5865 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5866 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5868 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5869 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5872 areawin
->panx
= areawin
->pany
= 0;
5873 if (op
!= XCF_Cancel
)
5874 panbutton((u_int
) 5, (areawin
->width
>> 1) - (x
- areawin
->origin
.x
),
5875 (areawin
->height
>> 1) - (y
- areawin
->origin
.y
), 0);
5881 /* Remove any selections */
5882 if ((eventmode
== SELAREA_MODE
) || (eventmode
== PAN_MODE
)
5883 || (eventmode
== MOVE_MODE
))
5885 eventmode
= NORMAL_MODE
;
5886 areawin
->redraw_needed
= True
;
5888 else if (eventmode
!= MOVE_MODE
&& eventmode
!= EPATH_MODE
&&
5889 eventmode
!= EPOLY_MODE
&& eventmode
!= ARC_MODE
&&
5890 eventmode
!= EARC_MODE
&& eventmode
!= SPLINE_MODE
&&
5891 eventmode
!= ESPLINE_MODE
&& eventmode
!= WIRE_MODE
&&
5892 eventmode
!= ETEXT_MODE
&& eventmode
!= TEXT_MODE
) {
5896 if (eventmode
== NORMAL_MODE
) {
5898 /* Return any highlighted networks to normal */
5899 highlightnetlist(topobject
, areawin
->topinstance
, 0);
5901 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5904 snap(x
, y
, &snappt
);
5905 printpos(snappt
.x
, snappt
.y
);
5908 /*--------------------------------------------------------------*/
5909 /* Edit operations for instances. This is used to allow */
5910 /* numeric parameters to be adjusted from the hierarchical */
5911 /* level above, shielding the the unparameterized parts from */
5913 /*--------------------------------------------------------------*/
5915 void inst_op(genericptr editpart
, int op
, int x
, int y
)
5917 UNUSED(editpart
); UNUSED(op
); UNUSED(x
); UNUSED(y
);
5920 /*--------------------------------------------------------------*/
5921 /* Operations for path components */
5922 /*--------------------------------------------------------------*/
5924 void path_op(genericptr editpart
, int op
, int x
, int y
)
5927 splineptr newspline
;
5928 Boolean donecycles
= False
;
5929 UNUSED(x
); UNUSED(y
);
5931 /* Don't allow point cycling in a multi-part edit. */
5932 /* Allowing it is just confusing. Instead, we treat */
5933 /* button 1 (cycle) like button 2 (finish). */
5934 if (op
== XCF_Continue_Element
&& areawin
->selects
> 1)
5935 op
= XCF_Finish_Element
;
5937 switch(ELEMENTTYPE(editpart
)) {
5939 pathptr newpath
= (pathptr
)editpart
;
5940 short dotrack
= True
;
5943 areawin
->attachto
= -1;
5945 if (op
!= XCF_Continue_Element
) {
5948 if (op
== XCF_Continue_Element
) {
5949 nextpathcycle(newpath
, 1);
5950 patheditpush(newpath
);
5952 else if (op
== XCF_Finish_Element
) {
5953 path_mode_draw(xcDRAW_FINAL
, newpath
);
5954 incr_changes(topobject
);
5956 else { /* restore previous path from edit stack */
5957 free_single((genericptr
)newpath
);
5958 if (areawin
->editstack
->parts
> 0) {
5959 if (op
== XCF_Cancel
) {
5960 editpath
= TOPATH(areawin
->editstack
->plist
);
5961 pathcopy(newpath
, editpath
);
5962 reset(areawin
->editstack
, NORMAL
);
5965 editpath
= TOPATH(areawin
->editstack
->plist
+
5966 areawin
->editstack
->parts
- 1);
5967 pathcopy(newpath
, editpath
);
5968 free_single((genericptr
)editpath
);
5970 areawin
->editstack
->parts
--;
5972 if (areawin
->editstack
->parts
> 0) {
5974 nextpathcycle(newpath
, 1);
5975 path_mode_draw(xcDRAW_EDIT
, newpath
);
5979 user_to_window(areawin
->origin
, &warppt
);
5980 warppointer(warppt
.x
, warppt
.y
);
5981 path_mode_draw(xcDRAW_FINAL
, newpath
);
5985 path_mode_draw(xcDRAW_EMPTY
, newpath
);
5987 free_single((genericptr
)newpath
);
5991 pwriteback(areawin
->topinstance
);
5994 /* Free the editstack */
5995 reset(areawin
->editstack
, NORMAL
);
5996 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
5997 (xcEventHandler
)trackelement
, NULL
);
5998 eventmode
= NORMAL_MODE
;
6004 if (eventmode
== BOX_MODE
) {
6007 newbox
= (polyptr
)editpart
;
6009 /* prevent length and/or width zero boxes */
6010 if (newbox
->points
->x
!= (newbox
->points
+ 2)->x
&& (newbox
->points
6011 + 1)->y
!= (newbox
->points
+ 3)->y
) {
6012 if (op
!= XCF_Cancel
) {
6013 poly_mode_draw(xcDRAW_FINAL
, newbox
);
6014 incr_changes(topobject
);
6015 if (!nonnetwork(newbox
)) invalidate_netlist(topobject
);
6016 register_for_undo(XCF_Box
, UNDO_MORE
, areawin
->topinstance
,
6020 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6021 free_single((genericptr
)newbox
);
6028 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6029 free_single((genericptr
)newbox
);
6034 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6035 (xcEventHandler
)trackbox
, NULL
);
6036 eventmode
= NORMAL_MODE
;
6038 else { /* EPOLY_MODE */
6040 short dotrack
= True
;
6042 newpoly
= (polyptr
)editpart
;
6043 areawin
->attachto
= -1;
6045 if (op
!= XCF_Continue_Element
) {
6049 if (op
== XCF_Continue_Element
) {
6050 nextpolycycle(&newpoly
, 1);
6051 polyeditpush(newpoly
);
6053 else if (op
== XCF_Finish_Element
) {
6055 /* Check for degenerate polygons (all points the same). */
6057 for (i
= 1; i
< newpoly
->number
; i
++)
6058 if ((newpoly
->points
[i
].x
!= newpoly
->points
[i
- 1].x
) ||
6059 (newpoly
->points
[i
].y
!= newpoly
->points
[i
- 1].y
))
6061 if (i
== newpoly
->number
) {
6062 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6063 /* Remove this polygon with the standard delete */
6064 /* method (saves polygon on undo stack). */
6065 newpoly
->type
|= REMOVE_TAG
;
6066 delete_tagged(areawin
->topinstance
);
6069 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6070 if (!nonnetwork(newpoly
)) invalidate_netlist(topobject
);
6071 incr_changes(topobject
);
6076 free_single((genericptr
)newpoly
);
6077 if (areawin
->editstack
->parts
> 0) {
6078 if (op
== XCF_Cancel
) {
6079 editpoly
= TOPOLY(areawin
->editstack
->plist
);
6080 polycopy(newpoly
, editpoly
);
6081 reset(areawin
->editstack
, NORMAL
);
6084 editpoly
= TOPOLY(areawin
->editstack
->plist
+
6085 areawin
->editstack
->parts
- 1);
6086 polycopy(newpoly
, editpoly
);
6087 free_single((genericptr
)editpoly
);
6089 areawin
->editstack
->parts
--;
6091 if (areawin
->editstack
->parts
> 0) {
6093 nextpolycycle(&newpoly
, -1);
6094 poly_mode_draw(xcDRAW_EDIT
, newpoly
);
6097 XcTopSetForeground(newpoly
->color
);
6098 user_to_window(areawin
->origin
, &warppt
);
6099 warppointer(warppt
.x
, warppt
.y
);
6100 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6104 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6109 pwriteback(areawin
->topinstance
);
6112 /* Free the editstack */
6113 reset(areawin
->editstack
, NORMAL
);
6115 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6116 (xcEventHandler
)trackelement
, NULL
);
6117 eventmode
= NORMAL_MODE
;
6124 arcptr newarc
, editarc
;
6125 short dotrack
= True
;
6127 newarc
= (arcptr
)editpart
;
6129 if (op
!= XCF_Continue_Element
) {
6133 if (op
== XCF_Continue_Element
) {
6134 nextarccycle(&newarc
, 1);
6135 arceditpush(newarc
);
6138 else if (op
== XCF_Finish_Element
) {
6141 if (newarc
->radius
!= 0 && newarc
->yaxis
!= 0 &&
6142 (newarc
->angle1
!= newarc
->angle2
)) {
6143 XTopSetForeground(newarc
->color
);
6144 incr_changes(topobject
);
6145 if (eventmode
== ARC_MODE
) {
6146 register_for_undo(XCF_Arc
, UNDO_MORE
, areawin
->topinstance
,
6149 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6153 /* Remove the record if the radius is zero. If we were */
6154 /* creating the arc, just delete it; it's as if it */
6155 /* never existed. If we were editing an arc, use the */
6156 /* standard delete method (saves arc on undo stack). */
6158 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6159 if (eventmode
== ARC_MODE
) {
6160 free_single((genericptr
)newarc
);
6165 newarc
->type
|= REMOVE_TAG
;
6166 delete_tagged(areawin
->topinstance
);
6170 else { /* Cancel: restore previous arc from edit stack */
6171 free_single((genericptr
)newarc
);
6172 if (areawin
->editstack
->parts
> 0) {
6173 if (op
== XCF_Cancel
) {
6174 editarc
= TOARC(areawin
->editstack
->plist
);
6175 arccopy(newarc
, editarc
);
6176 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6177 reset(areawin
->editstack
, NORMAL
);
6180 editarc
= TOARC(areawin
->editstack
->plist
+
6181 areawin
->editstack
->parts
- 1);
6182 arccopy(newarc
, editarc
);
6183 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6184 free_single((genericptr
)editarc
);
6186 areawin
->editstack
->parts
--;
6188 if (areawin
->editstack
->parts
> 0) {
6190 nextarccycle(&newarc
, -1);
6191 arc_mode_draw(xcDRAW_EDIT
, newarc
);
6194 if (eventmode
!= ARC_MODE
) {
6196 user_to_window(areawin
->origin
, &warppt
);
6197 warppointer(warppt
.x
, warppt
.y
);
6199 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6203 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6207 pwriteback(areawin
->topinstance
);
6210 /* Free the editstack */
6211 reset(areawin
->editstack
, NORMAL
);
6213 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6214 (xcEventHandler
)trackarc
, NULL
);
6215 eventmode
= NORMAL_MODE
;
6220 splineptr editspline
;
6221 short dotrack
= True
;
6223 newspline
= (splineptr
)editpart
;
6225 if (op
!= XCF_Continue_Element
) {
6229 if (op
== XCF_Continue_Element
) {
6230 /* Note: we work backwards through spline control points. */
6231 /* The reason is that when creating a spline, the sudden */
6232 /* move from the endpoint to the startpoint (forward */
6233 /* direction) is more disorienting than moving from the */
6234 /* endpoint to the endpoint's control point. */
6236 nextsplinecycle(&newspline
, -1);
6237 splineeditpush(newspline
);
6240 /* unlikely but possible to create zero-length splines */
6241 else if (newspline
->ctrl
[0].x
!= newspline
->ctrl
[3].x
||
6242 newspline
->ctrl
[0].x
!= newspline
->ctrl
[1].x
||
6243 newspline
->ctrl
[0].x
!= newspline
->ctrl
[2].x
||
6244 newspline
->ctrl
[0].y
!= newspline
->ctrl
[3].y
||
6245 newspline
->ctrl
[0].y
!= newspline
->ctrl
[1].y
||
6246 newspline
->ctrl
[0].y
!= newspline
->ctrl
[2].y
) {
6247 if (op
== XCF_Finish_Element
) {
6248 incr_changes(topobject
);
6249 if (eventmode
== SPLINE_MODE
) {
6250 register_for_undo(XCF_Spline
, UNDO_MORE
, areawin
->topinstance
,
6253 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6255 else { /* restore previous spline from edit stack */
6256 free_single((genericptr
)newspline
);
6257 if (areawin
->editstack
->parts
> 0) {
6258 if (op
== XCF_Cancel
) {
6259 editspline
= TOSPLINE(areawin
->editstack
->plist
);
6260 splinecopy(newspline
, editspline
);
6261 reset(areawin
->editstack
, NORMAL
);
6264 editspline
= TOSPLINE(areawin
->editstack
->plist
+
6265 areawin
->editstack
->parts
- 1);
6266 splinecopy(newspline
, editspline
);
6267 free_single((genericptr
)editspline
);
6269 areawin
->editstack
->parts
--;
6271 if (areawin
->editstack
->parts
> 0) {
6273 nextsplinecycle(&newspline
, 1);
6274 spline_mode_draw(xcDRAW_EDIT
, newspline
);
6277 if (eventmode
!= SPLINE_MODE
) {
6279 user_to_window(areawin
->origin
, &warppt
);
6280 warppointer(warppt
.x
, warppt
.y
);
6282 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6286 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6292 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6293 free_single((genericptr
)newspline
);
6297 pwriteback(areawin
->topinstance
);
6300 /* Free the editstack */
6301 reset(areawin
->editstack
, NORMAL
);
6303 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6304 (xcEventHandler
)trackelement
, NULL
);
6305 eventmode
= NORMAL_MODE
;
6310 calcbbox(areawin
->topinstance
);
6312 /* Multiple-element edit: Some items may have been moved as */
6313 /* opposed to edited, and should be registered here. To do */
6314 /* this correctly, we must first unselect the edited items, */
6315 /* then register the move for the remaining items. */
6320 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6321 areawin
->selects
; eselect
++)
6322 checkcycle(SELTOGENERIC(eselect
), 0);
6324 /* Remove all (remaining) cycles */
6325 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6326 areawin
->selects
; eselect
++)
6327 removecycle(SELTOGENERICPTR(eselect
));
6329 /* Remove edits from the undo stack when canceling */
6330 if (op
== XCF_Cancel
|| op
== XCF_Cancel_Last
) {
6331 if (xobjs
.undostack
&& (xobjs
.undostack
->type
== XCF_Edit
)) {
6332 undo_finish_series();
6339 /*-------------------------------------------------------*/
6340 /* Recalculate values for a drawing-area widget resizing */
6341 /*-------------------------------------------------------*/
6343 void resizearea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6349 int savewidth
= areawin
->width
, saveheight
= areawin
->height
;
6350 XCWindowData
*thiswin
;
6353 #endif /* !HAVE_CAIRO */
6354 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6356 if ((dpy
!= NULL
) && xcIsRealized(areawin
->area
)) {
6359 areawin
->width
= Tk_Width(w
);
6360 areawin
->height
= Tk_Height(w
);
6362 XtSetArg(wargs
[0], XtNwidth
, &areawin
->width
);
6363 XtSetArg(wargs
[1], XtNheight
, &areawin
->height
);
6364 XtGetValues(areawin
->area
, wargs
, 2);
6367 if (areawin
->width
!= savewidth
|| areawin
->height
!= saveheight
) {
6369 int maxwidth
= 0, maxheight
= 0;
6370 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6371 if (thiswin
->width
> maxwidth
) maxwidth
= thiswin
->width
;
6372 if (thiswin
->height
> maxheight
) maxheight
= thiswin
->height
;
6374 #if !defined(HAVE_CAIRO)
6375 if (dbuf
!= (Pixmap
)NULL
) XFreePixmap(dpy
, dbuf
);
6376 dbuf
= XCreatePixmap(dpy
, areawin
->window
, maxwidth
, maxheight
,
6377 DefaultDepthOfScreen(xcScreen(w
)));
6380 /* TODO: probably make this a generalized function call, which */
6381 /* should be handled depending on the surface in the xtgui.c, */
6382 /* xcwin32.c, etc. files. */
6383 /* For now only support xlib surface */
6384 cairo_xlib_surface_set_size(areawin
->surface
, areawin
->width
,
6387 if (areawin
->clipmask
!= (Pixmap
)NULL
) XFreePixmap(dpy
, areawin
->clipmask
);
6388 areawin
->clipmask
= XCreatePixmap(dpy
, areawin
->window
,
6389 maxwidth
, maxheight
, 1);
6391 if (areawin
->pbuf
!= (Pixmap
)NULL
) {
6392 XFreePixmap(dpy
, areawin
->pbuf
);
6393 areawin
->pbuf
= XCreatePixmap(dpy
, areawin
->window
,
6394 maxwidth
, maxheight
, 1);
6397 if (areawin
->cmgc
!= (GC
)NULL
) XFreeGC(dpy
, areawin
->cmgc
);
6398 values
.foreground
= 0;
6399 values
.background
= 0;
6400 areawin
->cmgc
= XCreateGC(dpy
, areawin
->clipmask
,
6401 GCForeground
| GCBackground
, &values
);
6402 #endif /* !HAVE_CAIRO */
6404 /* Clear fixed_pixmap */
6405 if (areawin
->fixed_pixmap
) {
6407 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6408 areawin
->fixed_pixmap
= NULL
;
6409 #else /* !HAVE_CAIRO */
6410 XFreePixmap(dpy
, areawin
->fixed_pixmap
);
6411 areawin
->fixed_pixmap
= (Pixmap
) NULL
;
6412 #endif /* !HAVE_CAIRO */
6417 /* Re-compose the directores to match the new dimensions */
6419 composelib(PAGELIB
);
6421 /* Re-center image in resized window */
6422 zoomview(NULL
, NULL
, NULL
);
6425 /* Flush all expose events from the buffer */
6426 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
) == True
);
6430 /*----------------------*/
6431 /* Draw the grids, etc. */
6432 /*----------------------*/
6435 void draw_grids(void)
6437 float x
, y
, spc
, spc2
, i
, j
, fpart
;
6438 float major_snapspace
, spc3
;
6440 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
6441 if (areawin
->gridon
&& spc
> 8) {
6442 fpart
= (float)(-areawin
->pcorner
.x
)
6443 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6444 x
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6445 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6446 fpart
= (float)(-areawin
->pcorner
.y
)
6447 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6448 y
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6449 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6451 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6452 for (i
= x
; i
< (float)areawin
->width
; i
+= spc
)
6453 DrawLine (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6454 0, (int)(i
+ 0.5), areawin
->height
);
6455 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc
)
6456 DrawLine (dpy
, areawin
->window
, areawin
->gc
, 0, (int)(j
- 0.5),
6457 areawin
->width
, (int)(j
- 0.5));
6460 if (areawin
->axeson
) {
6461 XPoint originpt
, zeropt
;
6462 zeropt
.x
= zeropt
.y
= 0;
6463 SetForeground(dpy
, areawin
->gc
, AXESCOLOR
);
6464 user_to_window(zeropt
, &originpt
);
6465 DrawLine(dpy
, areawin
->window
, areawin
->gc
, originpt
.x
, 0,
6466 originpt
.x
, areawin
->height
);
6467 DrawLine(dpy
, areawin
->window
, areawin
->gc
, 0, originpt
.y
,
6468 areawin
->width
, originpt
.y
);
6471 /* bounding box goes beneath everything except grid/axis lines */
6474 /* draw a little red dot at each snap-to point */
6476 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
6477 if (areawin
->snapto
&& spc2
> 8) {
6480 fpart
= (float)(-areawin
->pcorner
.x
)
6481 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6482 x2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6483 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6484 fpart
= (float)(-areawin
->pcorner
.y
)
6485 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6486 y2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6487 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6489 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6491 HDC hdc
= CreateCompatibleDC(NULL
);
6492 SelectObject(hdc
, Tk_GetHWND(areawin
->window
));
6494 SetForeground(dpy
, areawin
->gc
, SNAPCOLOR
);
6495 for (i
= x2
; i
< areawin
->width
; i
+= spc2
)
6496 for (j
= areawin
->height
- y2
; j
> 0; j
-= spc2
)
6497 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6498 SetPixelV(hdc
, (int)(i
+ 0.5), (int)(j
- 0.05), areawin
->gc
->foreground
);
6500 DrawPoint (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6502 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6508 /* Draw major snap points (code contributed by John Barry) */
6510 major_snapspace
= xobjs
.pagelist
[areawin
->page
]->gridspace
* 20;
6511 spc3
= major_snapspace
* areawin
->vscale
;
6513 fpart
= (float)(-areawin
->pcorner
.x
) / major_snapspace
;
6514 x
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6515 fpart
= (float)(-areawin
->pcorner
.y
) / major_snapspace
;
6516 y
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6518 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6519 for (i
= x
; i
< (float)areawin
->width
; i
+= spc3
) {
6520 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc3
) {
6521 XDrawArc(dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5) - 1,
6522 (int)(j
- 0.5) - 1, 2, 2, 0, 360*64);
6527 SetBackground(dpy
, areawin
->gc
, BACKGROUND
);
6529 #endif /* !HAVE_CAIRO */
6531 /*------------------------------------------------------*/
6532 /* Draw fixed parts of the primary graphics window */
6533 /*------------------------------------------------------*/
6535 void draw_fixed(void)
6537 Boolean old_ongoing
;
6540 #endif /* !HAVE_CAIRO */
6542 if (xobjs
.suspend
>= 0) return;
6543 old_ongoing
= areawin
->redraw_ongoing
;
6544 areawin
->redraw_ongoing
= True
;
6546 /* Set drawing context to fixed_pixmap */
6548 cairo_identity_matrix(areawin
->cr
);
6549 cairo_push_group(areawin
->cr
);
6550 #else /* HAVE_CAIRO */
6551 old_window
= areawin
->window
;
6552 areawin
->window
= areawin
->fixed_pixmap
;
6553 #endif /* HAVE_CAIRO */
6555 /* Clear background */
6557 if (xobjs
.pagelist
[areawin
->page
]->background
.name
!= (char *)NULL
) {
6561 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6562 cairo_paint(areawin
->cr
);
6563 #endif /* HAVE_GS */
6566 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6567 cairo_paint(areawin
->cr
);
6569 #else /* HAVE_CAIRO */
6570 if (xobjs
.pagelist
[areawin
->page
]->background
.name
== (char *)NULL
6571 || (copybackground() < 0)) {
6572 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6573 XFillRectangle(dpy
, areawin
->window
, areawin
->gc
, 0, 0, areawin
->width
,
6576 SetThinLineAttributes(dpy
, areawin
->gc
, 0, LineSolid
, CapRound
, JoinBevel
);
6577 #endif /* !HAVE_CAIRO */
6581 /* draw GRIDCOLOR lines for grid; mark axes in AXESCOLOR */
6583 if (eventmode
!= CATALOG_MODE
&& eventmode
!= ASSOC_MODE
6584 && eventmode
!= FONTCAT_MODE
&& eventmode
!= EFONTCAT_MODE
6585 && eventmode
!= CATMOVE_MODE
&& eventmode
!= CATTEXT_MODE
) {
6589 /* Determine the transformation matrix for the topmost object */
6590 /* and draw the hierarchy above the current edit object (if */
6591 /* "edit-in-place" is selected). */
6593 if (areawin
->editinplace
== True
) {
6594 if (areawin
->stack
!= NULL
) {
6595 pushlistptr lastlist
= NULL
, thislist
;
6598 UPushCTM(); /* save our current state */
6600 /* It's easiest if we first push the current page onto the stack, */
6601 /* then we don't need to treat the top-level page separately. We */
6602 /* pop it at the end. */
6603 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
6605 thislist
= areawin
->stack
;
6607 while ((thislist
!= NULL
) &&
6608 (is_library(thislist
->thisinst
->thisobject
) < 0)) {
6610 /* Invert the transformation matrix of the instance on the stack */
6611 /* to get the proper transformation matrix of the drawing one */
6612 /* up in the hierarchy. */
6615 UPreMultCTM(&mtmp
, thislist
->thisinst
->position
,
6616 thislist
->thisinst
->scale
, thislist
->thisinst
->rotation
);
6618 UPreMultCTMbyMat(DCTM
, &mtmp
);
6620 lastlist
= thislist
;
6621 thislist
= thislist
->next
;
6623 /* The following will be true for moves between schematics and symbols */
6624 if ((thislist
!= NULL
) && (thislist
->thisinst
->thisobject
->symschem
6625 == lastlist
->thisinst
->thisobject
))
6629 if (lastlist
!= NULL
) {
6630 pushlistptr stack
= NULL
;
6631 SetForeground(dpy
, areawin
->gc
, OFFBUTTONCOLOR
);
6632 UDrawObject(lastlist
->thisinst
, SINGLE
, DOFORALL
,
6633 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &stack
);
6634 /* This shouldn't happen, but just in case. . . */
6635 if (stack
) free_stack(&stack
);
6638 pop_stack(&areawin
->stack
); /* restore the original stack state */
6639 UPopCTM(); /* restore the original matrix state */
6644 /* draw all of the elements on the screen */
6646 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
6648 /* Initialize hierstack */
6649 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6650 UDrawObject(areawin
->topinstance
, TOPLEVEL
, FOREGROUND
,
6651 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &areawin
->hierstack
);
6652 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6655 if (areawin
->fixed_pixmap
)
6656 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6657 areawin
->fixed_pixmap
= cairo_pop_group(areawin
->cr
);
6658 #else /* HAVE_CAIRO */
6659 areawin
->window
= old_window
;
6660 #endif /* HAVE_CAIRO */
6661 areawin
->redraw_ongoing
= old_ongoing
;
6664 /*--------------------------------------*/
6665 /* Draw the primary graphics window */
6666 /*--------------------------------------*/
6668 void drawwindow(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6671 xcDrawType redrawtype
= xcDRAW_EDIT
;
6672 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6674 if (areawin
->area
== NULL
) return;
6675 if (!xcIsRealized(areawin
->area
)) return;
6676 if (xobjs
.suspend
>= 0) return;
6679 /* Make sure a fixed pixmap exists */
6680 if (!areawin
->fixed_pixmap
) {
6681 areawin
->fixed_pixmap
= XCreatePixmap(dpy
, areawin
->window
,
6682 areawin
->width
, areawin
->height
,
6683 DefaultDepthOfScreen(xcScreen(areawin
->area
)));
6685 #endif /* !HAVE_CAIRO */
6687 /* Sanity check---specifically to track down an error */
6688 if ((areawin
->selects
== 1) && *(areawin
->selectlist
) >= topobject
->parts
) {
6689 Wprintf("Internal error!");
6690 areawin
->selects
= 0;
6694 if (areawin
->redraw_needed
)
6695 redrawtype
= xcREDRAW_FORCED
;
6697 switch (eventmode
) {
6698 case ARC_MODE
: case EARC_MODE
:
6699 arc_mode_draw(redrawtype
, TOARC(EDITPART
));
6701 case SPLINE_MODE
: case ESPLINE_MODE
:
6702 spline_mode_draw(redrawtype
, TOSPLINE(EDITPART
));
6704 case BOX_MODE
: case EPOLY_MODE
: case WIRE_MODE
:
6705 poly_mode_draw(redrawtype
, TOPOLY(EDITPART
));
6708 path_mode_draw(redrawtype
, TOPATH(EDITPART
));
6710 case TEXT_MODE
: case CATTEXT_MODE
: case ETEXT_MODE
:
6711 text_mode_draw(redrawtype
, TOLABEL(EDITPART
));
6714 selarea_mode_draw(redrawtype
, NULL
);
6717 rescale_mode_draw(redrawtype
, NULL
);
6719 case CATMOVE_MODE
: case MOVE_MODE
: case COPY_MODE
:
6720 move_mode_draw(redrawtype
, NULL
);
6722 case ASSOC_MODE
: case EINST_MODE
: case FONTCAT_MODE
: case EFONTCAT_MODE
:
6723 case PAN_MODE
: case NORMAL_MODE
: case UNDO_MODE
: case CATALOG_MODE
:
6724 normal_mode_draw(redrawtype
, NULL
);
6727 /* flush out multiple expose/resize events from the event queue */
6728 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
));
6730 /* end by restoring graphics state */
6731 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
6733 areawin
->redraw_needed
= False
;
6736 /*----------------------------------------------------------------------*/
6737 /* Draw the current window (areawin). Check if other windows contain */
6738 /* the same object or one of its ancestors. If so, redraw them, too. */
6739 /*----------------------------------------------------------------------*/
6741 void drawarea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6743 XCWindowDataPtr thiswin
, focuswin
;
6745 if (xobjs
.suspend
>= 0) {
6746 if (xobjs
.suspend
== 0)
6747 xobjs
.suspend
= 1; /* Mark that a refresh is pending */
6753 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6754 if (thiswin
== focuswin
) continue;
6756 /* Note: need to check ancestry here, not just blindly redraw */
6757 /* all the windows all the time. */
6761 /* Don't respond to an expose event if the graphics context */
6762 /* has not yet been created. */
6763 if (areawin
->cr
!= NULL
)
6765 drawwindow(NULL
, NULL
, NULL
);
6768 drawwindow(w
, clientdata
, calldata
);
6771 /*-------------------------------------------------------------------------*/