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
;
2428 /* ASCII values already come upper/lowercase; we only want to register */
2429 /* a Shift key if it's a non-ASCII key or another modifier is in effect */
2431 keywstate
|= (((LockMask
| ControlMask
| Mod1Mask
) & event
->state
) << 16);
2432 if (keywstate
> 255) keywstate
|= ((ShiftMask
& event
->state
) << 16);
2434 /* Treat button events and key events in the same way by setting */
2435 /* a key state for buttons */
2437 if (keypressed
== 0)
2438 keywstate
|= (((Button1Mask
| Button2Mask
| Button3Mask
| Button4Mask
|
2439 Button5Mask
| ShiftMask
)
2440 & event
->state
) << 16);
2445 /*------------------------*/
2446 /* Handle keyboard inputs */
2447 /*------------------------*/
2449 void keyhandler(xcWidget w
, caddr_t clientdata
, XKeyEvent
*event
)
2451 int keywstate
; /* KeySym with prepended state information */
2453 UNUSED(w
); UNUSED(clientdata
);
2456 if (popups
> 0) return;
2458 if (popups
> 0 && help_up
== 0) return;
2461 if ((event
->type
== KeyRelease
) || (event
->type
== ButtonRelease
)) {
2463 /* Register a "tap" event if a key or button was released */
2464 /* while a timeout event is pending. */
2466 if (areawin
->time_id
!= 0) {
2467 xcRemoveTimeOut(areawin
->time_id
);
2468 areawin
->time_id
= 0;
2469 keywstate
= getkeysignature(event
);
2470 eventdispatch(keywstate
, areawin
->save
.x
, areawin
->save
.y
);
2473 keywstate
= getkeysignature(event
);
2474 if ((pressmode
!= 0) && (keywstate
== pressmode
)) {
2475 /* Events that require hold & drag (namely, MOVE_MODE) */
2476 /* must be resolved here. Call finish_op() to ensure */
2477 /* that we restore xcircuit to a state of sanity. */
2479 finish_op(XCF_Finish
, event
->x
, event
->y
);
2481 if (areawin
->redraw_needed
)
2482 drawarea(NULL
, NULL
, NULL
);
2484 return; /* Ignore all other release events */
2488 /* Check if any bindings match key/button "hold". If so, then start */
2489 /* the timer and wait for key release or timeout. */
2492 keywstate
= getkeysignature(event
);
2493 if ((keywstate
!= -1) && (xobjs
.hold
== TRUE
)) {
2495 /* Establish whether a HOLD modifier binding would apply in */
2496 /* the current eventmode. If so, set the HOLD timer. */
2498 func
= boundfunction(areawin
->area
, keywstate
| HOLD_MASK
, NULL
);
2500 areawin
->save
.x
= event
->x
;
2501 areawin
->save
.y
= event
->y
;
2502 areawin
->time_id
= xcAddTimeOut(app
, PRESSTIME
,
2503 makepress
, (ClientData
)((pointertype
)keywstate
));
2508 eventdispatch(keywstate
, event
->x
, event
->y
);
2512 /*--------------------------------*/
2513 /* Set snap spacing from keyboard */
2514 /*--------------------------------*/
2516 void setsnap(short direction
)
2518 float oldsnap
= xobjs
.pagelist
[areawin
->page
]->snapspace
;
2521 if (direction
> 0) xobjs
.pagelist
[areawin
->page
]->snapspace
*= 2;
2524 xobjs
.pagelist
[areawin
->page
]->snapspace
/= 2;
2526 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2527 Wprintf("Snap space at minimum value of %s", buffer
);
2530 if (xobjs
.pagelist
[areawin
->page
]->snapspace
!= oldsnap
) {
2531 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2532 Wprintf("Snap spacing set to %s", buffer
);
2533 areawin
->redraw_needed
= True
;
2534 drawarea(NULL
, NULL
, NULL
);
2538 /*-----------------------------------------*/
2539 /* Reposition an object onto the snap grid */
2540 /*-----------------------------------------*/
2545 Boolean preselected
;
2547 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
2548 if (!checkselect(ALL_TYPES
)) return;
2549 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
2550 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
2551 + areawin
->selects
; selectobj
++) {
2552 easydraw(*selectobj
, DOFORALL
);
2553 switch(SELECTTYPE(selectobj
)) {
2555 objinstptr snapobj
= SELTOOBJINST(selectobj
);
2557 u2u_snap(&snapobj
->position
);
2560 graphicptr snapg
= SELTOGRAPHIC(selectobj
);
2562 u2u_snap(&snapg
->position
);
2565 labelptr snaplabel
= SELTOLABEL(selectobj
);
2567 u2u_snap(&snaplabel
->position
);
2570 polyptr snappoly
= SELTOPOLY(selectobj
);
2571 pointlist snappoint
;
2573 for (snappoint
= snappoly
->points
; snappoint
< snappoly
->points
+
2574 snappoly
->number
; snappoint
++)
2575 u2u_snap(snappoint
);
2578 arcptr snaparc
= SELTOARC(selectobj
);
2580 u2u_snap(&snaparc
->position
);
2581 if (areawin
->snapto
) {
2582 snaparc
->radius
= (snaparc
->radius
/
2583 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2584 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2585 snaparc
->yaxis
= (snaparc
->yaxis
/
2586 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2587 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2592 splineptr snapspline
= SELTOSPLINE(selectobj
);
2595 for (i
= 0; i
< 4; i
++)
2596 u2u_snap(&snapspline
->ctrl
[i
]);
2597 calcspline(snapspline
);
2600 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
2601 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
2602 easydraw(*selectobj
, DOFORALL
);
2605 select_invalidate_netlist();
2606 if (eventmode
== NORMAL_MODE
)
2611 /*----------------------------------------------*/
2612 /* Routines to print the cursor position */
2613 /*----------------------------------------------*/
2615 /*----------------------------------------------*/
2616 /* fast integer power-of-10 routine */
2617 /*----------------------------------------------*/
2625 case 0: return 1; break;
2626 case 1: return 10; break;
2627 case 2: return 100; break;
2628 case 3: return 1000; break;
2631 for (i
= 1; i
< a
+ 1; i
++) istr
[i
] = '0';
2638 /*--------------------------------------------------*/
2639 /* find greatest common factor between two integers */
2640 /*--------------------------------------------------*/
2642 int calcgcf(int a
, int b
)
2646 if ((mod
= a
% b
) == 0) return (b
);
2647 else return (calcgcf(b
, mod
));
2650 /*--------------------------------------------------------------*/
2651 /* generate a fraction from a float, if possible */
2652 /* fraction returned as a string (must be allocated beforehand) */
2653 /*--------------------------------------------------------------*/
2655 void fraccalc(float xyval
, char *fstr
)
2658 int ip
, mant
, divisor
, denom
, numer
, rpart
;
2660 char num
[10], *nptr
= &num
[2], *sptr
;
2663 fp
= fabs(xyval
- ip
);
2665 /* write fractional part and grab mantissa as integer */
2667 sprintf(num
, "%1.7f", fp
);
2668 num
[8] = '\0'; /* no rounding up! */
2669 sscanf(nptr
, "%d", &mant
);
2671 if (mant
!= 0) { /* search for repeating substrings */
2672 for (i
= 1; i
<= 3; i
++) {
2675 while ((sptr
= nptr
- rept
* i
) >= &num
[2]) {
2676 for (t
= 0; t
< i
; t
++)
2677 if (*(sptr
+ t
) != *(nptr
+ t
)) break;
2681 if (rept
> 1) break;
2684 sscanf(nptr
, "%d", &rpart
); /* rpart is repeating part of mantissa */
2685 if (i
> 3 || rpart
== 0) { /* no repeat */
2686 divisor
= calcgcf(1000000, mant
);
2687 denom
= 1000000 / divisor
;
2693 sscanf(&num
[2], "%d", &z
);
2695 mant
= z
* p
+ rpart
;
2696 fd
= ipow10(nptr
- &num
[2]) * p
;
2698 divisor
= calcgcf(fd
, mant
);
2699 denom
= fd
/ divisor
;
2701 numer
= mant
/ divisor
;
2703 sprintf(fstr
, "%5.3f", xyval
);
2705 sprintf(fstr
, "%hd/%hd", (xyval
> 0) ? numer
: -numer
, denom
);
2707 sprintf(fstr
, "%hd %hd/%hd", ip
, numer
, denom
);
2709 else sprintf(fstr
, "%hd", ip
);
2712 /*------------------------------------------------------------------------------*/
2713 /* Print the position of the cursor in the upper right-hand message window */
2714 /*------------------------------------------------------------------------------*/
2716 void printpos(short xval
, short yval
)
2719 float oscale
, iscale
= (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
/
2720 (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
;
2723 XPoint
*tpoint
, *npoint
;
2727 /* For polygons, print the length (last line of a wire or polygon) or */
2728 /* length and width (box only) */
2730 if (eventmode
== BOX_MODE
|| eventmode
== EPOLY_MODE
|| eventmode
== WIRE_MODE
) {
2731 polyptr lwire
= (eventmode
== BOX_MODE
) ? TOPOLY(ENDPART
) : TOPOLY(EDITPART
);
2732 if ((eventmode
== EPOLY_MODE
) && (lwire
->number
> 2)) {
2733 /* sanity check on edit cycle */
2734 cycle
= (lwire
->cycle
) ? lwire
->cycle
->number
: -1;
2735 if (cycle
< 0 || cycle
>= lwire
->number
) {
2736 advancecycle((genericptr
*)(&lwire
), 0);
2739 tpoint
= lwire
->points
+ cycle
;
2740 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, 1);
2741 llen
= wirelength(tpoint
, npoint
);
2742 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, -1);
2743 lwid
= wirelength(tpoint
, npoint
);
2745 if (lwire
->style
& UNCLOSED
) { /* unclosed polys */
2748 else if (cycle
== lwire
->number
- 1) {
2753 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2759 else if (eventmode
== BOX_MODE
) {
2760 tpoint
= lwire
->points
;
2761 npoint
= lwire
->points
+ 1;
2762 llen
= wirelength(tpoint
, npoint
);
2763 npoint
= lwire
->points
+ 3;
2764 lwid
= wirelength(tpoint
, npoint
);
2765 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2773 tpoint
= lwire
->points
+ lwire
->number
- 1;
2774 llen
= wirelength(tpoint
- 1, tpoint
);
2778 else if (eventmode
== ARC_MODE
|| eventmode
== EARC_MODE
) {
2779 arcptr larc
= (eventmode
== ARC_MODE
) ? TOARC(ENDPART
) : TOARC(EDITPART
);
2780 llen
= larc
->radius
;
2781 if (abs(larc
->radius
) != larc
->yaxis
) {
2789 switch (xobjs
.pagelist
[areawin
->page
]->coordstyle
) {
2791 sprintf(_STR
, "%g, %g", xval
* iscale
, yval
* iscale
);
2792 sptr
= _STR
+ strlen(_STR
);
2795 sprintf(sptr
, " (%g x %g)", llen
* iscale
, lwid
* iscale
);
2797 sprintf(sptr
, " (length %g)", llen
* iscale
);
2801 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2802 f1
= ((float)(xval
) * iscale
* oscale
) / 72.0;
2803 f2
= ((float)(yval
) * iscale
* oscale
) / 72.0;
2804 sprintf(_STR
, "%5.3f, %5.3f in", f1
, f2
);
2805 sptr
= _STR
+ strlen(_STR
);
2807 f1
= ((float)(llen
) * iscale
* oscale
) / 72.0;
2809 f2
= ((float)(lwid
) * iscale
* oscale
) / 72.0;
2810 sprintf(sptr
, " (%5.3f x %5.3f in)", f1
, f2
);
2813 sprintf(sptr
, " (length %5.3f in)", f1
);
2817 char fstr1
[30], fstr2
[30];
2819 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2820 fraccalc((((float)(xval
) * iscale
* oscale
) / 72.0), fstr1
);
2821 fraccalc((((float)(yval
) * iscale
* oscale
) / 72.0), fstr2
);
2822 sprintf(_STR
, "%s, %s in", fstr1
, fstr2
);
2823 sptr
= _STR
+ strlen(_STR
);
2825 fraccalc((((float)(llen
) * iscale
* oscale
) / 72.0), fstr1
);
2827 fraccalc((((float)(lwid
) * iscale
* oscale
) / 72.0), fstr2
);
2828 sprintf(sptr
, " (%s x %s in)", fstr1
, fstr2
);
2831 sprintf(sptr
, " (length %s in)", fstr1
);
2835 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* CMSCALE
;
2836 f1
= ((float)(xval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2837 f2
= ((float)(yval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2838 sprintf(_STR
, "%5.3f, %5.3f cm", f1
, f2
);
2839 sptr
= _STR
+ strlen(_STR
);
2841 f1
= ((float)(llen
) * iscale
* oscale
) / IN_CM_CONVERT
;
2843 f2
= ((float)(lwid
) * iscale
* oscale
) / IN_CM_CONVERT
;
2844 sprintf(sptr
, " (%5.3f x %5.3f cm)", f1
, f2
);
2847 sprintf(sptr
, " (length %5.3f cm)", f1
);
2854 /*---------------------------------------------------*/
2855 /* Find nearest point of intersection of the cursor */
2856 /* position to a wire and move there. */
2857 /*---------------------------------------------------*/
2859 void findwirex(XPoint
*endpt1
, XPoint
*endpt2
, XPoint
*userpt
,
2860 XPoint
*newpos
, float *rot
)
2865 xsq
= sqwirelen(endpt1
, endpt2
);
2866 ysq
= sqwirelen(endpt1
, userpt
);
2867 zsq
= sqwirelen(endpt2
, userpt
);
2868 frac
= 0.5 + (float)(ysq
- zsq
) / (float)(xsq
<< 1);
2869 if (frac
> 1) frac
= 1;
2870 else if (frac
< 0) frac
= 0;
2871 newpos
->x
= endpt1
->x
+ (int)((endpt2
->x
- endpt1
->x
) * frac
);
2872 newpos
->y
= endpt1
->y
+ (int)((endpt2
->y
- endpt1
->y
) * frac
);
2874 *rot
= 180.0 + INVRFAC
* atan2((double)(endpt1
->x
-
2875 endpt2
->x
), (double)(endpt1
->y
- endpt2
->y
));
2878 /*----------------------------------------------------------------*/
2879 /* Find the closest point of attachment from the pointer position */
2880 /* to the "attachto" element. */
2881 /*----------------------------------------------------------------*/
2883 void findattach(XPoint
*newpos
, float *rot
, XPoint
*userpt
)
2885 XPoint
*endpt1
, *endpt2
;
2890 if (rot
) locrot
= *rot
;
2892 /* find point of intersection and slope */
2894 if (SELECTTYPE(&areawin
->attachto
) == ARC
) {
2895 arcptr aarc
= SELTOARC(&areawin
->attachto
);
2897 tmpang
= atan2((double)(userpt
->y
- aarc
->position
.y
) * (double)
2898 (abs(aarc
->radius
)), (double)(userpt
->x
- aarc
->position
.x
) *
2899 (double)aarc
->yaxis
);
2901 /* don't follow the arc beyond its endpoints */
2903 tmpdeg
= (float)(tmpang
* INVRFAC
);
2904 if (tmpdeg
< 0) tmpdeg
+= 360;
2905 if (((aarc
->angle2
> 360) && (tmpdeg
> aarc
->angle2
- 360) &&
2906 (tmpdeg
< aarc
->angle1
)) ||
2907 ((aarc
->angle1
< 0) && (tmpdeg
> aarc
->angle2
) &&
2908 (tmpdeg
< aarc
->angle1
+ 360)) ||
2909 ((aarc
->angle1
>= 0) && (aarc
->angle2
<= 360) && ((tmpdeg
2910 > aarc
->angle2
) || (tmpdeg
< aarc
->angle1
)))) {
2911 float testd1
= aarc
->angle1
- tmpdeg
;
2912 float testd2
= tmpdeg
- aarc
->angle2
;
2913 if (testd1
< 0) testd1
+= 360;
2914 if (testd2
< 0) testd2
+= 360;
2916 /* if arc is closed, attach to the line between the endpoints */
2918 if (!(aarc
->style
& UNCLOSED
)) {
2920 tmpang
= (double) aarc
->angle1
/ INVRFAC
;
2921 end1
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2922 end1
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2923 tmpang
= (double) aarc
->angle2
/ INVRFAC
;
2924 end2
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2925 end2
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2926 findwirex(&end1
, &end2
, userpt
, newpos
, &locrot
);
2927 if (rot
) *rot
= locrot
;
2931 tmpang
= (double)((testd1
< testd2
) ? aarc
->angle1
: aarc
->angle2
)
2935 /* get position in user coordinates nearest to the intersect pt */
2937 newpos
->x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2938 newpos
->y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2940 /* rotation of object is normal to the curve of the ellipse */
2943 *rot
= 90.0 - INVRFAC
* tmpang
;
2944 if (*rot
< 0.0) *rot
+= 360.0;
2947 else if (SELECTTYPE(&areawin
->attachto
) == SPLINE
) {
2948 splineptr aspline
= SELTOSPLINE(&areawin
->attachto
);
2949 frac
= findsplinemin(aspline
, userpt
);
2950 findsplinepos(aspline
, frac
, newpos
, &locrot
);
2951 if (rot
) *rot
= locrot
;
2953 else if (SELECTTYPE(&areawin
->attachto
) == OBJINST
) {
2955 objinstptr ainst
= SELTOOBJINST(&areawin
->attachto
);
2956 objectptr aobj
= ainst
->thisobject
;
2958 long testdist
, mindist
= 1e8
;
2961 /* In case instance has no pin labels, we will attach to */
2962 /* the instance's own origin. */
2964 mdpoint
.x
= mdpoint
.y
= 0;
2965 ReferencePosition(ainst
, &mdpoint
, newpos
);
2967 /* Find the nearest pin label in the object instance and attach to it */
2968 for (ggen
= aobj
->plist
; ggen
< aobj
->plist
+ aobj
->parts
; ggen
++) {
2969 if (ELEMENTTYPE(*ggen
) == LABEL
) {
2970 labelptr alab
= TOLABEL(ggen
);
2971 if (alab
->pin
== LOCAL
|| alab
->pin
== GLOBAL
) {
2972 ReferencePosition(ainst
, &alab
->position
, &mdpoint
);
2973 testdist
= sqwirelen(&mdpoint
, userpt
);
2974 if (testdist
< mindist
) {
2982 else if (SELECTTYPE(&areawin
->attachto
) == LABEL
) {
2983 /* Only one choice: Attach to the label position */
2984 labelptr alabel
= SELTOLABEL(&areawin
->attachto
);
2985 newpos
->x
= alabel
->position
.x
;
2986 newpos
->y
= alabel
->position
.y
;
2988 else if (SELECTTYPE(&areawin
->attachto
) == POLYGON
) {
2989 polyptr apoly
= SELTOPOLY(&areawin
->attachto
);
2990 XPoint
*testpt
, *minpt
, *nxtpt
;
2991 long mindist
= 1e8
, testdist
;
2992 minpt
= nxtpt
= apoly
->points
; /* so variables aren't uninitialized */
2993 for (testpt
= apoly
->points
; testpt
< apoly
->points
+
2994 apoly
->number
- 1; testpt
++) {
2995 testdist
= finddist(testpt
, testpt
+ 1, userpt
);
2996 if (testdist
< mindist
) {
3002 if (!(apoly
->style
& UNCLOSED
)) {
3003 testdist
= finddist(testpt
, apoly
->points
, userpt
);
3004 if (testdist
< mindist
) {
3007 nxtpt
= apoly
->points
;
3012 findwirex(endpt1
, endpt2
, userpt
, newpos
, &locrot
);
3013 if (rot
) *rot
= locrot
;
3017 /*--------------------------------------------*/
3018 /* Find closest point in a path to the cursor */
3019 /*--------------------------------------------*/
3021 XPoint
*pathclosepoint(pathptr dragpath
, XPoint
*newpos
)
3026 int mdist
= 1000000, tdist
;
3028 for (cpoint
= dragpath
->plist
; cpoint
< dragpath
->plist
+ dragpath
->parts
;
3030 switch(ELEMENTTYPE(*cpoint
)) {
3032 tdist
= wirelength(&(TOARC(cpoint
)->position
), newpos
);
3033 if (tdist
< mdist
) {
3035 rpoint
= &(TOARC(cpoint
)->position
);
3039 mpoint
= closepoint(TOPOLY(cpoint
), newpos
);
3040 tdist
= wirelength(TOPOLY(cpoint
)->points
+ mpoint
, newpos
);
3041 if (tdist
< mdist
) {
3043 rpoint
= TOPOLY(cpoint
)->points
+ mpoint
;
3047 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[0]), newpos
);
3048 if (tdist
< mdist
) {
3050 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[0]);
3052 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[3]), newpos
);
3053 if (tdist
< mdist
) {
3055 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[3]);
3063 /*-------------------------------------------*/
3064 /* Drag a selected element around the screen */
3065 /*-------------------------------------------*/
3067 void drag(int x
, int y
)
3070 Boolean eventcheck
= False
;
3072 short deltax
, deltay
;
3078 /* flush out multiple pointermotion events from the event queue */
3079 /* use only the last motion event */
3080 while (XCheckWindowEvent(dpy
, areawin
->window
, PointerMotionMask
|
3081 Button1MotionMask
, &again
) == True
) eventcheck
= True
;
3083 XButtonEvent
*event
= (XButtonEvent
*)(&again
);
3084 locx
= (int)event
->x
;
3085 locy
= (int)event
->y
;
3088 /* Determine if this event is supposed to be handled by */
3089 /* trackselarea(), or whether we should not be here at all */
3090 /* (button press and mouse movement in an unsupported mode) */
3092 if (eventmode
== SELAREA_MODE
) {
3096 else if (eventmode
== RESCALE_MODE
) {
3100 else if (eventmode
== PAN_MODE
) {
3101 trackpan(locx
, locy
);
3104 else if (eventmode
!= CATMOVE_MODE
&& eventmode
!= MOVE_MODE
3105 && eventmode
!= COPY_MODE
)
3108 snap(locx
, locy
, &userpt
);
3109 deltax
= userpt
.x
- areawin
->save
.x
;
3110 deltay
= userpt
.y
- areawin
->save
.y
;
3111 if (deltax
== 0 && deltay
== 0) return;
3113 areawin
->save
.x
= userpt
.x
;
3114 areawin
->save
.y
= userpt
.y
;
3116 /* set up the graphics state for moving a selected object */
3118 XTopSetForeground(SELECTCOLOR
);
3120 placeselects(deltax
, deltay
, &userpt
);
3122 /* restore graphics state */
3124 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
3126 /* print the position and other useful measurements */
3128 printpos(userpt
.x
, userpt
.y
);
3131 /*------------------------------------------------------*/
3132 /* Wrapper for drag() for xlib callback compatibility. */
3133 /*------------------------------------------------------*/
3135 void xlib_drag(xcWidget w
, caddr_t clientdata
, XEvent
*event
)
3137 XButtonEvent
*bevent
= (XButtonEvent
*)event
;
3138 UNUSED(w
); UNUSED(clientdata
);
3140 drag(bevent
->x
, bevent
->y
);
3141 if (areawin
->redraw_needed
)
3142 drawarea(NULL
, NULL
, NULL
);
3145 /*----------------------------------------------*/
3146 /* Rotate an element of a path */
3147 /*----------------------------------------------*/
3149 void elemrotate(genericptr
*genobj
, float direction
, XPoint
*position
)
3151 XPoint negpt
, *newpts
= (XPoint
*)NULL
;
3153 negpt
.x
= -position
->x
;
3154 negpt
.y
= -position
->y
;
3156 switch(ELEMENTTYPE(*genobj
)) {
3158 arcptr rotatearc
= TOARC(genobj
);
3159 rotatearc
->angle1
-= direction
;
3160 rotatearc
->angle2
-= direction
;
3161 if (rotatearc
->angle1
>= 360) {
3162 rotatearc
->angle1
-= 360;
3163 rotatearc
->angle2
-= 360;
3165 else if (rotatearc
->angle2
<= 0) {
3166 rotatearc
->angle1
+= 360;
3167 rotatearc
->angle2
+= 360;
3169 newpts
= (XPoint
*)malloc(sizeof(XPoint
));
3170 UTransformPoints(&rotatearc
->position
, newpts
, 1, negpt
, 1.0, 0);
3171 UTransformPoints(newpts
, &rotatearc
->position
, 1, *position
,
3177 splineptr rotatespline
= TOSPLINE(genobj
);
3178 newpts
= (XPoint
*)malloc(4 * sizeof(XPoint
));
3179 UTransformPoints(rotatespline
->ctrl
, newpts
, 4, negpt
, 1.0, 0);
3180 UTransformPoints(newpts
, rotatespline
->ctrl
, 4, *position
,
3182 calcspline(rotatespline
);
3186 polyptr rotatepoly
= TOPOLY(genobj
);
3187 newpts
= (XPoint
*)malloc(rotatepoly
->number
* sizeof(XPoint
));
3188 UTransformPoints(rotatepoly
->points
, newpts
, rotatepoly
->number
,
3190 UTransformPoints(newpts
, rotatepoly
->points
, rotatepoly
->number
,
3191 *position
, 1.0, direction
);
3194 if (newpts
) free(newpts
);
3197 /*------------------------------------------------------*/
3198 /* Rotate an element or group of elements */
3199 /* Objects and labels, if selected singly, rotate */
3200 /* about their position point. All other elements, */
3201 /* and groups, rotate about the cursor point. */
3202 /*------------------------------------------------------*/
3204 void elementrotate(float direction
, XPoint
*position
)
3206 short *selectobj
; /* , ld; (jdk) */
3207 Boolean single
= False
;
3208 Boolean need_refresh
= False
;
3209 Boolean preselected
;
3210 XPoint newpt
, negpt
;
3212 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3213 if (!checkselect(ALL_TYPES
)) return;
3214 if (areawin
->selects
== 1) single
= True
;
3216 negpt
.x
= -position
->x
;
3217 negpt
.y
= -position
->y
;
3219 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3220 + areawin
->selects
; selectobj
++) {
3222 /* erase the element */
3223 if (!need_refresh
) {
3224 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
3225 easydraw(*selectobj
, DOFORALL
);
3228 switch(SELECTTYPE(selectobj
)) {
3231 objinstptr rotateobj
= SELTOOBJINST(selectobj
);
3233 if (is_library(topobject
) >= 0 && !is_virtual(rotateobj
)) break;
3234 rotateobj
->rotation
+= direction
;
3235 while (rotateobj
->rotation
>= 360) rotateobj
->rotation
-= 360;
3236 while (rotateobj
->rotation
<= 0) rotateobj
->rotation
+= 360;
3238 UTransformPoints(&rotateobj
->position
, &newpt
, 1, negpt
, 1.0, 0);
3239 UTransformPoints(&newpt
, &rotateobj
->position
, 1, *position
,
3245 labelptr rotatetext
= SELTOLABEL(selectobj
);
3247 rotatetext
->rotation
+= direction
;
3248 while (rotatetext
->rotation
>= 360) rotatetext
->rotation
-= 360;
3249 while (rotatetext
->rotation
<= 0) rotatetext
->rotation
+= 360;
3251 UTransformPoints(&rotatetext
->position
, &newpt
, 1, negpt
, 1.0, 0);
3252 UTransformPoints(&newpt
, &rotatetext
->position
, 1, *position
,
3258 graphicptr rotateg
= SELTOGRAPHIC(selectobj
);
3260 rotateg
->rotation
+= direction
;
3261 while (rotateg
->rotation
>= 360) rotateg
->rotation
-= 360;
3262 while (rotateg
->rotation
<= 0) rotateg
->rotation
+= 360;
3264 rotateg
->valid
= FALSE
;
3265 #endif /* !HAVE_CAIRO */
3267 UTransformPoints(&rotateg
->position
, &newpt
, 1, negpt
, 1.0, 0);
3268 UTransformPoints(&newpt
, &rotateg
->position
, 1, *position
,
3271 need_refresh
= True
;
3274 case POLYGON
: case ARC
: case SPLINE
:{
3275 genericptr
*genpart
= topobject
->plist
+ *selectobj
;
3276 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3278 elemrotate(genpart
, direction
, position
);
3282 genericptr
*genpart
;
3283 pathptr rotatepath
= SELTOPATH(selectobj
);
3285 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3287 for (genpart
= rotatepath
->plist
; genpart
< rotatepath
->plist
3288 + rotatepath
->parts
; genpart
++)
3289 elemrotate(genpart
, direction
, position
);
3293 /* redisplay the element */
3294 if (preselected
|| ((eventmode
!= NORMAL_MODE
) && !need_refresh
)) {
3295 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
3296 easydraw(*selectobj
, DOFORALL
);
3300 /* This takes care of all selected instances and labels in one go, */
3301 /* because we only need to know the origin and amount of rotation. */
3303 if (eventmode
!= COPY_MODE
)
3304 register_for_undo(XCF_Rotate
, UNDO_MORE
, areawin
->topinstance
,
3305 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
,
3308 /* New rule (6/15/07) to be applied generally: If objects were */
3309 /* selected prior to calling elementrotate() and similar functions, */
3310 /* leave them selected upon exit. Otherwise, deselect them. */
3312 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
3316 if (eventmode
== CATALOG_MODE
) {
3318 if ((libnum
= is_library(topobject
)) >= 0) {
3319 composelib(libnum
+ LIBRARY
);
3320 need_refresh
= TRUE
;
3324 pwriteback(areawin
->topinstance
);
3325 calcbbox(areawin
->topinstance
);
3328 if (need_refresh
) drawarea(NULL
, NULL
, NULL
);
3331 /*----------------------------------------------*/
3332 /* Rescale the current edit element to the */
3333 /* dimensions of the rescale box. */
3334 /*----------------------------------------------*/
3336 void elementrescale(float newscale
)
3344 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3345 + areawin
->selects
; selectobj
++) {
3346 switch (SELECTTYPE(selectobj
)) {
3348 sclab
= SELTOLABEL(selectobj
);
3349 oldsize
= sclab
->scale
;
3350 sclab
->scale
= newscale
;
3353 scinst
= SELTOOBJINST(selectobj
);
3354 oldsize
= scinst
->scale
;
3355 scinst
->scale
= newscale
;
3358 scgraph
= SELTOGRAPHIC(selectobj
);
3359 oldsize
= scgraph
->scale
;
3360 scgraph
->scale
= newscale
;
3363 register_for_undo(XCF_Rescale
, UNDO_MORE
, areawin
->topinstance
,
3364 SELTOGENERIC(selectobj
), (double)oldsize
);
3366 calcbbox(areawin
->topinstance
);
3369 /*-------------------------------------------------*/
3370 /* Edit an element in an element-dependent fashion */
3371 /*-------------------------------------------------*/
3373 void edit(int x
, int y
)
3377 if (areawin
->selects
== 0) {
3378 Boolean saveredraw
= areawin
->redraw_needed
;
3379 selectobj
= select_element(ALL_TYPES
);
3380 areawin
->redraw_needed
= saveredraw
;
3383 selectobj
= areawin
->selectlist
;
3384 if (areawin
->selects
== 0)
3386 else if (areawin
->selects
!= 1) { /* Multiple object edit */
3388 short *selectlist
, selrefno
;
3389 Boolean save_redraw
= areawin
->redraw_needed
;
3391 /* Find the closest part to use as a reference */
3392 selnum
= areawin
->selects
;
3393 selectlist
= areawin
->selectlist
;
3394 areawin
->selects
= 0;
3395 areawin
->selectlist
= NULL
;
3396 selectobj
= select_element(ALL_TYPES
);
3397 if (selectobj
!= NULL
)
3398 selrefno
= *selectobj
;
3402 areawin
->selects
= selnum
;
3403 areawin
->selectlist
= selectlist
;
3404 areawin
->redraw_needed
= save_redraw
;
3405 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3406 + areawin
->selects
; selectobj
++) {
3407 if (*selectobj
== selrefno
) break;
3409 if (selectobj
== areawin
->selectlist
+ areawin
->selects
) {
3410 Wprintf("Put cursor close to the reference element.");
3414 /* Shuffle the reference element to the beginning of the select list */
3415 *selectobj
= *(areawin
->selectlist
);
3416 *(areawin
->selectlist
) = selrefno
;
3417 selectobj
= areawin
->selectlist
;
3420 switch(SELECTTYPE(selectobj
)) {
3422 labelptr
*lastlabel
= (labelptr
*)EDITPART
;
3427 /* save the old string, including parameters */
3428 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3431 /* fill any NULL instance parameters with the default value */
3432 copyparams(areawin
->topinstance
, areawin
->topinstance
);
3434 /* place text cursor line at point nearest the cursor */
3435 /* unless textend is set. . . */
3437 if (areawin
->textend
== 0) {
3438 TextLinesInfo tlinfo
;
3440 tlinfo
.tbreak
= NULL
;
3441 tlinfo
.padding
= NULL
;
3443 window_to_user(x
, y
, &areawin
->save
);
3444 InvTransformPoints(&areawin
->save
, &tmppt
, 1, (*lastlabel
)->position
,
3445 (*lastlabel
)->scale
, (*lastlabel
)->rotation
);
3446 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3447 tmppt
.x
+= ((*lastlabel
)->anchor
& NOTLEFT
?
3448 ((*lastlabel
)->anchor
& RIGHT
? tmpext
.maxwidth
3449 : tmpext
.maxwidth
>> 1) : 0);
3450 tmppt
.y
+= ((*lastlabel
)->anchor
& NOTBOTTOM
?
3451 ((*lastlabel
)->anchor
& TOP
? tmpext
.ascent
:
3452 (tmpext
.ascent
+ tmpext
.base
) >> 1) : tmpext
.base
);
3453 if ((*lastlabel
)->pin
)
3454 pinadjust((*lastlabel
)->anchor
, &tmppt
.x
, NULL
, -1);
3456 /* Where tbreak is passed to ULength, the character position */
3457 /* is returned in the TextLinesInfo dostop field. */
3458 tlinfo
.tbreak
= &tmppt
;
3459 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3460 areawin
->textpos
= tlinfo
.dostop
;
3462 if (tlinfo
.padding
!= NULL
) free(tlinfo
.padding
);
3465 /* find current font */
3467 curfont
= findcurfont(areawin
->textpos
, (*lastlabel
)->string
,
3468 areawin
->topinstance
);
3470 /* change menu buttons accordingly */
3472 setfontmarks(curfont
, (*lastlabel
)->anchor
);
3474 if (eventmode
== CATALOG_MODE
) {
3475 /* CATTEXT_MODE may show an otherwise hidden library namespace */
3476 undrawtext(*lastlabel
);
3477 eventmode
= CATTEXT_MODE
;
3478 redrawtext(*lastlabel
);
3479 areawin
->redraw_needed
= False
; /* ignore prev. redraw requests */
3480 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3483 eventmode
= ETEXT_MODE
;
3484 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3487 XDefineCursor(dpy
, areawin
->window
, TEXTPTR
);
3489 /* write the text at the bottom */
3491 charreport(*lastlabel
);
3495 case POLYGON
: case ARC
: case SPLINE
: case PATH
:
3496 window_to_user(x
, y
, &areawin
->save
);
3497 pathedit(*(EDITPART
));
3500 case OBJINST
: case GRAPHIC
:
3501 if (areawin
->selects
== 1)
3505 XDefineCursor (dpy
, areawin
->window
, EDCURSOR
);
3508 /*----------------------------------------------------------------------*/
3509 /* edit() routine for path-type elements (polygons, splines, arcs, and */
3511 /*----------------------------------------------------------------------*/
3513 void pathedit(genericptr editpart
)
3515 splineptr lastspline
= NULL
;
3517 polyptr lastpoly
= NULL
;
3524 /* Find and set constrained edit points on all elements. Register */
3525 /* each element with the undo mechanism. */
3527 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
3528 areawin
->selects
; eselect
++) {
3529 switch (SELECTTYPE(eselect
)) {
3531 findconstrained(SELTOPOLY(eselect
));
3534 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3535 SELTOGENERIC(eselect
));
3540 switch(ELEMENTTYPE(editpart
)) {
3542 genericptr
*ggen
, *savegen
= NULL
;
3543 int mincycle
, dist
, mindist
= 1e6
;
3545 lastpath
= (pathptr
)editpart
;
3546 havecycle
= (checkcycle(editpart
, 0) >= 0) ? True
: False
;
3548 /* determine which point of the path is closest to the cursor */
3549 for (ggen
= lastpath
->plist
; ggen
< lastpath
->plist
+ lastpath
->parts
;
3551 switch (ELEMENTTYPE(*ggen
)) {
3553 lastpoly
= TOPOLY(ggen
);
3554 cycle
= closepoint(lastpoly
, &areawin
->save
);
3555 dist
= wirelength(lastpoly
->points
+ cycle
, &areawin
->save
);
3558 lastspline
= TOSPLINE(ggen
);
3559 cycle
= (wirelength(&lastspline
->ctrl
[0],
3560 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3561 &areawin
->save
)) ? 0 : 3;
3562 dist
= wirelength(&lastspline
->ctrl
[cycle
], &areawin
->save
);
3565 if (dist
< mindist
) {
3571 if (savegen
== NULL
) return; /* something went terribly wrong */
3572 switch (ELEMENTTYPE(*savegen
)) {
3574 lastpoly
= TOPOLY(savegen
);
3575 addcycle(savegen
, mincycle
, 0);
3576 savept
= lastpoly
->points
+ mincycle
;
3577 makerefcycle(lastpoly
->cycle
, mincycle
);
3578 findconstrained(lastpoly
);
3581 lastspline
= TOSPLINE(savegen
);
3582 addcycle(savegen
, mincycle
, 0);
3583 savept
= &lastspline
->ctrl
[mincycle
];
3584 makerefcycle(lastspline
->cycle
, mincycle
);
3587 updatepath(lastpath
);
3589 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3590 (genericptr
)lastpath
);
3591 patheditpush(lastpath
);
3592 areawin
->origin
= areawin
->save
;
3595 path_mode_draw(xcDRAW_INIT
, lastpath
);
3597 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3598 (xcEventHandler
)trackelement
, NULL
);
3599 eventmode
= EPATH_MODE
;
3600 printpos(savept
->x
, savept
->y
);
3605 lastpoly
= (polyptr
)editpart
;
3607 /* Determine which point of polygon is closest to cursor */
3608 cycle
= closepoint(lastpoly
, &areawin
->save
);
3609 havecycle
= (lastpoly
->cycle
== NULL
) ? False
: True
;
3610 addcycle(&editpart
, cycle
, 0);
3611 savept
= lastpoly
->points
+ cycle
;
3612 makerefcycle(lastpoly
->cycle
, cycle
);
3614 findconstrained(lastpoly
);
3615 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3616 (genericptr
)lastpoly
);
3619 /* Push onto the editstack */
3620 polyeditpush(lastpoly
);
3622 /* remember our postion for pointer restore */
3623 areawin
->origin
= areawin
->save
;
3627 poly_mode_draw(xcDRAW_INIT
, lastpoly
);
3629 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3630 (xcEventHandler
)trackelement
, NULL
);
3631 eventmode
= EPOLY_MODE
;
3632 printeditbindings();
3633 printpos(savept
->x
, savept
->y
);
3638 lastspline
= (splineptr
)editpart
;
3640 /* find which point is closest to the cursor */
3642 cycle
= (wirelength(&lastspline
->ctrl
[0],
3643 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3644 &areawin
->save
)) ? 0 : 3;
3645 havecycle
= (lastspline
->cycle
== NULL
) ? False
: True
;
3646 addcycle(&editpart
, cycle
, 0);
3647 makerefcycle(lastspline
->cycle
, cycle
);
3648 curpt
= &lastspline
->ctrl
[cycle
];
3650 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3651 (genericptr
)lastspline
);
3653 /* Push onto the editstack */
3654 splineeditpush(lastspline
);
3656 /* remember our postion for pointer restore */
3657 areawin
->origin
= areawin
->save
;
3661 spline_mode_draw(xcDRAW_INIT
, lastspline
);
3662 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3663 (xcEventHandler
)trackelement
, NULL
);
3664 eventmode
= ESPLINE_MODE
;
3668 float tmpratio
, tlen
;
3670 lastarc
= (arcptr
)editpart
;
3672 /* find a part of the arc close to the pointer */
3674 tlen
= (float)wirelength(&areawin
->save
, &(lastarc
->position
));
3675 tmpratio
= (float)(abs(lastarc
->radius
)) / tlen
;
3676 curpt
.x
= lastarc
->position
.x
+ tmpratio
* (areawin
->save
.x
3677 - lastarc
->position
.x
);
3678 tmpratio
= (float)lastarc
->yaxis
/ tlen
;
3679 curpt
.y
= lastarc
->position
.y
+ tmpratio
* (areawin
->save
.y
3680 - lastarc
->position
.y
);
3681 addcycle(&editpart
, 0, 0);
3682 saveratio
= (double)(lastarc
->yaxis
) / (double)(abs(lastarc
->radius
));
3684 /* Push onto the editstack */
3685 arceditpush(lastarc
);
3686 areawin
->origin
= areawin
->save
;
3690 areawin
->save
.x
= curpt
.x
; /* for redrawing dotted edit line */
3691 areawin
->save
.y
= curpt
.y
;
3692 arc_mode_draw(xcDRAW_INIT
, lastarc
);
3693 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3694 (xcEventHandler
)trackarc
, NULL
);
3695 eventmode
= EARC_MODE
;
3696 printpos(curpt
.x
, curpt
.y
);
3701 /*------------------------------------------------------*/
3702 /* Raise an element to the top of the list */
3703 /*------------------------------------------------------*/
3705 void xc_top(short *selectno
, short *orderlist
)
3708 genericptr
*raiseobj
, *genobj
, temp
;
3710 raiseobj
= topobject
->plist
+ *selectno
;
3713 for (genobj
= topobject
->plist
+ *selectno
; genobj
<
3714 topobject
->plist
+ topobject
->parts
- 1; genobj
++) {
3715 *genobj
= *(genobj
+ 1);
3716 *(orderlist
+ i
) = *(orderlist
+ i
+ 1);
3719 *(topobject
->plist
+ topobject
->parts
- 1) = temp
;
3720 *(orderlist
+ topobject
->parts
- 1) = *selectno
;
3721 *selectno
= topobject
->parts
- 1;
3724 /*------------------------------------------------------*/
3725 /* Lower an element to the bottom of the list */
3726 /*------------------------------------------------------*/
3728 void xc_bottom(short *selectno
, short *orderlist
)
3731 genericptr
*lowerobj
, *genobj
, temp
;
3733 lowerobj
= topobject
->plist
+ *selectno
;
3736 for (genobj
= topobject
->plist
+ *selectno
;
3737 genobj
> topobject
->plist
; genobj
--) {
3738 *genobj
= *(genobj
- 1);
3739 *(orderlist
+ i
) = *(orderlist
+ i
- 1);
3743 *orderlist
= *selectno
;
3747 /*--------------------------------------------------------------*/
3748 /* Raise all selected elements by one position in the list */
3749 /*--------------------------------------------------------------*/
3753 short *sel
, topsel
, maxsel
, *topidx
, limit
, *orderlist
, i
;
3754 genericptr
*raiseobj
, temp
;
3756 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3757 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3759 /* Find topmost element in the select list */
3761 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3763 if (*sel
> maxsel
) {
3768 if (maxsel
== -1) return; /* Error condition */
3771 limit
= topobject
->parts
- 1;
3774 /* Exchange the topmost element with the one above it */
3775 if (topsel
< limit
) {
3776 raiseobj
= topobject
->plist
+ topsel
;
3778 *raiseobj
= *(raiseobj
+ 1);
3779 *(raiseobj
+ 1) = temp
;
3781 i
= *(orderlist
+ topsel
);
3782 *(orderlist
+ topsel
) = *(orderlist
+ topsel
+ 1);
3783 *(orderlist
+ topsel
+ 1) = i
;
3788 /* Find next topmost element */
3790 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3792 if (*sel
< maxsel
) {
3793 if (*sel
> topsel
) {
3799 if (topsel
== -1) break; /* No more elements to raise */
3802 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3806 /*--------------------------------------------------------------*/
3807 /* Lower all selected elements by one position in the list */
3808 /*--------------------------------------------------------------*/
3812 short *sel
, botsel
, minsel
, *botidx
, limit
, *orderlist
, i
;
3813 genericptr
*lowerobj
, temp
;
3815 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3816 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3818 /* Find bottommost element in the select list */
3819 minsel
= topobject
->parts
;
3820 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3822 if (*sel
< minsel
) {
3827 if (minsel
== topobject
->parts
) return; /* Error condition */
3833 /* Exchange the topmost element with the one below it */
3834 if (botsel
> limit
) {
3835 lowerobj
= topobject
->plist
+ botsel
;
3837 *lowerobj
= *(lowerobj
- 1);
3838 *(lowerobj
- 1) = temp
;
3840 i
= *(orderlist
+ botsel
);
3841 *(orderlist
+ botsel
) = *(orderlist
+ botsel
- 1);
3842 *(orderlist
+ botsel
- 1) = i
;
3847 /* Find next topmost element */
3848 botsel
= topobject
->parts
;
3849 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3851 if (*sel
> minsel
) {
3852 if (*sel
< botsel
) {
3858 if (botsel
== topobject
->parts
) break; /* No more elements to raise */
3861 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3865 /*------------------------------------------------------*/
3866 /* Generate a virtual copy of an object instance in the */
3867 /* user library. This is like the library virtual copy */
3868 /* except that it allows the user to generate a library */
3869 /* copy of an existing instance, without having to make */
3870 /* a copy of the master library instance and edit it. */
3871 /* copyvirtual() also allows the library virtual */
3872 /* instance to take on a specific rotation or flip */
3873 /* value, which cannot be done with the library virtual */
3874 /* copy function. */
3875 /*------------------------------------------------------*/
3879 short *selectno
, created
= 0;
3880 objinstptr vcpobj
, libinst
;
3882 for (selectno
= areawin
->selectlist
; selectno
< areawin
->selectlist
+
3883 areawin
->selects
; selectno
++) {
3884 if (SELECTTYPE(selectno
) == OBJINST
) {
3885 vcpobj
= SELTOOBJINST(selectno
);
3886 libinst
= addtoinstlist(USERLIB
- LIBRARY
, vcpobj
->thisobject
, TRUE
);
3887 instcopy(libinst
, vcpobj
);
3892 Wprintf("No object instances selected for virtual copy!");
3896 composelib(USERLIB
);
3900 /*------------------------------------------------------*/
3901 /* Exchange the list position (drawing order) of two */
3902 /* elements, or move the position of one element to the */
3903 /* top or bottom. */
3904 /*------------------------------------------------------*/
3908 short *selectno
, *orderlist
, i
;
3909 genericptr
*exchobj
, *exchobj2
, temp
;
3910 Boolean preselected
;
3912 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3913 if (!checkselect(ALL_TYPES
)) {
3914 Wprintf("Select 1 or 2 objects");
3918 selectno
= areawin
->selectlist
;
3919 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3920 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3922 if (areawin
->selects
== 1) { /* lower if on top; raise otherwise */
3923 if (*selectno
== topobject
->parts
- 1)
3924 xc_bottom(selectno
, orderlist
);
3926 xc_top(selectno
, orderlist
);
3928 else { /* exchange the two objects */
3929 exchobj
= topobject
->plist
+ *selectno
;
3930 exchobj2
= topobject
->plist
+ *(selectno
+ 1);
3933 *exchobj
= *exchobj2
;
3936 i
= *(orderlist
+ *selectno
);
3937 *(orderlist
+ *selectno
) = *(orderlist
+ *(selectno
+ 1));
3938 *(orderlist
+ *(selectno
+ 1)) = i
;
3940 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
3941 orderlist
, topobject
->parts
);
3943 incr_changes(topobject
);
3946 drawarea(NULL
, NULL
, NULL
);
3949 /*--------------------------------------------------------*/
3950 /* Flip an element horizontally (POLYGON, ARC, or SPLINE) */
3951 /*--------------------------------------------------------*/
3953 void elhflip(genericptr
*genobj
, short x
)
3955 switch(ELEMENTTYPE(*genobj
)) {
3957 polyptr flippoly
= TOPOLY(genobj
);
3959 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
3960 flippoly
->number
; ppoint
++)
3961 ppoint
->x
= (x
<< 1) - ppoint
->x
;
3965 arcptr fliparc
= TOARC(genobj
);
3966 float tmpang
= 180 - fliparc
->angle1
;
3967 fliparc
->angle1
= 180 - fliparc
->angle2
;
3968 fliparc
->angle2
= tmpang
;
3969 if (fliparc
->angle2
< 0) {
3970 fliparc
->angle1
+= 360;
3971 fliparc
->angle2
+= 360;
3973 fliparc
->radius
= -fliparc
->radius
;
3974 fliparc
->position
.x
= (x
<< 1) - fliparc
->position
.x
;
3979 splineptr flipspline
= TOSPLINE(genobj
);
3981 for (i
= 0; i
< 4; i
++)
3982 flipspline
->ctrl
[i
].x
= (x
<< 1) - flipspline
->ctrl
[i
].x
;
3983 calcspline(flipspline
);
3988 /*--------------------------------------------------------*/
3989 /* Flip an element vertically (POLYGON, ARC, or SPLINE) */
3990 /*--------------------------------------------------------*/
3992 void elvflip(genericptr
*genobj
, short y
)
3994 switch(ELEMENTTYPE(*genobj
)) {
3997 polyptr flippoly
= TOPOLY(genobj
);
4000 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
4001 flippoly
->number
; ppoint
++)
4002 ppoint
->y
= (y
<< 1) - ppoint
->y
;
4006 arcptr fliparc
= TOARC(genobj
);
4007 float tmpang
= 360 - fliparc
->angle1
;
4008 fliparc
->angle1
= 360 - fliparc
->angle2
;
4009 fliparc
->angle2
= tmpang
;
4010 if (fliparc
->angle1
>= 360) {
4011 fliparc
->angle1
-= 360;
4012 fliparc
->angle2
-= 360;
4014 fliparc
->radius
= -fliparc
->radius
;
4015 fliparc
->position
.y
= (y
<< 1) - fliparc
->position
.y
;
4020 splineptr flipspline
= TOSPLINE(genobj
);
4022 for (i
= 0; i
< 4; i
++)
4023 flipspline
->ctrl
[i
].y
= (y
<< 1) - flipspline
->ctrl
[i
].y
;
4024 calcspline(flipspline
);
4029 /*------------------------------------------------------*/
4030 /* Horizontally flip an element */
4031 /*------------------------------------------------------*/
4033 void elementflip(XPoint
*position
)
4036 Boolean single
= False
;
4037 Boolean preselected
;
4039 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4040 if (!checkselect(ALL_TYPES
)) return;
4041 if (areawin
->selects
== 1) single
= True
;
4043 if (eventmode
!= COPY_MODE
)
4044 register_for_undo(XCF_Flip_X
, UNDO_MORE
, areawin
->topinstance
,
4045 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4047 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4048 + areawin
->selects
; selectobj
++) {
4050 /* erase the object */
4051 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4052 easydraw(*selectobj
, DOFORALL
);
4054 switch(SELECTTYPE(selectobj
)) {
4056 labelptr fliplab
= SELTOLABEL(selectobj
);
4057 if ((fliplab
->anchor
& (RIGHT
| NOTLEFT
)) != NOTLEFT
)
4058 fliplab
->anchor
^= (RIGHT
| NOTLEFT
);
4060 fliplab
->position
.x
= (position
->x
<< 1) - fliplab
->position
.x
;
4063 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4064 flipg
->scale
= -flipg
->scale
;
4066 flipg
->valid
= FALSE
;
4067 #endif /* !HAVE_CAIRO */
4069 flipg
->position
.x
= (position
->x
<< 1) - flipg
->position
.x
;
4072 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4073 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4074 flipobj
->scale
= -flipobj
->scale
;
4076 flipobj
->position
.x
= (position
->x
<< 1) - flipobj
->position
.x
;
4078 case POLYGON
: case ARC
: case SPLINE
:
4079 elhflip(topobject
->plist
+ *selectobj
, position
->x
);
4082 genericptr
*genpart
;
4083 pathptr flippath
= SELTOPATH(selectobj
);
4085 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4086 + flippath
->parts
; genpart
++)
4087 elhflip(genpart
, position
->x
);
4091 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4092 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4093 easydraw(*selectobj
, DOFORALL
);
4096 select_invalidate_netlist();
4097 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4101 if (eventmode
== NORMAL_MODE
)
4102 incr_changes(topobject
);
4103 if (eventmode
== CATALOG_MODE
) {
4105 if ((libnum
= is_library(topobject
)) >= 0) {
4106 composelib(libnum
+ LIBRARY
);
4107 drawarea(NULL
, NULL
, NULL
);
4111 pwriteback(areawin
->topinstance
);
4112 calcbbox(areawin
->topinstance
);
4116 /*----------------------------------------------*/
4117 /* Vertically flip an element */
4118 /*----------------------------------------------*/
4120 void elementvflip(XPoint
*position
)
4123 /*short fsign; (jdk) */
4124 Boolean preselected
;
4125 Boolean single
= False
;
4127 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4128 if (!checkselect(ALL_TYPES
)) return;
4129 if (areawin
->selects
== 1) single
= True
;
4131 if (eventmode
!= COPY_MODE
)
4132 register_for_undo(XCF_Flip_Y
, UNDO_MORE
, areawin
->topinstance
,
4133 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4135 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4136 + areawin
->selects
; selectobj
++) {
4138 /* erase the object */
4139 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4140 easydraw(*selectobj
, DOFORALL
);
4142 switch(SELECTTYPE(selectobj
)) {
4144 labelptr fliplab
= SELTOLABEL(selectobj
);
4145 if ((fliplab
->anchor
& (TOP
| NOTBOTTOM
)) != NOTBOTTOM
)
4146 fliplab
->anchor
^= (TOP
| NOTBOTTOM
);
4148 fliplab
->position
.y
= (position
->y
<< 1) - fliplab
->position
.y
;
4151 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4153 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4154 flipobj
->scale
= -(flipobj
->scale
);
4155 flipobj
->rotation
+= 180;
4156 while (flipobj
->rotation
>= 360) flipobj
->rotation
-= 360;
4158 flipobj
->position
.y
= (position
->y
<< 1) - flipobj
->position
.y
;
4161 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4163 flipg
->scale
= -(flipg
->scale
);
4164 flipg
->rotation
+= 180;
4165 while (flipg
->rotation
>= 360) flipg
->rotation
-= 360;
4167 flipg
->position
.y
= (position
->y
<< 1) - flipg
->position
.y
;
4169 case POLYGON
: case ARC
: case SPLINE
:
4170 elvflip(topobject
->plist
+ *selectobj
, position
->y
);
4173 genericptr
*genpart
;
4174 pathptr flippath
= SELTOPATH(selectobj
);
4176 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4177 + flippath
->parts
; genpart
++)
4178 elvflip(genpart
, position
->y
);
4181 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4182 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4183 easydraw(*selectobj
, DOFORALL
);
4186 select_invalidate_netlist();
4187 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4190 if (eventmode
== NORMAL_MODE
) {
4191 incr_changes(topobject
);
4193 if (eventmode
== CATALOG_MODE
) {
4195 if ((libnum
= is_library(topobject
)) >= 0) {
4196 composelib(libnum
+ LIBRARY
);
4197 drawarea(NULL
, NULL
, NULL
);
4201 pwriteback(areawin
->topinstance
);
4202 calcbbox(areawin
->topinstance
);
4206 /*----------------------------------------*/
4207 /* ButtonPress handler during delete mode */
4208 /*----------------------------------------*/
4210 void deletebutton(int x
, int y
)
4212 UNUSED(x
); UNUSED(y
);
4214 if (checkselect(ALL_TYPES
)) {
4215 standard_element_delete(ERASE
);
4216 calcbbox(areawin
->topinstance
);
4218 setoptionmenu(); /* Return GUI check/radio boxes to default */
4221 /*----------------------------------------------------------------------*/
4222 /* Process of element deletion. Remove one element from the indicated */
4224 /*----------------------------------------------------------------------*/
4226 void delete_one_element(objinstptr thisinstance
, genericptr thiselement
)
4228 objectptr thisobject
;
4230 Boolean pinchange
= False
;
4232 thisobject
= thisinstance
->thisobject
;
4234 /* The netlist contains pointers to elements which no longer */
4235 /* exist on the page, so we should remove them from the netlist. */
4237 if (RemoveFromNetlist(thisobject
, thiselement
)) pinchange
= True
;
4238 for (genobj
= thisobject
->plist
; genobj
< thisobject
->plist
4239 + thisobject
->parts
; genobj
++)
4240 if (*genobj
== thiselement
)
4243 if (genobj
== thisobject
->plist
+ thisobject
->parts
) return;
4245 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4246 *(genobj
- 1) = *genobj
;
4247 thisobject
->parts
--;
4249 if (pinchange
) setobjecttype(thisobject
);
4250 incr_changes(thisobject
);
4251 calcbbox(thisinstance
);
4252 invalidate_netlist(thisobject
);
4253 /* freenetlist(thisobject); */
4256 /*----------------------------------------------------------------------*/
4257 /* Process of element deletion. Remove everything in the selection */
4258 /* list from the indicated object, and return a new object containing */
4259 /* only the deleted elements. */
4261 /* if drawmode is DRAW, we erase the objects as we remove them. */
4263 /* Note that if "slist" is areawin->selectlist, it is freed by this */
4264 /* routine (calls freeselects()), but not otherwise. */
4265 /*----------------------------------------------------------------------*/
4267 objectptr
delete_element(objinstptr thisinstance
, short *slist
, int selects
,
4271 objectptr delobj
, thisobject
;
4273 Boolean pinchange
= False
;
4275 if (slist
== NULL
|| selects
== 0) return NULL
;
4277 thisobject
= thisinstance
->thisobject
;
4279 delobj
= (objectptr
) malloc(sizeof(object
));
4283 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4286 for (selectobj
= slist
; selectobj
< slist
+ selects
; selectobj
++) {
4287 genobj
= thisobject
->plist
+ *selectobj
;
4288 if (drawmode
) easydraw(*selectobj
, DOFORALL
);
4290 *(delobj
->plist
+ delobj
->parts
) = *genobj
;
4293 /* The netlist contains pointers to elements which no longer */
4294 /* exist on the page, so we should remove them from the netlist. */
4296 if (RemoveFromNetlist(thisobject
, *genobj
)) pinchange
= True
;
4297 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4298 *(genobj
- 1) = *genobj
;
4299 thisobject
->parts
--;
4300 reviseselect(slist
, selects
, selectobj
);
4302 if (pinchange
) setobjecttype(thisobject
);
4304 if (slist
== areawin
->selectlist
)
4307 calcbbox(thisinstance
);
4308 /* freenetlist(thisobject); */
4311 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
4312 drawarea(NULL
, NULL
, NULL
);
4317 /*----------------------------------------------------------------------*/
4318 /* Wrapper for delete_element(). Remember this deletion for the undo */
4320 /*----------------------------------------------------------------------*/
4322 void standard_element_delete(short drawmode
)
4326 /* register_for_undo(XCF_Select, UNDO_MORE, areawin->topinstance, */
4327 /* areawin->selectlist, areawin->selects); */
4328 select_invalidate_netlist();
4329 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4330 areawin
->selects
, drawmode
);
4331 register_for_undo(XCF_Delete
, UNDO_DONE
, areawin
->topinstance
,
4332 delobj
, (int)drawmode
);
4333 incr_changes(topobject
); /* Treat as one change */
4336 /*----------------------------------------------------------------------*/
4337 /* Another wrapper for delete_element(), in which we do not save the */
4338 /* deletion as an undo event. However, the returned object is saved */
4339 /* on areawin->editstack, so that the objects can be grabbed. This */
4340 /* allows objects to be carried across pages and through the hierarchy. */
4341 /*----------------------------------------------------------------------*/
4343 void delete_for_xfer(short drawmode
, short *slist
, int selects
)
4346 reset(areawin
->editstack
, DESTROY
);
4347 areawin
->editstack
= delete_element(areawin
->topinstance
,
4348 slist
, selects
, drawmode
);
4352 /*----------------------------------------------------------------------*/
4353 /* Yet another wrapper for delete_element(), in which we destroy the */
4354 /* object returned and free all associated memory. */
4355 /*----------------------------------------------------------------------*/
4357 void delete_noundo(short drawmode
)
4361 select_invalidate_netlist();
4362 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4363 areawin
->selects
, drawmode
);
4365 if (delobj
!= NULL
) reset(delobj
, DESTROY
);
4368 /*----------------------------------------------------------------------*/
4369 /* Undelete last deleted elements and return a selectlist of the */
4370 /* elements. If "olist" is non-NULL, then the undeleted elements are */
4371 /* placed into the object of thisinstance in the order given by olist, */
4372 /* and a copy of olist is returned. If "olist" is NULL, then the */
4373 /* undeleted elements are placed at the end of thisinstance->thisobject */
4374 /* ->plist, and a new selection list is returned. If "olist" is non- */
4375 /* NULL, then the size of olist had better match the number of objects */
4376 /* in delobj! It is up to the calling routine to check this. */
4377 /*----------------------------------------------------------------------*/
4379 short *xc_undelete(objinstptr thisinstance
, objectptr delobj
, short mode
,
4382 objectptr thisobject
;
4384 short *slist
, count
, i
; /* position; (jdk) */
4386 thisobject
= thisinstance
->thisobject
;
4387 slist
= (short *)malloc(delobj
->parts
* sizeof(short));
4390 for (regen
= delobj
->plist
; regen
< delobj
->plist
+ delobj
->parts
; regen
++) {
4391 PLIST_INCR(thisobject
);
4392 if (olist
== NULL
) {
4393 *(slist
+ count
) = thisobject
->parts
;
4394 *(topobject
->plist
+ topobject
->parts
) = *regen
;
4397 *(slist
+ count
) = *(olist
+ count
);
4398 for (i
= thisobject
->parts
; i
> *(olist
+ count
); i
--)
4399 *(thisobject
->plist
+ i
) = *(thisobject
->plist
+ i
- 1);
4400 *(thisobject
->plist
+ i
) = *regen
;
4402 thisobject
->parts
++;
4404 XTopSetForeground((*regen
)->color
);
4405 easydraw(*(slist
+ count
), DEFAULTCOLOR
);
4409 /* If the element has passed parameters (eparam), then we have to */
4410 /* check if the key exists in the new parent object. If not, */
4411 /* delete the parameter. */
4413 if ((*regen
)->passed
) {
4414 eparamptr nextepp
, epp
= (*regen
)->passed
;
4415 while (epp
!= NULL
) {
4416 nextepp
= epp
->next
;
4417 if (!match_param(thisobject
, epp
->key
)) {
4418 if (epp
== (*regen
)->passed
) (*regen
)->passed
= nextepp
;
4419 free_element_param(*regen
, epp
);
4425 /* Likewise, string parameters must be checked in labels because */
4426 /* they act like element parameters. */
4428 if (IS_LABEL(*regen
)) {
4429 labelptr glab
= TOLABEL(regen
);
4430 stringpart
*gstr
, *lastpart
= NULL
;
4431 for (gstr
= glab
->string
; gstr
!= NULL
; gstr
= lastpart
->nextpart
) {
4432 if (gstr
->type
== PARAM_START
) {
4433 if (!match_param(thisobject
, gstr
->data
.string
)) {
4434 free(gstr
->data
.string
);
4436 lastpart
->nextpart
= gstr
->nextpart
;
4438 glab
->string
= gstr
->nextpart
;
4440 gstr
= (lastpart
) ? lastpart
: glab
->string
;
4447 incr_changes(thisobject
); /* treat as one change */
4448 calcbbox(thisinstance
);
4450 /* flush the delete buffer but don't delete the elements */
4451 reset(delobj
, SAVE
);
4453 if (delobj
!= areawin
->editstack
) free(delobj
);
4458 /*----------------------------*/
4459 /* select save object handler */
4460 /*----------------------------*/
4462 void printname(objectptr curobject
)
4464 char editstr
[10], pagestr
[10];
4469 Dimension swidth
, swidth2
, sarea
;
4471 char *sptr
= tmpname
;
4474 /* print full string to make message widget proper size */
4476 strcpy(editstr
, ((ispage
= is_page(curobject
)) >= 0) ? "Editing: " : "");
4477 strcpy(editstr
, (is_library(curobject
) >= 0) ? "Library: " : "");
4478 if (strstr(curobject
->name
, "Page") == NULL
&& (ispage
>= 0))
4479 sprintf(pagestr
, " (p. %d)", areawin
->page
+ 1);
4482 W2printf("%s%s%s", editstr
, curobject
->name
, pagestr
);
4484 /* Tcl doesn't update width changes immediately. . . what to do? */
4485 /* (i.e., Tk_Width(message2) gives the original width) */
4488 XtSetArg(wargs
[0], XtNwidth
, &sarea
);
4489 XtGetValues(message2
, wargs
, 1);
4491 /* in the remote case that the string is longer than message widget, */
4492 /* truncate the string and denote the truncation with an ellipsis (...) */
4494 strcpy(tmpname
, curobject
->name
);
4495 swidth2
= XTextWidth(appdata
.xcfont
, editstr
, strlen(editstr
));
4496 swidth
= XTextWidth(appdata
.xcfont
, tmpname
, strlen(tmpname
));
4498 if ((swidth
+ swidth2
) > sarea
) {
4500 while ((swidth
+ swidth2
) > sarea
) {
4502 swidth
= XTextWidth(appdata
.xcfont
, sptr
, strlen(sptr
));
4504 for(ip
= sptr
; ip
< sptr
+ 3 && *ip
!= '\0'; ip
++) *ip
= '.';
4506 W2printf("Editing: %s", sptr
);
4511 /*--------------------------------------------------------------*/
4512 /* Make sure that a string does not conflict with postscript */
4513 /* names (commands and definitions found in xcircps2.pro). */
4515 /* Return value is NULL if no change was made. Otherwise, the */
4516 /* return value is an allocated string. */
4517 /*--------------------------------------------------------------*/
4519 char *checkvalidname(char *teststring
, objectptr newobj
)
4522 short dupl
; /* flag a duplicate string */
4524 char *sptr
, *pptr
, *cptr
;
4528 /* Try not to allocate memory unless necessary */
4535 if (newobj
!= NULL
) {
4536 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4537 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4538 libobj
= xobjs
.userlibs
[i
].library
+ j
;
4540 if (*libobj
== newobj
) continue;
4541 if (!strcmp(pptr
, (*libobj
)->name
)) {
4543 /* Prepend an underscore to the object name. If the */
4544 /* object has no technology, create a null technology */
4545 /* name. Otherwise, the technology remains the same */
4546 /* but the object name gets the prepended underscore. */
4548 if ((cptr
= strstr(pptr
, "::")) == NULL
) {
4549 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 3);
4550 sprintf(pptr
, "::_%s", (*libobj
)->name
);
4553 int offset
= cptr
- pptr
+ 2;
4555 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 2);
4557 pptr
= (char *)realloc(pptr
, strlen((*libobj
)->name
) + 2);
4558 sprintf(pptr
, "%s", (*libobj
)->name
);
4559 sprintf(pptr
+ offset
, "_%s", (*libobj
)->name
+ offset
);
4566 /* If we're in the middle of a file load, the name cannot be */
4567 /* the same as an alias, either. */
4569 if (aliastop
!= NULL
) {
4570 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
4571 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
) {
4572 if (!strcmp(pptr
, sref
->alias
)) {
4574 pptr
= (char *)malloc(strlen(sref
->alias
) + 2);
4576 pptr
= (char *)realloc(pptr
, strlen(sref
->alias
) + 2);
4577 sprintf(pptr
, "_%s", sref
->alias
);
4585 } while (dupl
== 1);
4587 return (pptr
== sptr
) ? NULL
: pptr
;
4590 /*--------------------------------------------------------------*/
4591 /* Make sure that name for new object does not conflict with */
4592 /* existing object definitions */
4594 /* Return: True if name required change, False otherwise */
4595 /*--------------------------------------------------------------*/
4597 Boolean
checkname(objectptr newobj
)
4601 /* Check for empty string */
4602 if (strlen(newobj
->name
) == 0) {
4603 Wprintf("Blank object name changed to default");
4604 sprintf(newobj
->name
, "user_object");
4607 pptr
= checkvalidname(newobj
->name
, newobj
);
4609 /* Change name if necessary to avoid naming conflicts */
4611 Wprintf("Created new object %s", newobj
->name
);
4615 Wprintf("Changed name from %s to %s to avoid conflict with "
4616 "existing object", newobj
->name
, pptr
);
4617 strncpy(newobj
->name
, pptr
, 79);
4623 /*------------------------------------------------------------*/
4624 /* Find the object "dot" in the builtin library, if it exists */
4625 /*------------------------------------------------------------*/
4633 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4634 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4635 dotobj
= *(xobjs
.userlibs
[i
].library
+ j
);
4636 name
= dotobj
->name
;
4637 if ((pptr
= strstr(name
, "::")) != NULL
) name
= pptr
+ 2;
4638 if (!strcmp(name
, "dot")) {
4643 return (objectptr
)NULL
;
4646 /*--------------------------------------*/
4647 /* Add value origin to all points */
4648 /*--------------------------------------*/
4650 void movepoints(genericptr
*ssgen
, short deltax
, short deltay
)
4652 switch(ELEMENTTYPE(*ssgen
)) {
4654 fpointlist sspoints
;
4655 TOARC(ssgen
)->position
.x
+= deltax
;
4656 TOARC(ssgen
)->position
.y
+= deltay
;
4657 for (sspoints
= TOARC(ssgen
)->points
; sspoints
< TOARC(ssgen
)->points
+
4658 TOARC(ssgen
)->number
; sspoints
++) {
4659 sspoints
->x
+= deltax
;
4660 sspoints
->y
+= deltay
;
4666 for (sspoints
= TOPOLY(ssgen
)->points
; sspoints
< TOPOLY(ssgen
)->points
+
4667 TOPOLY(ssgen
)->number
; sspoints
++) {
4668 sspoints
->x
+= deltax
;
4669 sspoints
->y
+= deltay
;
4674 fpointlist sspoints
;
4676 for (sspoints
= TOSPLINE(ssgen
)->points
; sspoints
<
4677 TOSPLINE(ssgen
)->points
+ INTSEGS
; sspoints
++) {
4678 sspoints
->x
+= deltax
;
4679 sspoints
->y
+= deltay
;
4681 for (j
= 0; j
< 4; j
++) {
4682 TOSPLINE(ssgen
)->ctrl
[j
].x
+= deltax
;
4683 TOSPLINE(ssgen
)->ctrl
[j
].y
+= deltay
;
4687 TOOBJINST(ssgen
)->position
.x
+= deltax
;
4688 TOOBJINST(ssgen
)->position
.y
+= deltay
;
4691 TOGRAPHIC(ssgen
)->position
.x
+= deltax
;
4692 TOGRAPHIC(ssgen
)->position
.y
+= deltay
;
4695 TOLABEL(ssgen
)->position
.x
+= deltax
;
4696 TOLABEL(ssgen
)->position
.y
+= deltay
;
4701 /*----------------------------------------------------------------------*/
4702 /* Add value origin to all edited points, according to edit flags */
4703 /*----------------------------------------------------------------------*/
4705 void editpoints(genericptr
*ssgen
, short deltax
, short deltay
)
4709 splineptr editspline
;
4710 short cycle
, cpoint
;
4715 switch(ELEMENTTYPE(*ssgen
)) {
4717 editpoly
= TOPOLY(ssgen
);
4718 if (editpoly
->cycle
== NULL
)
4719 movepoints(ssgen
, deltax
, deltay
);
4721 for (cptr
= editpoly
->cycle
;; cptr
++) {
4722 cycle
= cptr
->number
;
4723 curpt
= editpoly
->points
+ cycle
;
4724 if (cptr
->flags
& EDITX
) curpt
->x
+= deltax
;
4725 if (cptr
->flags
& EDITY
) curpt
->y
+= deltay
;
4726 if (cptr
->flags
& LASTENTRY
) break;
4733 editspline
= TOSPLINE(ssgen
);
4734 if (editspline
->cycle
== NULL
)
4735 movepoints(ssgen
, deltax
, deltay
);
4737 for (cptr
= editspline
->cycle
;; cptr
++) {
4738 cycle
= cptr
->number
;
4739 if (cycle
== 0 || cycle
== 3) {
4740 cpoint
= (cycle
== 0) ? 1 : 2;
4741 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cpoint
].x
+= deltax
;
4742 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cpoint
].y
+= deltay
;
4744 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cycle
].x
+= deltax
;
4745 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cycle
].y
+= deltay
;
4746 if (cptr
->flags
& ANTIXY
) {
4747 editspline
->ctrl
[cycle
].x
-= deltax
;
4748 editspline
->ctrl
[cycle
].y
-= deltay
;
4750 if (cptr
->flags
& LASTENTRY
) break;
4754 calcspline(editspline
);
4758 editpath
= TOPATH(ssgen
);
4759 if (checkcycle(*ssgen
, 0) < 0) {
4760 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4762 movepoints(ggen
, deltax
, deltay
);
4765 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4767 if (checkcycle(*ggen
, 0) >= 0)
4768 editpoints(ggen
, deltax
, deltay
);
4774 movepoints(ssgen
, deltax
, deltay
);
4782 void xlib_makeobject(xcWidget w
, caddr_t nulldata
)
4784 UNUSED(w
); UNUSED(nulldata
);
4786 domakeobject(-1, (char *)_STR2
, FALSE
);
4789 #endif /* !TCL_WRAPPER */
4791 /*--------------------------------------------------------------*/
4792 /* Set the name for a new user-defined object and make the */
4793 /* object. If "forceempty" is true, we allow creation of a new */
4794 /* object with no elements (normally would be used only from a */
4795 /* script, where an object is being constructed automatically). */
4796 /*--------------------------------------------------------------*/
4798 objinstptr
domakeobject(int libnum
, char *name
, Boolean forceempty
)
4801 objinstptr
*newinst
;
4803 oparamptr ops
, newop
;
4804 eparamptr epp
, newepp
;
4807 short loclibnum
= libnum
;
4809 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
4811 /* make room for new entry in library list */
4813 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
4814 realloc(xobjs
.userlibs
[loclibnum
].library
,
4815 (xobjs
.userlibs
[loclibnum
].number
+ 1) * sizeof(objectptr
));
4817 newobj
= xobjs
.userlibs
[loclibnum
].library
+ xobjs
.userlibs
[loclibnum
].number
;
4819 *newobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4820 areawin
->selects
, NORMAL
);
4822 if (*newobj
== NULL
) {
4825 if (!forceempty
) return NULL
;
4827 /* Create a new (empty) object */
4829 initobj
= (objectptr
) malloc(sizeof(object
));
4834 invalidate_netlist(topobject
);
4835 xobjs
.userlibs
[loclibnum
].number
++;
4837 /* Create the instance of this object so we can compute a bounding box */
4839 NEW_OBJINST(newinst
, topobject
);
4840 instancedefaults(*newinst
, *newobj
, 0, 0);
4843 /* find closest snap point to bbox center and make this the obj. center */
4845 if (areawin
->center
) {
4846 origin
.x
= (*newobj
)->bbox
.lowerleft
.x
+ (*newobj
)->bbox
.width
/ 2;
4847 origin
.y
= (*newobj
)->bbox
.lowerleft
.y
+ (*newobj
)->bbox
.height
/ 2;
4850 origin
.x
= origin
.y
= 0;
4853 instancedefaults(*newinst
, *newobj
, origin
.x
, origin
.y
);
4855 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4857 switch(ELEMENTTYPE(*ssgen
)) {
4860 TOOBJINST(ssgen
)->position
.x
-= origin
.x
;
4861 TOOBJINST(ssgen
)->position
.y
-= origin
.y
;
4865 TOGRAPHIC(ssgen
)->position
.x
-= origin
.x
;
4866 TOGRAPHIC(ssgen
)->position
.y
-= origin
.y
;
4870 TOLABEL(ssgen
)->position
.x
-= origin
.x
;
4871 TOLABEL(ssgen
)->position
.y
-= origin
.y
;
4875 genericptr
*pathlist
;
4876 for (pathlist
= TOPATH(ssgen
)->plist
; pathlist
< TOPATH(ssgen
)->plist
4877 + TOPATH(ssgen
)->parts
; pathlist
++) {
4878 movepoints(pathlist
, -origin
.x
, -origin
.y
);
4883 movepoints(ssgen
, -origin
.x
, -origin
.y
);
4888 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4890 for (epp
= (*ssgen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
4891 ops
= match_param(topobject
, epp
->key
);
4892 newop
= copyparameter(ops
);
4893 newop
->next
= (*newobj
)->params
;
4894 (*newobj
)->params
= newop
;
4896 /* Generate an indirect parameter reference from child to parent */
4897 newepp
= make_new_eparam(epp
->key
);
4898 newepp
->flags
|= P_INDIRECT
;
4899 newepp
->pdata
.refkey
= strdup(epp
->key
);
4900 newepp
->next
= (*newinst
)->passed
;
4901 (*newinst
)->passed
= newepp
;
4903 if (IS_LABEL(*ssgen
)) {
4904 /* Also need to check for substring parameters in labels */
4905 for (sptr
= TOLABEL(ssgen
)->string
; sptr
!= NULL
; sptr
= sptr
->nextpart
) {
4906 if (sptr
->type
== PARAM_START
) {
4907 ops
= match_param(topobject
, sptr
->data
.string
);
4908 newop
= copyparameter(ops
);
4909 newop
->next
= (*newobj
)->params
;
4910 (*newobj
)->params
= newop
;
4912 /* Generate an indirect parameter reference from child to parent */
4913 newepp
= make_new_eparam(sptr
->data
.string
);
4914 newepp
->flags
|= P_INDIRECT
;
4915 newepp
->pdata
.refkey
= strdup(sptr
->data
.string
);
4916 newepp
->next
= (*newinst
)->passed
;
4917 (*newinst
)->passed
= newepp
;
4923 /* any parameters in the top-level object that used by the selected */
4924 /* elements must be copied into the new object. */
4926 /* put new object back into place */
4928 (*newobj
)->hidden
= False
;
4929 (*newobj
)->schemtype
= SYMBOL
;
4932 incr_changes(*newobj
);
4934 /* (netlist invalidation was taken care of by delete_element() */
4935 /* Also, incr_changes(topobject) was done by delete_element()) */
4937 XTopSetForeground((*newinst
)->color
);
4938 UDrawObject(*newinst
, SINGLE
, (*newinst
)->color
,
4939 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
4942 /* Copy name into object and check for conflicts */
4944 strcpy((*newobj
)->name
, name
);
4947 /* register the technology and mark the technology as not saved */
4948 AddObjectTechnology(*newobj
);
4950 /* generate library instance for this object (bounding box */
4951 /* should be default, so don't do calcbbox() on it) */
4953 addtoinstlist(loclibnum
, *newobj
, FALSE
);
4955 /* recompile the user catalog and reset view bounds */
4957 composelib(loclibnum
+ LIBRARY
);
4958 centerview(xobjs
.libtop
[loclibnum
+ LIBRARY
]);
4965 /*-------------------------------------------*/
4966 /* Make a user object from selected elements */
4967 /*-------------------------------------------*/
4969 void selectsave(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
4971 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
4972 UNUSED(clientdata
); UNUSED(calldata
);
4974 if (areawin
->selects
== 0) return; /* nothing was selected */
4976 /* Get a name for the new object */
4978 eventmode
= NORMAL_MODE
;
4979 popdata
->dataptr
= NULL
;
4980 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
4981 popupprompt(w
, "Enter name for new object:", "\0", xlib_makeobject
, popdata
, NULL
);
4986 /*-----------------------------*/
4987 /* Edit-stack support routines */
4988 /*-----------------------------*/
4990 void arceditpush(arcptr lastarc
)
4994 NEW_ARC(newarc
, areawin
->editstack
);
4995 arccopy(*newarc
, lastarc
);
4996 copycycles(&((*newarc
)->cycle
), &(lastarc
->cycle
));
4999 /*--------------------------------------*/
5001 void splineeditpush(splineptr lastspline
)
5003 splineptr
*newspline
;
5005 NEW_SPLINE(newspline
, areawin
->editstack
);
5006 splinecopy(*newspline
, lastspline
);
5009 /*--------------------------------------*/
5011 void polyeditpush(polyptr lastpoly
)
5015 NEW_POLY(newpoly
, areawin
->editstack
);
5016 polycopy(*newpoly
, lastpoly
);
5019 /*--------------------------------------*/
5021 void patheditpush(pathptr lastpath
)
5025 NEW_PATH(newpath
, areawin
->editstack
);
5026 pathcopy(*newpath
, lastpath
);
5029 /*-----------------------------*/
5030 /* Copying support routines */
5031 /*-----------------------------*/
5033 pointlist
copypoints(pointlist points
, int number
)
5035 pointlist rpoints
, cpoints
, newpoints
;
5037 rpoints
= (pointlist
) malloc(number
* sizeof(XPoint
));
5038 for (newpoints
= rpoints
, cpoints
= points
;
5039 newpoints
< rpoints
+ number
;
5040 newpoints
++, cpoints
++) {
5041 newpoints
->x
= cpoints
->x
;
5042 newpoints
->y
= cpoints
->y
;
5047 /*------------------------------------------*/
5049 void graphiccopy(graphicptr newg
, graphicptr copyg
)
5054 newg
->source
= copyg
->source
;
5055 newg
->position
.x
= copyg
->position
.x
;
5056 newg
->position
.y
= copyg
->position
.y
;
5057 newg
->rotation
= copyg
->rotation
;
5058 newg
->scale
= copyg
->scale
;
5059 newg
->color
= copyg
->color
;
5060 newg
->passed
= NULL
;
5061 copyalleparams((genericptr
)newg
, (genericptr
)copyg
);
5063 newg
->valid
= FALSE
;
5064 newg
->target
= NULL
;
5065 newg
->clipmask
= (Pixmap
)NULL
;
5066 #endif /* HAVE_CAIRO */
5068 /* Update the refcount of the source image */
5069 for (i
= 0; i
< xobjs
.images
; i
++) {
5070 iptr
= xobjs
.imagelist
+ i
;
5071 if (iptr
->image
== newg
->source
) {
5078 /*------------------------------------------*/
5080 void labelcopy(labelptr newtext
, labelptr copytext
)
5082 newtext
->string
= stringcopy(copytext
->string
);
5083 newtext
->position
.x
= copytext
->position
.x
;
5084 newtext
->position
.y
= copytext
->position
.y
;
5085 newtext
->rotation
= copytext
->rotation
;
5086 newtext
->scale
= copytext
->scale
;
5087 newtext
->anchor
= copytext
->anchor
;
5088 newtext
->color
= copytext
->color
;
5089 newtext
->passed
= NULL
;
5090 newtext
->cycle
= NULL
;
5091 copyalleparams((genericptr
)newtext
, (genericptr
)copytext
);
5092 newtext
->pin
= copytext
->pin
;
5095 /*------------------------------------------*/
5097 void arccopy(arcptr newarc
, arcptr copyarc
)
5099 newarc
->style
= copyarc
->style
;
5100 newarc
->color
= copyarc
->color
;
5101 newarc
->position
.x
= copyarc
->position
.x
;
5102 newarc
->position
.y
= copyarc
->position
.y
;
5103 newarc
->radius
= copyarc
->radius
;
5104 newarc
->yaxis
= copyarc
->yaxis
;
5105 newarc
->angle1
= copyarc
->angle1
;
5106 newarc
->angle2
= copyarc
->angle2
;
5107 newarc
->width
= copyarc
->width
;
5108 newarc
->passed
= NULL
;
5109 newarc
->cycle
= NULL
;
5110 copyalleparams((genericptr
)newarc
, (genericptr
)copyarc
);
5114 /*------------------------------------------*/
5116 void polycopy(polyptr newpoly
, polyptr copypoly
)
5118 newpoly
->style
= copypoly
->style
;
5119 newpoly
->color
= copypoly
->color
;
5120 newpoly
->width
= copypoly
->width
;
5121 newpoly
->number
= copypoly
->number
;
5122 copycycles(&(newpoly
->cycle
), &(copypoly
->cycle
));
5123 newpoly
->points
= copypoints(copypoly
->points
, copypoly
->number
);
5125 newpoly
->passed
= NULL
;
5126 copyalleparams((genericptr
)newpoly
, (genericptr
)copypoly
);
5129 /*------------------------------------------*/
5131 void splinecopy(splineptr newspline
, splineptr copyspline
)
5135 newspline
->style
= copyspline
->style
;
5136 newspline
->color
= copyspline
->color
;
5137 newspline
->width
= copyspline
->width
;
5138 copycycles(&(newspline
->cycle
), &(copyspline
->cycle
));
5139 for (i
= 0; i
< 4; i
++) {
5140 newspline
->ctrl
[i
].x
= copyspline
->ctrl
[i
].x
;
5141 newspline
->ctrl
[i
].y
= copyspline
->ctrl
[i
].y
;
5143 for (i
= 0; i
< INTSEGS
; i
++) {
5144 newspline
->points
[i
].x
= copyspline
->points
[i
].x
;
5145 newspline
->points
[i
].y
= copyspline
->points
[i
].y
;
5147 newspline
->passed
= NULL
;
5148 copyalleparams((genericptr
)newspline
, (genericptr
)copyspline
);
5151 /*----------------------------------------------*/
5153 /*----------------------------------------------*/
5155 void pathcopy(pathptr newpath
, pathptr copypath
)
5158 splineptr
*newspline
, copyspline
;
5159 polyptr
*newpoly
, copypoly
;
5161 newpath
->style
= copypath
->style
;
5162 newpath
->color
= copypath
->color
;
5163 newpath
->width
= copypath
->width
;
5165 newpath
->passed
= NULL
;
5166 copyalleparams((genericptr
)newpath
, (genericptr
)copypath
);
5167 newpath
->plist
= (genericptr
*)malloc(copypath
->parts
* sizeof(genericptr
));
5169 for (ggen
= copypath
->plist
; ggen
< copypath
->plist
+ copypath
->parts
; ggen
++) {
5170 switch (ELEMENTTYPE(*ggen
)) {
5172 copypoly
= TOPOLY(ggen
);
5173 NEW_POLY(newpoly
, newpath
);
5174 polycopy(*newpoly
, copypoly
);
5177 copyspline
= TOSPLINE(ggen
);
5178 NEW_SPLINE(newspline
, newpath
);
5179 splinecopy(*newspline
, copyspline
);
5185 /*--------------------------------------------------------------*/
5186 /* Copy an object instance */
5187 /*--------------------------------------------------------------*/
5189 void instcopy(objinstptr newobj
, objinstptr copyobj
)
5191 newobj
->position
.x
= copyobj
->position
.x
;
5192 newobj
->position
.y
= copyobj
->position
.y
;
5193 newobj
->rotation
= copyobj
->rotation
;
5194 newobj
->scale
= copyobj
->scale
;
5195 newobj
->style
= copyobj
->style
;
5196 newobj
->thisobject
= copyobj
->thisobject
;
5197 newobj
->color
= copyobj
->color
;
5198 newobj
->bbox
.lowerleft
.x
= copyobj
->bbox
.lowerleft
.x
;
5199 newobj
->bbox
.lowerleft
.y
= copyobj
->bbox
.lowerleft
.y
;
5200 newobj
->bbox
.width
= copyobj
->bbox
.width
;
5201 newobj
->bbox
.height
= copyobj
->bbox
.height
;
5203 newobj
->passed
= NULL
;
5204 copyalleparams((genericptr
)newobj
, (genericptr
)copyobj
);
5206 newobj
->params
= NULL
;
5207 copyparams(newobj
, copyobj
);
5209 /* If the parameters are the same, the bounding box should be, too. */
5210 if (copyobj
->schembbox
!= NULL
) {
5211 newobj
->schembbox
= (BBox
*)malloc(sizeof(BBox
));
5212 newobj
->schembbox
->lowerleft
.x
= copyobj
->schembbox
->lowerleft
.x
;
5213 newobj
->schembbox
->lowerleft
.y
= copyobj
->schembbox
->lowerleft
.y
;
5214 newobj
->schembbox
->width
= copyobj
->schembbox
->width
;
5215 newobj
->schembbox
->height
= copyobj
->schembbox
->height
;
5218 newobj
->schembbox
= NULL
;
5221 /*--------------------------------------------------------------*/
5222 /* The method for removing objects from a list is to add the */
5223 /* value REMOVE_TAG to the type of each object needing to be */
5224 /* removed, and then calling this routine. */
5225 /*--------------------------------------------------------------*/
5227 void delete_tagged(objinstptr thisinst
) {
5228 Boolean tagged
= True
;
5229 objectptr thisobject
, delobj
;
5233 thisobject
= thisinst
->thisobject
;
5237 for (stmp
= 0; stmp
< thisobject
->parts
; stmp
++) {
5238 pgen
= thisobject
->plist
+ stmp
;
5239 if ((*pgen
)->type
& REMOVE_TAG
) {
5240 (*pgen
)->type
&= (~REMOVE_TAG
);
5243 delobj
= delete_element(thisinst
, &stmp
, 1, 0);
5244 register_for_undo(XCF_Delete
, UNDO_MORE
, thisinst
, delobj
, 0);
5246 /* If we destroy elements in the current window, we need to */
5247 /* make sure that the selection list is updated appropriately. */
5249 if ((thisobject
== topobject
) && (areawin
->selects
> 0)) {
5250 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5251 areawin
->selects
; sobj
++)
5252 if (*sobj
> stmp
) (*sobj
)--;
5255 /* Also ensure that this element is not referenced in any */
5256 /* netlist. If it is, remove it and mark the netlist as */
5259 remove_netlist_element(thisobject
, *pgen
);
5263 undo_finish_series();
5266 /*-----------------------------------------------------------------*/
5267 /* For copying: Check if an object is about to be placed directly */
5268 /* on top of the same object. If so, delete the one underneath. */
5269 /*-----------------------------------------------------------------*/
5274 genericptr
*sgen
, *pgen
;
5275 Boolean tagged
= False
;
5277 /* Work through the select list */
5279 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5280 areawin
->selects
; sobj
++) {
5281 sgen
= topobject
->plist
+ (*sobj
);
5283 /* For each object being copied, compare it against every object */
5284 /* on the current page (except self). Flag if it's the same. */
5286 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+ topobject
->parts
;
5288 if (pgen
== sgen
) continue;
5289 if (compare_single(sgen
, pgen
)) {
5290 /* Make sure that this object is not part of the selection, */
5291 /* else chaos will reign. */
5292 for (cobj
= areawin
->selectlist
; cobj
< areawin
->selectlist
+
5293 areawin
->selects
; cobj
++) {
5294 if (pgen
== topobject
->plist
+ (*cobj
)) break;
5296 /* Tag it for future deletion and prevent further compares */
5297 if (cobj
== areawin
->selectlist
+ areawin
->selects
) {
5299 (*pgen
)->type
|= REMOVE_TAG
;
5305 /* Delete the tagged elements */
5306 Wprintf("Duplicate object deleted");
5307 delete_tagged(areawin
->topinstance
);
5308 incr_changes(topobject
);
5312 /*--------------------------------------------------------------*/
5313 /* Direct placement of elements. Assumes that the selectlist */
5314 /* contains all the elements to be positioned. "deltax" and */
5315 /* "deltay" are relative x and y positions to move the */
5317 /*--------------------------------------------------------------*/
5319 void placeselects(short deltax
, short deltay
, XPoint
*userpt
)
5322 XPoint newpos
, *ppt
;
5329 doattach
= ((userpt
== NULL
) || (areawin
->attachto
< 0)) ? FALSE
: TRUE
;
5331 /* under attachto condition, keep element attached to */
5332 /* the attachto element. */
5334 if (doattach
) findattach(&newpos
, &rot
, userpt
);
5338 areawin
->clipped
= -1; /* Prevent clipping */
5339 #endif /* HAVE_CAIRO */
5341 for (dragselect
= areawin
->selectlist
; dragselect
< areawin
->selectlist
5342 + areawin
->selects
; dragselect
++) {
5344 switch(SELECTTYPE(dragselect
)) {
5346 objinstptr draginst
= SELTOOBJINST(dragselect
);
5349 draginst
->position
.x
= newpos
.x
;
5350 draginst
->position
.y
= newpos
.y
;
5351 while (rot
>= 360.0) rot
-= 360.0;
5352 while (rot
< 0.0) rot
+= 360.0;
5353 draginst
->rotation
= rot
;
5356 draginst
->position
.x
+= deltax
;
5357 draginst
->position
.y
+= deltay
;
5362 graphicptr dragg
= SELTOGRAPHIC(dragselect
);
5363 dragg
->position
.x
+= deltax
;
5364 dragg
->position
.y
+= deltay
;
5367 labelptr draglabel
= SELTOLABEL(dragselect
);
5369 draglabel
->position
.x
= newpos
.x
;
5370 draglabel
->position
.y
= newpos
.y
;
5371 draglabel
->rotation
= rot
;
5374 draglabel
->position
.x
+= deltax
;
5375 draglabel
->position
.y
+= deltay
;
5379 pathptr dragpath
= SELTOPATH(dragselect
);
5380 genericptr
*pathlist
;
5383 XPoint
*pdelta
= pathclosepoint(dragpath
, &newpos
);
5384 deltax
= newpos
.x
- pdelta
->x
;
5385 deltay
= newpos
.y
- pdelta
->y
;
5387 for (pathlist
= dragpath
->plist
; pathlist
< dragpath
->plist
5388 + dragpath
->parts
; pathlist
++) {
5389 movepoints(pathlist
, deltax
, deltay
);
5393 polyptr dragpoly
= SELTOPOLY(dragselect
);
5394 pointlist dragpoints
;
5396 /* if (dragpoly->cycle != NULL) continue; */
5398 closest
= closepoint(dragpoly
, &newpos
);
5399 deltax
= newpos
.x
- dragpoly
->points
[closest
].x
;
5400 deltay
= newpos
.y
- dragpoly
->points
[closest
].y
;
5402 for (dragpoints
= dragpoly
->points
; dragpoints
< dragpoly
->points
5403 + dragpoly
->number
; dragpoints
++) {
5404 dragpoints
->x
+= deltax
;
5405 dragpoints
->y
+= deltay
;
5409 splineptr dragspline
= SELTOSPLINE(dragselect
);
5411 fpointlist dragpoints
;
5413 /* if (dragspline->cycle != NULL) continue; */
5415 closest
= (wirelength(&dragspline
->ctrl
[0], &newpos
)
5416 > wirelength(&dragspline
->ctrl
[3], &newpos
)) ? 3 : 0;
5417 deltax
= newpos
.x
- dragspline
->ctrl
[closest
].x
;
5418 deltay
= newpos
.y
- dragspline
->ctrl
[closest
].y
;
5420 for (dragpoints
= dragspline
->points
; dragpoints
< dragspline
->
5421 points
+ INTSEGS
; dragpoints
++) {
5422 dragpoints
->x
+= deltax
;
5423 dragpoints
->y
+= deltay
;
5425 for (j
= 0; j
< 4; j
++) {
5426 dragspline
->ctrl
[j
].x
+= deltax
;
5427 dragspline
->ctrl
[j
].y
+= deltay
;
5431 arcptr dragarc
= SELTOARC(dragselect
);
5432 fpointlist dragpoints
;
5435 deltax
= newpos
.x
- dragarc
->position
.x
;
5436 deltay
= newpos
.y
- dragarc
->position
.y
;
5438 dragarc
->position
.x
+= deltax
;
5439 dragarc
->position
.y
+= deltay
;
5440 for (dragpoints
= dragarc
->points
; dragpoints
< dragarc
->
5441 points
+ dragarc
->number
; dragpoints
++) {
5442 dragpoints
->x
+= deltax
;
5443 dragpoints
->y
+= deltay
;
5449 if (areawin
->pinattach
) {
5450 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
5451 topobject
->parts
; pgen
++) {
5452 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
5453 cpoly
= TOPOLY(pgen
);
5454 if (cpoly
->cycle
!= NULL
) {
5455 ppt
= cpoly
->points
+ cpoly
->cycle
->number
;
5456 newpos
.x
= ppt
->x
+ deltax
;
5457 newpos
.y
= ppt
->y
+ deltay
;
5458 if (areawin
->manhatn
)
5459 manhattanize(&newpos
, cpoly
, cpoly
->cycle
->number
, FALSE
);
5467 move_mode_draw(xcDRAW_EDIT
, NULL
);
5470 areawin
->clipped
= 0;
5471 #endif /* HAVE_CAIRO */
5474 /*----------------------------------------------------------------------*/
5475 /* Copy handler. Assumes that the selectlist contains the elements */
5476 /* to be copied, and that the initial position of the copy is held */
5477 /* in areawin->save. */
5478 /*----------------------------------------------------------------------*/
5484 if (!checkselect_draw(ALL_TYPES
, True
)) return;
5485 u2u_snap(&areawin
->save
);
5486 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
5487 + areawin
->selects
; selectobj
++) {
5489 /* Cycles will not be used for copy mode: remove them */
5490 removecycle(topobject
->plist
+ (*selectobj
));
5492 switch(SELECTTYPE(selectobj
)) {
5493 case LABEL
: { /* copy label */
5494 labelptr copytext
= SELTOLABEL(selectobj
);
5497 NEW_LABEL(newtext
, topobject
);
5498 labelcopy(*newtext
, copytext
);
5500 case OBJINST
: { /* copy object instance */
5501 objinstptr copyobj
= SELTOOBJINST(selectobj
);
5503 NEW_OBJINST(newobj
, topobject
);
5504 instcopy(*newobj
, copyobj
);
5506 case GRAPHIC
: { /* copy graphic instance */
5507 graphicptr copyg
= SELTOGRAPHIC(selectobj
);
5509 NEW_GRAPHIC(newg
, topobject
);
5510 graphiccopy(*newg
, copyg
);
5512 case PATH
: { /* copy path */
5513 pathptr copypath
= SELTOPATH(selectobj
);
5515 NEW_PATH(newpath
, topobject
);
5516 pathcopy(*newpath
, copypath
);
5518 case ARC
: { /* copy arc */
5519 arcptr copyarc
= SELTOARC(selectobj
);
5521 NEW_ARC(newarc
, topobject
);
5522 arccopy(*newarc
, copyarc
);
5524 case POLYGON
: { /* copy polygons */
5525 polyptr copypoly
= SELTOPOLY(selectobj
);
5527 NEW_POLY(newpoly
, topobject
);
5528 polycopy(*newpoly
, copypoly
);
5530 case SPLINE
: { /* copy spline */
5531 splineptr copyspline
= SELTOSPLINE(selectobj
);
5532 splineptr
*newspline
;
5533 NEW_SPLINE(newspline
, topobject
);
5534 splinecopy(*newspline
, copyspline
);
5538 /* change selection from the old to the new object */
5540 *selectobj
= topobject
->parts
- 1;
5544 /*--------------------------------------------------------------*/
5545 /* Function which initiates interactive placement of copied */
5547 /*--------------------------------------------------------------*/
5551 if (areawin
->selects
> 0) {
5552 move_mode_draw(xcDRAW_INIT
, NULL
);
5553 if (eventmode
== NORMAL_MODE
) {
5554 XDefineCursor(dpy
, areawin
->window
, COPYCURSOR
);
5555 eventmode
= COPY_MODE
;
5557 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
5558 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5560 XtAddEventHandler(areawin
->area
, PointerMotionMask
|
5561 ButtonMotionMask
, False
, (XtEventHandler
)xlib_drag
,
5565 select_invalidate_netlist();
5569 /*-----------------------------------------------------------*/
5570 /* Copy handler for copying from a button push or key event. */
5571 /*-----------------------------------------------------------*/
5573 void copy_op(int op
, int x
, int y
)
5575 if (op
== XCF_Copy
) {
5576 window_to_user(x
, y
, &areawin
->save
);
5577 createcopies(); /* This function does all the hard work */
5578 copydrag(); /* Start interactive placement */
5581 eventmode
= NORMAL_MODE
;
5582 areawin
->attachto
= -1;
5585 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5586 ButtonMotionMask
, False
, (xcEventHandler
)xctk_drag
,
5589 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5590 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5593 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5594 u2u_snap(&areawin
->save
);
5595 if (op
== XCF_Cancel
) {
5596 move_mode_draw(xcDRAW_EMPTY
, NULL
);
5597 delete_noundo(NORMAL
);
5599 else if (op
== XCF_Finish_Copy
) {
5600 move_mode_draw(xcDRAW_FINAL
, NULL
);
5601 /* If selected objects are the only ones on the page, */
5602 /* then do a full bbox calculation. */
5603 if (topobject
->parts
== areawin
->selects
)
5604 calcbbox(areawin
->topinstance
);
5608 register_for_undo(XCF_Copy
, UNDO_MORE
, areawin
->topinstance
,
5609 areawin
->selectlist
, areawin
->selects
);
5611 incr_changes(topobject
);
5613 else { /* XCF_Continue_Copy */
5614 move_mode_draw(xcDRAW_FINAL
, NULL
);
5615 if (topobject
->parts
== areawin
->selects
)
5616 calcbbox(areawin
->topinstance
);
5620 register_for_undo(XCF_Copy
, UNDO_DONE
, areawin
->topinstance
,
5621 areawin
->selectlist
, areawin
->selects
);
5623 copydrag(); /* Start interactive placement again */
5624 incr_changes(topobject
);
5629 /*----------------------------------------------*/
5630 /* Check for more than one button being pressed */
5631 /*----------------------------------------------*/
5633 Boolean
checkmultiple(XButtonEvent
*event
)
5635 int state
= Button1Mask
| Button2Mask
| Button3Mask
|
5636 Button4Mask
| Button5Mask
;
5637 state
&= event
->state
;
5638 /* ((x - 1) & x) is always non-zero if x has more than one bit set */
5639 return (((state
- 1) & state
) == 0) ? False
: True
;
5642 /*----------------------------------------------------------------------*/
5643 /* Operation continuation---dependent upon the ongoing operation. */
5644 /* This operation only pertains to a few event modes for which */
5645 /* continuation of action makes sense---drawing wires (polygons), and */
5646 /* editing polygons, arcs, splines, and paths. */
5647 /*----------------------------------------------------------------------*/
5649 void continue_op(int op
, int x
, int y
)
5653 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5654 window_to_user(x
, y
, &areawin
->save
);
5657 printpos(ppos
.x
, ppos
.y
);
5666 case(EPATH_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5667 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5668 path_op(*(EDITPART
), op
, x
, y
);
5671 inst_op(*(EDITPART
), op
, x
, y
);
5674 finish_op(XCF_Finish_Element
, x
, y
);
5681 /*--------------------------------------------------------------*/
5682 /* Finish or cancel an operation. This forces a return to */
5683 /* "normal" mode, with whatever other side effects are caused */
5684 /* by the operation. */
5685 /*--------------------------------------------------------------*/
5687 void finish_op(int op
, int x
, int y
)
5691 XPoint snappt
, boxpts
[4];
5694 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5695 window_to_user(x
, y
, &areawin
->save
);
5698 case(EPATH_MODE
): case(BOX_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5699 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5700 path_op(*(EDITPART
), op
, x
, y
);
5704 inst_op(*(EDITPART
), op
, x
, y
);
5707 case (FONTCAT_MODE
):
5708 case (EFONTCAT_MODE
):
5709 fontcat_op(op
, x
, y
);
5710 eventmode
= (eventmode
== FONTCAT_MODE
) ? TEXT_MODE
: ETEXT_MODE
;
5711 text_mode_draw(xcDRAW_INIT
, TOLABEL(EDITPART
));
5712 XDefineCursor (dpy
, areawin
->window
, TEXTPTR
);
5717 catalog_op(op
, x
, y
);
5729 curlabel
= TOLABEL(EDITPART
);
5730 if (op
== XCF_Cancel
) {
5731 redrawtext(curlabel
);
5732 areawin
->redraw_needed
= False
; /* ignore previous requests */
5733 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5734 freelabel(curlabel
->string
);
5740 singlebbox(EDITPART
);
5741 incr_changes(topobject
);
5742 select_invalidate_netlist();
5743 text_mode_draw(xcDRAW_FINAL
, curlabel
);
5745 setdefaultfontmarks();
5746 eventmode
= NORMAL_MODE
;
5749 case(ETEXT_MODE
): case(CATTEXT_MODE
):
5750 curlabel
= TOLABEL(EDITPART
);
5751 if (op
== XCF_Cancel
) {
5752 /* restore the original text */
5753 undrawtext(curlabel
);
5754 undo_finish_series();
5756 redrawtext(curlabel
);
5757 areawin
->redraw_needed
= False
; /* ignore previous requests */
5758 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5759 if (eventmode
== CATTEXT_MODE
) eventmode
= CATALOG_MODE
;
5761 setdefaultfontmarks();
5763 else textreturn(); /* Generate "return" key character */
5764 areawin
->textend
= 0;
5768 u2u_snap(&areawin
->save
);
5770 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5771 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5773 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5774 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5777 if (op
== XCF_Cancel
) {
5778 /* Just regenerate the library where we started */
5779 if (areawin
->selects
>= 1) {
5780 objinstptr selinst
= SELTOOBJINST(areawin
->selectlist
);
5781 libnum
= libfindobject(selinst
->thisobject
, NULL
);
5783 composelib(libnum
+ LIBRARY
);
5790 eventmode
= CATALOG_MODE
;
5791 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5795 u2u_snap(&areawin
->save
);
5797 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5798 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5800 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5801 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5804 if (op
== XCF_Cancel
) {
5805 /* If we came from the library with an object instance, in */
5806 /* MOVE_MODE, then "cancel" should delete the element. */
5807 /* Otherwise, put the position of the element back to what */
5808 /* it was before we started the move. The difference is */
5809 /* indicated by the value of areawin->editpart. */
5811 if ((areawin
->selects
> 0) && (*areawin
->selectlist
== topobject
->parts
))
5812 delete_noundo(NORMAL
);
5814 placeselects(areawin
->origin
.x
- areawin
->save
.x
,
5815 areawin
->origin
.y
- areawin
->save
.y
, NULL
);
5817 drawarea(NULL
, NULL
, NULL
);
5820 if (areawin
->selects
> 0) {
5821 register_for_undo(XCF_Move
,
5822 /* (was_preselected) ? UNDO_DONE : UNDO_MORE, */
5824 areawin
->topinstance
,
5825 (int)(areawin
->save
.x
- areawin
->origin
.x
),
5826 (int)(areawin
->save
.y
- areawin
->origin
.y
));
5827 pwriteback(areawin
->topinstance
);
5828 incr_changes(topobject
);
5829 select_invalidate_netlist();
5830 unselect_all(); /* The way it used to be. . . */
5833 /* full calc needed: move may shrink bbox */
5834 calcbbox(areawin
->topinstance
);
5836 /* if (!was_preselected) clearselects(); */
5838 areawin
->attachto
= -1;
5844 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5845 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5847 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5848 ButtonMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5851 rescale_mode_draw(xcDRAW_FINAL
, NULL
);
5852 if (op
!= XCF_Cancel
) {
5853 XPoint newpoints
[5];
5854 fscale
= UGetRescaleBox(&areawin
->save
, newpoints
);
5856 elementrescale(fscale
);
5857 areawin
->redraw_needed
= True
;
5860 eventmode
= NORMAL_MODE
;
5864 selarea_mode_draw(xcDRAW_FINAL
, NULL
);
5867 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5868 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5870 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5871 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5874 /* Zero-width boxes act like a normal selection. Otherwise, */
5875 /* proceed with the area select. */
5877 if ((areawin
->origin
.x
== areawin
->save
.x
) &&
5878 (areawin
->origin
.y
== areawin
->save
.y
))
5879 select_add_element(ALL_TYPES
);
5881 boxpts
[0] = areawin
->origin
;
5882 boxpts
[1].x
= areawin
->save
.x
;
5883 boxpts
[1].y
= areawin
->origin
.y
;
5884 boxpts
[2] = areawin
->save
;
5885 boxpts
[3].x
= areawin
->origin
.x
;
5886 boxpts
[3].y
= areawin
->save
.y
;
5887 selectarea(topobject
, boxpts
, 0);
5892 u2u_snap(&areawin
->save
);
5895 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5896 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5898 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5899 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5902 areawin
->panx
= areawin
->pany
= 0;
5903 if (op
!= XCF_Cancel
)
5904 panbutton((u_int
) 5, (areawin
->width
>> 1) - (x
- areawin
->origin
.x
),
5905 (areawin
->height
>> 1) - (y
- areawin
->origin
.y
), 0);
5911 /* Remove any selections */
5912 if ((eventmode
== SELAREA_MODE
) || (eventmode
== PAN_MODE
)
5913 || (eventmode
== MOVE_MODE
))
5915 eventmode
= NORMAL_MODE
;
5916 areawin
->redraw_needed
= True
;
5918 else if (eventmode
!= MOVE_MODE
&& eventmode
!= EPATH_MODE
&&
5919 eventmode
!= EPOLY_MODE
&& eventmode
!= ARC_MODE
&&
5920 eventmode
!= EARC_MODE
&& eventmode
!= SPLINE_MODE
&&
5921 eventmode
!= ESPLINE_MODE
&& eventmode
!= WIRE_MODE
&&
5922 eventmode
!= ETEXT_MODE
&& eventmode
!= TEXT_MODE
) {
5926 if (eventmode
== NORMAL_MODE
) {
5928 /* Return any highlighted networks to normal */
5929 highlightnetlist(topobject
, areawin
->topinstance
, 0);
5931 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5934 snap(x
, y
, &snappt
);
5935 printpos(snappt
.x
, snappt
.y
);
5938 /*--------------------------------------------------------------*/
5939 /* Edit operations for instances. This is used to allow */
5940 /* numeric parameters to be adjusted from the hierarchical */
5941 /* level above, shielding the the unparameterized parts from */
5943 /*--------------------------------------------------------------*/
5945 void inst_op(genericptr editpart
, int op
, int x
, int y
)
5947 UNUSED(editpart
); UNUSED(op
); UNUSED(x
); UNUSED(y
);
5950 /*--------------------------------------------------------------*/
5951 /* Operations for path components */
5952 /*--------------------------------------------------------------*/
5954 void path_op(genericptr editpart
, int op
, int x
, int y
)
5957 splineptr newspline
;
5958 Boolean donecycles
= False
;
5959 UNUSED(x
); UNUSED(y
);
5961 /* Don't allow point cycling in a multi-part edit. */
5962 /* Allowing it is just confusing. Instead, we treat */
5963 /* button 1 (cycle) like button 2 (finish). */
5964 if (op
== XCF_Continue_Element
&& areawin
->selects
> 1)
5965 op
= XCF_Finish_Element
;
5967 switch(ELEMENTTYPE(editpart
)) {
5969 pathptr newpath
= (pathptr
)editpart
;
5970 short dotrack
= True
;
5973 areawin
->attachto
= -1;
5975 if (op
!= XCF_Continue_Element
) {
5978 if (op
== XCF_Continue_Element
) {
5979 nextpathcycle(newpath
, 1);
5980 patheditpush(newpath
);
5982 else if (op
== XCF_Finish_Element
) {
5983 path_mode_draw(xcDRAW_FINAL
, newpath
);
5984 incr_changes(topobject
);
5986 else { /* restore previous path from edit stack */
5987 free_single((genericptr
)newpath
);
5988 if (areawin
->editstack
->parts
> 0) {
5989 if (op
== XCF_Cancel
) {
5990 editpath
= TOPATH(areawin
->editstack
->plist
);
5991 pathcopy(newpath
, editpath
);
5992 reset(areawin
->editstack
, NORMAL
);
5995 editpath
= TOPATH(areawin
->editstack
->plist
+
5996 areawin
->editstack
->parts
- 1);
5997 pathcopy(newpath
, editpath
);
5998 free_single((genericptr
)editpath
);
6000 areawin
->editstack
->parts
--;
6002 if (areawin
->editstack
->parts
> 0) {
6004 nextpathcycle(newpath
, 1);
6005 path_mode_draw(xcDRAW_EDIT
, newpath
);
6009 user_to_window(areawin
->origin
, &warppt
);
6010 warppointer(warppt
.x
, warppt
.y
);
6011 path_mode_draw(xcDRAW_FINAL
, newpath
);
6015 path_mode_draw(xcDRAW_EMPTY
, newpath
);
6017 free_single((genericptr
)newpath
);
6021 pwriteback(areawin
->topinstance
);
6024 /* Free the editstack */
6025 reset(areawin
->editstack
, NORMAL
);
6026 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6027 (xcEventHandler
)trackelement
, NULL
);
6028 eventmode
= NORMAL_MODE
;
6034 if (eventmode
== BOX_MODE
) {
6037 newbox
= (polyptr
)editpart
;
6039 /* prevent length and/or width zero boxes */
6040 if (newbox
->points
->x
!= (newbox
->points
+ 2)->x
&& (newbox
->points
6041 + 1)->y
!= (newbox
->points
+ 3)->y
) {
6042 if (op
!= XCF_Cancel
) {
6043 poly_mode_draw(xcDRAW_FINAL
, newbox
);
6044 incr_changes(topobject
);
6045 if (!nonnetwork(newbox
)) invalidate_netlist(topobject
);
6046 register_for_undo(XCF_Box
, UNDO_MORE
, areawin
->topinstance
,
6050 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6051 free_single((genericptr
)newbox
);
6058 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6059 free_single((genericptr
)newbox
);
6064 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6065 (xcEventHandler
)trackbox
, NULL
);
6066 eventmode
= NORMAL_MODE
;
6068 else { /* EPOLY_MODE */
6070 short dotrack
= True
;
6072 newpoly
= (polyptr
)editpart
;
6073 areawin
->attachto
= -1;
6075 if (op
!= XCF_Continue_Element
) {
6079 if (op
== XCF_Continue_Element
) {
6080 nextpolycycle(&newpoly
, 1);
6081 polyeditpush(newpoly
);
6083 else if (op
== XCF_Finish_Element
) {
6085 /* Check for degenerate polygons (all points the same). */
6087 for (i
= 1; i
< newpoly
->number
; i
++)
6088 if ((newpoly
->points
[i
].x
!= newpoly
->points
[i
- 1].x
) ||
6089 (newpoly
->points
[i
].y
!= newpoly
->points
[i
- 1].y
))
6091 if (i
== newpoly
->number
) {
6092 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6093 /* Remove this polygon with the standard delete */
6094 /* method (saves polygon on undo stack). */
6095 newpoly
->type
|= REMOVE_TAG
;
6096 delete_tagged(areawin
->topinstance
);
6099 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6100 if (!nonnetwork(newpoly
)) invalidate_netlist(topobject
);
6101 incr_changes(topobject
);
6106 free_single((genericptr
)newpoly
);
6107 if (areawin
->editstack
->parts
> 0) {
6108 if (op
== XCF_Cancel
) {
6109 editpoly
= TOPOLY(areawin
->editstack
->plist
);
6110 polycopy(newpoly
, editpoly
);
6111 reset(areawin
->editstack
, NORMAL
);
6114 editpoly
= TOPOLY(areawin
->editstack
->plist
+
6115 areawin
->editstack
->parts
- 1);
6116 polycopy(newpoly
, editpoly
);
6117 free_single((genericptr
)editpoly
);
6119 areawin
->editstack
->parts
--;
6121 if (areawin
->editstack
->parts
> 0) {
6123 nextpolycycle(&newpoly
, -1);
6124 poly_mode_draw(xcDRAW_EDIT
, newpoly
);
6127 XcTopSetForeground(newpoly
->color
);
6128 user_to_window(areawin
->origin
, &warppt
);
6129 warppointer(warppt
.x
, warppt
.y
);
6130 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6134 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6139 pwriteback(areawin
->topinstance
);
6142 /* Free the editstack */
6143 reset(areawin
->editstack
, NORMAL
);
6145 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6146 (xcEventHandler
)trackelement
, NULL
);
6147 eventmode
= NORMAL_MODE
;
6154 arcptr newarc
, editarc
;
6155 short dotrack
= True
;
6157 newarc
= (arcptr
)editpart
;
6159 if (op
!= XCF_Continue_Element
) {
6163 if (op
== XCF_Continue_Element
) {
6164 nextarccycle(&newarc
, 1);
6165 arceditpush(newarc
);
6168 else if (op
== XCF_Finish_Element
) {
6171 if (newarc
->radius
!= 0 && newarc
->yaxis
!= 0 &&
6172 (newarc
->angle1
!= newarc
->angle2
)) {
6173 XTopSetForeground(newarc
->color
);
6174 incr_changes(topobject
);
6175 if (eventmode
== ARC_MODE
) {
6176 register_for_undo(XCF_Arc
, UNDO_MORE
, areawin
->topinstance
,
6179 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6183 /* Remove the record if the radius is zero. If we were */
6184 /* creating the arc, just delete it; it's as if it */
6185 /* never existed. If we were editing an arc, use the */
6186 /* standard delete method (saves arc on undo stack). */
6188 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6189 if (eventmode
== ARC_MODE
) {
6190 free_single((genericptr
)newarc
);
6195 newarc
->type
|= REMOVE_TAG
;
6196 delete_tagged(areawin
->topinstance
);
6200 else { /* Cancel: restore previous arc from edit stack */
6201 free_single((genericptr
)newarc
);
6202 if (areawin
->editstack
->parts
> 0) {
6203 if (op
== XCF_Cancel
) {
6204 editarc
= TOARC(areawin
->editstack
->plist
);
6205 arccopy(newarc
, editarc
);
6206 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6207 reset(areawin
->editstack
, NORMAL
);
6210 editarc
= TOARC(areawin
->editstack
->plist
+
6211 areawin
->editstack
->parts
- 1);
6212 arccopy(newarc
, editarc
);
6213 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6214 free_single((genericptr
)editarc
);
6216 areawin
->editstack
->parts
--;
6218 if (areawin
->editstack
->parts
> 0) {
6220 nextarccycle(&newarc
, -1);
6221 arc_mode_draw(xcDRAW_EDIT
, newarc
);
6224 if (eventmode
!= ARC_MODE
) {
6226 user_to_window(areawin
->origin
, &warppt
);
6227 warppointer(warppt
.x
, warppt
.y
);
6229 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6233 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6237 pwriteback(areawin
->topinstance
);
6240 /* Free the editstack */
6241 reset(areawin
->editstack
, NORMAL
);
6243 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6244 (xcEventHandler
)trackarc
, NULL
);
6245 eventmode
= NORMAL_MODE
;
6250 splineptr editspline
;
6251 short dotrack
= True
;
6253 newspline
= (splineptr
)editpart
;
6255 if (op
!= XCF_Continue_Element
) {
6259 if (op
== XCF_Continue_Element
) {
6260 /* Note: we work backwards through spline control points. */
6261 /* The reason is that when creating a spline, the sudden */
6262 /* move from the endpoint to the startpoint (forward */
6263 /* direction) is more disorienting than moving from the */
6264 /* endpoint to the endpoint's control point. */
6266 nextsplinecycle(&newspline
, -1);
6267 splineeditpush(newspline
);
6270 /* unlikely but possible to create zero-length splines */
6271 else if (newspline
->ctrl
[0].x
!= newspline
->ctrl
[3].x
||
6272 newspline
->ctrl
[0].x
!= newspline
->ctrl
[1].x
||
6273 newspline
->ctrl
[0].x
!= newspline
->ctrl
[2].x
||
6274 newspline
->ctrl
[0].y
!= newspline
->ctrl
[3].y
||
6275 newspline
->ctrl
[0].y
!= newspline
->ctrl
[1].y
||
6276 newspline
->ctrl
[0].y
!= newspline
->ctrl
[2].y
) {
6277 if (op
== XCF_Finish_Element
) {
6278 incr_changes(topobject
);
6279 if (eventmode
== SPLINE_MODE
) {
6280 register_for_undo(XCF_Spline
, UNDO_MORE
, areawin
->topinstance
,
6283 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6285 else { /* restore previous spline from edit stack */
6286 free_single((genericptr
)newspline
);
6287 if (areawin
->editstack
->parts
> 0) {
6288 if (op
== XCF_Cancel
) {
6289 editspline
= TOSPLINE(areawin
->editstack
->plist
);
6290 splinecopy(newspline
, editspline
);
6291 reset(areawin
->editstack
, NORMAL
);
6294 editspline
= TOSPLINE(areawin
->editstack
->plist
+
6295 areawin
->editstack
->parts
- 1);
6296 splinecopy(newspline
, editspline
);
6297 free_single((genericptr
)editspline
);
6299 areawin
->editstack
->parts
--;
6301 if (areawin
->editstack
->parts
> 0) {
6303 nextsplinecycle(&newspline
, 1);
6304 spline_mode_draw(xcDRAW_EDIT
, newspline
);
6307 if (eventmode
!= SPLINE_MODE
) {
6309 user_to_window(areawin
->origin
, &warppt
);
6310 warppointer(warppt
.x
, warppt
.y
);
6312 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6316 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6322 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6323 free_single((genericptr
)newspline
);
6327 pwriteback(areawin
->topinstance
);
6330 /* Free the editstack */
6331 reset(areawin
->editstack
, NORMAL
);
6333 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6334 (xcEventHandler
)trackelement
, NULL
);
6335 eventmode
= NORMAL_MODE
;
6340 calcbbox(areawin
->topinstance
);
6342 /* Multiple-element edit: Some items may have been moved as */
6343 /* opposed to edited, and should be registered here. To do */
6344 /* this correctly, we must first unselect the edited items, */
6345 /* then register the move for the remaining items. */
6350 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6351 areawin
->selects
; eselect
++)
6352 checkcycle(SELTOGENERIC(eselect
), 0);
6354 /* Remove all (remaining) cycles */
6355 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6356 areawin
->selects
; eselect
++)
6357 removecycle(SELTOGENERICPTR(eselect
));
6359 /* Remove edits from the undo stack when canceling */
6360 if (op
== XCF_Cancel
|| op
== XCF_Cancel_Last
) {
6361 if (xobjs
.undostack
&& (xobjs
.undostack
->type
== XCF_Edit
)) {
6362 undo_finish_series();
6369 /*-------------------------------------------------------*/
6370 /* Recalculate values for a drawing-area widget resizing */
6371 /*-------------------------------------------------------*/
6373 void resizearea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6379 int savewidth
= areawin
->width
, saveheight
= areawin
->height
;
6380 XCWindowData
*thiswin
;
6383 #endif /* !HAVE_CAIRO */
6384 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6386 if ((dpy
!= NULL
) && xcIsRealized(areawin
->area
)) {
6389 areawin
->width
= Tk_Width(w
);
6390 areawin
->height
= Tk_Height(w
);
6392 XtSetArg(wargs
[0], XtNwidth
, &areawin
->width
);
6393 XtSetArg(wargs
[1], XtNheight
, &areawin
->height
);
6394 XtGetValues(areawin
->area
, wargs
, 2);
6397 if (areawin
->width
!= savewidth
|| areawin
->height
!= saveheight
) {
6399 int maxwidth
= 0, maxheight
= 0;
6400 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6401 if (thiswin
->width
> maxwidth
) maxwidth
= thiswin
->width
;
6402 if (thiswin
->height
> maxheight
) maxheight
= thiswin
->height
;
6404 #if !defined(HAVE_CAIRO)
6405 if (dbuf
!= (Pixmap
)NULL
) XFreePixmap(dpy
, dbuf
);
6406 dbuf
= XCreatePixmap(dpy
, areawin
->window
, maxwidth
, maxheight
,
6407 DefaultDepthOfScreen(xcScreen(w
)));
6410 /* TODO: probably make this a generalized function call, which */
6411 /* should be handled depending on the surface in the xtgui.c, */
6412 /* xcwin32.c, etc. files. */
6413 /* For now only support xlib surface */
6414 cairo_xlib_surface_set_size(areawin
->surface
, areawin
->width
,
6417 if (areawin
->clipmask
!= (Pixmap
)NULL
) XFreePixmap(dpy
, areawin
->clipmask
);
6418 areawin
->clipmask
= XCreatePixmap(dpy
, areawin
->window
,
6419 maxwidth
, maxheight
, 1);
6421 if (areawin
->pbuf
!= (Pixmap
)NULL
) {
6422 XFreePixmap(dpy
, areawin
->pbuf
);
6423 areawin
->pbuf
= XCreatePixmap(dpy
, areawin
->window
,
6424 maxwidth
, maxheight
, 1);
6427 if (areawin
->cmgc
!= (GC
)NULL
) XFreeGC(dpy
, areawin
->cmgc
);
6428 values
.foreground
= 0;
6429 values
.background
= 0;
6430 areawin
->cmgc
= XCreateGC(dpy
, areawin
->clipmask
,
6431 GCForeground
| GCBackground
, &values
);
6432 #endif /* !HAVE_CAIRO */
6434 /* Clear fixed_pixmap */
6435 if (areawin
->fixed_pixmap
) {
6437 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6438 areawin
->fixed_pixmap
= NULL
;
6439 #else /* !HAVE_CAIRO */
6440 XFreePixmap(dpy
, areawin
->fixed_pixmap
);
6441 areawin
->fixed_pixmap
= (Pixmap
) NULL
;
6442 #endif /* !HAVE_CAIRO */
6447 /* Re-compose the directores to match the new dimensions */
6449 composelib(PAGELIB
);
6451 /* Re-center image in resized window */
6452 zoomview(NULL
, NULL
, NULL
);
6455 /* Flush all expose events from the buffer */
6456 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
) == True
);
6460 /*----------------------*/
6461 /* Draw the grids, etc. */
6462 /*----------------------*/
6465 void draw_grids(void)
6467 float x
, y
, spc
, spc2
, i
, j
, fpart
;
6468 float major_snapspace
, spc3
;
6470 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
6471 if (areawin
->gridon
&& spc
> 8) {
6472 fpart
= (float)(-areawin
->pcorner
.x
)
6473 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6474 x
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6475 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6476 fpart
= (float)(-areawin
->pcorner
.y
)
6477 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6478 y
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6479 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6481 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6482 for (i
= x
; i
< (float)areawin
->width
; i
+= spc
)
6483 DrawLine (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6484 0, (int)(i
+ 0.5), areawin
->height
);
6485 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc
)
6486 DrawLine (dpy
, areawin
->window
, areawin
->gc
, 0, (int)(j
- 0.5),
6487 areawin
->width
, (int)(j
- 0.5));
6490 if (areawin
->axeson
) {
6491 XPoint originpt
, zeropt
;
6492 zeropt
.x
= zeropt
.y
= 0;
6493 SetForeground(dpy
, areawin
->gc
, AXESCOLOR
);
6494 user_to_window(zeropt
, &originpt
);
6495 DrawLine(dpy
, areawin
->window
, areawin
->gc
, originpt
.x
, 0,
6496 originpt
.x
, areawin
->height
);
6497 DrawLine(dpy
, areawin
->window
, areawin
->gc
, 0, originpt
.y
,
6498 areawin
->width
, originpt
.y
);
6501 /* bounding box goes beneath everything except grid/axis lines */
6504 /* draw a little red dot at each snap-to point */
6506 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
6507 if (areawin
->snapto
&& spc2
> 8) {
6510 fpart
= (float)(-areawin
->pcorner
.x
)
6511 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6512 x2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6513 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6514 fpart
= (float)(-areawin
->pcorner
.y
)
6515 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6516 y2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6517 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6519 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6521 HDC hdc
= CreateCompatibleDC(NULL
);
6522 SelectObject(hdc
, Tk_GetHWND(areawin
->window
));
6524 SetForeground(dpy
, areawin
->gc
, SNAPCOLOR
);
6525 for (i
= x2
; i
< areawin
->width
; i
+= spc2
)
6526 for (j
= areawin
->height
- y2
; j
> 0; j
-= spc2
)
6527 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6528 SetPixelV(hdc
, (int)(i
+ 0.5), (int)(j
- 0.05), areawin
->gc
->foreground
);
6530 DrawPoint (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6532 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6538 /* Draw major snap points (code contributed by John Barry) */
6540 major_snapspace
= xobjs
.pagelist
[areawin
->page
]->gridspace
* 20;
6541 spc3
= major_snapspace
* areawin
->vscale
;
6543 fpart
= (float)(-areawin
->pcorner
.x
) / major_snapspace
;
6544 x
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6545 fpart
= (float)(-areawin
->pcorner
.y
) / major_snapspace
;
6546 y
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6548 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6549 for (i
= x
; i
< (float)areawin
->width
; i
+= spc3
) {
6550 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc3
) {
6551 XDrawArc(dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5) - 1,
6552 (int)(j
- 0.5) - 1, 2, 2, 0, 360*64);
6557 SetBackground(dpy
, areawin
->gc
, BACKGROUND
);
6559 #endif /* !HAVE_CAIRO */
6561 /*------------------------------------------------------*/
6562 /* Draw fixed parts of the primary graphics window */
6563 /*------------------------------------------------------*/
6565 void draw_fixed(void)
6567 Boolean old_ongoing
;
6570 #endif /* !HAVE_CAIRO */
6572 if (xobjs
.suspend
>= 0) return;
6573 old_ongoing
= areawin
->redraw_ongoing
;
6574 areawin
->redraw_ongoing
= True
;
6576 /* Set drawing context to fixed_pixmap */
6578 cairo_identity_matrix(areawin
->cr
);
6579 cairo_push_group(areawin
->cr
);
6580 #else /* HAVE_CAIRO */
6581 old_window
= areawin
->window
;
6582 areawin
->window
= areawin
->fixed_pixmap
;
6583 #endif /* HAVE_CAIRO */
6585 /* Clear background */
6587 if (xobjs
.pagelist
[areawin
->page
]->background
.name
!= (char *)NULL
) {
6591 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6592 cairo_paint(areawin
->cr
);
6593 #endif /* HAVE_GS */
6596 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6597 cairo_paint(areawin
->cr
);
6599 #else /* HAVE_CAIRO */
6600 if (xobjs
.pagelist
[areawin
->page
]->background
.name
== (char *)NULL
6601 || (copybackground() < 0)) {
6602 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6603 XFillRectangle(dpy
, areawin
->window
, areawin
->gc
, 0, 0, areawin
->width
,
6606 SetThinLineAttributes(dpy
, areawin
->gc
, 0, LineSolid
, CapRound
, JoinBevel
);
6607 #endif /* !HAVE_CAIRO */
6611 /* draw GRIDCOLOR lines for grid; mark axes in AXESCOLOR */
6613 if (eventmode
!= CATALOG_MODE
&& eventmode
!= ASSOC_MODE
6614 && eventmode
!= FONTCAT_MODE
&& eventmode
!= EFONTCAT_MODE
6615 && eventmode
!= CATMOVE_MODE
&& eventmode
!= CATTEXT_MODE
) {
6619 /* Determine the transformation matrix for the topmost object */
6620 /* and draw the hierarchy above the current edit object (if */
6621 /* "edit-in-place" is selected). */
6623 if (areawin
->editinplace
== True
) {
6624 if (areawin
->stack
!= NULL
) {
6625 pushlistptr lastlist
= NULL
, thislist
;
6628 UPushCTM(); /* save our current state */
6630 /* It's easiest if we first push the current page onto the stack, */
6631 /* then we don't need to treat the top-level page separately. We */
6632 /* pop it at the end. */
6633 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
6635 thislist
= areawin
->stack
;
6637 while ((thislist
!= NULL
) &&
6638 (is_library(thislist
->thisinst
->thisobject
) < 0)) {
6640 /* Invert the transformation matrix of the instance on the stack */
6641 /* to get the proper transformation matrix of the drawing one */
6642 /* up in the hierarchy. */
6645 UPreMultCTM(&mtmp
, thislist
->thisinst
->position
,
6646 thislist
->thisinst
->scale
, thislist
->thisinst
->rotation
);
6648 UPreMultCTMbyMat(DCTM
, &mtmp
);
6650 lastlist
= thislist
;
6651 thislist
= thislist
->next
;
6653 /* The following will be true for moves between schematics and symbols */
6654 if ((thislist
!= NULL
) && (thislist
->thisinst
->thisobject
->symschem
6655 == lastlist
->thisinst
->thisobject
))
6659 if (lastlist
!= NULL
) {
6660 pushlistptr stack
= NULL
;
6661 SetForeground(dpy
, areawin
->gc
, OFFBUTTONCOLOR
);
6662 UDrawObject(lastlist
->thisinst
, SINGLE
, DOFORALL
,
6663 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &stack
);
6664 /* This shouldn't happen, but just in case. . . */
6665 if (stack
) free_stack(&stack
);
6668 pop_stack(&areawin
->stack
); /* restore the original stack state */
6669 UPopCTM(); /* restore the original matrix state */
6674 /* draw all of the elements on the screen */
6676 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
6678 /* Initialize hierstack */
6679 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6680 UDrawObject(areawin
->topinstance
, TOPLEVEL
, FOREGROUND
,
6681 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &areawin
->hierstack
);
6682 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6685 if (areawin
->fixed_pixmap
)
6686 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6687 areawin
->fixed_pixmap
= cairo_pop_group(areawin
->cr
);
6688 #else /* HAVE_CAIRO */
6689 areawin
->window
= old_window
;
6690 #endif /* HAVE_CAIRO */
6691 areawin
->redraw_ongoing
= old_ongoing
;
6694 /*--------------------------------------*/
6695 /* Draw the primary graphics window */
6696 /*--------------------------------------*/
6698 void drawwindow(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6701 xcDrawType redrawtype
= xcDRAW_EDIT
;
6702 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6704 if (areawin
->area
== NULL
) return;
6705 if (!xcIsRealized(areawin
->area
)) return;
6706 if (xobjs
.suspend
>= 0) return;
6709 /* Make sure a fixed pixmap exists */
6710 if (!areawin
->fixed_pixmap
) {
6711 areawin
->fixed_pixmap
= XCreatePixmap(dpy
, areawin
->window
,
6712 areawin
->width
, areawin
->height
,
6713 DefaultDepthOfScreen(xcScreen(areawin
->area
)));
6715 #endif /* !HAVE_CAIRO */
6717 /* Sanity check---specifically to track down an error */
6718 if ((areawin
->selects
== 1) && *(areawin
->selectlist
) >= topobject
->parts
) {
6719 Wprintf("Internal error!");
6720 areawin
->selects
= 0;
6724 if (areawin
->redraw_needed
)
6725 redrawtype
= xcREDRAW_FORCED
;
6727 switch (eventmode
) {
6728 case ARC_MODE
: case EARC_MODE
:
6729 arc_mode_draw(redrawtype
, TOARC(EDITPART
));
6731 case SPLINE_MODE
: case ESPLINE_MODE
:
6732 spline_mode_draw(redrawtype
, TOSPLINE(EDITPART
));
6734 case BOX_MODE
: case EPOLY_MODE
: case WIRE_MODE
:
6735 poly_mode_draw(redrawtype
, TOPOLY(EDITPART
));
6738 path_mode_draw(redrawtype
, TOPATH(EDITPART
));
6740 case TEXT_MODE
: case CATTEXT_MODE
: case ETEXT_MODE
:
6741 text_mode_draw(redrawtype
, TOLABEL(EDITPART
));
6744 selarea_mode_draw(redrawtype
, NULL
);
6747 rescale_mode_draw(redrawtype
, NULL
);
6749 case CATMOVE_MODE
: case MOVE_MODE
: case COPY_MODE
:
6750 move_mode_draw(redrawtype
, NULL
);
6752 case ASSOC_MODE
: case EINST_MODE
: case FONTCAT_MODE
: case EFONTCAT_MODE
:
6753 case PAN_MODE
: case NORMAL_MODE
: case UNDO_MODE
: case CATALOG_MODE
:
6754 normal_mode_draw(redrawtype
, NULL
);
6757 /* flush out multiple expose/resize events from the event queue */
6758 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
));
6760 /* end by restoring graphics state */
6761 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
6763 areawin
->redraw_needed
= False
;
6766 /*----------------------------------------------------------------------*/
6767 /* Draw the current window (areawin). Check if other windows contain */
6768 /* the same object or one of its ancestors. If so, redraw them, too. */
6769 /*----------------------------------------------------------------------*/
6771 void drawarea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6773 XCWindowDataPtr thiswin
, focuswin
;
6775 if (xobjs
.suspend
>= 0) {
6776 if (xobjs
.suspend
== 0)
6777 xobjs
.suspend
= 1; /* Mark that a refresh is pending */
6783 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6784 if (thiswin
== focuswin
) continue;
6786 /* Note: need to check ancestry here, not just blindly redraw */
6787 /* all the windows all the time. */
6791 /* Don't respond to an expose event if the graphics context */
6792 /* has not yet been created. */
6793 if (areawin
->cr
!= NULL
)
6795 drawwindow(NULL
, NULL
, NULL
);
6798 drawwindow(w
, clientdata
, calldata
);
6801 /*-------------------------------------------------------------------------*/