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 /* forward declaration */
2362 extern int utf8_reverse_lookup(char *);
2364 /*------------------------------------------------------*/
2365 /* Get a canonical signature for a button/key event */
2366 /*------------------------------------------------------*/
2368 int getkeysignature(XKeyEvent
*event
)
2371 int keywstate
; /* KeySym with prepended state information */
2373 int utf8enc
; /* 8-bit value bound to UTF-8 encoding */
2377 static XIM xim
= NULL
;
2378 static XIC xic
= NULL
;
2381 if (event
->keycode
== 0 && event
->state
== 0)
2384 XLookupString(event
, _STR
, 150, &keypressed
, NULL
);
2386 /* Ignore Shift, Control, Caps Lock, and Meta (Alt) keys */
2387 /* when pressed alone. */
2389 if (keypressed
== XK_Control_L
|| keypressed
== XK_Control_R
||
2390 keypressed
== XK_Alt_L
|| keypressed
== XK_Alt_R
||
2391 keypressed
== XK_Caps_Lock
|| keypressed
== XK_Shift_L
||
2392 keypressed
== XK_Shift_R
)
2395 /* Only keep key state information pertaining to Shift, Caps Lock, */
2396 /* Control, and Alt (Meta) */
2398 keywstate
= (keypressed
& 0xffff);
2400 /* Convert codes outside the character (0 - 255) range but within */
2401 /* the ISO-Latin1,...,9 encoding scheme (256-5120). X11 has unique */
2402 /* keysyms for each character, but the ISO-Latin encodings define */
2403 /* mappings to the 8-bit (256) character set. */
2405 if (keywstate
>= 256 && keywstate
< 5120)
2406 keywstate
= XKeysymToKeycode(dpy
, (KeySym
)keywstate
);
2408 if (event
->keycode
!= 0) { /* Only for actual key events */
2410 /* Get keyboard input method */
2412 xim
= XOpenIM(dpy
, 0, 0, 0);
2413 xic
= XCreateIC(xim
,
2414 XNInputStyle
, XIMPreeditNothing
| XIMStatusNothing
,
2415 XNClientWindow
, areawin
->window
,
2416 XNFocusWindow
, areawin
->window
,
2421 /* Do a UTF-8 code lookup */
2422 Xutf8LookupString(xic
, event
, buffer
, 15, &keysym
, &status
);
2423 /* Convert a UTF-8 code to a known encoding */
2424 utf8enc
= utf8_reverse_lookup(buffer
);
2425 if ((utf8enc
!= -1) && (utf8enc
!= (keywstate
& 0xff))) keywstate
= utf8enc
;
2429 /* ASCII values already come upper/lowercase; we only want to register */
2430 /* a Shift key if it's a non-ASCII key or another modifier is in effect */
2432 keywstate
|= (((LockMask
| ControlMask
| Mod1Mask
) & event
->state
) << 16);
2433 if (keywstate
> 255) keywstate
|= ((ShiftMask
& event
->state
) << 16);
2435 /* Treat button events and key events in the same way by setting */
2436 /* a key state for buttons */
2438 if (keypressed
== 0)
2439 keywstate
|= (((Button1Mask
| Button2Mask
| Button3Mask
| Button4Mask
|
2440 Button5Mask
| ShiftMask
)
2441 & event
->state
) << 16);
2446 /*------------------------*/
2447 /* Handle keyboard inputs */
2448 /*------------------------*/
2450 void keyhandler(xcWidget w
, caddr_t clientdata
, XKeyEvent
*event
)
2452 int keywstate
; /* KeySym with prepended state information */
2454 UNUSED(w
); UNUSED(clientdata
);
2457 if (popups
> 0) return;
2459 if (popups
> 0 && help_up
== 0) return;
2462 if ((event
->type
== KeyRelease
) || (event
->type
== ButtonRelease
)) {
2464 /* Register a "tap" event if a key or button was released */
2465 /* while a timeout event is pending. */
2467 if (areawin
->time_id
!= 0) {
2468 xcRemoveTimeOut(areawin
->time_id
);
2469 areawin
->time_id
= 0;
2470 keywstate
= getkeysignature(event
);
2471 eventdispatch(keywstate
, areawin
->save
.x
, areawin
->save
.y
);
2474 keywstate
= getkeysignature(event
);
2475 if ((pressmode
!= 0) && (keywstate
== pressmode
)) {
2476 /* Events that require hold & drag (namely, MOVE_MODE) */
2477 /* must be resolved here. Call finish_op() to ensure */
2478 /* that we restore xcircuit to a state of sanity. */
2480 finish_op(XCF_Finish
, event
->x
, event
->y
);
2482 if (areawin
->redraw_needed
)
2483 drawarea(NULL
, NULL
, NULL
);
2485 return; /* Ignore all other release events */
2489 /* Check if any bindings match key/button "hold". If so, then start */
2490 /* the timer and wait for key release or timeout. */
2493 keywstate
= getkeysignature(event
);
2494 if ((keywstate
!= -1) && (xobjs
.hold
== TRUE
)) {
2496 /* Establish whether a HOLD modifier binding would apply in */
2497 /* the current eventmode. If so, set the HOLD timer. */
2499 func
= boundfunction(areawin
->area
, keywstate
| HOLD_MASK
, NULL
);
2501 areawin
->save
.x
= event
->x
;
2502 areawin
->save
.y
= event
->y
;
2503 areawin
->time_id
= xcAddTimeOut(app
, PRESSTIME
,
2504 makepress
, (ClientData
)((pointertype
)keywstate
));
2509 eventdispatch(keywstate
, event
->x
, event
->y
);
2513 /*--------------------------------*/
2514 /* Set snap spacing from keyboard */
2515 /*--------------------------------*/
2517 void setsnap(short direction
)
2519 float oldsnap
= xobjs
.pagelist
[areawin
->page
]->snapspace
;
2522 if (direction
> 0) xobjs
.pagelist
[areawin
->page
]->snapspace
*= 2;
2525 xobjs
.pagelist
[areawin
->page
]->snapspace
/= 2;
2527 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2528 Wprintf("Snap space at minimum value of %s", buffer
);
2531 if (xobjs
.pagelist
[areawin
->page
]->snapspace
!= oldsnap
) {
2532 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2533 Wprintf("Snap spacing set to %s", buffer
);
2534 areawin
->redraw_needed
= True
;
2535 drawarea(NULL
, NULL
, NULL
);
2539 /*-----------------------------------------*/
2540 /* Reposition an object onto the snap grid */
2541 /*-----------------------------------------*/
2546 Boolean preselected
;
2548 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
2549 if (!checkselect(ALL_TYPES
)) return;
2550 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
2551 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
2552 + areawin
->selects
; selectobj
++) {
2553 easydraw(*selectobj
, DOFORALL
);
2554 switch(SELECTTYPE(selectobj
)) {
2556 objinstptr snapobj
= SELTOOBJINST(selectobj
);
2558 u2u_snap(&snapobj
->position
);
2561 graphicptr snapg
= SELTOGRAPHIC(selectobj
);
2563 u2u_snap(&snapg
->position
);
2566 labelptr snaplabel
= SELTOLABEL(selectobj
);
2568 u2u_snap(&snaplabel
->position
);
2571 polyptr snappoly
= SELTOPOLY(selectobj
);
2572 pointlist snappoint
;
2574 for (snappoint
= snappoly
->points
; snappoint
< snappoly
->points
+
2575 snappoly
->number
; snappoint
++)
2576 u2u_snap(snappoint
);
2579 arcptr snaparc
= SELTOARC(selectobj
);
2581 u2u_snap(&snaparc
->position
);
2582 if (areawin
->snapto
) {
2583 snaparc
->radius
= (snaparc
->radius
/
2584 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2585 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2586 snaparc
->yaxis
= (snaparc
->yaxis
/
2587 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2588 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2593 splineptr snapspline
= SELTOSPLINE(selectobj
);
2596 for (i
= 0; i
< 4; i
++)
2597 u2u_snap(&snapspline
->ctrl
[i
]);
2598 calcspline(snapspline
);
2601 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
2602 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
2603 easydraw(*selectobj
, DOFORALL
);
2606 select_invalidate_netlist();
2607 if (eventmode
== NORMAL_MODE
)
2612 /*----------------------------------------------*/
2613 /* Routines to print the cursor position */
2614 /*----------------------------------------------*/
2616 /*----------------------------------------------*/
2617 /* fast integer power-of-10 routine */
2618 /*----------------------------------------------*/
2626 case 0: return 1; break;
2627 case 1: return 10; break;
2628 case 2: return 100; break;
2629 case 3: return 1000; break;
2632 for (i
= 1; i
< a
+ 1; i
++) istr
[i
] = '0';
2639 /*--------------------------------------------------*/
2640 /* find greatest common factor between two integers */
2641 /*--------------------------------------------------*/
2643 int calcgcf(int a
, int b
)
2647 if ((mod
= a
% b
) == 0) return (b
);
2648 else return (calcgcf(b
, mod
));
2651 /*--------------------------------------------------------------*/
2652 /* generate a fraction from a float, if possible */
2653 /* fraction returned as a string (must be allocated beforehand) */
2654 /*--------------------------------------------------------------*/
2656 void fraccalc(float xyval
, char *fstr
)
2659 int ip
, mant
, divisor
, denom
, numer
, rpart
;
2661 char num
[10], *nptr
= &num
[2], *sptr
;
2664 fp
= fabs(xyval
- ip
);
2666 /* write fractional part and grab mantissa as integer */
2668 sprintf(num
, "%1.7f", fp
);
2669 num
[8] = '\0'; /* no rounding up! */
2670 sscanf(nptr
, "%d", &mant
);
2672 if (mant
!= 0) { /* search for repeating substrings */
2673 for (i
= 1; i
<= 3; i
++) {
2676 while ((sptr
= nptr
- rept
* i
) >= &num
[2]) {
2677 for (t
= 0; t
< i
; t
++)
2678 if (*(sptr
+ t
) != *(nptr
+ t
)) break;
2682 if (rept
> 1) break;
2685 sscanf(nptr
, "%d", &rpart
); /* rpart is repeating part of mantissa */
2686 if (i
> 3 || rpart
== 0) { /* no repeat */
2687 divisor
= calcgcf(1000000, mant
);
2688 denom
= 1000000 / divisor
;
2694 sscanf(&num
[2], "%d", &z
);
2696 mant
= z
* p
+ rpart
;
2697 fd
= ipow10(nptr
- &num
[2]) * p
;
2699 divisor
= calcgcf(fd
, mant
);
2700 denom
= fd
/ divisor
;
2702 numer
= mant
/ divisor
;
2704 sprintf(fstr
, "%5.3f", xyval
);
2706 sprintf(fstr
, "%hd/%hd", (xyval
> 0) ? numer
: -numer
, denom
);
2708 sprintf(fstr
, "%hd %hd/%hd", ip
, numer
, denom
);
2710 else sprintf(fstr
, "%hd", ip
);
2713 /*------------------------------------------------------------------------------*/
2714 /* Print the position of the cursor in the upper right-hand message window */
2715 /*------------------------------------------------------------------------------*/
2717 void printpos(short xval
, short yval
)
2720 float oscale
, iscale
= (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
/
2721 (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
;
2724 XPoint
*tpoint
, *npoint
;
2728 /* For polygons, print the length (last line of a wire or polygon) or */
2729 /* length and width (box only) */
2731 if (eventmode
== BOX_MODE
|| eventmode
== EPOLY_MODE
|| eventmode
== WIRE_MODE
) {
2732 polyptr lwire
= (eventmode
== BOX_MODE
) ? TOPOLY(ENDPART
) : TOPOLY(EDITPART
);
2733 if ((eventmode
== EPOLY_MODE
) && (lwire
->number
> 2)) {
2734 /* sanity check on edit cycle */
2735 cycle
= (lwire
->cycle
) ? lwire
->cycle
->number
: -1;
2736 if (cycle
< 0 || cycle
>= lwire
->number
) {
2737 advancecycle((genericptr
*)(&lwire
), 0);
2740 tpoint
= lwire
->points
+ cycle
;
2741 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, 1);
2742 llen
= wirelength(tpoint
, npoint
);
2743 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, -1);
2744 lwid
= wirelength(tpoint
, npoint
);
2746 if (lwire
->style
& UNCLOSED
) { /* unclosed polys */
2749 else if (cycle
== lwire
->number
- 1) {
2754 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2760 else if (eventmode
== BOX_MODE
) {
2761 tpoint
= lwire
->points
;
2762 npoint
= lwire
->points
+ 1;
2763 llen
= wirelength(tpoint
, npoint
);
2764 npoint
= lwire
->points
+ 3;
2765 lwid
= wirelength(tpoint
, npoint
);
2766 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2774 tpoint
= lwire
->points
+ lwire
->number
- 1;
2775 llen
= wirelength(tpoint
- 1, tpoint
);
2779 else if (eventmode
== ARC_MODE
|| eventmode
== EARC_MODE
) {
2780 arcptr larc
= (eventmode
== ARC_MODE
) ? TOARC(ENDPART
) : TOARC(EDITPART
);
2781 llen
= larc
->radius
;
2782 if (abs(larc
->radius
) != larc
->yaxis
) {
2790 switch (xobjs
.pagelist
[areawin
->page
]->coordstyle
) {
2792 sprintf(_STR
, "%g, %g", xval
* iscale
, yval
* iscale
);
2793 sptr
= _STR
+ strlen(_STR
);
2796 sprintf(sptr
, " (%g x %g)", llen
* iscale
, lwid
* iscale
);
2798 sprintf(sptr
, " (length %g)", llen
* iscale
);
2802 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2803 f1
= ((float)(xval
) * iscale
* oscale
) / 72.0;
2804 f2
= ((float)(yval
) * iscale
* oscale
) / 72.0;
2805 sprintf(_STR
, "%5.3f, %5.3f in", f1
, f2
);
2806 sptr
= _STR
+ strlen(_STR
);
2808 f1
= ((float)(llen
) * iscale
* oscale
) / 72.0;
2810 f2
= ((float)(lwid
) * iscale
* oscale
) / 72.0;
2811 sprintf(sptr
, " (%5.3f x %5.3f in)", f1
, f2
);
2814 sprintf(sptr
, " (length %5.3f in)", f1
);
2818 char fstr1
[30], fstr2
[30];
2820 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2821 fraccalc((((float)(xval
) * iscale
* oscale
) / 72.0), fstr1
);
2822 fraccalc((((float)(yval
) * iscale
* oscale
) / 72.0), fstr2
);
2823 sprintf(_STR
, "%s, %s in", fstr1
, fstr2
);
2824 sptr
= _STR
+ strlen(_STR
);
2826 fraccalc((((float)(llen
) * iscale
* oscale
) / 72.0), fstr1
);
2828 fraccalc((((float)(lwid
) * iscale
* oscale
) / 72.0), fstr2
);
2829 sprintf(sptr
, " (%s x %s in)", fstr1
, fstr2
);
2832 sprintf(sptr
, " (length %s in)", fstr1
);
2836 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* CMSCALE
;
2837 f1
= ((float)(xval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2838 f2
= ((float)(yval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2839 sprintf(_STR
, "%5.3f, %5.3f cm", f1
, f2
);
2840 sptr
= _STR
+ strlen(_STR
);
2842 f1
= ((float)(llen
) * iscale
* oscale
) / IN_CM_CONVERT
;
2844 f2
= ((float)(lwid
) * iscale
* oscale
) / IN_CM_CONVERT
;
2845 sprintf(sptr
, " (%5.3f x %5.3f cm)", f1
, f2
);
2848 sprintf(sptr
, " (length %5.3f cm)", f1
);
2855 /*---------------------------------------------------*/
2856 /* Find nearest point of intersection of the cursor */
2857 /* position to a wire and move there. */
2858 /*---------------------------------------------------*/
2860 void findwirex(XPoint
*endpt1
, XPoint
*endpt2
, XPoint
*userpt
,
2861 XPoint
*newpos
, float *rot
)
2866 xsq
= sqwirelen(endpt1
, endpt2
);
2867 ysq
= sqwirelen(endpt1
, userpt
);
2868 zsq
= sqwirelen(endpt2
, userpt
);
2869 frac
= 0.5 + (float)(ysq
- zsq
) / (float)(xsq
<< 1);
2870 if (frac
> 1) frac
= 1;
2871 else if (frac
< 0) frac
= 0;
2872 newpos
->x
= endpt1
->x
+ (int)((endpt2
->x
- endpt1
->x
) * frac
);
2873 newpos
->y
= endpt1
->y
+ (int)((endpt2
->y
- endpt1
->y
) * frac
);
2875 *rot
= 180.0 + INVRFAC
* atan2((double)(endpt1
->x
-
2876 endpt2
->x
), (double)(endpt1
->y
- endpt2
->y
));
2879 /*----------------------------------------------------------------*/
2880 /* Find the closest point of attachment from the pointer position */
2881 /* to the "attachto" element. */
2882 /*----------------------------------------------------------------*/
2884 void findattach(XPoint
*newpos
, float *rot
, XPoint
*userpt
)
2886 XPoint
*endpt1
, *endpt2
;
2891 if (rot
) locrot
= *rot
;
2893 /* find point of intersection and slope */
2895 if (SELECTTYPE(&areawin
->attachto
) == ARC
) {
2896 arcptr aarc
= SELTOARC(&areawin
->attachto
);
2898 tmpang
= atan2((double)(userpt
->y
- aarc
->position
.y
) * (double)
2899 (abs(aarc
->radius
)), (double)(userpt
->x
- aarc
->position
.x
) *
2900 (double)aarc
->yaxis
);
2902 /* don't follow the arc beyond its endpoints */
2904 tmpdeg
= (float)(tmpang
* INVRFAC
);
2905 if (tmpdeg
< 0) tmpdeg
+= 360;
2906 if (((aarc
->angle2
> 360) && (tmpdeg
> aarc
->angle2
- 360) &&
2907 (tmpdeg
< aarc
->angle1
)) ||
2908 ((aarc
->angle1
< 0) && (tmpdeg
> aarc
->angle2
) &&
2909 (tmpdeg
< aarc
->angle1
+ 360)) ||
2910 ((aarc
->angle1
>= 0) && (aarc
->angle2
<= 360) && ((tmpdeg
2911 > aarc
->angle2
) || (tmpdeg
< aarc
->angle1
)))) {
2912 float testd1
= aarc
->angle1
- tmpdeg
;
2913 float testd2
= tmpdeg
- aarc
->angle2
;
2914 if (testd1
< 0) testd1
+= 360;
2915 if (testd2
< 0) testd2
+= 360;
2917 /* if arc is closed, attach to the line between the endpoints */
2919 if (!(aarc
->style
& UNCLOSED
)) {
2921 tmpang
= (double) aarc
->angle1
/ INVRFAC
;
2922 end1
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2923 end1
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2924 tmpang
= (double) aarc
->angle2
/ INVRFAC
;
2925 end2
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2926 end2
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2927 findwirex(&end1
, &end2
, userpt
, newpos
, &locrot
);
2928 if (rot
) *rot
= locrot
;
2932 tmpang
= (double)((testd1
< testd2
) ? aarc
->angle1
: aarc
->angle2
)
2936 /* get position in user coordinates nearest to the intersect pt */
2938 newpos
->x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2939 newpos
->y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2941 /* rotation of object is normal to the curve of the ellipse */
2944 *rot
= 90.0 - INVRFAC
* tmpang
;
2945 if (*rot
< 0.0) *rot
+= 360.0;
2948 else if (SELECTTYPE(&areawin
->attachto
) == SPLINE
) {
2949 splineptr aspline
= SELTOSPLINE(&areawin
->attachto
);
2950 frac
= findsplinemin(aspline
, userpt
);
2951 findsplinepos(aspline
, frac
, newpos
, &locrot
);
2952 if (rot
) *rot
= locrot
;
2954 else if (SELECTTYPE(&areawin
->attachto
) == OBJINST
) {
2956 objinstptr ainst
= SELTOOBJINST(&areawin
->attachto
);
2957 objectptr aobj
= ainst
->thisobject
;
2959 long testdist
, mindist
= 1e8
;
2962 /* In case instance has no pin labels, we will attach to */
2963 /* the instance's own origin. */
2965 mdpoint
.x
= mdpoint
.y
= 0;
2966 ReferencePosition(ainst
, &mdpoint
, newpos
);
2968 /* Find the nearest pin label in the object instance and attach to it */
2969 for (ggen
= aobj
->plist
; ggen
< aobj
->plist
+ aobj
->parts
; ggen
++) {
2970 if (ELEMENTTYPE(*ggen
) == LABEL
) {
2971 labelptr alab
= TOLABEL(ggen
);
2972 if (alab
->pin
== LOCAL
|| alab
->pin
== GLOBAL
) {
2973 ReferencePosition(ainst
, &alab
->position
, &mdpoint
);
2974 testdist
= sqwirelen(&mdpoint
, userpt
);
2975 if (testdist
< mindist
) {
2983 else if (SELECTTYPE(&areawin
->attachto
) == LABEL
) {
2984 /* Only one choice: Attach to the label position */
2985 labelptr alabel
= SELTOLABEL(&areawin
->attachto
);
2986 newpos
->x
= alabel
->position
.x
;
2987 newpos
->y
= alabel
->position
.y
;
2989 else if (SELECTTYPE(&areawin
->attachto
) == POLYGON
) {
2990 polyptr apoly
= SELTOPOLY(&areawin
->attachto
);
2991 XPoint
*testpt
, *minpt
, *nxtpt
;
2992 long mindist
= 1e8
, testdist
;
2993 minpt
= nxtpt
= apoly
->points
; /* so variables aren't uninitialized */
2994 for (testpt
= apoly
->points
; testpt
< apoly
->points
+
2995 apoly
->number
- 1; testpt
++) {
2996 testdist
= finddist(testpt
, testpt
+ 1, userpt
);
2997 if (testdist
< mindist
) {
3003 if (!(apoly
->style
& UNCLOSED
)) {
3004 testdist
= finddist(testpt
, apoly
->points
, userpt
);
3005 if (testdist
< mindist
) {
3008 nxtpt
= apoly
->points
;
3013 findwirex(endpt1
, endpt2
, userpt
, newpos
, &locrot
);
3014 if (rot
) *rot
= locrot
;
3018 /*--------------------------------------------*/
3019 /* Find closest point in a path to the cursor */
3020 /*--------------------------------------------*/
3022 XPoint
*pathclosepoint(pathptr dragpath
, XPoint
*newpos
)
3027 int mdist
= 1000000, tdist
;
3029 for (cpoint
= dragpath
->plist
; cpoint
< dragpath
->plist
+ dragpath
->parts
;
3031 switch(ELEMENTTYPE(*cpoint
)) {
3033 tdist
= wirelength(&(TOARC(cpoint
)->position
), newpos
);
3034 if (tdist
< mdist
) {
3036 rpoint
= &(TOARC(cpoint
)->position
);
3040 mpoint
= closepoint(TOPOLY(cpoint
), newpos
);
3041 tdist
= wirelength(TOPOLY(cpoint
)->points
+ mpoint
, newpos
);
3042 if (tdist
< mdist
) {
3044 rpoint
= TOPOLY(cpoint
)->points
+ mpoint
;
3048 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[0]), newpos
);
3049 if (tdist
< mdist
) {
3051 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[0]);
3053 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[3]), newpos
);
3054 if (tdist
< mdist
) {
3056 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[3]);
3064 /*-------------------------------------------*/
3065 /* Drag a selected element around the screen */
3066 /*-------------------------------------------*/
3068 void drag(int x
, int y
)
3071 Boolean eventcheck
= False
;
3073 short deltax
, deltay
;
3079 /* flush out multiple pointermotion events from the event queue */
3080 /* use only the last motion event */
3081 while (XCheckWindowEvent(dpy
, areawin
->window
, PointerMotionMask
|
3082 Button1MotionMask
, &again
) == True
) eventcheck
= True
;
3084 XButtonEvent
*event
= (XButtonEvent
*)(&again
);
3085 locx
= (int)event
->x
;
3086 locy
= (int)event
->y
;
3089 /* Determine if this event is supposed to be handled by */
3090 /* trackselarea(), or whether we should not be here at all */
3091 /* (button press and mouse movement in an unsupported mode) */
3093 if (eventmode
== SELAREA_MODE
) {
3097 else if (eventmode
== RESCALE_MODE
) {
3101 else if (eventmode
== PAN_MODE
) {
3102 trackpan(locx
, locy
);
3105 else if (eventmode
!= CATMOVE_MODE
&& eventmode
!= MOVE_MODE
3106 && eventmode
!= COPY_MODE
)
3109 snap(locx
, locy
, &userpt
);
3110 deltax
= userpt
.x
- areawin
->save
.x
;
3111 deltay
= userpt
.y
- areawin
->save
.y
;
3112 if (deltax
== 0 && deltay
== 0) return;
3114 areawin
->save
.x
= userpt
.x
;
3115 areawin
->save
.y
= userpt
.y
;
3117 /* set up the graphics state for moving a selected object */
3119 XTopSetForeground(SELECTCOLOR
);
3121 placeselects(deltax
, deltay
, &userpt
);
3123 /* restore graphics state */
3125 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
3127 /* print the position and other useful measurements */
3129 printpos(userpt
.x
, userpt
.y
);
3132 /*------------------------------------------------------*/
3133 /* Wrapper for drag() for xlib callback compatibility. */
3134 /*------------------------------------------------------*/
3136 void xlib_drag(xcWidget w
, caddr_t clientdata
, XEvent
*event
)
3138 XButtonEvent
*bevent
= (XButtonEvent
*)event
;
3139 UNUSED(w
); UNUSED(clientdata
);
3141 drag(bevent
->x
, bevent
->y
);
3142 if (areawin
->redraw_needed
)
3143 drawarea(NULL
, NULL
, NULL
);
3146 /*----------------------------------------------*/
3147 /* Rotate an element of a path */
3148 /*----------------------------------------------*/
3150 void elemrotate(genericptr
*genobj
, float direction
, XPoint
*position
)
3152 XPoint negpt
, *newpts
= (XPoint
*)NULL
;
3154 negpt
.x
= -position
->x
;
3155 negpt
.y
= -position
->y
;
3157 switch(ELEMENTTYPE(*genobj
)) {
3159 arcptr rotatearc
= TOARC(genobj
);
3160 rotatearc
->angle1
-= direction
;
3161 rotatearc
->angle2
-= direction
;
3162 if (rotatearc
->angle1
>= 360) {
3163 rotatearc
->angle1
-= 360;
3164 rotatearc
->angle2
-= 360;
3166 else if (rotatearc
->angle2
<= 0) {
3167 rotatearc
->angle1
+= 360;
3168 rotatearc
->angle2
+= 360;
3170 newpts
= (XPoint
*)malloc(sizeof(XPoint
));
3171 UTransformPoints(&rotatearc
->position
, newpts
, 1, negpt
, 1.0, 0);
3172 UTransformPoints(newpts
, &rotatearc
->position
, 1, *position
,
3178 splineptr rotatespline
= TOSPLINE(genobj
);
3179 newpts
= (XPoint
*)malloc(4 * sizeof(XPoint
));
3180 UTransformPoints(rotatespline
->ctrl
, newpts
, 4, negpt
, 1.0, 0);
3181 UTransformPoints(newpts
, rotatespline
->ctrl
, 4, *position
,
3183 calcspline(rotatespline
);
3187 polyptr rotatepoly
= TOPOLY(genobj
);
3188 newpts
= (XPoint
*)malloc(rotatepoly
->number
* sizeof(XPoint
));
3189 UTransformPoints(rotatepoly
->points
, newpts
, rotatepoly
->number
,
3191 UTransformPoints(newpts
, rotatepoly
->points
, rotatepoly
->number
,
3192 *position
, 1.0, direction
);
3195 if (newpts
) free(newpts
);
3198 /*------------------------------------------------------*/
3199 /* Rotate an element or group of elements */
3200 /* Objects and labels, if selected singly, rotate */
3201 /* about their position point. All other elements, */
3202 /* and groups, rotate about the cursor point. */
3203 /*------------------------------------------------------*/
3205 void elementrotate(float direction
, XPoint
*position
)
3207 short *selectobj
; /* , ld; (jdk) */
3208 Boolean single
= False
;
3209 Boolean need_refresh
= False
;
3210 Boolean preselected
;
3211 XPoint newpt
, negpt
;
3213 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3214 if (!checkselect(ALL_TYPES
)) return;
3215 if (areawin
->selects
== 1) single
= True
;
3217 negpt
.x
= -position
->x
;
3218 negpt
.y
= -position
->y
;
3220 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3221 + areawin
->selects
; selectobj
++) {
3223 /* erase the element */
3224 if (!need_refresh
) {
3225 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
3226 easydraw(*selectobj
, DOFORALL
);
3229 switch(SELECTTYPE(selectobj
)) {
3232 objinstptr rotateobj
= SELTOOBJINST(selectobj
);
3234 if (is_library(topobject
) >= 0 && !is_virtual(rotateobj
)) break;
3235 rotateobj
->rotation
+= direction
;
3236 while (rotateobj
->rotation
>= 360) rotateobj
->rotation
-= 360;
3237 while (rotateobj
->rotation
<= 0) rotateobj
->rotation
+= 360;
3239 UTransformPoints(&rotateobj
->position
, &newpt
, 1, negpt
, 1.0, 0);
3240 UTransformPoints(&newpt
, &rotateobj
->position
, 1, *position
,
3246 labelptr rotatetext
= SELTOLABEL(selectobj
);
3248 rotatetext
->rotation
+= direction
;
3249 while (rotatetext
->rotation
>= 360) rotatetext
->rotation
-= 360;
3250 while (rotatetext
->rotation
<= 0) rotatetext
->rotation
+= 360;
3252 UTransformPoints(&rotatetext
->position
, &newpt
, 1, negpt
, 1.0, 0);
3253 UTransformPoints(&newpt
, &rotatetext
->position
, 1, *position
,
3259 graphicptr rotateg
= SELTOGRAPHIC(selectobj
);
3261 rotateg
->rotation
+= direction
;
3262 while (rotateg
->rotation
>= 360) rotateg
->rotation
-= 360;
3263 while (rotateg
->rotation
<= 0) rotateg
->rotation
+= 360;
3265 rotateg
->valid
= FALSE
;
3266 #endif /* !HAVE_CAIRO */
3268 UTransformPoints(&rotateg
->position
, &newpt
, 1, negpt
, 1.0, 0);
3269 UTransformPoints(&newpt
, &rotateg
->position
, 1, *position
,
3272 need_refresh
= True
;
3275 case POLYGON
: case ARC
: case SPLINE
:{
3276 genericptr
*genpart
= topobject
->plist
+ *selectobj
;
3277 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3279 elemrotate(genpart
, direction
, position
);
3283 genericptr
*genpart
;
3284 pathptr rotatepath
= SELTOPATH(selectobj
);
3286 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3288 for (genpart
= rotatepath
->plist
; genpart
< rotatepath
->plist
3289 + rotatepath
->parts
; genpart
++)
3290 elemrotate(genpart
, direction
, position
);
3294 /* redisplay the element */
3295 if (preselected
|| ((eventmode
!= NORMAL_MODE
) && !need_refresh
)) {
3296 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
3297 easydraw(*selectobj
, DOFORALL
);
3301 /* This takes care of all selected instances and labels in one go, */
3302 /* because we only need to know the origin and amount of rotation. */
3304 if (eventmode
!= COPY_MODE
)
3305 register_for_undo(XCF_Rotate
, UNDO_MORE
, areawin
->topinstance
,
3306 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
,
3309 /* New rule (6/15/07) to be applied generally: If objects were */
3310 /* selected prior to calling elementrotate() and similar functions, */
3311 /* leave them selected upon exit. Otherwise, deselect them. */
3313 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
3317 if (eventmode
== CATALOG_MODE
) {
3319 if ((libnum
= is_library(topobject
)) >= 0) {
3320 composelib(libnum
+ LIBRARY
);
3321 need_refresh
= TRUE
;
3325 pwriteback(areawin
->topinstance
);
3326 calcbbox(areawin
->topinstance
);
3329 if (need_refresh
) drawarea(NULL
, NULL
, NULL
);
3332 /*----------------------------------------------*/
3333 /* Rescale the current edit element to the */
3334 /* dimensions of the rescale box. */
3335 /*----------------------------------------------*/
3337 void elementrescale(float newscale
)
3345 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3346 + areawin
->selects
; selectobj
++) {
3347 switch (SELECTTYPE(selectobj
)) {
3349 sclab
= SELTOLABEL(selectobj
);
3350 oldsize
= sclab
->scale
;
3351 sclab
->scale
= newscale
;
3354 scinst
= SELTOOBJINST(selectobj
);
3355 oldsize
= scinst
->scale
;
3356 scinst
->scale
= newscale
;
3359 scgraph
= SELTOGRAPHIC(selectobj
);
3360 oldsize
= scgraph
->scale
;
3361 scgraph
->scale
= newscale
;
3364 register_for_undo(XCF_Rescale
, UNDO_MORE
, areawin
->topinstance
,
3365 SELTOGENERIC(selectobj
), (double)oldsize
);
3367 calcbbox(areawin
->topinstance
);
3370 /*-------------------------------------------------*/
3371 /* Edit an element in an element-dependent fashion */
3372 /*-------------------------------------------------*/
3374 void edit(int x
, int y
)
3378 if (areawin
->selects
== 0) {
3379 Boolean saveredraw
= areawin
->redraw_needed
;
3380 selectobj
= select_element(ALL_TYPES
);
3381 areawin
->redraw_needed
= saveredraw
;
3384 selectobj
= areawin
->selectlist
;
3385 if (areawin
->selects
== 0)
3387 else if (areawin
->selects
!= 1) { /* Multiple object edit */
3389 short *selectlist
, selrefno
;
3390 Boolean save_redraw
= areawin
->redraw_needed
;
3392 /* Find the closest part to use as a reference */
3393 selnum
= areawin
->selects
;
3394 selectlist
= areawin
->selectlist
;
3395 areawin
->selects
= 0;
3396 areawin
->selectlist
= NULL
;
3397 selectobj
= select_element(ALL_TYPES
);
3398 if (selectobj
!= NULL
)
3399 selrefno
= *selectobj
;
3403 areawin
->selects
= selnum
;
3404 areawin
->selectlist
= selectlist
;
3405 areawin
->redraw_needed
= save_redraw
;
3406 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3407 + areawin
->selects
; selectobj
++) {
3408 if (*selectobj
== selrefno
) break;
3410 if (selectobj
== areawin
->selectlist
+ areawin
->selects
) {
3411 Wprintf("Put cursor close to the reference element.");
3415 /* Shuffle the reference element to the beginning of the select list */
3416 *selectobj
= *(areawin
->selectlist
);
3417 *(areawin
->selectlist
) = selrefno
;
3418 selectobj
= areawin
->selectlist
;
3421 switch(SELECTTYPE(selectobj
)) {
3423 labelptr
*lastlabel
= (labelptr
*)EDITPART
;
3428 /* save the old string, including parameters */
3429 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3432 /* fill any NULL instance parameters with the default value */
3433 copyparams(areawin
->topinstance
, areawin
->topinstance
);
3435 /* place text cursor line at point nearest the cursor */
3436 /* unless textend is set. . . */
3438 if (areawin
->textend
== 0) {
3439 TextLinesInfo tlinfo
;
3441 tlinfo
.tbreak
= NULL
;
3442 tlinfo
.padding
= NULL
;
3444 window_to_user(x
, y
, &areawin
->save
);
3445 InvTransformPoints(&areawin
->save
, &tmppt
, 1, (*lastlabel
)->position
,
3446 (*lastlabel
)->scale
, (*lastlabel
)->rotation
);
3447 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3448 tmppt
.x
+= ((*lastlabel
)->anchor
& NOTLEFT
?
3449 ((*lastlabel
)->anchor
& RIGHT
? tmpext
.maxwidth
3450 : tmpext
.maxwidth
>> 1) : 0);
3451 tmppt
.y
+= ((*lastlabel
)->anchor
& NOTBOTTOM
?
3452 ((*lastlabel
)->anchor
& TOP
? tmpext
.ascent
:
3453 (tmpext
.ascent
+ tmpext
.base
) >> 1) : tmpext
.base
);
3454 if ((*lastlabel
)->pin
)
3455 pinadjust((*lastlabel
)->anchor
, &tmppt
.x
, NULL
, -1);
3457 /* Where tbreak is passed to ULength, the character position */
3458 /* is returned in the TextLinesInfo dostop field. */
3459 tlinfo
.tbreak
= &tmppt
;
3460 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3461 areawin
->textpos
= tlinfo
.dostop
;
3463 if (tlinfo
.padding
!= NULL
) free(tlinfo
.padding
);
3466 /* find current font */
3468 curfont
= findcurfont(areawin
->textpos
, (*lastlabel
)->string
,
3469 areawin
->topinstance
);
3471 /* change menu buttons accordingly */
3473 setfontmarks(curfont
, (*lastlabel
)->anchor
);
3475 if (eventmode
== CATALOG_MODE
) {
3476 /* CATTEXT_MODE may show an otherwise hidden library namespace */
3477 undrawtext(*lastlabel
);
3478 eventmode
= CATTEXT_MODE
;
3479 redrawtext(*lastlabel
);
3480 areawin
->redraw_needed
= False
; /* ignore prev. redraw requests */
3481 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3484 eventmode
= ETEXT_MODE
;
3485 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3488 XDefineCursor(dpy
, areawin
->window
, TEXTPTR
);
3490 /* write the text at the bottom */
3492 charreport(*lastlabel
);
3496 case POLYGON
: case ARC
: case SPLINE
: case PATH
:
3497 window_to_user(x
, y
, &areawin
->save
);
3498 pathedit(*(EDITPART
));
3501 case OBJINST
: case GRAPHIC
:
3502 if (areawin
->selects
== 1)
3506 XDefineCursor (dpy
, areawin
->window
, EDCURSOR
);
3509 /*----------------------------------------------------------------------*/
3510 /* edit() routine for path-type elements (polygons, splines, arcs, and */
3512 /*----------------------------------------------------------------------*/
3514 void pathedit(genericptr editpart
)
3516 splineptr lastspline
= NULL
;
3518 polyptr lastpoly
= NULL
;
3525 /* Find and set constrained edit points on all elements. Register */
3526 /* each element with the undo mechanism. */
3528 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
3529 areawin
->selects
; eselect
++) {
3530 switch (SELECTTYPE(eselect
)) {
3532 findconstrained(SELTOPOLY(eselect
));
3535 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3536 SELTOGENERIC(eselect
));
3541 switch(ELEMENTTYPE(editpart
)) {
3543 genericptr
*ggen
, *savegen
= NULL
;
3544 int mincycle
, dist
, mindist
= 1e6
;
3546 lastpath
= (pathptr
)editpart
;
3547 havecycle
= (checkcycle(editpart
, 0) >= 0) ? True
: False
;
3549 /* determine which point of the path is closest to the cursor */
3550 for (ggen
= lastpath
->plist
; ggen
< lastpath
->plist
+ lastpath
->parts
;
3552 switch (ELEMENTTYPE(*ggen
)) {
3554 lastpoly
= TOPOLY(ggen
);
3555 cycle
= closepoint(lastpoly
, &areawin
->save
);
3556 dist
= wirelength(lastpoly
->points
+ cycle
, &areawin
->save
);
3559 lastspline
= TOSPLINE(ggen
);
3560 cycle
= (wirelength(&lastspline
->ctrl
[0],
3561 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3562 &areawin
->save
)) ? 0 : 3;
3563 dist
= wirelength(&lastspline
->ctrl
[cycle
], &areawin
->save
);
3566 if (dist
< mindist
) {
3572 if (savegen
== NULL
) return; /* something went terribly wrong */
3573 switch (ELEMENTTYPE(*savegen
)) {
3575 lastpoly
= TOPOLY(savegen
);
3576 addcycle(savegen
, mincycle
, 0);
3577 savept
= lastpoly
->points
+ mincycle
;
3578 makerefcycle(lastpoly
->cycle
, mincycle
);
3579 findconstrained(lastpoly
);
3582 lastspline
= TOSPLINE(savegen
);
3583 addcycle(savegen
, mincycle
, 0);
3584 savept
= &lastspline
->ctrl
[mincycle
];
3585 makerefcycle(lastspline
->cycle
, mincycle
);
3588 updatepath(lastpath
);
3590 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3591 (genericptr
)lastpath
);
3592 patheditpush(lastpath
);
3593 areawin
->origin
= areawin
->save
;
3596 path_mode_draw(xcDRAW_INIT
, lastpath
);
3598 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3599 (xcEventHandler
)trackelement
, NULL
);
3600 eventmode
= EPATH_MODE
;
3601 printpos(savept
->x
, savept
->y
);
3606 lastpoly
= (polyptr
)editpart
;
3608 /* Determine which point of polygon is closest to cursor */
3609 cycle
= closepoint(lastpoly
, &areawin
->save
);
3610 havecycle
= (lastpoly
->cycle
== NULL
) ? False
: True
;
3611 addcycle(&editpart
, cycle
, 0);
3612 savept
= lastpoly
->points
+ cycle
;
3613 makerefcycle(lastpoly
->cycle
, cycle
);
3615 findconstrained(lastpoly
);
3616 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3617 (genericptr
)lastpoly
);
3620 /* Push onto the editstack */
3621 polyeditpush(lastpoly
);
3623 /* remember our postion for pointer restore */
3624 areawin
->origin
= areawin
->save
;
3628 poly_mode_draw(xcDRAW_INIT
, lastpoly
);
3630 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3631 (xcEventHandler
)trackelement
, NULL
);
3632 eventmode
= EPOLY_MODE
;
3633 printeditbindings();
3634 printpos(savept
->x
, savept
->y
);
3639 lastspline
= (splineptr
)editpart
;
3641 /* find which point is closest to the cursor */
3643 cycle
= (wirelength(&lastspline
->ctrl
[0],
3644 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3645 &areawin
->save
)) ? 0 : 3;
3646 havecycle
= (lastspline
->cycle
== NULL
) ? False
: True
;
3647 addcycle(&editpart
, cycle
, 0);
3648 makerefcycle(lastspline
->cycle
, cycle
);
3649 curpt
= &lastspline
->ctrl
[cycle
];
3651 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3652 (genericptr
)lastspline
);
3654 /* Push onto the editstack */
3655 splineeditpush(lastspline
);
3657 /* remember our postion for pointer restore */
3658 areawin
->origin
= areawin
->save
;
3662 spline_mode_draw(xcDRAW_INIT
, lastspline
);
3663 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3664 (xcEventHandler
)trackelement
, NULL
);
3665 eventmode
= ESPLINE_MODE
;
3669 float tmpratio
, tlen
;
3671 lastarc
= (arcptr
)editpart
;
3673 /* find a part of the arc close to the pointer */
3675 tlen
= (float)wirelength(&areawin
->save
, &(lastarc
->position
));
3676 tmpratio
= (float)(abs(lastarc
->radius
)) / tlen
;
3677 curpt
.x
= lastarc
->position
.x
+ tmpratio
* (areawin
->save
.x
3678 - lastarc
->position
.x
);
3679 tmpratio
= (float)lastarc
->yaxis
/ tlen
;
3680 curpt
.y
= lastarc
->position
.y
+ tmpratio
* (areawin
->save
.y
3681 - lastarc
->position
.y
);
3682 addcycle(&editpart
, 0, 0);
3683 saveratio
= (double)(lastarc
->yaxis
) / (double)(abs(lastarc
->radius
));
3685 /* Push onto the editstack */
3686 arceditpush(lastarc
);
3687 areawin
->origin
= areawin
->save
;
3691 areawin
->save
.x
= curpt
.x
; /* for redrawing dotted edit line */
3692 areawin
->save
.y
= curpt
.y
;
3693 arc_mode_draw(xcDRAW_INIT
, lastarc
);
3694 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3695 (xcEventHandler
)trackarc
, NULL
);
3696 eventmode
= EARC_MODE
;
3697 printpos(curpt
.x
, curpt
.y
);
3702 /*------------------------------------------------------*/
3703 /* Raise an element to the top of the list */
3704 /*------------------------------------------------------*/
3706 void xc_top(short *selectno
, short *orderlist
)
3709 genericptr
*raiseobj
, *genobj
, temp
;
3711 raiseobj
= topobject
->plist
+ *selectno
;
3714 for (genobj
= topobject
->plist
+ *selectno
; genobj
<
3715 topobject
->plist
+ topobject
->parts
- 1; genobj
++) {
3716 *genobj
= *(genobj
+ 1);
3717 *(orderlist
+ i
) = *(orderlist
+ i
+ 1);
3720 *(topobject
->plist
+ topobject
->parts
- 1) = temp
;
3721 *(orderlist
+ topobject
->parts
- 1) = *selectno
;
3722 *selectno
= topobject
->parts
- 1;
3725 /*------------------------------------------------------*/
3726 /* Lower an element to the bottom of the list */
3727 /*------------------------------------------------------*/
3729 void xc_bottom(short *selectno
, short *orderlist
)
3732 genericptr
*lowerobj
, *genobj
, temp
;
3734 lowerobj
= topobject
->plist
+ *selectno
;
3737 for (genobj
= topobject
->plist
+ *selectno
;
3738 genobj
> topobject
->plist
; genobj
--) {
3739 *genobj
= *(genobj
- 1);
3740 *(orderlist
+ i
) = *(orderlist
+ i
- 1);
3744 *orderlist
= *selectno
;
3748 /*--------------------------------------------------------------*/
3749 /* Raise all selected elements by one position in the list */
3750 /*--------------------------------------------------------------*/
3754 short *sel
, topsel
, maxsel
, *topidx
, limit
, *orderlist
, i
;
3755 genericptr
*raiseobj
, temp
;
3757 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3758 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3760 /* Find topmost element in the select list */
3762 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3764 if (*sel
> maxsel
) {
3769 if (maxsel
== -1) return; /* Error condition */
3772 limit
= topobject
->parts
- 1;
3775 /* Exchange the topmost element with the one above it */
3776 if (topsel
< limit
) {
3777 raiseobj
= topobject
->plist
+ topsel
;
3779 *raiseobj
= *(raiseobj
+ 1);
3780 *(raiseobj
+ 1) = temp
;
3782 i
= *(orderlist
+ topsel
);
3783 *(orderlist
+ topsel
) = *(orderlist
+ topsel
+ 1);
3784 *(orderlist
+ topsel
+ 1) = i
;
3789 /* Find next topmost element */
3791 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3793 if (*sel
< maxsel
) {
3794 if (*sel
> topsel
) {
3800 if (topsel
== -1) break; /* No more elements to raise */
3803 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3807 /*--------------------------------------------------------------*/
3808 /* Lower all selected elements by one position in the list */
3809 /*--------------------------------------------------------------*/
3813 short *sel
, botsel
, minsel
, *botidx
, limit
, *orderlist
, i
;
3814 genericptr
*lowerobj
, temp
;
3816 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3817 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3819 /* Find bottommost element in the select list */
3820 minsel
= topobject
->parts
;
3821 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3823 if (*sel
< minsel
) {
3828 if (minsel
== topobject
->parts
) return; /* Error condition */
3834 /* Exchange the topmost element with the one below it */
3835 if (botsel
> limit
) {
3836 lowerobj
= topobject
->plist
+ botsel
;
3838 *lowerobj
= *(lowerobj
- 1);
3839 *(lowerobj
- 1) = temp
;
3841 i
= *(orderlist
+ botsel
);
3842 *(orderlist
+ botsel
) = *(orderlist
+ botsel
- 1);
3843 *(orderlist
+ botsel
- 1) = i
;
3848 /* Find next topmost element */
3849 botsel
= topobject
->parts
;
3850 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3852 if (*sel
> minsel
) {
3853 if (*sel
< botsel
) {
3859 if (botsel
== topobject
->parts
) break; /* No more elements to raise */
3862 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3866 /*------------------------------------------------------*/
3867 /* Generate a virtual copy of an object instance in the */
3868 /* user library. This is like the library virtual copy */
3869 /* except that it allows the user to generate a library */
3870 /* copy of an existing instance, without having to make */
3871 /* a copy of the master library instance and edit it. */
3872 /* copyvirtual() also allows the library virtual */
3873 /* instance to take on a specific rotation or flip */
3874 /* value, which cannot be done with the library virtual */
3875 /* copy function. */
3876 /*------------------------------------------------------*/
3880 short *selectno
, created
= 0;
3881 objinstptr vcpobj
, libinst
;
3883 for (selectno
= areawin
->selectlist
; selectno
< areawin
->selectlist
+
3884 areawin
->selects
; selectno
++) {
3885 if (SELECTTYPE(selectno
) == OBJINST
) {
3886 vcpobj
= SELTOOBJINST(selectno
);
3887 libinst
= addtoinstlist(USERLIB
- LIBRARY
, vcpobj
->thisobject
, TRUE
);
3888 instcopy(libinst
, vcpobj
);
3893 Wprintf("No object instances selected for virtual copy!");
3897 composelib(USERLIB
);
3901 /*------------------------------------------------------*/
3902 /* Exchange the list position (drawing order) of two */
3903 /* elements, or move the position of one element to the */
3904 /* top or bottom. */
3905 /*------------------------------------------------------*/
3909 short *selectno
, *orderlist
, i
;
3910 genericptr
*exchobj
, *exchobj2
, temp
;
3911 Boolean preselected
;
3913 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3914 if (!checkselect(ALL_TYPES
)) {
3915 Wprintf("Select 1 or 2 objects");
3919 selectno
= areawin
->selectlist
;
3920 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3921 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3923 if (areawin
->selects
== 1) { /* lower if on top; raise otherwise */
3924 if (*selectno
== topobject
->parts
- 1)
3925 xc_bottom(selectno
, orderlist
);
3927 xc_top(selectno
, orderlist
);
3929 else { /* exchange the two objects */
3930 exchobj
= topobject
->plist
+ *selectno
;
3931 exchobj2
= topobject
->plist
+ *(selectno
+ 1);
3934 *exchobj
= *exchobj2
;
3937 i
= *(orderlist
+ *selectno
);
3938 *(orderlist
+ *selectno
) = *(orderlist
+ *(selectno
+ 1));
3939 *(orderlist
+ *(selectno
+ 1)) = i
;
3941 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
3942 orderlist
, topobject
->parts
);
3944 incr_changes(topobject
);
3947 drawarea(NULL
, NULL
, NULL
);
3950 /*--------------------------------------------------------*/
3951 /* Flip an element horizontally (POLYGON, ARC, or SPLINE) */
3952 /*--------------------------------------------------------*/
3954 void elhflip(genericptr
*genobj
, short x
)
3956 switch(ELEMENTTYPE(*genobj
)) {
3958 polyptr flippoly
= TOPOLY(genobj
);
3960 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
3961 flippoly
->number
; ppoint
++)
3962 ppoint
->x
= (x
<< 1) - ppoint
->x
;
3966 arcptr fliparc
= TOARC(genobj
);
3967 float tmpang
= 180 - fliparc
->angle1
;
3968 fliparc
->angle1
= 180 - fliparc
->angle2
;
3969 fliparc
->angle2
= tmpang
;
3970 if (fliparc
->angle2
< 0) {
3971 fliparc
->angle1
+= 360;
3972 fliparc
->angle2
+= 360;
3974 fliparc
->radius
= -fliparc
->radius
;
3975 fliparc
->position
.x
= (x
<< 1) - fliparc
->position
.x
;
3980 splineptr flipspline
= TOSPLINE(genobj
);
3982 for (i
= 0; i
< 4; i
++)
3983 flipspline
->ctrl
[i
].x
= (x
<< 1) - flipspline
->ctrl
[i
].x
;
3984 calcspline(flipspline
);
3989 /*--------------------------------------------------------*/
3990 /* Flip an element vertically (POLYGON, ARC, or SPLINE) */
3991 /*--------------------------------------------------------*/
3993 void elvflip(genericptr
*genobj
, short y
)
3995 switch(ELEMENTTYPE(*genobj
)) {
3998 polyptr flippoly
= TOPOLY(genobj
);
4001 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
4002 flippoly
->number
; ppoint
++)
4003 ppoint
->y
= (y
<< 1) - ppoint
->y
;
4007 arcptr fliparc
= TOARC(genobj
);
4008 float tmpang
= 360 - fliparc
->angle1
;
4009 fliparc
->angle1
= 360 - fliparc
->angle2
;
4010 fliparc
->angle2
= tmpang
;
4011 if (fliparc
->angle1
>= 360) {
4012 fliparc
->angle1
-= 360;
4013 fliparc
->angle2
-= 360;
4015 fliparc
->radius
= -fliparc
->radius
;
4016 fliparc
->position
.y
= (y
<< 1) - fliparc
->position
.y
;
4021 splineptr flipspline
= TOSPLINE(genobj
);
4023 for (i
= 0; i
< 4; i
++)
4024 flipspline
->ctrl
[i
].y
= (y
<< 1) - flipspline
->ctrl
[i
].y
;
4025 calcspline(flipspline
);
4030 /*------------------------------------------------------*/
4031 /* Horizontally flip an element */
4032 /*------------------------------------------------------*/
4034 void elementflip(XPoint
*position
)
4037 Boolean single
= False
;
4038 Boolean preselected
;
4040 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4041 if (!checkselect(ALL_TYPES
)) return;
4042 if (areawin
->selects
== 1) single
= True
;
4044 if (eventmode
!= COPY_MODE
)
4045 register_for_undo(XCF_Flip_X
, UNDO_MORE
, areawin
->topinstance
,
4046 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4048 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4049 + areawin
->selects
; selectobj
++) {
4051 /* erase the object */
4052 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4053 easydraw(*selectobj
, DOFORALL
);
4055 switch(SELECTTYPE(selectobj
)) {
4057 labelptr fliplab
= SELTOLABEL(selectobj
);
4058 if ((fliplab
->anchor
& (RIGHT
| NOTLEFT
)) != NOTLEFT
)
4059 fliplab
->anchor
^= (RIGHT
| NOTLEFT
);
4061 fliplab
->position
.x
= (position
->x
<< 1) - fliplab
->position
.x
;
4064 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4065 flipg
->scale
= -flipg
->scale
;
4067 flipg
->valid
= FALSE
;
4068 #endif /* !HAVE_CAIRO */
4070 flipg
->position
.x
= (position
->x
<< 1) - flipg
->position
.x
;
4073 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4074 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4075 flipobj
->scale
= -flipobj
->scale
;
4077 flipobj
->position
.x
= (position
->x
<< 1) - flipobj
->position
.x
;
4079 case POLYGON
: case ARC
: case SPLINE
:
4080 elhflip(topobject
->plist
+ *selectobj
, position
->x
);
4083 genericptr
*genpart
;
4084 pathptr flippath
= SELTOPATH(selectobj
);
4086 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4087 + flippath
->parts
; genpart
++)
4088 elhflip(genpart
, position
->x
);
4092 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4093 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4094 easydraw(*selectobj
, DOFORALL
);
4097 select_invalidate_netlist();
4098 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4102 if (eventmode
== NORMAL_MODE
)
4103 incr_changes(topobject
);
4104 if (eventmode
== CATALOG_MODE
) {
4106 if ((libnum
= is_library(topobject
)) >= 0) {
4107 composelib(libnum
+ LIBRARY
);
4108 drawarea(NULL
, NULL
, NULL
);
4112 pwriteback(areawin
->topinstance
);
4113 calcbbox(areawin
->topinstance
);
4117 /*----------------------------------------------*/
4118 /* Vertically flip an element */
4119 /*----------------------------------------------*/
4121 void elementvflip(XPoint
*position
)
4124 /*short fsign; (jdk) */
4125 Boolean preselected
;
4126 Boolean single
= False
;
4128 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4129 if (!checkselect(ALL_TYPES
)) return;
4130 if (areawin
->selects
== 1) single
= True
;
4132 if (eventmode
!= COPY_MODE
)
4133 register_for_undo(XCF_Flip_Y
, UNDO_MORE
, areawin
->topinstance
,
4134 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4136 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4137 + areawin
->selects
; selectobj
++) {
4139 /* erase the object */
4140 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4141 easydraw(*selectobj
, DOFORALL
);
4143 switch(SELECTTYPE(selectobj
)) {
4145 labelptr fliplab
= SELTOLABEL(selectobj
);
4146 if ((fliplab
->anchor
& (TOP
| NOTBOTTOM
)) != NOTBOTTOM
)
4147 fliplab
->anchor
^= (TOP
| NOTBOTTOM
);
4149 fliplab
->position
.y
= (position
->y
<< 1) - fliplab
->position
.y
;
4152 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4154 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4155 flipobj
->scale
= -(flipobj
->scale
);
4156 flipobj
->rotation
+= 180;
4157 while (flipobj
->rotation
>= 360) flipobj
->rotation
-= 360;
4159 flipobj
->position
.y
= (position
->y
<< 1) - flipobj
->position
.y
;
4162 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4164 flipg
->scale
= -(flipg
->scale
);
4165 flipg
->rotation
+= 180;
4166 while (flipg
->rotation
>= 360) flipg
->rotation
-= 360;
4168 flipg
->position
.y
= (position
->y
<< 1) - flipg
->position
.y
;
4170 case POLYGON
: case ARC
: case SPLINE
:
4171 elvflip(topobject
->plist
+ *selectobj
, position
->y
);
4174 genericptr
*genpart
;
4175 pathptr flippath
= SELTOPATH(selectobj
);
4177 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4178 + flippath
->parts
; genpart
++)
4179 elvflip(genpart
, position
->y
);
4182 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4183 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4184 easydraw(*selectobj
, DOFORALL
);
4187 select_invalidate_netlist();
4188 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4191 if (eventmode
== NORMAL_MODE
) {
4192 incr_changes(topobject
);
4194 if (eventmode
== CATALOG_MODE
) {
4196 if ((libnum
= is_library(topobject
)) >= 0) {
4197 composelib(libnum
+ LIBRARY
);
4198 drawarea(NULL
, NULL
, NULL
);
4202 pwriteback(areawin
->topinstance
);
4203 calcbbox(areawin
->topinstance
);
4207 /*----------------------------------------*/
4208 /* ButtonPress handler during delete mode */
4209 /*----------------------------------------*/
4211 void deletebutton(int x
, int y
)
4213 UNUSED(x
); UNUSED(y
);
4215 if (checkselect(ALL_TYPES
)) {
4216 standard_element_delete(ERASE
);
4217 calcbbox(areawin
->topinstance
);
4219 setoptionmenu(); /* Return GUI check/radio boxes to default */
4222 /*----------------------------------------------------------------------*/
4223 /* Process of element deletion. Remove one element from the indicated */
4225 /*----------------------------------------------------------------------*/
4227 void delete_one_element(objinstptr thisinstance
, genericptr thiselement
)
4229 objectptr thisobject
;
4231 Boolean pinchange
= False
;
4233 thisobject
= thisinstance
->thisobject
;
4235 /* The netlist contains pointers to elements which no longer */
4236 /* exist on the page, so we should remove them from the netlist. */
4238 if (RemoveFromNetlist(thisobject
, thiselement
)) pinchange
= True
;
4239 for (genobj
= thisobject
->plist
; genobj
< thisobject
->plist
4240 + thisobject
->parts
; genobj
++)
4241 if (*genobj
== thiselement
)
4244 if (genobj
== thisobject
->plist
+ thisobject
->parts
) return;
4246 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4247 *(genobj
- 1) = *genobj
;
4248 thisobject
->parts
--;
4250 if (pinchange
) setobjecttype(thisobject
);
4251 incr_changes(thisobject
);
4252 calcbbox(thisinstance
);
4253 invalidate_netlist(thisobject
);
4254 /* freenetlist(thisobject); */
4257 /*----------------------------------------------------------------------*/
4258 /* Process of element deletion. Remove everything in the selection */
4259 /* list from the indicated object, and return a new object containing */
4260 /* only the deleted elements. */
4262 /* if drawmode is DRAW, we erase the objects as we remove them. */
4264 /* Note that if "slist" is areawin->selectlist, it is freed by this */
4265 /* routine (calls freeselects()), but not otherwise. */
4266 /*----------------------------------------------------------------------*/
4268 objectptr
delete_element(objinstptr thisinstance
, short *slist
, int selects
,
4272 objectptr delobj
, thisobject
;
4274 Boolean pinchange
= False
;
4276 if (slist
== NULL
|| selects
== 0) return NULL
;
4278 thisobject
= thisinstance
->thisobject
;
4280 delobj
= (objectptr
) malloc(sizeof(object
));
4284 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4287 for (selectobj
= slist
; selectobj
< slist
+ selects
; selectobj
++) {
4288 genobj
= thisobject
->plist
+ *selectobj
;
4289 if (drawmode
) easydraw(*selectobj
, DOFORALL
);
4291 *(delobj
->plist
+ delobj
->parts
) = *genobj
;
4294 /* The netlist contains pointers to elements which no longer */
4295 /* exist on the page, so we should remove them from the netlist. */
4297 if (RemoveFromNetlist(thisobject
, *genobj
)) pinchange
= True
;
4298 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4299 *(genobj
- 1) = *genobj
;
4300 thisobject
->parts
--;
4301 reviseselect(slist
, selects
, selectobj
);
4303 if (pinchange
) setobjecttype(thisobject
);
4305 if (slist
== areawin
->selectlist
)
4308 calcbbox(thisinstance
);
4309 /* freenetlist(thisobject); */
4312 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
4313 drawarea(NULL
, NULL
, NULL
);
4318 /*----------------------------------------------------------------------*/
4319 /* Wrapper for delete_element(). Remember this deletion for the undo */
4321 /*----------------------------------------------------------------------*/
4323 void standard_element_delete(short drawmode
)
4327 /* register_for_undo(XCF_Select, UNDO_MORE, areawin->topinstance, */
4328 /* areawin->selectlist, areawin->selects); */
4329 select_invalidate_netlist();
4330 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4331 areawin
->selects
, drawmode
);
4332 register_for_undo(XCF_Delete
, UNDO_DONE
, areawin
->topinstance
,
4333 delobj
, (int)drawmode
);
4334 incr_changes(topobject
); /* Treat as one change */
4337 /*----------------------------------------------------------------------*/
4338 /* Another wrapper for delete_element(), in which we do not save the */
4339 /* deletion as an undo event. However, the returned object is saved */
4340 /* on areawin->editstack, so that the objects can be grabbed. This */
4341 /* allows objects to be carried across pages and through the hierarchy. */
4342 /*----------------------------------------------------------------------*/
4344 void delete_for_xfer(short drawmode
, short *slist
, int selects
)
4347 reset(areawin
->editstack
, DESTROY
);
4348 areawin
->editstack
= delete_element(areawin
->topinstance
,
4349 slist
, selects
, drawmode
);
4353 /*----------------------------------------------------------------------*/
4354 /* Yet another wrapper for delete_element(), in which we destroy the */
4355 /* object returned and free all associated memory. */
4356 /*----------------------------------------------------------------------*/
4358 void delete_noundo(short drawmode
)
4362 select_invalidate_netlist();
4363 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4364 areawin
->selects
, drawmode
);
4366 if (delobj
!= NULL
) reset(delobj
, DESTROY
);
4369 /*----------------------------------------------------------------------*/
4370 /* Undelete last deleted elements and return a selectlist of the */
4371 /* elements. If "olist" is non-NULL, then the undeleted elements are */
4372 /* placed into the object of thisinstance in the order given by olist, */
4373 /* and a copy of olist is returned. If "olist" is NULL, then the */
4374 /* undeleted elements are placed at the end of thisinstance->thisobject */
4375 /* ->plist, and a new selection list is returned. If "olist" is non- */
4376 /* NULL, then the size of olist had better match the number of objects */
4377 /* in delobj! It is up to the calling routine to check this. */
4378 /*----------------------------------------------------------------------*/
4380 short *xc_undelete(objinstptr thisinstance
, objectptr delobj
, short mode
,
4383 objectptr thisobject
;
4385 short *slist
, count
, i
; /* position; (jdk) */
4387 thisobject
= thisinstance
->thisobject
;
4388 slist
= (short *)malloc(delobj
->parts
* sizeof(short));
4391 for (regen
= delobj
->plist
; regen
< delobj
->plist
+ delobj
->parts
; regen
++) {
4392 PLIST_INCR(thisobject
);
4393 if (olist
== NULL
) {
4394 *(slist
+ count
) = thisobject
->parts
;
4395 *(topobject
->plist
+ topobject
->parts
) = *regen
;
4398 *(slist
+ count
) = *(olist
+ count
);
4399 for (i
= thisobject
->parts
; i
> *(olist
+ count
); i
--)
4400 *(thisobject
->plist
+ i
) = *(thisobject
->plist
+ i
- 1);
4401 *(thisobject
->plist
+ i
) = *regen
;
4403 thisobject
->parts
++;
4405 XTopSetForeground((*regen
)->color
);
4406 easydraw(*(slist
+ count
), DEFAULTCOLOR
);
4410 /* If the element has passed parameters (eparam), then we have to */
4411 /* check if the key exists in the new parent object. If not, */
4412 /* delete the parameter. */
4414 if ((*regen
)->passed
) {
4415 eparamptr nextepp
, epp
= (*regen
)->passed
;
4416 while (epp
!= NULL
) {
4417 nextepp
= epp
->next
;
4418 if (!match_param(thisobject
, epp
->key
)) {
4419 if (epp
== (*regen
)->passed
) (*regen
)->passed
= nextepp
;
4420 free_element_param(*regen
, epp
);
4426 /* Likewise, string parameters must be checked in labels because */
4427 /* they act like element parameters. */
4429 if (IS_LABEL(*regen
)) {
4430 labelptr glab
= TOLABEL(regen
);
4431 stringpart
*gstr
, *lastpart
= NULL
;
4432 for (gstr
= glab
->string
; gstr
!= NULL
; gstr
= lastpart
->nextpart
) {
4433 if (gstr
->type
== PARAM_START
) {
4434 if (!match_param(thisobject
, gstr
->data
.string
)) {
4435 free(gstr
->data
.string
);
4437 lastpart
->nextpart
= gstr
->nextpart
;
4439 glab
->string
= gstr
->nextpart
;
4441 gstr
= (lastpart
) ? lastpart
: glab
->string
;
4448 incr_changes(thisobject
); /* treat as one change */
4449 calcbbox(thisinstance
);
4451 /* flush the delete buffer but don't delete the elements */
4452 reset(delobj
, SAVE
);
4454 if (delobj
!= areawin
->editstack
) free(delobj
);
4459 /*----------------------------*/
4460 /* select save object handler */
4461 /*----------------------------*/
4463 void printname(objectptr curobject
)
4465 char editstr
[10], pagestr
[10];
4470 Dimension swidth
, swidth2
, sarea
;
4472 char *sptr
= tmpname
;
4475 /* print full string to make message widget proper size */
4477 strcpy(editstr
, ((ispage
= is_page(curobject
)) >= 0) ? "Editing: " : "");
4478 strcpy(editstr
, (is_library(curobject
) >= 0) ? "Library: " : "");
4479 if (strstr(curobject
->name
, "Page") == NULL
&& (ispage
>= 0))
4480 sprintf(pagestr
, " (p. %d)", areawin
->page
+ 1);
4483 W2printf("%s%s%s", editstr
, curobject
->name
, pagestr
);
4485 /* Tcl doesn't update width changes immediately. . . what to do? */
4486 /* (i.e., Tk_Width(message2) gives the original width) */
4489 XtSetArg(wargs
[0], XtNwidth
, &sarea
);
4490 XtGetValues(message2
, wargs
, 1);
4492 /* in the remote case that the string is longer than message widget, */
4493 /* truncate the string and denote the truncation with an ellipsis (...) */
4495 strcpy(tmpname
, curobject
->name
);
4496 swidth2
= XTextWidth(appdata
.xcfont
, editstr
, strlen(editstr
));
4497 swidth
= XTextWidth(appdata
.xcfont
, tmpname
, strlen(tmpname
));
4499 if ((swidth
+ swidth2
) > sarea
) {
4501 while ((swidth
+ swidth2
) > sarea
) {
4503 swidth
= XTextWidth(appdata
.xcfont
, sptr
, strlen(sptr
));
4505 for(ip
= sptr
; ip
< sptr
+ 3 && *ip
!= '\0'; ip
++) *ip
= '.';
4507 W2printf("Editing: %s", sptr
);
4512 /*--------------------------------------------------------------*/
4513 /* Make sure that a string does not conflict with postscript */
4514 /* names (commands and definitions found in xcircps2.pro). */
4516 /* Return value is NULL if no change was made. Otherwise, the */
4517 /* return value is an allocated string. */
4518 /*--------------------------------------------------------------*/
4520 char *checkvalidname(char *teststring
, objectptr newobj
)
4523 short dupl
; /* flag a duplicate string */
4525 char *sptr
, *pptr
, *cptr
;
4529 /* Try not to allocate memory unless necessary */
4536 if (newobj
!= NULL
) {
4537 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4538 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4539 libobj
= xobjs
.userlibs
[i
].library
+ j
;
4541 if (*libobj
== newobj
) continue;
4542 if (!strcmp(pptr
, (*libobj
)->name
)) {
4544 /* Prepend an underscore to the object name. If the */
4545 /* object has no technology, create a null technology */
4546 /* name. Otherwise, the technology remains the same */
4547 /* but the object name gets the prepended underscore. */
4549 if ((cptr
= strstr(pptr
, "::")) == NULL
) {
4550 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 4);
4551 sprintf(pptr
, "::_%s", (*libobj
)->name
);
4554 int offset
= cptr
- pptr
+ 2;
4556 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 2);
4558 pptr
= (char *)realloc(pptr
, strlen((*libobj
)->name
) + 2);
4559 sprintf(pptr
, "%s", (*libobj
)->name
);
4560 sprintf(pptr
+ offset
, "_%s", (*libobj
)->name
+ offset
);
4567 /* If we're in the middle of a file load, the name cannot be */
4568 /* the same as an alias, either. */
4570 if (aliastop
!= NULL
) {
4571 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
4572 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
) {
4573 if (!strcmp(pptr
, sref
->alias
)) {
4575 pptr
= (char *)malloc(strlen(sref
->alias
) + 2);
4577 pptr
= (char *)realloc(pptr
, strlen(sref
->alias
) + 2);
4578 sprintf(pptr
, "_%s", sref
->alias
);
4586 } while (dupl
== 1);
4588 return (pptr
== sptr
) ? NULL
: pptr
;
4591 /*--------------------------------------------------------------*/
4592 /* Make sure that name for new object does not conflict with */
4593 /* existing object definitions */
4595 /* Return: True if name required change, False otherwise */
4596 /*--------------------------------------------------------------*/
4598 Boolean
checkname(objectptr newobj
)
4602 /* Check for empty string */
4603 if (strlen(newobj
->name
) == 0) {
4604 Wprintf("Blank object name changed to default");
4605 sprintf(newobj
->name
, "user_object");
4608 pptr
= checkvalidname(newobj
->name
, newobj
);
4610 /* Change name if necessary to avoid naming conflicts */
4612 Wprintf("Created new object %s", newobj
->name
);
4616 Wprintf("Changed name from %s to %s to avoid conflict with "
4617 "existing object", newobj
->name
, pptr
);
4619 strncpy(newobj
->name
, pptr
, 79);
4625 /*------------------------------------------------------------*/
4626 /* Find the object "dot" in the builtin library, if it exists */
4627 /*------------------------------------------------------------*/
4635 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4636 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4637 dotobj
= *(xobjs
.userlibs
[i
].library
+ j
);
4638 name
= dotobj
->name
;
4639 if ((pptr
= strstr(name
, "::")) != NULL
) name
= pptr
+ 2;
4640 if (!strcmp(name
, "dot")) {
4645 return (objectptr
)NULL
;
4648 /*--------------------------------------*/
4649 /* Add value origin to all points */
4650 /*--------------------------------------*/
4652 void movepoints(genericptr
*ssgen
, short deltax
, short deltay
)
4654 switch(ELEMENTTYPE(*ssgen
)) {
4656 fpointlist sspoints
;
4657 TOARC(ssgen
)->position
.x
+= deltax
;
4658 TOARC(ssgen
)->position
.y
+= deltay
;
4659 for (sspoints
= TOARC(ssgen
)->points
; sspoints
< TOARC(ssgen
)->points
+
4660 TOARC(ssgen
)->number
; sspoints
++) {
4661 sspoints
->x
+= deltax
;
4662 sspoints
->y
+= deltay
;
4668 for (sspoints
= TOPOLY(ssgen
)->points
; sspoints
< TOPOLY(ssgen
)->points
+
4669 TOPOLY(ssgen
)->number
; sspoints
++) {
4670 sspoints
->x
+= deltax
;
4671 sspoints
->y
+= deltay
;
4676 fpointlist sspoints
;
4678 for (sspoints
= TOSPLINE(ssgen
)->points
; sspoints
<
4679 TOSPLINE(ssgen
)->points
+ INTSEGS
; sspoints
++) {
4680 sspoints
->x
+= deltax
;
4681 sspoints
->y
+= deltay
;
4683 for (j
= 0; j
< 4; j
++) {
4684 TOSPLINE(ssgen
)->ctrl
[j
].x
+= deltax
;
4685 TOSPLINE(ssgen
)->ctrl
[j
].y
+= deltay
;
4689 TOOBJINST(ssgen
)->position
.x
+= deltax
;
4690 TOOBJINST(ssgen
)->position
.y
+= deltay
;
4693 TOGRAPHIC(ssgen
)->position
.x
+= deltax
;
4694 TOGRAPHIC(ssgen
)->position
.y
+= deltay
;
4697 TOLABEL(ssgen
)->position
.x
+= deltax
;
4698 TOLABEL(ssgen
)->position
.y
+= deltay
;
4703 /*----------------------------------------------------------------------*/
4704 /* Add value origin to all edited points, according to edit flags */
4705 /*----------------------------------------------------------------------*/
4707 void editpoints(genericptr
*ssgen
, short deltax
, short deltay
)
4711 splineptr editspline
;
4712 short cycle
, cpoint
;
4717 switch(ELEMENTTYPE(*ssgen
)) {
4719 editpoly
= TOPOLY(ssgen
);
4720 if (editpoly
->cycle
== NULL
)
4721 movepoints(ssgen
, deltax
, deltay
);
4723 for (cptr
= editpoly
->cycle
;; cptr
++) {
4724 cycle
= cptr
->number
;
4725 curpt
= editpoly
->points
+ cycle
;
4726 if (cptr
->flags
& EDITX
) curpt
->x
+= deltax
;
4727 if (cptr
->flags
& EDITY
) curpt
->y
+= deltay
;
4728 if (cptr
->flags
& LASTENTRY
) break;
4735 editspline
= TOSPLINE(ssgen
);
4736 if (editspline
->cycle
== NULL
)
4737 movepoints(ssgen
, deltax
, deltay
);
4739 for (cptr
= editspline
->cycle
;; cptr
++) {
4740 cycle
= cptr
->number
;
4741 if (cycle
== 0 || cycle
== 3) {
4742 cpoint
= (cycle
== 0) ? 1 : 2;
4743 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cpoint
].x
+= deltax
;
4744 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cpoint
].y
+= deltay
;
4746 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cycle
].x
+= deltax
;
4747 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cycle
].y
+= deltay
;
4748 if (cptr
->flags
& ANTIXY
) {
4749 editspline
->ctrl
[cycle
].x
-= deltax
;
4750 editspline
->ctrl
[cycle
].y
-= deltay
;
4752 if (cptr
->flags
& LASTENTRY
) break;
4756 calcspline(editspline
);
4760 editpath
= TOPATH(ssgen
);
4761 if (checkcycle(*ssgen
, 0) < 0) {
4762 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4764 movepoints(ggen
, deltax
, deltay
);
4767 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4769 if (checkcycle(*ggen
, 0) >= 0)
4770 editpoints(ggen
, deltax
, deltay
);
4776 movepoints(ssgen
, deltax
, deltay
);
4784 void xlib_makeobject(xcWidget w
, caddr_t nulldata
)
4786 UNUSED(w
); UNUSED(nulldata
);
4788 domakeobject(-1, (char *)_STR2
, FALSE
);
4791 #endif /* !TCL_WRAPPER */
4793 /*--------------------------------------------------------------*/
4794 /* Set the name for a new user-defined object and make the */
4795 /* object. If "forceempty" is true, we allow creation of a new */
4796 /* object with no elements (normally would be used only from a */
4797 /* script, where an object is being constructed automatically). */
4798 /*--------------------------------------------------------------*/
4800 objinstptr
domakeobject(int libnum
, char *name
, Boolean forceempty
)
4803 objinstptr
*newinst
;
4805 oparamptr ops
, newop
;
4806 eparamptr epp
, newepp
;
4809 short loclibnum
= libnum
;
4811 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
4813 /* make room for new entry in library list */
4815 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
4816 realloc(xobjs
.userlibs
[loclibnum
].library
,
4817 (xobjs
.userlibs
[loclibnum
].number
+ 1) * sizeof(objectptr
));
4819 newobj
= xobjs
.userlibs
[loclibnum
].library
+ xobjs
.userlibs
[loclibnum
].number
;
4821 *newobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4822 areawin
->selects
, NORMAL
);
4824 if (*newobj
== NULL
) {
4827 if (!forceempty
) return NULL
;
4829 /* Create a new (empty) object */
4831 initobj
= (objectptr
) malloc(sizeof(object
));
4836 invalidate_netlist(topobject
);
4837 xobjs
.userlibs
[loclibnum
].number
++;
4839 /* Create the instance of this object so we can compute a bounding box */
4841 NEW_OBJINST(newinst
, topobject
);
4842 instancedefaults(*newinst
, *newobj
, 0, 0);
4845 /* find closest snap point to bbox center and make this the obj. center */
4847 if (areawin
->center
) {
4848 origin
.x
= (*newobj
)->bbox
.lowerleft
.x
+ (*newobj
)->bbox
.width
/ 2;
4849 origin
.y
= (*newobj
)->bbox
.lowerleft
.y
+ (*newobj
)->bbox
.height
/ 2;
4852 origin
.x
= origin
.y
= 0;
4855 instancedefaults(*newinst
, *newobj
, origin
.x
, origin
.y
);
4857 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4859 switch(ELEMENTTYPE(*ssgen
)) {
4862 TOOBJINST(ssgen
)->position
.x
-= origin
.x
;
4863 TOOBJINST(ssgen
)->position
.y
-= origin
.y
;
4867 TOGRAPHIC(ssgen
)->position
.x
-= origin
.x
;
4868 TOGRAPHIC(ssgen
)->position
.y
-= origin
.y
;
4872 TOLABEL(ssgen
)->position
.x
-= origin
.x
;
4873 TOLABEL(ssgen
)->position
.y
-= origin
.y
;
4877 genericptr
*pathlist
;
4878 for (pathlist
= TOPATH(ssgen
)->plist
; pathlist
< TOPATH(ssgen
)->plist
4879 + TOPATH(ssgen
)->parts
; pathlist
++) {
4880 movepoints(pathlist
, -origin
.x
, -origin
.y
);
4885 movepoints(ssgen
, -origin
.x
, -origin
.y
);
4890 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4892 for (epp
= (*ssgen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
4893 ops
= match_param(topobject
, epp
->key
);
4894 newop
= copyparameter(ops
);
4895 newop
->next
= (*newobj
)->params
;
4896 (*newobj
)->params
= newop
;
4898 /* Generate an indirect parameter reference from child to parent */
4899 newepp
= make_new_eparam(epp
->key
);
4900 newepp
->flags
|= P_INDIRECT
;
4901 newepp
->pdata
.refkey
= strdup(epp
->key
);
4902 newepp
->next
= (*newinst
)->passed
;
4903 (*newinst
)->passed
= newepp
;
4905 if (IS_LABEL(*ssgen
)) {
4906 /* Also need to check for substring parameters in labels */
4907 for (sptr
= TOLABEL(ssgen
)->string
; sptr
!= NULL
; sptr
= sptr
->nextpart
) {
4908 if (sptr
->type
== PARAM_START
) {
4909 ops
= match_param(topobject
, sptr
->data
.string
);
4911 newop
= copyparameter(ops
);
4912 newop
->next
= (*newobj
)->params
;
4913 (*newobj
)->params
= newop
;
4916 /* Generate an indirect parameter reference from child to parent */
4917 newepp
= make_new_eparam(sptr
->data
.string
);
4918 newepp
->flags
|= P_INDIRECT
;
4919 newepp
->pdata
.refkey
= strdup(sptr
->data
.string
);
4920 newepp
->next
= (*newinst
)->passed
;
4921 (*newinst
)->passed
= newepp
;
4927 /* any parameters in the top-level object that used by the selected */
4928 /* elements must be copied into the new object. */
4930 /* put new object back into place */
4932 (*newobj
)->hidden
= False
;
4933 (*newobj
)->schemtype
= SYMBOL
;
4936 incr_changes(*newobj
);
4938 /* (netlist invalidation was taken care of by delete_element() */
4939 /* Also, incr_changes(topobject) was done by delete_element()) */
4941 XTopSetForeground((*newinst
)->color
);
4942 UDrawObject(*newinst
, SINGLE
, (*newinst
)->color
,
4943 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
4946 /* Copy name into object and check for conflicts */
4948 strcpy((*newobj
)->name
, name
);
4951 /* register the technology and mark the technology as not saved */
4952 AddObjectTechnology(*newobj
);
4954 /* generate library instance for this object (bounding box */
4955 /* should be default, so don't do calcbbox() on it) */
4957 addtoinstlist(loclibnum
, *newobj
, FALSE
);
4959 /* recompile the user catalog and reset view bounds */
4961 composelib(loclibnum
+ LIBRARY
);
4962 centerview(xobjs
.libtop
[loclibnum
+ LIBRARY
]);
4969 /*-------------------------------------------*/
4970 /* Make a user object from selected elements */
4971 /*-------------------------------------------*/
4973 void selectsave(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
4975 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
4976 UNUSED(clientdata
); UNUSED(calldata
);
4978 if (areawin
->selects
== 0) return; /* nothing was selected */
4980 /* Get a name for the new object */
4982 eventmode
= NORMAL_MODE
;
4983 popdata
->dataptr
= NULL
;
4984 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
4985 popupprompt(w
, "Enter name for new object:", "\0", xlib_makeobject
, popdata
, NULL
);
4990 /*-----------------------------*/
4991 /* Edit-stack support routines */
4992 /*-----------------------------*/
4994 void arceditpush(arcptr lastarc
)
4998 NEW_ARC(newarc
, areawin
->editstack
);
4999 arccopy(*newarc
, lastarc
);
5000 copycycles(&((*newarc
)->cycle
), &(lastarc
->cycle
));
5003 /*--------------------------------------*/
5005 void splineeditpush(splineptr lastspline
)
5007 splineptr
*newspline
;
5009 NEW_SPLINE(newspline
, areawin
->editstack
);
5010 splinecopy(*newspline
, lastspline
);
5013 /*--------------------------------------*/
5015 void polyeditpush(polyptr lastpoly
)
5019 NEW_POLY(newpoly
, areawin
->editstack
);
5020 polycopy(*newpoly
, lastpoly
);
5023 /*--------------------------------------*/
5025 void patheditpush(pathptr lastpath
)
5029 NEW_PATH(newpath
, areawin
->editstack
);
5030 pathcopy(*newpath
, lastpath
);
5033 /*-----------------------------*/
5034 /* Copying support routines */
5035 /*-----------------------------*/
5037 pointlist
copypoints(pointlist points
, int number
)
5039 pointlist rpoints
, cpoints
, newpoints
;
5041 rpoints
= (pointlist
) malloc(number
* sizeof(XPoint
));
5042 for (newpoints
= rpoints
, cpoints
= points
;
5043 newpoints
< rpoints
+ number
;
5044 newpoints
++, cpoints
++) {
5045 newpoints
->x
= cpoints
->x
;
5046 newpoints
->y
= cpoints
->y
;
5051 /*------------------------------------------*/
5053 void graphiccopy(graphicptr newg
, graphicptr copyg
)
5058 newg
->source
= copyg
->source
;
5059 newg
->position
.x
= copyg
->position
.x
;
5060 newg
->position
.y
= copyg
->position
.y
;
5061 newg
->rotation
= copyg
->rotation
;
5062 newg
->scale
= copyg
->scale
;
5063 newg
->color
= copyg
->color
;
5064 newg
->passed
= NULL
;
5065 copyalleparams((genericptr
)newg
, (genericptr
)copyg
);
5067 newg
->valid
= FALSE
;
5068 newg
->target
= NULL
;
5069 newg
->clipmask
= (Pixmap
)NULL
;
5070 #endif /* HAVE_CAIRO */
5072 /* Update the refcount of the source image */
5073 for (i
= 0; i
< xobjs
.images
; i
++) {
5074 iptr
= xobjs
.imagelist
+ i
;
5075 if (iptr
->image
== newg
->source
) {
5082 /*------------------------------------------*/
5084 void labelcopy(labelptr newtext
, labelptr copytext
)
5086 newtext
->string
= stringcopy(copytext
->string
);
5087 newtext
->position
.x
= copytext
->position
.x
;
5088 newtext
->position
.y
= copytext
->position
.y
;
5089 newtext
->rotation
= copytext
->rotation
;
5090 newtext
->scale
= copytext
->scale
;
5091 newtext
->anchor
= copytext
->anchor
;
5092 newtext
->color
= copytext
->color
;
5093 newtext
->passed
= NULL
;
5094 newtext
->cycle
= NULL
;
5095 copyalleparams((genericptr
)newtext
, (genericptr
)copytext
);
5096 newtext
->pin
= copytext
->pin
;
5099 /*------------------------------------------*/
5101 void arccopy(arcptr newarc
, arcptr copyarc
)
5103 newarc
->style
= copyarc
->style
;
5104 newarc
->color
= copyarc
->color
;
5105 newarc
->position
.x
= copyarc
->position
.x
;
5106 newarc
->position
.y
= copyarc
->position
.y
;
5107 newarc
->radius
= copyarc
->radius
;
5108 newarc
->yaxis
= copyarc
->yaxis
;
5109 newarc
->angle1
= copyarc
->angle1
;
5110 newarc
->angle2
= copyarc
->angle2
;
5111 newarc
->width
= copyarc
->width
;
5112 newarc
->passed
= NULL
;
5113 newarc
->cycle
= NULL
;
5114 copyalleparams((genericptr
)newarc
, (genericptr
)copyarc
);
5118 /*------------------------------------------*/
5120 void polycopy(polyptr newpoly
, polyptr copypoly
)
5122 newpoly
->style
= copypoly
->style
;
5123 newpoly
->color
= copypoly
->color
;
5124 newpoly
->width
= copypoly
->width
;
5125 newpoly
->number
= copypoly
->number
;
5126 copycycles(&(newpoly
->cycle
), &(copypoly
->cycle
));
5127 newpoly
->points
= copypoints(copypoly
->points
, copypoly
->number
);
5129 newpoly
->passed
= NULL
;
5130 copyalleparams((genericptr
)newpoly
, (genericptr
)copypoly
);
5133 /*------------------------------------------*/
5135 void splinecopy(splineptr newspline
, splineptr copyspline
)
5139 newspline
->style
= copyspline
->style
;
5140 newspline
->color
= copyspline
->color
;
5141 newspline
->width
= copyspline
->width
;
5142 copycycles(&(newspline
->cycle
), &(copyspline
->cycle
));
5143 for (i
= 0; i
< 4; i
++) {
5144 newspline
->ctrl
[i
].x
= copyspline
->ctrl
[i
].x
;
5145 newspline
->ctrl
[i
].y
= copyspline
->ctrl
[i
].y
;
5147 for (i
= 0; i
< INTSEGS
; i
++) {
5148 newspline
->points
[i
].x
= copyspline
->points
[i
].x
;
5149 newspline
->points
[i
].y
= copyspline
->points
[i
].y
;
5151 newspline
->passed
= NULL
;
5152 copyalleparams((genericptr
)newspline
, (genericptr
)copyspline
);
5155 /*----------------------------------------------*/
5157 /*----------------------------------------------*/
5159 void pathcopy(pathptr newpath
, pathptr copypath
)
5162 splineptr
*newspline
, copyspline
;
5163 polyptr
*newpoly
, copypoly
;
5165 newpath
->style
= copypath
->style
;
5166 newpath
->color
= copypath
->color
;
5167 newpath
->width
= copypath
->width
;
5169 newpath
->passed
= NULL
;
5170 copyalleparams((genericptr
)newpath
, (genericptr
)copypath
);
5171 newpath
->plist
= (genericptr
*)malloc(copypath
->parts
* sizeof(genericptr
));
5173 for (ggen
= copypath
->plist
; ggen
< copypath
->plist
+ copypath
->parts
; ggen
++) {
5174 switch (ELEMENTTYPE(*ggen
)) {
5176 copypoly
= TOPOLY(ggen
);
5177 NEW_POLY(newpoly
, newpath
);
5178 polycopy(*newpoly
, copypoly
);
5181 copyspline
= TOSPLINE(ggen
);
5182 NEW_SPLINE(newspline
, newpath
);
5183 splinecopy(*newspline
, copyspline
);
5189 /*--------------------------------------------------------------*/
5190 /* Copy an object instance */
5191 /*--------------------------------------------------------------*/
5193 void instcopy(objinstptr newobj
, objinstptr copyobj
)
5195 newobj
->position
.x
= copyobj
->position
.x
;
5196 newobj
->position
.y
= copyobj
->position
.y
;
5197 newobj
->rotation
= copyobj
->rotation
;
5198 newobj
->scale
= copyobj
->scale
;
5199 newobj
->style
= copyobj
->style
;
5200 newobj
->thisobject
= copyobj
->thisobject
;
5201 newobj
->color
= copyobj
->color
;
5202 newobj
->bbox
.lowerleft
.x
= copyobj
->bbox
.lowerleft
.x
;
5203 newobj
->bbox
.lowerleft
.y
= copyobj
->bbox
.lowerleft
.y
;
5204 newobj
->bbox
.width
= copyobj
->bbox
.width
;
5205 newobj
->bbox
.height
= copyobj
->bbox
.height
;
5207 newobj
->passed
= NULL
;
5208 copyalleparams((genericptr
)newobj
, (genericptr
)copyobj
);
5210 newobj
->params
= NULL
;
5211 copyparams(newobj
, copyobj
);
5213 /* If the parameters are the same, the bounding box should be, too. */
5214 if (copyobj
->schembbox
!= NULL
) {
5215 newobj
->schembbox
= (BBox
*)malloc(sizeof(BBox
));
5216 newobj
->schembbox
->lowerleft
.x
= copyobj
->schembbox
->lowerleft
.x
;
5217 newobj
->schembbox
->lowerleft
.y
= copyobj
->schembbox
->lowerleft
.y
;
5218 newobj
->schembbox
->width
= copyobj
->schembbox
->width
;
5219 newobj
->schembbox
->height
= copyobj
->schembbox
->height
;
5222 newobj
->schembbox
= NULL
;
5225 /*--------------------------------------------------------------*/
5226 /* The method for removing objects from a list is to add the */
5227 /* value REMOVE_TAG to the type of each object needing to be */
5228 /* removed, and then calling this routine. */
5229 /*--------------------------------------------------------------*/
5231 void delete_tagged(objinstptr thisinst
) {
5232 Boolean tagged
= True
;
5233 objectptr thisobject
, delobj
;
5237 thisobject
= thisinst
->thisobject
;
5241 for (stmp
= 0; stmp
< thisobject
->parts
; stmp
++) {
5242 pgen
= thisobject
->plist
+ stmp
;
5243 if ((*pgen
)->type
& REMOVE_TAG
) {
5244 (*pgen
)->type
&= (~REMOVE_TAG
);
5247 delobj
= delete_element(thisinst
, &stmp
, 1, 0);
5248 register_for_undo(XCF_Delete
, UNDO_MORE
, thisinst
, delobj
, 0);
5250 /* If we destroy elements in the current window, we need to */
5251 /* make sure that the selection list is updated appropriately. */
5253 if ((thisobject
== topobject
) && (areawin
->selects
> 0)) {
5254 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5255 areawin
->selects
; sobj
++)
5256 if (*sobj
> stmp
) (*sobj
)--;
5259 /* Also ensure that this element is not referenced in any */
5260 /* netlist. If it is, remove it and mark the netlist as */
5263 remove_netlist_element(thisobject
, *pgen
);
5267 undo_finish_series();
5270 /*-----------------------------------------------------------------*/
5271 /* For copying: Check if an object is about to be placed directly */
5272 /* on top of the same object. If so, delete the one underneath. */
5273 /*-----------------------------------------------------------------*/
5278 genericptr
*sgen
, *pgen
;
5279 Boolean tagged
= False
;
5281 /* Work through the select list */
5283 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5284 areawin
->selects
; sobj
++) {
5285 sgen
= topobject
->plist
+ (*sobj
);
5287 /* For each object being copied, compare it against every object */
5288 /* on the current page (except self). Flag if it's the same. */
5290 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+ topobject
->parts
;
5292 if (pgen
== sgen
) continue;
5293 if (compare_single(sgen
, pgen
)) {
5294 /* Make sure that this object is not part of the selection, */
5295 /* else chaos will reign. */
5296 for (cobj
= areawin
->selectlist
; cobj
< areawin
->selectlist
+
5297 areawin
->selects
; cobj
++) {
5298 if (pgen
== topobject
->plist
+ (*cobj
)) break;
5300 /* Tag it for future deletion and prevent further compares */
5301 if (cobj
== areawin
->selectlist
+ areawin
->selects
) {
5303 (*pgen
)->type
|= REMOVE_TAG
;
5309 /* Delete the tagged elements */
5310 Wprintf("Duplicate object deleted");
5311 delete_tagged(areawin
->topinstance
);
5312 incr_changes(topobject
);
5316 /*--------------------------------------------------------------*/
5317 /* Direct placement of elements. Assumes that the selectlist */
5318 /* contains all the elements to be positioned. "deltax" and */
5319 /* "deltay" are relative x and y positions to move the */
5321 /*--------------------------------------------------------------*/
5323 void placeselects(short deltax
, short deltay
, XPoint
*userpt
)
5326 XPoint newpos
, *ppt
;
5333 doattach
= ((userpt
== NULL
) || (areawin
->attachto
< 0)) ? FALSE
: TRUE
;
5335 /* under attachto condition, keep element attached to */
5336 /* the attachto element. */
5338 if (doattach
) findattach(&newpos
, &rot
, userpt
);
5342 areawin
->clipped
= -1; /* Prevent clipping */
5343 #endif /* HAVE_CAIRO */
5345 for (dragselect
= areawin
->selectlist
; dragselect
< areawin
->selectlist
5346 + areawin
->selects
; dragselect
++) {
5348 switch(SELECTTYPE(dragselect
)) {
5350 objinstptr draginst
= SELTOOBJINST(dragselect
);
5353 draginst
->position
.x
= newpos
.x
;
5354 draginst
->position
.y
= newpos
.y
;
5355 while (rot
>= 360.0) rot
-= 360.0;
5356 while (rot
< 0.0) rot
+= 360.0;
5357 draginst
->rotation
= rot
;
5360 draginst
->position
.x
+= deltax
;
5361 draginst
->position
.y
+= deltay
;
5366 graphicptr dragg
= SELTOGRAPHIC(dragselect
);
5367 dragg
->position
.x
+= deltax
;
5368 dragg
->position
.y
+= deltay
;
5371 labelptr draglabel
= SELTOLABEL(dragselect
);
5373 draglabel
->position
.x
= newpos
.x
;
5374 draglabel
->position
.y
= newpos
.y
;
5375 draglabel
->rotation
= rot
;
5378 draglabel
->position
.x
+= deltax
;
5379 draglabel
->position
.y
+= deltay
;
5383 pathptr dragpath
= SELTOPATH(dragselect
);
5384 genericptr
*pathlist
;
5387 XPoint
*pdelta
= pathclosepoint(dragpath
, &newpos
);
5388 deltax
= newpos
.x
- pdelta
->x
;
5389 deltay
= newpos
.y
- pdelta
->y
;
5391 for (pathlist
= dragpath
->plist
; pathlist
< dragpath
->plist
5392 + dragpath
->parts
; pathlist
++) {
5393 movepoints(pathlist
, deltax
, deltay
);
5397 polyptr dragpoly
= SELTOPOLY(dragselect
);
5398 pointlist dragpoints
;
5400 /* if (dragpoly->cycle != NULL) continue; */
5402 closest
= closepoint(dragpoly
, &newpos
);
5403 deltax
= newpos
.x
- dragpoly
->points
[closest
].x
;
5404 deltay
= newpos
.y
- dragpoly
->points
[closest
].y
;
5406 for (dragpoints
= dragpoly
->points
; dragpoints
< dragpoly
->points
5407 + dragpoly
->number
; dragpoints
++) {
5408 dragpoints
->x
+= deltax
;
5409 dragpoints
->y
+= deltay
;
5413 splineptr dragspline
= SELTOSPLINE(dragselect
);
5415 fpointlist dragpoints
;
5417 /* if (dragspline->cycle != NULL) continue; */
5419 closest
= (wirelength(&dragspline
->ctrl
[0], &newpos
)
5420 > wirelength(&dragspline
->ctrl
[3], &newpos
)) ? 3 : 0;
5421 deltax
= newpos
.x
- dragspline
->ctrl
[closest
].x
;
5422 deltay
= newpos
.y
- dragspline
->ctrl
[closest
].y
;
5424 for (dragpoints
= dragspline
->points
; dragpoints
< dragspline
->
5425 points
+ INTSEGS
; dragpoints
++) {
5426 dragpoints
->x
+= deltax
;
5427 dragpoints
->y
+= deltay
;
5429 for (j
= 0; j
< 4; j
++) {
5430 dragspline
->ctrl
[j
].x
+= deltax
;
5431 dragspline
->ctrl
[j
].y
+= deltay
;
5435 arcptr dragarc
= SELTOARC(dragselect
);
5436 fpointlist dragpoints
;
5439 deltax
= newpos
.x
- dragarc
->position
.x
;
5440 deltay
= newpos
.y
- dragarc
->position
.y
;
5442 dragarc
->position
.x
+= deltax
;
5443 dragarc
->position
.y
+= deltay
;
5444 for (dragpoints
= dragarc
->points
; dragpoints
< dragarc
->
5445 points
+ dragarc
->number
; dragpoints
++) {
5446 dragpoints
->x
+= deltax
;
5447 dragpoints
->y
+= deltay
;
5453 if (areawin
->pinattach
) {
5454 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
5455 topobject
->parts
; pgen
++) {
5456 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
5457 cpoly
= TOPOLY(pgen
);
5458 if (cpoly
->cycle
!= NULL
) {
5459 ppt
= cpoly
->points
+ cpoly
->cycle
->number
;
5460 newpos
.x
= ppt
->x
+ deltax
;
5461 newpos
.y
= ppt
->y
+ deltay
;
5462 if (areawin
->manhatn
)
5463 manhattanize(&newpos
, cpoly
, cpoly
->cycle
->number
, FALSE
);
5471 move_mode_draw(xcDRAW_EDIT
, NULL
);
5474 areawin
->clipped
= 0;
5475 #endif /* HAVE_CAIRO */
5478 /*----------------------------------------------------------------------*/
5479 /* Copy handler. Assumes that the selectlist contains the elements */
5480 /* to be copied, and that the initial position of the copy is held */
5481 /* in areawin->save. */
5482 /*----------------------------------------------------------------------*/
5488 if (!checkselect_draw(ALL_TYPES
, True
)) return;
5489 u2u_snap(&areawin
->save
);
5490 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
5491 + areawin
->selects
; selectobj
++) {
5493 /* Cycles will not be used for copy mode: remove them */
5494 removecycle(topobject
->plist
+ (*selectobj
));
5496 switch(SELECTTYPE(selectobj
)) {
5497 case LABEL
: { /* copy label */
5498 labelptr copytext
= SELTOLABEL(selectobj
);
5501 NEW_LABEL(newtext
, topobject
);
5502 labelcopy(*newtext
, copytext
);
5504 case OBJINST
: { /* copy object instance */
5505 objinstptr copyobj
= SELTOOBJINST(selectobj
);
5507 NEW_OBJINST(newobj
, topobject
);
5508 instcopy(*newobj
, copyobj
);
5510 case GRAPHIC
: { /* copy graphic instance */
5511 graphicptr copyg
= SELTOGRAPHIC(selectobj
);
5513 NEW_GRAPHIC(newg
, topobject
);
5514 graphiccopy(*newg
, copyg
);
5516 case PATH
: { /* copy path */
5517 pathptr copypath
= SELTOPATH(selectobj
);
5519 NEW_PATH(newpath
, topobject
);
5520 pathcopy(*newpath
, copypath
);
5522 case ARC
: { /* copy arc */
5523 arcptr copyarc
= SELTOARC(selectobj
);
5525 NEW_ARC(newarc
, topobject
);
5526 arccopy(*newarc
, copyarc
);
5528 case POLYGON
: { /* copy polygons */
5529 polyptr copypoly
= SELTOPOLY(selectobj
);
5531 NEW_POLY(newpoly
, topobject
);
5532 polycopy(*newpoly
, copypoly
);
5534 case SPLINE
: { /* copy spline */
5535 splineptr copyspline
= SELTOSPLINE(selectobj
);
5536 splineptr
*newspline
;
5537 NEW_SPLINE(newspline
, topobject
);
5538 splinecopy(*newspline
, copyspline
);
5542 /* change selection from the old to the new object */
5544 *selectobj
= topobject
->parts
- 1;
5548 /*--------------------------------------------------------------*/
5549 /* Function which initiates interactive placement of copied */
5551 /*--------------------------------------------------------------*/
5555 if (areawin
->selects
> 0) {
5556 move_mode_draw(xcDRAW_INIT
, NULL
);
5557 if (eventmode
== NORMAL_MODE
) {
5558 XDefineCursor(dpy
, areawin
->window
, COPYCURSOR
);
5559 eventmode
= COPY_MODE
;
5561 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
5562 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5564 XtAddEventHandler(areawin
->area
, PointerMotionMask
|
5565 ButtonMotionMask
, False
, (XtEventHandler
)xlib_drag
,
5569 select_invalidate_netlist();
5573 /*-----------------------------------------------------------*/
5574 /* Copy handler for copying from a button push or key event. */
5575 /*-----------------------------------------------------------*/
5577 void copy_op(int op
, int x
, int y
)
5579 if (op
== XCF_Copy
) {
5580 window_to_user(x
, y
, &areawin
->save
);
5581 createcopies(); /* This function does all the hard work */
5582 copydrag(); /* Start interactive placement */
5585 eventmode
= NORMAL_MODE
;
5586 areawin
->attachto
= -1;
5589 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5590 ButtonMotionMask
, False
, (xcEventHandler
)xctk_drag
,
5593 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5594 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5597 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5598 u2u_snap(&areawin
->save
);
5599 if (op
== XCF_Cancel
) {
5600 move_mode_draw(xcDRAW_EMPTY
, NULL
);
5601 delete_noundo(NORMAL
);
5603 else if (op
== XCF_Finish_Copy
) {
5604 move_mode_draw(xcDRAW_FINAL
, NULL
);
5605 /* If selected objects are the only ones on the page, */
5606 /* then do a full bbox calculation. */
5607 if (topobject
->parts
== areawin
->selects
)
5608 calcbbox(areawin
->topinstance
);
5612 register_for_undo(XCF_Copy
, UNDO_MORE
, areawin
->topinstance
,
5613 areawin
->selectlist
, areawin
->selects
);
5615 incr_changes(topobject
);
5617 else { /* XCF_Continue_Copy */
5618 move_mode_draw(xcDRAW_FINAL
, NULL
);
5619 if (topobject
->parts
== areawin
->selects
)
5620 calcbbox(areawin
->topinstance
);
5624 register_for_undo(XCF_Copy
, UNDO_DONE
, areawin
->topinstance
,
5625 areawin
->selectlist
, areawin
->selects
);
5627 copydrag(); /* Start interactive placement again */
5628 incr_changes(topobject
);
5633 /*----------------------------------------------*/
5634 /* Check for more than one button being pressed */
5635 /*----------------------------------------------*/
5637 Boolean
checkmultiple(XButtonEvent
*event
)
5639 int state
= Button1Mask
| Button2Mask
| Button3Mask
|
5640 Button4Mask
| Button5Mask
;
5641 state
&= event
->state
;
5642 /* ((x - 1) & x) is always non-zero if x has more than one bit set */
5643 return (((state
- 1) & state
) == 0) ? False
: True
;
5646 /*----------------------------------------------------------------------*/
5647 /* Operation continuation---dependent upon the ongoing operation. */
5648 /* This operation only pertains to a few event modes for which */
5649 /* continuation of action makes sense---drawing wires (polygons), and */
5650 /* editing polygons, arcs, splines, and paths. */
5651 /*----------------------------------------------------------------------*/
5653 void continue_op(int op
, int x
, int y
)
5657 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5658 window_to_user(x
, y
, &areawin
->save
);
5661 printpos(ppos
.x
, ppos
.y
);
5670 case(EPATH_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5671 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5672 path_op(*(EDITPART
), op
, x
, y
);
5675 inst_op(*(EDITPART
), op
, x
, y
);
5678 finish_op(XCF_Finish_Element
, x
, y
);
5685 /*--------------------------------------------------------------*/
5686 /* Finish or cancel an operation. This forces a return to */
5687 /* "normal" mode, with whatever other side effects are caused */
5688 /* by the operation. */
5689 /*--------------------------------------------------------------*/
5691 void finish_op(int op
, int x
, int y
)
5695 XPoint snappt
, boxpts
[4];
5698 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5699 window_to_user(x
, y
, &areawin
->save
);
5702 case(EPATH_MODE
): case(BOX_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5703 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5704 path_op(*(EDITPART
), op
, x
, y
);
5708 inst_op(*(EDITPART
), op
, x
, y
);
5711 case (FONTCAT_MODE
):
5712 case (EFONTCAT_MODE
):
5713 fontcat_op(op
, x
, y
);
5714 eventmode
= (eventmode
== FONTCAT_MODE
) ? TEXT_MODE
: ETEXT_MODE
;
5715 text_mode_draw(xcDRAW_INIT
, TOLABEL(EDITPART
));
5716 XDefineCursor (dpy
, areawin
->window
, TEXTPTR
);
5721 catalog_op(op
, x
, y
);
5733 curlabel
= TOLABEL(EDITPART
);
5734 if (op
== XCF_Cancel
) {
5735 redrawtext(curlabel
);
5736 areawin
->redraw_needed
= False
; /* ignore previous requests */
5737 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5738 freelabel(curlabel
->string
);
5744 singlebbox(EDITPART
);
5745 incr_changes(topobject
);
5746 select_invalidate_netlist();
5747 text_mode_draw(xcDRAW_FINAL
, curlabel
);
5749 setdefaultfontmarks();
5750 eventmode
= NORMAL_MODE
;
5753 case(ETEXT_MODE
): case(CATTEXT_MODE
):
5754 curlabel
= TOLABEL(EDITPART
);
5755 if (op
== XCF_Cancel
) {
5756 /* restore the original text */
5757 undrawtext(curlabel
);
5758 undo_finish_series();
5760 redrawtext(curlabel
);
5761 areawin
->redraw_needed
= False
; /* ignore previous requests */
5762 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5763 if (eventmode
== CATTEXT_MODE
) eventmode
= CATALOG_MODE
;
5765 setdefaultfontmarks();
5767 else textreturn(); /* Generate "return" key character */
5768 areawin
->textend
= 0;
5772 u2u_snap(&areawin
->save
);
5774 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5775 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5777 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5778 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5781 if (op
== XCF_Cancel
) {
5782 /* Just regenerate the library where we started */
5783 if (areawin
->selects
>= 1) {
5784 objinstptr selinst
= SELTOOBJINST(areawin
->selectlist
);
5785 libnum
= libfindobject(selinst
->thisobject
, NULL
);
5787 composelib(libnum
+ LIBRARY
);
5794 eventmode
= CATALOG_MODE
;
5795 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5799 u2u_snap(&areawin
->save
);
5801 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5802 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5804 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5805 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5808 if (op
== XCF_Cancel
) {
5809 /* If we came from the library with an object instance, in */
5810 /* MOVE_MODE, then "cancel" should delete the element. */
5811 /* Otherwise, put the position of the element back to what */
5812 /* it was before we started the move. The difference is */
5813 /* indicated by the value of areawin->editpart. */
5815 if ((areawin
->selects
> 0) && (*areawin
->selectlist
== topobject
->parts
))
5816 delete_noundo(NORMAL
);
5818 placeselects(areawin
->origin
.x
- areawin
->save
.x
,
5819 areawin
->origin
.y
- areawin
->save
.y
, NULL
);
5821 drawarea(NULL
, NULL
, NULL
);
5824 if (areawin
->selects
> 0) {
5825 register_for_undo(XCF_Move
,
5826 /* (was_preselected) ? UNDO_DONE : UNDO_MORE, */
5828 areawin
->topinstance
,
5829 (int)(areawin
->save
.x
- areawin
->origin
.x
),
5830 (int)(areawin
->save
.y
- areawin
->origin
.y
));
5831 pwriteback(areawin
->topinstance
);
5832 incr_changes(topobject
);
5833 select_invalidate_netlist();
5834 unselect_all(); /* The way it used to be. . . */
5837 /* full calc needed: move may shrink bbox */
5838 calcbbox(areawin
->topinstance
);
5840 /* if (!was_preselected) clearselects(); */
5842 areawin
->attachto
= -1;
5848 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5849 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5851 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5852 ButtonMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5855 rescale_mode_draw(xcDRAW_FINAL
, NULL
);
5856 if (op
!= XCF_Cancel
) {
5857 XPoint newpoints
[5];
5858 fscale
= UGetRescaleBox(&areawin
->save
, newpoints
);
5860 elementrescale(fscale
);
5861 areawin
->redraw_needed
= True
;
5864 eventmode
= NORMAL_MODE
;
5868 selarea_mode_draw(xcDRAW_FINAL
, NULL
);
5871 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5872 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5874 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5875 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5878 /* Zero-width boxes act like a normal selection. Otherwise, */
5879 /* proceed with the area select. */
5881 if ((areawin
->origin
.x
== areawin
->save
.x
) &&
5882 (areawin
->origin
.y
== areawin
->save
.y
))
5883 select_add_element(ALL_TYPES
);
5885 boxpts
[0] = areawin
->origin
;
5886 boxpts
[1].x
= areawin
->save
.x
;
5887 boxpts
[1].y
= areawin
->origin
.y
;
5888 boxpts
[2] = areawin
->save
;
5889 boxpts
[3].x
= areawin
->origin
.x
;
5890 boxpts
[3].y
= areawin
->save
.y
;
5891 selectarea(topobject
, boxpts
, 0);
5896 u2u_snap(&areawin
->save
);
5899 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5900 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5902 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5903 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5906 areawin
->panx
= areawin
->pany
= 0;
5907 if (op
!= XCF_Cancel
)
5908 panbutton((u_int
) 5, (areawin
->width
>> 1) - (x
- areawin
->origin
.x
),
5909 (areawin
->height
>> 1) - (y
- areawin
->origin
.y
), 0);
5915 /* Remove any selections */
5916 if ((eventmode
== SELAREA_MODE
) || (eventmode
== PAN_MODE
)
5917 || (eventmode
== MOVE_MODE
))
5919 eventmode
= NORMAL_MODE
;
5920 areawin
->redraw_needed
= True
;
5922 else if (eventmode
!= MOVE_MODE
&& eventmode
!= EPATH_MODE
&&
5923 eventmode
!= EPOLY_MODE
&& eventmode
!= ARC_MODE
&&
5924 eventmode
!= EARC_MODE
&& eventmode
!= SPLINE_MODE
&&
5925 eventmode
!= ESPLINE_MODE
&& eventmode
!= WIRE_MODE
&&
5926 eventmode
!= ETEXT_MODE
&& eventmode
!= TEXT_MODE
) {
5930 if (eventmode
== NORMAL_MODE
) {
5932 /* Return any highlighted networks to normal */
5933 highlightnetlist(topobject
, areawin
->topinstance
, 0);
5935 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5938 snap(x
, y
, &snappt
);
5939 printpos(snappt
.x
, snappt
.y
);
5942 /*--------------------------------------------------------------*/
5943 /* Edit operations for instances. This is used to allow */
5944 /* numeric parameters to be adjusted from the hierarchical */
5945 /* level above, shielding the the unparameterized parts from */
5947 /*--------------------------------------------------------------*/
5949 void inst_op(genericptr editpart
, int op
, int x
, int y
)
5951 UNUSED(editpart
); UNUSED(op
); UNUSED(x
); UNUSED(y
);
5954 /*--------------------------------------------------------------*/
5955 /* Operations for path components */
5956 /*--------------------------------------------------------------*/
5958 void path_op(genericptr editpart
, int op
, int x
, int y
)
5961 splineptr newspline
;
5962 Boolean donecycles
= False
;
5963 UNUSED(x
); UNUSED(y
);
5965 /* Don't allow point cycling in a multi-part edit. */
5966 /* Allowing it is just confusing. Instead, we treat */
5967 /* button 1 (cycle) like button 2 (finish). */
5968 if (op
== XCF_Continue_Element
&& areawin
->selects
> 1)
5969 op
= XCF_Finish_Element
;
5971 switch(ELEMENTTYPE(editpart
)) {
5973 pathptr newpath
= (pathptr
)editpart
;
5974 short dotrack
= True
;
5977 areawin
->attachto
= -1;
5979 if (op
!= XCF_Continue_Element
) {
5982 if (op
== XCF_Continue_Element
) {
5983 nextpathcycle(newpath
, 1);
5984 patheditpush(newpath
);
5986 else if (op
== XCF_Finish_Element
) {
5987 path_mode_draw(xcDRAW_FINAL
, newpath
);
5988 incr_changes(topobject
);
5990 else { /* restore previous path from edit stack */
5991 free_single((genericptr
)newpath
);
5992 if (areawin
->editstack
->parts
> 0) {
5993 if (op
== XCF_Cancel
) {
5994 editpath
= TOPATH(areawin
->editstack
->plist
);
5995 pathcopy(newpath
, editpath
);
5996 reset(areawin
->editstack
, NORMAL
);
5999 editpath
= TOPATH(areawin
->editstack
->plist
+
6000 areawin
->editstack
->parts
- 1);
6001 pathcopy(newpath
, editpath
);
6002 free_single((genericptr
)editpath
);
6004 areawin
->editstack
->parts
--;
6006 if (areawin
->editstack
->parts
> 0) {
6008 nextpathcycle(newpath
, 1);
6009 path_mode_draw(xcDRAW_EDIT
, newpath
);
6013 user_to_window(areawin
->origin
, &warppt
);
6014 warppointer(warppt
.x
, warppt
.y
);
6015 path_mode_draw(xcDRAW_FINAL
, newpath
);
6019 path_mode_draw(xcDRAW_EMPTY
, newpath
);
6021 free_single((genericptr
)newpath
);
6025 pwriteback(areawin
->topinstance
);
6028 /* Free the editstack */
6029 reset(areawin
->editstack
, NORMAL
);
6030 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6031 (xcEventHandler
)trackelement
, NULL
);
6032 eventmode
= NORMAL_MODE
;
6038 if (eventmode
== BOX_MODE
) {
6041 newbox
= (polyptr
)editpart
;
6043 /* prevent length and/or width zero boxes */
6044 if (newbox
->points
->x
!= (newbox
->points
+ 2)->x
&& (newbox
->points
6045 + 1)->y
!= (newbox
->points
+ 3)->y
) {
6046 if (op
!= XCF_Cancel
) {
6047 poly_mode_draw(xcDRAW_FINAL
, newbox
);
6048 incr_changes(topobject
);
6049 if (!nonnetwork(newbox
)) invalidate_netlist(topobject
);
6050 register_for_undo(XCF_Box
, UNDO_MORE
, areawin
->topinstance
,
6054 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6055 free_single((genericptr
)newbox
);
6062 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6063 free_single((genericptr
)newbox
);
6068 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6069 (xcEventHandler
)trackbox
, NULL
);
6070 eventmode
= NORMAL_MODE
;
6072 else { /* EPOLY_MODE */
6074 short dotrack
= True
;
6076 newpoly
= (polyptr
)editpart
;
6077 areawin
->attachto
= -1;
6079 if (op
!= XCF_Continue_Element
) {
6083 if (op
== XCF_Continue_Element
) {
6084 nextpolycycle(&newpoly
, 1);
6085 polyeditpush(newpoly
);
6087 else if (op
== XCF_Finish_Element
) {
6089 /* Check for degenerate polygons (all points the same). */
6091 for (i
= 1; i
< newpoly
->number
; i
++)
6092 if ((newpoly
->points
[i
].x
!= newpoly
->points
[i
- 1].x
) ||
6093 (newpoly
->points
[i
].y
!= newpoly
->points
[i
- 1].y
))
6095 if (i
== newpoly
->number
) {
6096 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6097 /* Remove this polygon with the standard delete */
6098 /* method (saves polygon on undo stack). */
6099 newpoly
->type
|= REMOVE_TAG
;
6100 delete_tagged(areawin
->topinstance
);
6103 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6104 if (!nonnetwork(newpoly
)) invalidate_netlist(topobject
);
6105 incr_changes(topobject
);
6110 free_single((genericptr
)newpoly
);
6111 if (areawin
->editstack
->parts
> 0) {
6112 if (op
== XCF_Cancel
) {
6113 editpoly
= TOPOLY(areawin
->editstack
->plist
);
6114 polycopy(newpoly
, editpoly
);
6115 reset(areawin
->editstack
, NORMAL
);
6118 editpoly
= TOPOLY(areawin
->editstack
->plist
+
6119 areawin
->editstack
->parts
- 1);
6120 polycopy(newpoly
, editpoly
);
6121 free_single((genericptr
)editpoly
);
6123 areawin
->editstack
->parts
--;
6125 if (areawin
->editstack
->parts
> 0) {
6127 nextpolycycle(&newpoly
, -1);
6128 poly_mode_draw(xcDRAW_EDIT
, newpoly
);
6131 XcTopSetForeground(newpoly
->color
);
6132 user_to_window(areawin
->origin
, &warppt
);
6133 warppointer(warppt
.x
, warppt
.y
);
6134 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6138 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6143 pwriteback(areawin
->topinstance
);
6146 /* Free the editstack */
6147 reset(areawin
->editstack
, NORMAL
);
6149 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6150 (xcEventHandler
)trackelement
, NULL
);
6151 eventmode
= NORMAL_MODE
;
6158 arcptr newarc
, editarc
;
6159 short dotrack
= True
;
6161 newarc
= (arcptr
)editpart
;
6163 if (op
!= XCF_Continue_Element
) {
6167 if (op
== XCF_Continue_Element
) {
6168 nextarccycle(&newarc
, 1);
6169 arceditpush(newarc
);
6172 else if (op
== XCF_Finish_Element
) {
6175 if (newarc
->radius
!= 0 && newarc
->yaxis
!= 0 &&
6176 (newarc
->angle1
!= newarc
->angle2
)) {
6177 XTopSetForeground(newarc
->color
);
6178 incr_changes(topobject
);
6179 if (eventmode
== ARC_MODE
) {
6180 register_for_undo(XCF_Arc
, UNDO_MORE
, areawin
->topinstance
,
6183 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6187 /* Remove the record if the radius is zero. If we were */
6188 /* creating the arc, just delete it; it's as if it */
6189 /* never existed. If we were editing an arc, use the */
6190 /* standard delete method (saves arc on undo stack). */
6192 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6193 if (eventmode
== ARC_MODE
) {
6194 free_single((genericptr
)newarc
);
6199 newarc
->type
|= REMOVE_TAG
;
6200 delete_tagged(areawin
->topinstance
);
6204 else { /* Cancel: restore previous arc from edit stack */
6205 free_single((genericptr
)newarc
);
6206 if (areawin
->editstack
->parts
> 0) {
6207 if (op
== XCF_Cancel
) {
6208 editarc
= TOARC(areawin
->editstack
->plist
);
6209 arccopy(newarc
, editarc
);
6210 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6211 reset(areawin
->editstack
, NORMAL
);
6214 editarc
= TOARC(areawin
->editstack
->plist
+
6215 areawin
->editstack
->parts
- 1);
6216 arccopy(newarc
, editarc
);
6217 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6218 free_single((genericptr
)editarc
);
6220 areawin
->editstack
->parts
--;
6222 if (areawin
->editstack
->parts
> 0) {
6224 nextarccycle(&newarc
, -1);
6225 arc_mode_draw(xcDRAW_EDIT
, newarc
);
6228 if (eventmode
!= ARC_MODE
) {
6230 user_to_window(areawin
->origin
, &warppt
);
6231 warppointer(warppt
.x
, warppt
.y
);
6233 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6237 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6241 pwriteback(areawin
->topinstance
);
6244 /* Free the editstack */
6245 reset(areawin
->editstack
, NORMAL
);
6247 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6248 (xcEventHandler
)trackarc
, NULL
);
6249 eventmode
= NORMAL_MODE
;
6254 splineptr editspline
;
6255 short dotrack
= True
;
6257 newspline
= (splineptr
)editpart
;
6259 if (op
!= XCF_Continue_Element
) {
6263 if (op
== XCF_Continue_Element
) {
6264 /* Note: we work backwards through spline control points. */
6265 /* The reason is that when creating a spline, the sudden */
6266 /* move from the endpoint to the startpoint (forward */
6267 /* direction) is more disorienting than moving from the */
6268 /* endpoint to the endpoint's control point. */
6270 nextsplinecycle(&newspline
, -1);
6271 splineeditpush(newspline
);
6274 /* unlikely but possible to create zero-length splines */
6275 else if (newspline
->ctrl
[0].x
!= newspline
->ctrl
[3].x
||
6276 newspline
->ctrl
[0].x
!= newspline
->ctrl
[1].x
||
6277 newspline
->ctrl
[0].x
!= newspline
->ctrl
[2].x
||
6278 newspline
->ctrl
[0].y
!= newspline
->ctrl
[3].y
||
6279 newspline
->ctrl
[0].y
!= newspline
->ctrl
[1].y
||
6280 newspline
->ctrl
[0].y
!= newspline
->ctrl
[2].y
) {
6281 if (op
== XCF_Finish_Element
) {
6282 incr_changes(topobject
);
6283 if (eventmode
== SPLINE_MODE
) {
6284 register_for_undo(XCF_Spline
, UNDO_MORE
, areawin
->topinstance
,
6287 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6289 else { /* restore previous spline from edit stack */
6290 free_single((genericptr
)newspline
);
6291 if (areawin
->editstack
->parts
> 0) {
6292 if (op
== XCF_Cancel
) {
6293 editspline
= TOSPLINE(areawin
->editstack
->plist
);
6294 splinecopy(newspline
, editspline
);
6295 reset(areawin
->editstack
, NORMAL
);
6298 editspline
= TOSPLINE(areawin
->editstack
->plist
+
6299 areawin
->editstack
->parts
- 1);
6300 splinecopy(newspline
, editspline
);
6301 free_single((genericptr
)editspline
);
6303 areawin
->editstack
->parts
--;
6305 if (areawin
->editstack
->parts
> 0) {
6307 nextsplinecycle(&newspline
, 1);
6308 spline_mode_draw(xcDRAW_EDIT
, newspline
);
6311 if (eventmode
!= SPLINE_MODE
) {
6313 user_to_window(areawin
->origin
, &warppt
);
6314 warppointer(warppt
.x
, warppt
.y
);
6316 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6320 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6326 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6327 free_single((genericptr
)newspline
);
6331 pwriteback(areawin
->topinstance
);
6334 /* Free the editstack */
6335 reset(areawin
->editstack
, NORMAL
);
6337 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6338 (xcEventHandler
)trackelement
, NULL
);
6339 eventmode
= NORMAL_MODE
;
6344 calcbbox(areawin
->topinstance
);
6346 /* Multiple-element edit: Some items may have been moved as */
6347 /* opposed to edited, and should be registered here. To do */
6348 /* this correctly, we must first unselect the edited items, */
6349 /* then register the move for the remaining items. */
6354 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6355 areawin
->selects
; eselect
++)
6356 checkcycle(SELTOGENERIC(eselect
), 0);
6358 /* Remove all (remaining) cycles */
6359 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6360 areawin
->selects
; eselect
++)
6361 removecycle(SELTOGENERICPTR(eselect
));
6363 /* Remove edits from the undo stack when canceling */
6364 if (op
== XCF_Cancel
|| op
== XCF_Cancel_Last
) {
6365 if (xobjs
.undostack
&& (xobjs
.undostack
->type
== XCF_Edit
)) {
6366 undo_finish_series();
6373 /*-------------------------------------------------------*/
6374 /* Recalculate values for a drawing-area widget resizing */
6375 /*-------------------------------------------------------*/
6377 void resizearea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6383 int savewidth
= areawin
->width
, saveheight
= areawin
->height
;
6384 XCWindowData
*thiswin
;
6387 #endif /* !HAVE_CAIRO */
6388 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6390 if ((dpy
!= NULL
) && xcIsRealized(areawin
->area
)) {
6393 areawin
->width
= Tk_Width(w
);
6394 areawin
->height
= Tk_Height(w
);
6396 XtSetArg(wargs
[0], XtNwidth
, &areawin
->width
);
6397 XtSetArg(wargs
[1], XtNheight
, &areawin
->height
);
6398 XtGetValues(areawin
->area
, wargs
, 2);
6401 if (areawin
->width
!= savewidth
|| areawin
->height
!= saveheight
) {
6403 int maxwidth
= 0, maxheight
= 0;
6404 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6405 if (thiswin
->width
> maxwidth
) maxwidth
= thiswin
->width
;
6406 if (thiswin
->height
> maxheight
) maxheight
= thiswin
->height
;
6408 #if !defined(HAVE_CAIRO)
6409 if (dbuf
!= (Pixmap
)NULL
) XFreePixmap(dpy
, dbuf
);
6410 dbuf
= XCreatePixmap(dpy
, areawin
->window
, maxwidth
, maxheight
,
6411 DefaultDepthOfScreen(xcScreen(w
)));
6414 /* TODO: probably make this a generalized function call, which */
6415 /* should be handled depending on the surface in the xtgui.c, */
6416 /* xcwin32.c, etc. files. */
6417 /* For now only support xlib surface */
6418 cairo_xlib_surface_set_size(areawin
->surface
, areawin
->width
,
6421 if (areawin
->clipmask
!= (Pixmap
)NULL
) XFreePixmap(dpy
, areawin
->clipmask
);
6422 areawin
->clipmask
= XCreatePixmap(dpy
, areawin
->window
,
6423 maxwidth
, maxheight
, 1);
6425 if (areawin
->pbuf
!= (Pixmap
)NULL
) {
6426 XFreePixmap(dpy
, areawin
->pbuf
);
6427 areawin
->pbuf
= XCreatePixmap(dpy
, areawin
->window
,
6428 maxwidth
, maxheight
, 1);
6431 if (areawin
->cmgc
!= (GC
)NULL
) XFreeGC(dpy
, areawin
->cmgc
);
6432 values
.foreground
= 0;
6433 values
.background
= 0;
6434 areawin
->cmgc
= XCreateGC(dpy
, areawin
->clipmask
,
6435 GCForeground
| GCBackground
, &values
);
6436 #endif /* !HAVE_CAIRO */
6438 /* Clear fixed_pixmap */
6439 if (areawin
->fixed_pixmap
) {
6441 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6442 areawin
->fixed_pixmap
= NULL
;
6443 #else /* !HAVE_CAIRO */
6444 XFreePixmap(dpy
, areawin
->fixed_pixmap
);
6445 areawin
->fixed_pixmap
= (Pixmap
) NULL
;
6446 #endif /* !HAVE_CAIRO */
6451 /* Re-compose the directores to match the new dimensions */
6453 composelib(PAGELIB
);
6455 /* Re-center image in resized window */
6456 zoomview(NULL
, NULL
, NULL
);
6459 /* Flush all expose events from the buffer */
6460 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
) == True
);
6464 /*----------------------*/
6465 /* Draw the grids, etc. */
6466 /*----------------------*/
6469 void draw_grids(void)
6471 float x
, y
, spc
, spc2
, i
, j
, fpart
;
6472 float major_snapspace
, spc3
;
6474 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
6475 if (areawin
->gridon
&& spc
> 8) {
6476 fpart
= (float)(-areawin
->pcorner
.x
)
6477 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6478 x
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6479 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6480 fpart
= (float)(-areawin
->pcorner
.y
)
6481 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6482 y
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6483 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6485 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6486 for (i
= x
; i
< (float)areawin
->width
; i
+= spc
)
6487 DrawLine (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6488 0, (int)(i
+ 0.5), areawin
->height
);
6489 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc
)
6490 DrawLine (dpy
, areawin
->window
, areawin
->gc
, 0, (int)(j
- 0.5),
6491 areawin
->width
, (int)(j
- 0.5));
6494 if (areawin
->axeson
) {
6495 XPoint originpt
, zeropt
;
6496 zeropt
.x
= zeropt
.y
= 0;
6497 SetForeground(dpy
, areawin
->gc
, AXESCOLOR
);
6498 user_to_window(zeropt
, &originpt
);
6499 DrawLine(dpy
, areawin
->window
, areawin
->gc
, originpt
.x
, 0,
6500 originpt
.x
, areawin
->height
);
6501 DrawLine(dpy
, areawin
->window
, areawin
->gc
, 0, originpt
.y
,
6502 areawin
->width
, originpt
.y
);
6505 /* bounding box goes beneath everything except grid/axis lines */
6508 /* draw a little red dot at each snap-to point */
6510 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
6511 if (areawin
->snapto
&& spc2
> 8) {
6514 fpart
= (float)(-areawin
->pcorner
.x
)
6515 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6516 x2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6517 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6518 fpart
= (float)(-areawin
->pcorner
.y
)
6519 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6520 y2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6521 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6523 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6525 HDC hdc
= CreateCompatibleDC(NULL
);
6526 SelectObject(hdc
, Tk_GetHWND(areawin
->window
));
6528 SetForeground(dpy
, areawin
->gc
, SNAPCOLOR
);
6529 for (i
= x2
; i
< areawin
->width
; i
+= spc2
)
6530 for (j
= areawin
->height
- y2
; j
> 0; j
-= spc2
)
6531 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6532 SetPixelV(hdc
, (int)(i
+ 0.5), (int)(j
- 0.05), areawin
->gc
->foreground
);
6534 DrawPoint (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6536 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6542 /* Draw major snap points (code contributed by John Barry) */
6544 major_snapspace
= xobjs
.pagelist
[areawin
->page
]->gridspace
* 20;
6545 spc3
= major_snapspace
* areawin
->vscale
;
6547 fpart
= (float)(-areawin
->pcorner
.x
) / major_snapspace
;
6548 x
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6549 fpart
= (float)(-areawin
->pcorner
.y
) / major_snapspace
;
6550 y
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6552 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6553 for (i
= x
; i
< (float)areawin
->width
; i
+= spc3
) {
6554 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc3
) {
6555 XDrawArc(dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5) - 1,
6556 (int)(j
- 0.5) - 1, 2, 2, 0, 360*64);
6561 SetBackground(dpy
, areawin
->gc
, BACKGROUND
);
6563 #endif /* !HAVE_CAIRO */
6565 /*------------------------------------------------------*/
6566 /* Draw fixed parts of the primary graphics window */
6567 /*------------------------------------------------------*/
6569 void draw_fixed(void)
6571 Boolean old_ongoing
;
6574 #endif /* !HAVE_CAIRO */
6576 if (xobjs
.suspend
>= 0) return;
6577 old_ongoing
= areawin
->redraw_ongoing
;
6578 areawin
->redraw_ongoing
= True
;
6580 /* Set drawing context to fixed_pixmap */
6582 cairo_identity_matrix(areawin
->cr
);
6583 cairo_push_group(areawin
->cr
);
6584 #else /* HAVE_CAIRO */
6585 old_window
= areawin
->window
;
6586 areawin
->window
= areawin
->fixed_pixmap
;
6587 #endif /* HAVE_CAIRO */
6589 /* Clear background */
6591 if (xobjs
.pagelist
[areawin
->page
]->background
.name
!= (char *)NULL
) {
6595 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6596 cairo_paint(areawin
->cr
);
6597 #endif /* HAVE_GS */
6600 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6601 cairo_paint(areawin
->cr
);
6603 #else /* HAVE_CAIRO */
6604 if (xobjs
.pagelist
[areawin
->page
]->background
.name
== (char *)NULL
6605 || (copybackground() < 0)) {
6606 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6607 XFillRectangle(dpy
, areawin
->window
, areawin
->gc
, 0, 0, areawin
->width
,
6610 SetThinLineAttributes(dpy
, areawin
->gc
, 0, LineSolid
, CapRound
, JoinBevel
);
6611 #endif /* !HAVE_CAIRO */
6615 /* draw GRIDCOLOR lines for grid; mark axes in AXESCOLOR */
6617 if (eventmode
!= CATALOG_MODE
&& eventmode
!= ASSOC_MODE
6618 && eventmode
!= FONTCAT_MODE
&& eventmode
!= EFONTCAT_MODE
6619 && eventmode
!= CATMOVE_MODE
&& eventmode
!= CATTEXT_MODE
) {
6623 /* Determine the transformation matrix for the topmost object */
6624 /* and draw the hierarchy above the current edit object (if */
6625 /* "edit-in-place" is selected). */
6627 if (areawin
->editinplace
== True
) {
6628 if (areawin
->stack
!= NULL
) {
6629 pushlistptr lastlist
= NULL
, thislist
;
6632 UPushCTM(); /* save our current state */
6634 /* It's easiest if we first push the current page onto the stack, */
6635 /* then we don't need to treat the top-level page separately. We */
6636 /* pop it at the end. */
6637 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
6639 thislist
= areawin
->stack
;
6641 while ((thislist
!= NULL
) &&
6642 (is_library(thislist
->thisinst
->thisobject
) < 0)) {
6644 /* Invert the transformation matrix of the instance on the stack */
6645 /* to get the proper transformation matrix of the drawing one */
6646 /* up in the hierarchy. */
6649 UPreMultCTM(&mtmp
, thislist
->thisinst
->position
,
6650 thislist
->thisinst
->scale
, thislist
->thisinst
->rotation
);
6652 UPreMultCTMbyMat(DCTM
, &mtmp
);
6654 lastlist
= thislist
;
6655 thislist
= thislist
->next
;
6657 /* The following will be true for moves between schematics and symbols */
6658 if ((thislist
!= NULL
) && (thislist
->thisinst
->thisobject
->symschem
6659 == lastlist
->thisinst
->thisobject
))
6663 if (lastlist
!= NULL
) {
6664 pushlistptr stack
= NULL
;
6665 SetForeground(dpy
, areawin
->gc
, OFFBUTTONCOLOR
);
6666 UDrawObject(lastlist
->thisinst
, SINGLE
, DOFORALL
,
6667 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &stack
);
6668 /* This shouldn't happen, but just in case. . . */
6669 if (stack
) free_stack(&stack
);
6672 pop_stack(&areawin
->stack
); /* restore the original stack state */
6673 UPopCTM(); /* restore the original matrix state */
6678 /* draw all of the elements on the screen */
6680 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
6682 /* Initialize hierstack */
6683 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6684 UDrawObject(areawin
->topinstance
, TOPLEVEL
, FOREGROUND
,
6685 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &areawin
->hierstack
);
6686 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6689 if (areawin
->fixed_pixmap
)
6690 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6691 areawin
->fixed_pixmap
= cairo_pop_group(areawin
->cr
);
6692 #else /* HAVE_CAIRO */
6693 areawin
->window
= old_window
;
6694 #endif /* HAVE_CAIRO */
6695 areawin
->redraw_ongoing
= old_ongoing
;
6698 /*--------------------------------------*/
6699 /* Draw the primary graphics window */
6700 /*--------------------------------------*/
6702 void drawwindow(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6705 xcDrawType redrawtype
= xcDRAW_EDIT
;
6706 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6708 if (areawin
->area
== NULL
) return;
6709 if (!xcIsRealized(areawin
->area
)) return;
6710 if (xobjs
.suspend
>= 0) return;
6713 /* Make sure a fixed pixmap exists */
6714 if (!areawin
->fixed_pixmap
) {
6715 areawin
->fixed_pixmap
= XCreatePixmap(dpy
, areawin
->window
,
6716 areawin
->width
, areawin
->height
,
6717 DefaultDepthOfScreen(xcScreen(areawin
->area
)));
6719 #endif /* !HAVE_CAIRO */
6721 /* Sanity check---specifically to track down an error */
6722 if ((areawin
->selects
== 1) && *(areawin
->selectlist
) >= topobject
->parts
) {
6723 Wprintf("Internal error!");
6724 areawin
->selects
= 0;
6728 if (areawin
->redraw_needed
)
6729 redrawtype
= xcREDRAW_FORCED
;
6731 switch (eventmode
) {
6732 case ARC_MODE
: case EARC_MODE
:
6733 arc_mode_draw(redrawtype
, TOARC(EDITPART
));
6735 case SPLINE_MODE
: case ESPLINE_MODE
:
6736 spline_mode_draw(redrawtype
, TOSPLINE(EDITPART
));
6738 case BOX_MODE
: case EPOLY_MODE
: case WIRE_MODE
:
6739 poly_mode_draw(redrawtype
, TOPOLY(EDITPART
));
6742 path_mode_draw(redrawtype
, TOPATH(EDITPART
));
6744 case TEXT_MODE
: case CATTEXT_MODE
: case ETEXT_MODE
:
6745 text_mode_draw(redrawtype
, TOLABEL(EDITPART
));
6748 selarea_mode_draw(redrawtype
, NULL
);
6751 rescale_mode_draw(redrawtype
, NULL
);
6753 case CATMOVE_MODE
: case MOVE_MODE
: case COPY_MODE
:
6754 move_mode_draw(redrawtype
, NULL
);
6756 case ASSOC_MODE
: case EINST_MODE
: case FONTCAT_MODE
: case EFONTCAT_MODE
:
6757 case PAN_MODE
: case NORMAL_MODE
: case UNDO_MODE
: case CATALOG_MODE
:
6758 normal_mode_draw(redrawtype
, NULL
);
6761 /* flush out multiple expose/resize events from the event queue */
6762 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
));
6764 /* end by restoring graphics state */
6765 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
6767 areawin
->redraw_needed
= False
;
6770 /*----------------------------------------------------------------------*/
6771 /* Draw the current window (areawin). Check if other windows contain */
6772 /* the same object or one of its ancestors. If so, redraw them, too. */
6773 /*----------------------------------------------------------------------*/
6775 void drawarea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6777 XCWindowDataPtr thiswin
, focuswin
;
6779 if (xobjs
.suspend
>= 0) {
6780 if (xobjs
.suspend
== 0)
6781 xobjs
.suspend
= 1; /* Mark that a refresh is pending */
6787 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6788 if (thiswin
== focuswin
) continue;
6790 /* Note: need to check ancestry here, not just blindly redraw */
6791 /* all the windows all the time. */
6795 /* Don't respond to an expose event if the graphics context */
6796 /* has not yet been created. */
6797 if (areawin
->cr
!= NULL
)
6799 drawwindow(NULL
, NULL
, NULL
);
6802 drawwindow(w
, clientdata
, calldata
);
6805 /*-------------------------------------------------------------------------*/