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
;
527 UNUSED(clientdata
); UNUSED(calldata
);
529 if (!xcIsRealized(bar
)) return;
530 if (xobjs
.suspend
>= 0) return;
533 scale
= (char *)Tcl_GetVar2(xcinterp
, "XCOps", "scale", TCL_GLOBAL_ONLY
);
534 sbarsize
= SBARSIZE
* atoi(scale
);
539 bwin
= xcWindow(bar
);
541 if (topobject
->bbox
.width
> 0) {
542 frac
= (float) areawin
->width
/ (float) topobject
->bbox
.width
;
543 rleft
= (long)(frac
* (float)(areawin
->pcorner
.x
544 - topobject
->bbox
.lowerleft
.x
));
545 rright
= rleft
+ (long)(frac
* (float)areawin
->width
/ areawin
->vscale
);
549 rright
= (long)areawin
->width
;
551 rmid
= (rright
+ rleft
) >> 1;
553 if (rleft
< 0) rleft
= 0;
554 if (rright
> areawin
->width
) rright
= areawin
->width
;
556 XSetFunction(dpy
, areawin
->gc
, GXcopy
);
557 XSetForeground(dpy
, areawin
->gc
, colorlist
[BARCOLOR
].color
.pixel
);
558 if (rmid
> 0 && rleft
> 0)
559 XClearArea(dpy
, bwin
, 0, 0, (int)rleft
, sbarsize
, FALSE
);
560 XFillRectangle(dpy
, bwin
, areawin
->gc
, (int)rleft
+ 1, 1,
561 (int)(rright
- rleft
), sbarsize
- 1);
563 XClearArea(dpy
, bwin
, (int)rright
+ 1, 0, areawin
->width
564 - (int)rright
, sbarsize
, FALSE
);
565 XClearArea(dpy
, bwin
, (int)rmid
- 1, 1, 3, sbarsize
, FALSE
);
567 XSetForeground(dpy
, areawin
->gc
, colorlist
[areawin
->gccolor
].color
.pixel
);
570 /*------------------------------------------------------*/
571 /* Redraw the vertical scrollbar */
572 /*------------------------------------------------------*/
574 void drawvbar(xcWidget bar
, caddr_t clientdata
, caddr_t calldata
)
576 Window bwin
= xcWindow(bar
);
580 long rtop
, rbot
, rmid
;
581 UNUSED(clientdata
); UNUSED(calldata
);
584 scale
= (char *)Tcl_GetVar2(xcinterp
, "XCOps", "scale", TCL_GLOBAL_ONLY
);
585 sbarsize
= SBARSIZE
* atoi(scale
);
590 if (!xcIsRealized(bar
)) return;
591 if (xobjs
.suspend
>= 0) return;
593 if (topobject
->bbox
.height
> 0) {
594 frac
= (float)areawin
->height
/ (float)topobject
->bbox
.height
;
595 rbot
= (long)(frac
* (float)(topobject
->bbox
.lowerleft
.y
596 - areawin
->pcorner
.y
+ topobject
->bbox
.height
));
597 rtop
= rbot
- (long)(frac
* (float)areawin
->height
/ areawin
->vscale
);
600 rbot
= areawin
->height
;
603 rmid
= (rtop
+ rbot
) >> 1;
605 if (rtop
< 0) rtop
= 0;
606 if (rbot
> areawin
->height
) rbot
= areawin
->height
;
608 XSetFunction(dpy
, areawin
->gc
, GXcopy
);
609 XSetForeground(dpy
, areawin
->gc
, colorlist
[BARCOLOR
].color
.pixel
);
610 if (rmid
> 0 && rtop
> 0)
611 XClearArea(dpy
, bwin
, 0, 0, sbarsize
, (int)rtop
, FALSE
);
612 XFillRectangle(dpy
, bwin
, areawin
->gc
, 0, (int)rtop
+ 2, sbarsize
,
615 XClearArea(dpy
, bwin
, 0, (int)rbot
+ 1, sbarsize
, areawin
->height
617 XClearArea(dpy
, bwin
, 0, (int)rmid
- 1, sbarsize
, 3, FALSE
);
619 XSetForeground(dpy
, areawin
->gc
, colorlist
[areawin
->gccolor
].color
.pixel
);
622 /*------------------------------------------------------*/
623 /* Simultaneously scroll the screen and horizontal */
624 /* bar when dragging the mouse in the scrollbar area */
625 /*------------------------------------------------------*/
627 void panhbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
630 short savex
= areawin
->pcorner
.x
;
633 if (eventmode
== SELAREA_MODE
) return;
635 newx
= (long)(event
->x
* ((float)topobject
->bbox
.width
/
636 areawin
->width
) + topobject
->bbox
.lowerleft
.x
- 0.5 *
637 ((float)areawin
->width
/ areawin
->vscale
));
638 areawin
->pcorner
.x
= (short)newx
;
639 drawhbar(bar
, NULL
, NULL
);
640 areawin
->pcorner
.x
= savex
;
642 if ((newpx
= (long)(newx
- savex
) * areawin
->vscale
) == 0)
645 areawin
->panx
= -newpx
;
646 drawarea(NULL
, NULL
, NULL
);
649 /*------------------------------------------------------*/
650 /* End the horizontal scroll and refresh entire screen */
651 /*------------------------------------------------------*/
653 void endhbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
656 short savex
= areawin
->pcorner
.x
;
661 newx
= (long)(event
->x
* ((float)topobject
->bbox
.width
/
662 areawin
->width
) + topobject
->bbox
.lowerleft
.x
- 0.5 *
663 ((float)areawin
->width
/ areawin
->vscale
));
665 areawin
->pcorner
.x
= (short)newx
;
667 if ((newx
<< 1) != (long)((short)(newx
<< 1)) || checkbounds() == -1) {
668 areawin
->pcorner
.x
= savex
;
669 Wprintf("Reached boundary: cannot pan further");
674 areawin
->redraw_needed
= True
;
675 areawin
->lastbackground
= NULL
;
677 drawhbar(bar
, NULL
, NULL
);
678 drawarea(bar
, NULL
, NULL
);
681 /*------------------------------------------------------*/
682 /* Simultaneously scroll the screen and vertical */
683 /* bar when dragging the mouse in the scrollbar area */
684 /*------------------------------------------------------*/
686 void panvbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
689 short savey
= areawin
->pcorner
.y
;
692 if (eventmode
== SELAREA_MODE
) return;
694 newy
= (int)((areawin
->height
- event
->y
) *
695 ((float)topobject
->bbox
.height
/ areawin
->height
) +
696 topobject
->bbox
.lowerleft
.y
- 0.5 * ((float)areawin
->height
/
698 areawin
->pcorner
.y
= (short)newy
;
699 drawvbar(bar
, NULL
, NULL
);
700 areawin
->pcorner
.y
= savey
;
702 if ((newpy
= (long)(newy
- savey
) * areawin
->vscale
) == 0)
705 areawin
->pany
= newpy
;
706 drawarea(NULL
, NULL
, NULL
);
709 /*------------------------------------------------------*/
710 /* Pan the screen to follow the cursor position */
711 /*------------------------------------------------------*/
713 void trackpan(int x
, int y
)
716 short savey
= areawin
->pcorner
.y
;
717 short savex
= areawin
->pcorner
.x
;
719 newpos
.x
= areawin
->origin
.x
- x
;
720 newpos
.y
= y
- areawin
->origin
.y
;
722 areawin
->pcorner
.x
+= newpos
.x
/ areawin
->vscale
;
723 areawin
->pcorner
.y
+= newpos
.y
/ areawin
->vscale
;
725 drawhbar(areawin
->scrollbarh
, NULL
, NULL
);
726 drawvbar(areawin
->scrollbarv
, NULL
, NULL
);
728 areawin
->panx
= -newpos
.x
;
729 areawin
->pany
= newpos
.y
;
731 drawarea(NULL
, NULL
, NULL
);
733 areawin
->pcorner
.x
= savex
;
734 areawin
->pcorner
.y
= savey
;
738 /*------------------------------------------------------*/
739 /* End the vertical scroll and refresh entire screen */
740 /*------------------------------------------------------*/
742 void endvbar(xcWidget bar
, caddr_t clientdata
, XButtonEvent
*event
)
745 short savey
= areawin
->pcorner
.y
;
750 newy
= (int)((areawin
->height
- event
->y
) *
751 ((float)topobject
->bbox
.height
/ areawin
->height
) +
752 topobject
->bbox
.lowerleft
.y
- 0.5 * ((float)areawin
->height
/
755 areawin
->pcorner
.y
= (short)newy
;
757 if ((newy
<< 1) != (long)((short)(newy
<< 1)) || checkbounds() == -1) {
758 areawin
->pcorner
.y
= savey
;
759 Wprintf("Reached boundary: cannot pan further");
764 areawin
->redraw_needed
= True
;
765 areawin
->lastbackground
= NULL
;
767 drawvbar(bar
, NULL
, NULL
);
768 drawarea(bar
, NULL
, NULL
);
771 /*--------------------------------------------------------------------*/
772 /* Zoom functions-- zoom box, zoom in, zoom out, and pan. */
773 /*--------------------------------------------------------------------*/
778 areawin
->lastbackground
= NULL
;
783 /*--------------------------------------------------------------------*/
785 void zoominbox(int x
, int y
)
788 float delxscale
, delyscale
;
789 XPoint savell
; /* ucenter, ncenter, (jdk)*/
790 UNUSED(x
); UNUSED(y
);
792 savescale
= areawin
->vscale
;
793 savell
.x
= areawin
->pcorner
.x
;
794 savell
.y
= areawin
->pcorner
.y
;
796 /* zoom-box function: corners are in areawin->save and areawin->origin */
797 /* select box has lower-left corner in .origin, upper-right in .save */
798 /* ignore if zoom box is size zero */
800 if (areawin
->save
.x
== areawin
->origin
.x
|| areawin
->save
.y
== areawin
->origin
.y
) {
801 Wprintf("Zoom box of size zero: Ignoring.");
802 eventmode
= NORMAL_MODE
;
806 /* determine whether x or y is limiting factor in zoom */
807 delxscale
= (areawin
->width
/ areawin
->vscale
) /
808 abs(areawin
->save
.x
- areawin
->origin
.x
);
809 delyscale
= (areawin
->height
/ areawin
->vscale
) /
810 abs(areawin
->save
.y
- areawin
->origin
.y
);
811 areawin
->vscale
*= min(delxscale
, delyscale
);
813 areawin
->pcorner
.x
= min(areawin
->origin
.x
, areawin
->save
.x
) -
814 (areawin
->width
/ areawin
->vscale
-
815 abs(areawin
->save
.x
- areawin
->origin
.x
)) / 2;
816 areawin
->pcorner
.y
= min(areawin
->origin
.y
, areawin
->save
.y
) -
817 (areawin
->height
/ areawin
->vscale
-
818 abs(areawin
->save
.y
- areawin
->origin
.y
)) / 2;
819 eventmode
= NORMAL_MODE
;
821 /* check for minimum scale */
823 if (checkbounds() == -1) {
824 areawin
->pcorner
.x
= savell
.x
;
825 areawin
->pcorner
.y
= savell
.y
;
826 areawin
->vscale
= savescale
;
827 Wprintf("At minimum scale: cannot scale further");
829 /* this is a rare case where an object gets out-of-bounds */
831 if (checkbounds() == -1) {
832 if (beeper
) XBell(dpy
, 100);
833 Wprintf("Unable to scale: Delete out-of-bounds object!");
840 /*--------------------------------------------------------------------*/
842 void zoomin(int x
, int y
)
845 XPoint ucenter
, ncenter
, savell
;
847 savescale
= areawin
->vscale
;
848 savell
.x
= areawin
->pcorner
.x
;
849 savell
.y
= areawin
->pcorner
.y
;
851 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ucenter
);
852 areawin
->vscale
*= areawin
->zoomfactor
;
853 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ncenter
);
854 areawin
->pcorner
.x
+= (ucenter
.x
- ncenter
.x
);
855 areawin
->pcorner
.y
+= (ucenter
.y
- ncenter
.y
);
857 /* check for minimum scale */
859 if (checkbounds() == -1) {
860 areawin
->pcorner
.x
= savell
.x
;
861 areawin
->pcorner
.y
= savell
.y
;
862 areawin
->vscale
= savescale
;
863 Wprintf("At minimum scale: cannot scale further");
865 /* this is a rare case where an object gets out-of-bounds */
867 if (checkbounds() == -1) {
868 if (beeper
) XBell(dpy
, 100);
869 Wprintf("Unable to scale: Delete out-of-bounds object!");
873 else if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
874 eventmode
== CATMOVE_MODE
)
880 /*--------------------------------------------------------------------*/
882 void zoominrefresh(int x
, int y
)
884 if (eventmode
== SELAREA_MODE
)
888 refresh(NULL
, NULL
, NULL
);
891 /*--------------------------------------------------------------------*/
893 void zoomoutbox(int x
, int y
)
896 float delxscale
, delyscale
, scalefac
;
897 XPoint savell
; /* ucenter, ncenter, (jdk)*/
899 UNUSED(x
); UNUSED(y
);
901 savescale
= areawin
->vscale
;
902 savell
.x
= areawin
->pcorner
.x
;
903 savell
.y
= areawin
->pcorner
.y
;
905 /* zoom-box function, analogous to that for zoom-in */
906 /* ignore if zoom box is size zero */
908 if (areawin
->save
.x
== areawin
->origin
.x
|| areawin
->save
.y
== areawin
->origin
.y
) {
909 Wprintf("Zoom box of size zero: Ignoring.");
910 eventmode
= NORMAL_MODE
;
914 /* determine whether x or y is limiting factor in zoom */
915 delxscale
= abs(areawin
->save
.x
- areawin
->origin
.x
) /
916 (areawin
->width
/ areawin
->vscale
);
917 delyscale
= abs(areawin
->save
.y
- areawin
->origin
.y
) /
918 (areawin
->height
/ areawin
->vscale
);
919 scalefac
= min(delxscale
, delyscale
);
920 areawin
->vscale
*= scalefac
;
922 /* compute lower-left corner of (reshaped) select box */
923 if (delxscale
< delyscale
) {
924 newll
.y
= min(areawin
->save
.y
, areawin
->origin
.y
);
925 newll
.x
= (areawin
->save
.x
+ areawin
->origin
.x
926 - (abs(areawin
->save
.y
- areawin
->origin
.y
) *
927 areawin
->width
/ areawin
->height
)) / 2;
930 newll
.x
= min(areawin
->save
.x
, areawin
->origin
.x
);
931 newll
.y
= (areawin
->save
.y
+ areawin
->origin
.y
932 - (abs(areawin
->save
.x
- areawin
->origin
.x
) *
933 areawin
->height
/ areawin
->width
)) / 2;
936 /* extrapolate to find new lower-left corner of screen */
937 newll
.x
= areawin
->pcorner
.x
- (int)((float)(newll
.x
-
938 areawin
->pcorner
.x
) / scalefac
);
939 newll
.y
= areawin
->pcorner
.y
- (int)((float)(newll
.y
-
940 areawin
->pcorner
.y
) / scalefac
);
942 eventmode
= NORMAL_MODE
;
943 areawin
->pcorner
.x
= (short)newll
.x
;
944 areawin
->pcorner
.y
= (short)newll
.y
;
946 if ((newll
.x
<< 1) != (long)(areawin
->pcorner
.x
<< 1) || (newll
.y
<< 1)
947 != (long)(areawin
->pcorner
.y
<< 1) || checkbounds() == -1) {
948 areawin
->vscale
= savescale
;
949 areawin
->pcorner
.x
= savell
.x
;
950 areawin
->pcorner
.y
= savell
.y
;
951 Wprintf("At maximum scale: cannot scale further.");
957 /*--------------------------------------------------------------------*/
959 void zoomout(int x
, int y
)
962 XPoint ucenter
, ncenter
, savell
;
965 savescale
= areawin
->vscale
;
966 savell
.x
= areawin
->pcorner
.x
;
967 savell
.y
= areawin
->pcorner
.y
;
969 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ucenter
);
970 areawin
->vscale
/= areawin
->zoomfactor
;
971 window_to_user(areawin
->width
/ 2, areawin
->height
/ 2, &ncenter
);
972 newll
.x
= (long)areawin
->pcorner
.x
+ (long)(ucenter
.x
- ncenter
.x
);
973 newll
.y
= (long)areawin
->pcorner
.y
+ (long)(ucenter
.y
- ncenter
.y
);
974 areawin
->pcorner
.x
= (short)newll
.x
;
975 areawin
->pcorner
.y
= (short)newll
.y
;
977 if ((newll
.x
<< 1) != (long)(areawin
->pcorner
.x
<< 1) || (newll
.y
<< 1)
978 != (long)(areawin
->pcorner
.y
<< 1) || checkbounds() == -1) {
979 areawin
->vscale
= savescale
;
980 areawin
->pcorner
.x
= savell
.x
;
981 areawin
->pcorner
.y
= savell
.y
;
982 Wprintf("At maximum scale: cannot scale further.");
985 else if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
986 eventmode
== CATMOVE_MODE
)
992 /*--------------------------------------------------------------------*/
994 void zoomoutrefresh(int x
, int y
)
996 if (eventmode
== SELAREA_MODE
)
1000 refresh(NULL
, NULL
, NULL
);
1003 /*--------------------------------------*/
1004 /* Call to XWarpPointer */
1005 /*--------------------------------------*/
1007 void warppointer(int x
, int y
)
1009 XWarpPointer(dpy
, None
, areawin
->window
, 0, 0, 0, 0, x
, y
);
1012 /*--------------------------------------------------------------*/
1013 /* ButtonPress handler during center pan */
1014 /* x and y are cursor coordinates. */
1015 /* If ptype is 1-4 (directional), then "value" is a fraction of */
1016 /* the screen to scroll. */
1017 /*--------------------------------------------------------------*/
1019 void panbutton(u_int ptype
, int x
, int y
, float value
)
1021 /* Window pwin; (jdk) */
1022 int xpos
, ypos
, newllx
, newlly
;
1023 XPoint savell
; /* , newpos; (jdk)*/
1024 Dimension hwidth
= areawin
->width
>> 1, hheight
= areawin
->height
>> 1;
1026 savell
.x
= areawin
->pcorner
.x
;
1027 savell
.y
= areawin
->pcorner
.y
;
1031 xpos
= hwidth
- (hwidth
* 2 * value
);
1035 xpos
= hwidth
+ (hwidth
* 2 * value
);
1040 ypos
= hheight
- (hheight
* 2 * value
);
1044 ypos
= hheight
+ (hheight
* 2 * value
);
1050 case 6: /* "pan follow" */
1051 if (eventmode
== PAN_MODE
)
1052 finish_op(XCF_Finish
, x
, y
);
1053 else if (eventmode
== NORMAL_MODE
) {
1054 eventmode
= PAN_MODE
;
1055 areawin
->save
.x
= x
;
1056 areawin
->save
.y
= y
;
1057 u2u_snap(&areawin
->save
);
1058 areawin
->origin
= areawin
->save
;
1060 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
1061 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
1063 xcAddEventHandler(areawin
->area
, PointerMotionMask
|
1064 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
1070 default: /* "pan here" */
1073 warppointer(hwidth
, hheight
);
1078 ypos
= hheight
- ypos
;
1080 newllx
= (int)areawin
->pcorner
.x
+ (int)((float)xpos
/ areawin
->vscale
);
1081 newlly
= (int)areawin
->pcorner
.y
+ (int)((float)ypos
/ areawin
->vscale
);
1083 areawin
->pcorner
.x
= (short) newllx
;
1084 areawin
->pcorner
.y
= (short) newlly
;
1086 if ((newllx
<< 1) != (long)(areawin
->pcorner
.x
<< 1) || (newlly
<< 1)
1087 != (long)(areawin
->pcorner
.y
<< 1) || checkbounds() == -1) {
1088 areawin
->pcorner
.x
= savell
.x
;
1089 areawin
->pcorner
.x
= savell
.y
;
1090 Wprintf("Reached bounds: cannot pan further.");
1093 else if (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1094 eventmode
== CATMOVE_MODE
)
1100 /*--------------------------------------------------------------*/
1102 void panrefresh(u_int ptype
, int x
, int y
, float value
)
1104 panbutton(ptype
, x
, y
, value
);
1105 refresh(NULL
, NULL
, NULL
);
1108 /*----------------------------------------------------------------*/
1109 /* Check for out-of-bounds before warping pointer, and pan window */
1111 /*----------------------------------------------------------------*/
1113 void checkwarp(XPoint
*userpt
)
1117 user_to_window(*userpt
, &wpoint
);
1119 if (wpoint
.x
< 0 || wpoint
.y
< 0 || wpoint
.x
> areawin
->width
||
1120 wpoint
.y
> areawin
->height
) {
1121 panrefresh(5, wpoint
.x
, wpoint
.y
, 0);
1122 wpoint
.x
= areawin
->width
>> 1;
1123 wpoint
.y
= areawin
->height
>> 1;
1124 /* snap(wpoint.x, wpoint.y, userpt); */
1126 warppointer(wpoint
.x
, wpoint
.y
);
1129 /*--------------------------------------------------------------*/
1130 /* Return a pointer to the element containing a reference point */
1131 /*--------------------------------------------------------------*/
1133 genericptr
getsubpart(pathptr editpath
, int *idx
)
1135 pointselect
*tmpptr
= NULL
;
1140 for (pgen
= editpath
->plist
; pgen
< editpath
->plist
+ editpath
->parts
; pgen
++) {
1141 switch (ELEMENTTYPE(*pgen
)) {
1143 if (TOPOLY(pgen
)->cycle
!= NULL
) {
1144 for (tmpptr
= TOPOLY(pgen
)->cycle
;; tmpptr
++) {
1145 if (tmpptr
->flags
& REFERENCE
) break;
1146 if (tmpptr
->flags
& LASTENTRY
) break;
1148 if (tmpptr
->flags
& REFERENCE
) return *pgen
;
1152 if (TOSPLINE(pgen
)->cycle
!= NULL
) {
1153 for (tmpptr
= TOSPLINE(pgen
)->cycle
;; tmpptr
++) {
1154 if (tmpptr
->flags
& REFERENCE
) break;
1155 if (tmpptr
->flags
& LASTENTRY
) break;
1157 if (tmpptr
->flags
& REFERENCE
) return *pgen
;
1166 /*--------------------------------------------------------------*/
1167 /* Return a pointer to the current reference point of an */
1168 /* edited element (polygon, spline, or path) */
1169 /*--------------------------------------------------------------*/
1171 pointselect
*getrefpoint(genericptr genptr
, XPoint
**refpt
)
1173 pointselect
*tmpptr
= NULL
;
1176 if (refpt
) *refpt
= NULL
;
1177 switch (genptr
->type
) {
1179 if (((polyptr
)genptr
)->cycle
!= NULL
) {
1180 for (tmpptr
= ((polyptr
)genptr
)->cycle
;; tmpptr
++) {
1181 if (tmpptr
->flags
& REFERENCE
) break;
1182 if (tmpptr
->flags
& LASTENTRY
) break;
1184 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= NULL
;
1185 else if (refpt
) *refpt
= ((polyptr
)genptr
)->points
+ tmpptr
->number
;
1189 if (((splineptr
)genptr
)->cycle
!= NULL
) {
1190 for (tmpptr
= ((splineptr
)genptr
)->cycle
;; tmpptr
++) {
1191 if (tmpptr
->flags
& REFERENCE
) break;
1192 if (tmpptr
->flags
& LASTENTRY
) break;
1194 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= NULL
;
1195 else if (refpt
) *refpt
= &((splineptr
)genptr
)->ctrl
[tmpptr
->number
];
1199 for (pgen
= ((pathptr
)genptr
)->plist
; pgen
< ((pathptr
)genptr
)->plist
+
1200 ((pathptr
)genptr
)->parts
; pgen
++) {
1201 if ((tmpptr
= getrefpoint(*pgen
, refpt
)) != NULL
)
1212 /*--------------------------------------------------------------*/
1213 /* Return next edit point on a polygon, arc, or spline. Do not */
1214 /* update the cycle of the element. */
1215 /*--------------------------------------------------------------*/
1217 int checkcycle(genericptr genptr
, short dir
)
1219 pointselect
*tmpptr
;
1220 short tmppt
, points
;
1223 switch (genptr
->type
) {
1225 if (((polyptr
)genptr
)->cycle
== NULL
)
1228 for (tmpptr
= ((polyptr
)genptr
)->cycle
;; tmpptr
++) {
1229 if (tmpptr
->flags
& REFERENCE
) break;
1230 if (tmpptr
->flags
& LASTENTRY
) break;
1232 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= ((polyptr
)genptr
)->cycle
;
1234 tmppt
= (tmpptr
== NULL
) ? -1 : tmpptr
->number
;
1235 points
= ((polyptr
)genptr
)->number
;
1238 if (((splineptr
)genptr
)->cycle
== NULL
)
1241 for (tmpptr
= ((splineptr
)genptr
)->cycle
;; tmpptr
++) {
1242 if (tmpptr
->flags
& REFERENCE
) break;
1243 if (tmpptr
->flags
& LASTENTRY
) break;
1245 if (!(tmpptr
->flags
& REFERENCE
)) tmpptr
= ((splineptr
)genptr
)->cycle
;
1247 tmppt
= (tmpptr
== NULL
) ? -1 : tmpptr
->number
;
1251 tmpptr
= ((arcptr
)genptr
)->cycle
;
1252 tmppt
= (tmpptr
== NULL
) ? -1 : tmpptr
->number
;
1256 for (pgen
= ((pathptr
)genptr
)->plist
; pgen
< ((pathptr
)genptr
)->plist
+
1257 ((pathptr
)genptr
)->parts
; pgen
++) {
1258 if ((tmppt
= checkcycle(*pgen
, dir
)) >= 0)
1266 if (tmppt
>= 0) { /* Ignore nonexistent cycles */
1268 if (tmppt
< 0) tmppt
+= points
;
1274 /*--------------------------------------------------------------*/
1275 /* Change to the next part of a path for editing */
1276 /* For now, |dir| is treated as 1 regardless of its value. */
1277 /*--------------------------------------------------------------*/
1279 void nextpathcycle(pathptr nextpath
, short dir
)
1281 genericptr ppart
= getsubpart(nextpath
, NULL
);
1285 splineptr thisspline
;
1287 short cycle
, newcycle
;
1289 /* Simple cases---don't need to switch elements */
1291 switch (ELEMENTTYPE(ppart
)) {
1293 thispoly
= (polyptr
)ppart
;
1294 cptr
= thispoly
->cycle
;
1295 if (cptr
== NULL
) return;
1296 curpt
= thispoly
->points
+ cptr
->number
;
1297 newcycle
= checkcycle(ppart
, dir
);
1298 advancecycle(&ppart
, newcycle
);
1299 if (cptr
->number
< thispoly
->number
&& cptr
->number
> 0) {
1300 checkwarp(thispoly
->points
+ cptr
->number
);
1301 removeothercycles(nextpath
, ppart
);
1302 updatepath(nextpath
);
1307 thisspline
= (splineptr
)ppart
;
1308 cptr
= ((splineptr
)ppart
)->cycle
;
1309 if (cptr
== NULL
) return;
1310 curpt
= &thisspline
->ctrl
[cptr
->number
];
1311 newcycle
= checkcycle(ppart
, dir
);
1312 advancecycle(&ppart
, newcycle
);
1313 if (cptr
->number
< 4 && cptr
->number
> 0) {
1314 checkwarp(&thisspline
->ctrl
[cptr
->number
]);
1315 removeothercycles(nextpath
, ppart
);
1316 updatepath(nextpath
);
1317 if (newcycle
== 1 || newcycle
== 2)
1318 addanticycle(nextpath
, thisspline
, newcycle
);
1324 /* Moving on to the next element. . . */
1326 /* If dir < 0, go to the penultimate cycle of the last part */
1327 /* If dir > 0, go to the second cycle of the next part */
1329 for (ggen
= nextpath
->plist
; (*ggen
!= ppart
) &&
1330 (ggen
< nextpath
->plist
+ nextpath
->parts
); ggen
++);
1332 if (ggen
== nextpath
->plist
+ nextpath
->parts
) return; /* shouldn't happen! */
1339 if (ggen
< nextpath
->plist
)
1340 ggen
= nextpath
->plist
+ nextpath
->parts
- 1;
1341 else if (ggen
== nextpath
->plist
+ nextpath
->parts
)
1342 ggen
= nextpath
->plist
;
1344 removecycle((genericptr
*)(&nextpath
));
1346 /* The next point to edit is the first point in the next segment */
1347 /* that is not at the same position as the one we were last editing. */
1349 switch (ELEMENTTYPE(*ggen
)) {
1351 thispoly
= TOPOLY(ggen
);
1352 cycle
= (dir
> 0) ? 0 : thispoly
->number
- 1;
1353 addcycle(ggen
, cycle
, 0);
1354 makerefcycle(thispoly
->cycle
, cycle
);
1355 if ((thispoly
->points
+ cycle
)->x
== curpt
->x
&&
1356 (thispoly
->points
+ cycle
)->y
== curpt
->y
) {
1357 newcycle
= checkcycle((genericptr
)thispoly
, 1);
1358 advancecycle(ggen
, newcycle
);
1361 checkwarp(thispoly
->points
+ cycle
);
1364 thisspline
= TOSPLINE(ggen
);
1365 cycle
= (dir
> 0) ? 0 : 3;
1366 addcycle(ggen
, cycle
, 0);
1367 makerefcycle(thisspline
->cycle
, cycle
);
1368 if (thisspline
->ctrl
[cycle
].x
== curpt
->x
&&
1369 thisspline
->ctrl
[cycle
].y
== curpt
->y
) {
1370 newcycle
= checkcycle((genericptr
)thisspline
, 1);
1371 advancecycle(ggen
, newcycle
);
1373 if (cycle
== 1 || cycle
== 2)
1374 addanticycle(nextpath
, thisspline
, cycle
);
1376 checkwarp(&(thisspline
->ctrl
[cycle
]));
1379 updatepath(nextpath
);
1382 /*--------------------------------------------------------------*/
1383 /* Change to next edit point on a polygon */
1384 /*--------------------------------------------------------------*/
1386 void nextpolycycle(polyptr
*nextpoly
, short dir
)
1390 newcycle
= checkcycle((genericptr
)(*nextpoly
), dir
);
1391 advancecycle((genericptr
*)nextpoly
, newcycle
);
1392 findconstrained(*nextpoly
);
1393 printeditbindings();
1395 newcycle
= (*nextpoly
)->cycle
->number
;
1396 checkwarp((*nextpoly
)->points
+ newcycle
);
1399 /*--------------------------------------------------------------*/
1400 /* Change to next edit cycle on a spline */
1401 /*--------------------------------------------------------------*/
1403 void nextsplinecycle(splineptr
*nextspline
, short dir
)
1406 newcycle
= checkcycle((genericptr
)(*nextspline
), dir
);
1407 advancecycle((genericptr
*)nextspline
, newcycle
);
1409 if (newcycle
== 1 || newcycle
== 2)
1410 Wprintf("Adjust control point");
1412 Wprintf("Adjust endpoint position");
1414 checkwarp(&(*nextspline
)->ctrl
[newcycle
]);
1417 /*--------------------------------------------------------------*/
1418 /* Warp pointer to the edit point on an arc. */
1419 /*--------------------------------------------------------------*/
1421 void warparccycle(arcptr nextarc
, short cycle
)
1428 curang
.x
= nextarc
->position
.x
+ abs(nextarc
->radius
);
1429 curang
.y
= nextarc
->position
.y
;
1430 if (abs(nextarc
->radius
) != nextarc
->yaxis
)
1431 Wprintf("Adjust ellipse size");
1433 Wprintf("Adjust arc radius");
1436 rad
= (double)(nextarc
->angle1
* RADFAC
);
1437 curang
.x
= nextarc
->position
.x
+ abs(nextarc
->radius
) * cos(rad
);
1438 curang
.y
= nextarc
->position
.y
+ nextarc
->yaxis
* sin(rad
);
1439 Wprintf("Adjust arc endpoint");
1442 rad
= (double)(nextarc
->angle2
* RADFAC
);
1443 curang
.x
= nextarc
->position
.x
+ abs(nextarc
->radius
) * cos(rad
);
1444 curang
.y
= nextarc
->position
.y
+ nextarc
->yaxis
* sin(rad
);
1445 Wprintf("Adjust arc endpoint");
1448 curang
.x
= nextarc
->position
.x
;
1449 curang
.y
= nextarc
->position
.y
+ nextarc
->yaxis
;
1450 Wprintf("Adjust ellipse minor axis");
1456 /*--------------------------------------------------------------*/
1457 /* Change to next edit cycle on an arc */
1458 /*--------------------------------------------------------------*/
1460 void nextarccycle(arcptr
*nextarc
, short dir
)
1464 newcycle
= checkcycle((genericptr
)(*nextarc
), dir
);
1465 advancecycle((genericptr
*)nextarc
, newcycle
);
1466 warparccycle(*nextarc
, newcycle
);
1469 /*------------------------------------------------------*/
1470 /* Get a numerical response from the keyboard (0-9) */
1471 /*------------------------------------------------------*/
1478 XKeyEvent
*keyevent
= (XKeyEvent
*)(&event
);
1482 XNextEvent(dpy
, &event
);
1483 if (event
.type
== KeyPress
) break;
1484 else xcDispatchEvent(&event
);
1486 XLookupString(keyevent
, _STR
, 150, &keypressed
, NULL
);
1487 if (keypressed
> XK_0
&& keypressed
<= XK_9
)
1488 return (short)(keypressed
- XK_1
);
1495 /*--------------------------*/
1496 /* Register a "press" event */
1497 /*--------------------------*/
1500 void makepress(ClientData clientdata
)
1502 void makepress(XtPointer clientdata
, xcIntervalId
*id
)
1505 int keywstate
= (int)((pointertype
)clientdata
);
1510 /* Button/Key was pressed long enough to make a "press", not a "tap" */
1512 areawin
->time_id
= 0;
1513 pressmode
= keywstate
;
1514 eventdispatch(keywstate
| HOLD_MASK
, areawin
->save
.x
, areawin
->save
.y
);
1517 /*------------------------------------------------------*/
1518 /* Handle button events as if they were keyboard events */
1519 /*------------------------------------------------------*/
1521 void buttonhandler(xcWidget w
, caddr_t clientdata
, XButtonEvent
*event
)
1523 XKeyEvent
*kevent
= (XKeyEvent
*)event
;
1525 if (event
->type
== ButtonPress
)
1526 kevent
->type
= KeyPress
;
1528 kevent
->type
= KeyRelease
;
1530 switch (event
->button
) {
1532 kevent
->state
|= Button1Mask
;
1535 kevent
->state
|= Button2Mask
;
1538 kevent
->state
|= Button3Mask
;
1541 kevent
->state
|= Button4Mask
;
1544 kevent
->state
|= Button5Mask
;
1547 keyhandler(w
, clientdata
, kevent
);
1550 /*--------------------------------------------------------------*/
1551 /* Edit operations specific to polygons (point manipulation) */
1552 /*--------------------------------------------------------------*/
1554 void poly_edit_op(int op
)
1556 genericptr keygen
= *(EDITPART
);
1561 if (IS_PATH(keygen
))
1562 keygen
= getsubpart((pathptr
)keygen
, NULL
);
1564 switch(ELEMENTTYPE(keygen
)) {
1566 lwire
= (polyptr
)keygen
;
1568 /* Remove a point from the polygon */
1569 if (op
== XCF_Edit_Delete
) {
1570 if (lwire
->number
< 3) return;
1571 if (lwire
->number
== 3 && !(lwire
->style
& UNCLOSED
))
1572 lwire
->style
|= UNCLOSED
;
1573 cycle
= checkcycle((genericptr
)lwire
, 0);
1575 for (lpoint
= lwire
->points
+ cycle
; lpoint
<
1576 lwire
->points
+ lwire
->number
; lpoint
++)
1577 *lpoint
= *(lpoint
+ 1);
1578 if (eventmode
== EPOLY_MODE
)
1579 poly_mode_draw(xcDRAW_EDIT
, TOPOLY(EDITPART
));
1581 path_mode_draw(xcDRAW_EDIT
, TOPATH(EDITPART
));
1582 nextpolycycle(&lwire
, -1);
1585 /* Add a point to the polygon */
1586 else if (op
== XCF_Edit_Insert
|| op
== XCF_Edit_Append
) {
1588 lwire
->points
= (XPoint
*)realloc(lwire
->points
, lwire
->number
1590 cycle
= checkcycle((genericptr
)lwire
, 0);
1591 for (lpoint
= lwire
->points
+ lwire
->number
- 1; lpoint
> lwire
->
1592 points
+ cycle
; lpoint
--)
1593 *lpoint
= *(lpoint
- 1);
1594 if (eventmode
== EPOLY_MODE
)
1595 poly_mode_draw(xcDRAW_EDIT
, TOPOLY(EDITPART
));
1597 path_mode_draw(xcDRAW_EDIT
, TOPATH(EDITPART
));
1598 if (op
== XCF_Edit_Append
)
1599 nextpolycycle(&lwire
, 1);
1602 /* Parameterize the position of a polygon point */
1603 else if (op
== XCF_Edit_Param
) {
1604 cycle
= checkcycle((genericptr
)lwire
, 0);
1605 makenumericalp(&keygen
, P_POSITION_X
, NULL
, cycle
);
1606 makenumericalp(&keygen
, P_POSITION_Y
, NULL
, cycle
);
1612 /*----------------------------------------------------------------------*/
1613 /* Handle attachment of edited elements to nearby elements */
1614 /*----------------------------------------------------------------------*/
1618 /* Conditions: One element is selected, key "A" is pressed. */
1619 /* Then there must exist a spline, polygon, arc, or label */
1622 if (areawin
->selects
<= 1) {
1625 if (areawin
->attachto
>= 0) {
1626 areawin
->attachto
= -1; /* default value---no attachments */
1627 Wprintf("Unconstrained moving");
1632 select_prev
= areawin
->selects
;
1633 refsel
= select_add_element(SPLINE
|ARC
|POLYGON
|LABEL
|OBJINST
);
1634 if ((refsel
!= NULL
) && (areawin
->selects
> select_prev
)) {
1636 /* transfer refsel over to attachto */
1638 areawin
->attachto
= *(refsel
+ areawin
->selects
- 1);
1640 if (areawin
->selects
== 0) freeselects();
1641 XTopSetForeground(SELTOCOLOR(refsel
));
1642 easydraw(areawin
->attachto
, DEFAULTCOLOR
);
1644 /* restore graphics state */
1645 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
1647 Wprintf("Constrained attach");
1649 /* Starting a new wire? */
1650 if (eventmode
== NORMAL_MODE
) {
1651 XPoint newpos
, userpt
;
1652 userpt
= UGetCursorPos();
1653 findattach(&newpos
, NULL
, &userpt
);
1655 eventmode
= WIRE_MODE
;
1656 areawin
->attachto
= -1;
1660 Wprintf("Nothing found to attach to");
1666 /*--------------------------------------------------------------*/
1667 /* This function returns TRUE if the indicated function is */
1668 /* compatible with the current eventmode; that is, whether */
1669 /* the function could ever be called from eventdispatch() */
1670 /* given the existing eventmode. */
1672 /* Note that this function has to be carefully written or the */
1673 /* function dispatch mechanism can put xcircuit into a bad */
1675 /*--------------------------------------------------------------*/
1677 Boolean
compatible_function(int function
)
1683 case XCF_Text_Left
: case XCF_Text_Right
:
1684 case XCF_Text_Home
: case XCF_Text_End
:
1685 case XCF_Text_Return
: case XCF_Text_Delete
:
1686 case XCF_Text_Delete_Param
:
1687 r
= (eventmode
== CATTEXT_MODE
|| eventmode
== TEXT_MODE
||
1688 eventmode
== ETEXT_MODE
) ?
1692 case XCF_Linebreak
: case XCF_Halfspace
:
1693 case XCF_Quarterspace
: case XCF_TabStop
:
1694 case XCF_TabForward
: case XCF_TabBackward
:
1695 case XCF_Superscript
: case XCF_Subscript
:
1696 case XCF_Normalscript
: case XCF_Underline
:
1697 case XCF_Overline
: case XCF_Font
:
1698 case XCF_Boldfont
: case XCF_Italicfont
:
1699 case XCF_Normalfont
: case XCF_ISO_Encoding
:
1700 case XCF_Special
: case XCF_Text_Split
:
1701 case XCF_Text_Up
: case XCF_Text_Down
:
1703 r
= (eventmode
== TEXT_MODE
|| eventmode
== ETEXT_MODE
) ?
1708 r
= (eventmode
== TEXT_MODE
|| eventmode
== ETEXT_MODE
||
1709 eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1710 eventmode
== NORMAL_MODE
) ?
1714 case XCF_Edit_Delete
: case XCF_Edit_Insert
: case XCF_Edit_Append
:
1715 case XCF_Edit_Param
:
1716 r
= (eventmode
== EPOLY_MODE
|| eventmode
== EPATH_MODE
) ?
1721 r
= (eventmode
== EPOLY_MODE
|| eventmode
== EPATH_MODE
||
1722 eventmode
== EINST_MODE
|| eventmode
== EARC_MODE
||
1723 eventmode
== ESPLINE_MODE
) ?
1728 r
= (eventmode
== EPOLY_MODE
|| eventmode
== EPATH_MODE
||
1729 eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1730 eventmode
== WIRE_MODE
|| eventmode
== NORMAL_MODE
) ?
1734 case XCF_Rotate
: case XCF_Flip_X
:
1736 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1737 eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
) ?
1741 case XCF_Snap
: case XCF_Swap
:
1742 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1743 eventmode
== NORMAL_MODE
) ?
1747 case XCF_Double_Snap
: case XCF_Halve_Snap
:
1749 r
= (eventmode
== CATALOG_MODE
|| eventmode
== CATTEXT_MODE
||
1750 eventmode
== ASSOC_MODE
|| eventmode
== CATMOVE_MODE
) ?
1754 case XCF_Library_Pop
:
1755 r
= (eventmode
== CATALOG_MODE
|| eventmode
== ASSOC_MODE
) ?
1759 case XCF_Library_Edit
: case XCF_Library_Delete
:
1760 case XCF_Library_Duplicate
: case XCF_Library_Hide
:
1761 case XCF_Library_Virtual
: case XCF_Library_Move
:
1762 case XCF_Library_Copy
:
1763 r
= (eventmode
== CATALOG_MODE
) ?
1767 case XCF_Library_Directory
:
1768 r
= (eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
||
1769 eventmode
== ASSOC_MODE
) ?
1773 case XCF_Next_Library
:
1774 r
= (eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
||
1775 eventmode
== ASSOC_MODE
|| eventmode
== CATMOVE_MODE
) ?
1779 case XCF_Select
: case XCF_Exit
:
1780 r
= (eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
) ?
1785 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1786 eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
||
1787 eventmode
== ASSOC_MODE
) ?
1792 r
= (eventmode
== MOVE_MODE
|| eventmode
== COPY_MODE
||
1793 eventmode
== CATALOG_MODE
|| eventmode
== NORMAL_MODE
) ?
1797 case XCF_SelectBox
: case XCF_Wire
:
1798 case XCF_Delete
: case XCF_Rescale
:
1799 case XCF_Pin_Label
: case XCF_Pin_Global
:
1800 case XCF_Info_Label
: case XCF_Connectivity
:
1801 case XCF_Box
: case XCF_Arc
:
1802 case XCF_Text
: case XCF_Exchange
:
1803 case XCF_Copy
: case XCF_Virtual
:
1804 case XCF_Page_Directory
: case XCF_Join
:
1805 case XCF_Unjoin
: case XCF_Spline
:
1806 case XCF_Edit
: case XCF_Undo
:
1807 case XCF_Redo
: case XCF_Select_Save
:
1808 case XCF_Unselect
: case XCF_Dashed
:
1809 case XCF_Dotted
: case XCF_Solid
:
1810 case XCF_Dot
: case XCF_Write
:
1811 case XCF_Netlist
: case XCF_Sim
:
1812 case XCF_SPICE
: case XCF_SPICEflat
:
1813 case XCF_PCB
: case XCF_Move
:
1814 r
= (eventmode
== NORMAL_MODE
) ?
1818 case XCF_Nothing
: case XCF_View
:
1819 case XCF_Redraw
: case XCF_Zoom_In
:
1820 case XCF_Zoom_Out
: case XCF_Pan
:
1821 case XCF_Page
: case XCF_Help
:
1822 case XCF_Cancel
: case XCF_Prompt
:
1826 case XCF_Continue_Copy
:
1827 case XCF_Finish_Copy
:
1828 r
= (eventmode
== COPY_MODE
) ?
1832 case XCF_Continue_Element
:
1833 case XCF_Finish_Element
:
1834 r
= (eventmode
== WIRE_MODE
|| eventmode
== BOX_MODE
||
1835 eventmode
== ARC_MODE
|| eventmode
== SPLINE_MODE
||
1836 eventmode
== EPATH_MODE
|| eventmode
== EPOLY_MODE
||
1837 eventmode
== EARC_MODE
|| eventmode
== ESPLINE_MODE
||
1838 eventmode
== MOVE_MODE
|| eventmode
== CATMOVE_MODE
||
1839 eventmode
== EINST_MODE
|| eventmode
== RESCALE_MODE
) ?
1843 case XCF_Cancel_Last
:
1844 r
= (eventmode
== WIRE_MODE
|| eventmode
== ARC_MODE
||
1845 eventmode
== SPLINE_MODE
|| eventmode
== EPATH_MODE
||
1846 eventmode
== EPOLY_MODE
|| eventmode
== EARC_MODE
||
1847 eventmode
== EINST_MODE
|| eventmode
== ESPLINE_MODE
) ?
1852 r
= (eventmode
== FONTCAT_MODE
|| eventmode
== EFONTCAT_MODE
||
1853 eventmode
== ASSOC_MODE
|| eventmode
== CATALOG_MODE
||
1854 eventmode
== CATTEXT_MODE
|| eventmode
== MOVE_MODE
||
1855 eventmode
== RESCALE_MODE
|| eventmode
== SELAREA_MODE
||
1856 eventmode
== PAN_MODE
|| eventmode
== NORMAL_MODE
||
1857 eventmode
== CATMOVE_MODE
) ?
1861 default: /* Function type was not handled. */
1862 funcname
= func_to_string(function
);
1863 if (funcname
== NULL
)
1864 Wprintf("Error: \"%s\" is not a known function!");
1866 Wprintf("Error: Function type \"%s\" (%d) not handled by "
1867 "compatible_function()", func_to_string(function
),
1874 /*----------------------------------------------------------------------*/
1875 /* Main event dispatch routine. Call one of the known routines based */
1876 /* on the key binding. Some handling is done by secondary dispatch */
1877 /* routines in other files; when this is done, the key binding is */
1878 /* determined here and the bound operation type passed to the secondary */
1879 /* dispatch routine. */
1881 /* Return value: 0 if event was handled, -1 if not. */
1882 /*----------------------------------------------------------------------*/
1884 int eventdispatch(int keywstate
, int x
, int y
)
1886 short value
; /* For return values from boundfunction() */
1887 int function
; /* What function should be invoked */
1888 int handled
= -1; /* event was handled */
1890 /* Invalid key state returned from getkeysignature(); usually this */
1891 /* means a modifier key pressed by itself. */
1893 if (keywstate
== -1) return -1;
1894 function
= boundfunction(areawin
->area
, keywstate
, &value
);
1896 /* Check for ASCII or ISO-Latin1-9 characters in keywstate while in */
1897 /* a text-entry state. Only the function XCF_Special is allowed in */
1898 /* text-entry mode, because XCF_Special can be used to enter the */
1899 /* character bound to the XCF_Special function. */
1901 if (keywstate
>= 32 && keywstate
< 256) {
1902 if (eventmode
== CATTEXT_MODE
|| eventmode
== TEXT_MODE
||
1903 eventmode
== ETEXT_MODE
) {
1904 if (function
!= XCF_Special
)
1905 handled
= labeltext(keywstate
, NULL
);
1906 else if (eventmode
!= CATTEXT_MODE
) {
1907 labelptr elabel
= TOLABEL(EDITPART
);
1908 if (elabel
->anchor
& LATEXLABEL
)
1909 handled
= labeltext(keywstate
, NULL
);
1914 if (handled
== -1) {
1916 handled
= functiondispatch(function
, value
, x
, y
);
1918 char *keystring
= key_to_string(keywstate
);
1920 if (python_key_command(keywstate
) < 0)
1922 Wprintf("Key \'%s\' is not bound to a macro", keystring
);
1927 if (areawin
->redraw_needed
)
1928 drawarea(NULL
, NULL
, NULL
);
1933 /*----------------------------------------------------------------------*/
1934 /* Dispatch actions by function number. Note that the structure of */
1935 /* this function is closely tied to the routine compatible_function(). */
1936 /*----------------------------------------------------------------------*/
1938 int functiondispatch(int function
, short value
, int x
, int y
)
1942 switch (eventmode
) {
1945 snap(x
, y
, &areawin
->save
);
1948 window_to_user(x
, y
, &areawin
->save
);
1956 if (value
< 0 || value
> xobjs
.pages
)
1957 Wprintf("Page %d out of range.", (int)value
);
1964 case XCF_Superscript
:
1965 labeltext(SUPERSCRIPT
, (char *)1);
1968 labeltext(SUBSCRIPT
, (char *)1);
1970 case XCF_Normalscript
:
1971 labeltext(NORMALSCRIPT
, (char *)1);
1974 setfont(NULL
, 1000, NULL
);
1977 fontstyle(NULL
, 1, NULL
);
1979 case XCF_Italicfont
:
1980 fontstyle(NULL
, 2, NULL
);
1982 case XCF_Normalfont
:
1983 fontstyle(NULL
, 0, NULL
);
1986 labeltext(UNDERLINE
, (char *)1);
1989 labeltext(OVERLINE
, (char *)1);
1991 case XCF_ISO_Encoding
:
1992 fontencoding(NULL
, 2, NULL
);
1995 labeltext(HALFSPACE
, (char *)1);
1997 case XCF_Quarterspace
:
1998 labeltext(QTRSPACE
, (char *)1);
2001 result
= dospecial();
2009 labeltext(TABSTOP
, (char *)1);
2011 case XCF_TabForward
:
2012 labeltext(TABFORWARD
, (char *)1);
2014 case XCF_TabBackward
:
2015 labeltext(TABBACKWARD
, (char *)1);
2017 case XCF_Text_Return
:
2018 labeltext(TEXT_RETURN
, (char *)1);
2020 case XCF_Text_Delete
:
2021 labeltext(TEXT_DELETE
, (char *)1);
2023 case XCF_Text_Delete_Param
:
2024 labeltext(TEXT_DEL_PARAM
, (char *)1);
2026 case XCF_Text_Right
:
2027 labeltext(TEXT_RIGHT
, (char *)1);
2030 labeltext(TEXT_LEFT
, (char *)1);
2033 labeltext(TEXT_UP
, (char *)1);
2036 labeltext(TEXT_DOWN
, (char *)1);
2038 case XCF_Text_Split
:
2039 labeltext(TEXT_SPLIT
, (char *)1);
2042 labeltext(TEXT_HOME
, (char *)1);
2045 labeltext(TEXT_END
, (char *)1);
2048 labeltext(RETURN
, (char *)1);
2050 case XCF_Edit_Param
:
2051 case XCF_Edit_Delete
:
2052 case XCF_Edit_Insert
:
2053 case XCF_Edit_Append
:
2054 poly_edit_op(function
);
2057 path_op(*(EDITPART
), XCF_Continue_Element
, x
, y
);
2062 case XCF_Next_Library
:
2065 case XCF_Library_Directory
:
2066 startcatalog(NULL
, LIBLIB
, NULL
);
2068 case XCF_Library_Edit
:
2069 window_to_user(x
, y
, &areawin
->save
);
2071 select_element(LABEL
);
2072 if (areawin
->selects
== 1)
2075 case XCF_Library_Delete
:
2076 catalog_op(XCF_Select
, x
, y
);
2079 case XCF_Library_Duplicate
:
2080 catalog_op(XCF_Select
, x
, y
);
2083 case XCF_Library_Hide
:
2084 catalog_op(XCF_Select
, x
, y
);
2087 case XCF_Library_Virtual
:
2088 catalog_op(XCF_Select
, x
, y
);
2091 case XCF_Page_Directory
:
2092 startcatalog(NULL
, PAGELIB
, NULL
);
2094 case XCF_Library_Copy
:
2095 case XCF_Library_Pop
:
2096 catalog_op(function
, x
, y
);
2102 starthelp(NULL
, NULL
, NULL
);
2105 areawin
->redraw_needed
= True
;
2108 zoomview(NULL
, NULL
, NULL
);
2111 zoominrefresh(x
, y
);
2114 zoomoutrefresh(x
, y
);
2117 panrefresh(value
, x
, y
, 0.3);
2119 case XCF_Double_Snap
:
2122 case XCF_Halve_Snap
:
2127 Tcl_Eval(xcinterp
, "xcircuit::promptsavepage");
2129 outputpopup(NULL
, NULL
, NULL
);
2133 elementrotate(value
, &areawin
->save
);
2136 elementflip(&areawin
->save
);
2139 elementvflip(&areawin
->save
);
2145 if (areawin
->snapto
) {
2146 areawin
->snapto
= False
;
2147 Wprintf("Snap-to off");
2150 areawin
->snapto
= True
;
2151 Wprintf("Snap-to on");
2155 if (eventmode
== CATALOG_MODE
|| eventmode
== ASSOC_MODE
) {
2156 eventmode
= NORMAL_MODE
;
2160 popobject(NULL
, 0, NULL
);
2163 if (eventmode
== CATALOG_MODE
) {
2164 /* Don't allow push from library directory */
2165 if ((areawin
->topinstance
!= xobjs
.libtop
[LIBLIB
])
2166 && (areawin
->topinstance
!= xobjs
.libtop
[PAGELIB
])) {
2167 window_to_user(x
, y
, &areawin
->save
);
2168 eventmode
= NORMAL_MODE
;
2179 if (eventmode
== CATALOG_MODE
)
2180 catalog_op(function
, x
, y
);
2182 select_add_element(ALL_TYPES
);
2191 eventmode
= TEXT_MODE
;
2192 textbutton(NORMAL
, x
, y
);
2197 case XCF_Library_Move
:
2198 /* Don't allow from library directory. Then fall through to XCF_Move */
2199 if (areawin
->topinstance
== xobjs
.libtop
[LIBLIB
]) break;
2201 if (areawin
->selects
== 0) {
2202 was_preselected
= FALSE
;
2203 if (eventmode
== CATALOG_MODE
)
2204 catalog_op(XCF_Select
, x
, y
);
2206 select_element(ALL_TYPES
);
2208 else was_preselected
= TRUE
;
2210 if (areawin
->selects
> 0) {
2211 eventmode
= (eventmode
== CATALOG_MODE
) ? CATMOVE_MODE
: MOVE_MODE
;
2212 u2u_snap(&areawin
->save
);
2213 areawin
->origin
= areawin
->save
;
2215 select_connected_pins();
2216 XDefineCursor(dpy
, areawin
->window
, ARROW
);
2217 move_mode_draw(xcDRAW_INIT
, NULL
);
2219 Tk_CreateEventHandler(areawin
->area
, ButtonMotionMask
|
2220 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
,
2243 case XCF_Select_Save
:
2245 Tcl_Eval(xcinterp
, "xcircuit::promptmakeobject");
2247 selectsave(NULL
, NULL
, NULL
);
2251 select_add_element(-ALL_TYPES
);
2254 setelementstyle(NULL
, DASHED
, NOBORDER
| DOTTED
| DASHED
);
2257 setelementstyle(NULL
, DOTTED
, NOBORDER
| DOTTED
| DASHED
);
2260 setelementstyle(NULL
, NORMAL
, NOBORDER
| DOTTED
| DASHED
);
2266 snap(x
, y
, &areawin
->save
);
2267 drawdot(areawin
->save
.x
, areawin
->save
.y
);
2268 areawin
->redraw_needed
= True
;
2269 drawarea(NULL
, NULL
, NULL
);
2272 u2u_snap(&areawin
->save
);
2273 startwire(&areawin
->save
);
2274 eventmode
= WIRE_MODE
;
2277 DoNothing(NULL
, NULL
, NULL
);
2280 quitcheck(areawin
->area
, NULL
, NULL
);
2283 callwritenet(NULL
, 0, NULL
);
2286 swapschem(0, -1, NULL
);
2289 eventmode
= TEXT_MODE
;
2290 textbutton(LOCAL
, x
, y
);
2292 case XCF_Pin_Global
:
2293 eventmode
= TEXT_MODE
;
2294 textbutton(GLOBAL
, x
, y
);
2296 case XCF_Info_Label
:
2297 eventmode
= TEXT_MODE
;
2298 textbutton(INFO
, x
, y
);
2301 if (checkselect(LABEL
| OBJINST
| GRAPHIC
) == TRUE
) {
2302 eventmode
= RESCALE_MODE
;
2303 rescale_mode_draw(xcDRAW_INIT
, NULL
);
2305 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
2306 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
2308 xcAddEventHandler(areawin
->area
, PointerMotionMask
|
2309 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
2317 case XCF_Connectivity
:
2318 connectivity(NULL
, NULL
, NULL
);
2321 case XCF_Continue_Copy
:
2322 case XCF_Finish_Copy
:
2323 copy_op(function
, x
, y
);
2325 case XCF_Continue_Element
:
2326 if (eventmode
== CATMOVE_MODE
|| eventmode
== MOVE_MODE
||
2327 eventmode
== RESCALE_MODE
)
2328 finish_op(XCF_Finish
, x
, y
);
2330 continue_op(function
, x
, y
);
2332 case XCF_Finish_Element
:
2333 case XCF_Cancel_Last
:
2335 finish_op(function
, x
, y
);
2338 if (eventmode
== CATALOG_MODE
|| eventmode
== ASSOC_MODE
)
2339 catalog_op(XCF_Library_Pop
, x
, y
);
2341 finish_op(function
, x
, y
);
2344 writenet(topobject
, "flatsim", "sim");
2347 writenet(topobject
, "spice", "spc");
2350 writenet(topobject
, "pcb", "pcbnet");
2353 writenet(topobject
, "flatspice", "fspc");
2356 Wprintf("Action not handled");
2359 case XCF_ChangeStyle
:
2360 Wprintf("Action not handled");
2365 /* Ensure that we do not get stuck in suspend mode */
2366 /* by removing the suspend state whenever a key is */
2369 if (xobjs
.suspend
== 1) {
2371 refresh(NULL
, NULL
, NULL
);
2373 else if (xobjs
.suspend
!= 2)
2379 /* forward declaration */
2380 extern int utf8_reverse_lookup(char *);
2382 /*------------------------------------------------------*/
2383 /* Get a canonical signature for a button/key event */
2384 /*------------------------------------------------------*/
2386 int getkeysignature(XKeyEvent
*event
)
2389 int keywstate
; /* KeySym with prepended state information */
2391 int utf8enc
; /* 8-bit value bound to UTF-8 encoding */
2395 static XIM xim
= NULL
;
2396 static XIC xic
= NULL
;
2399 if (event
->keycode
== 0 && event
->state
== 0)
2402 /* XLookupString() will fail if the display is not valid */
2403 if (dpy
== NULL
) return -1;
2405 XLookupString(event
, _STR
, 150, &keypressed
, NULL
);
2407 /* Ignore Shift, Control, Caps Lock, and Meta (Alt) keys */
2408 /* when pressed alone. */
2410 if (keypressed
== XK_Control_L
|| keypressed
== XK_Control_R
||
2411 keypressed
== XK_Alt_L
|| keypressed
== XK_Alt_R
||
2412 keypressed
== XK_Caps_Lock
|| keypressed
== XK_Shift_L
||
2413 keypressed
== XK_Shift_R
)
2416 /* Only keep key state information pertaining to Shift, Caps Lock, */
2417 /* Control, and Alt (Meta) */
2419 keywstate
= (keypressed
& 0xffff);
2421 /* Convert codes outside the character (0 - 255) range but within */
2422 /* the ISO-Latin1,...,9 encoding scheme (256-5120). X11 has unique */
2423 /* keysyms for each character, but the ISO-Latin encodings define */
2424 /* mappings to the 8-bit (256) character set. */
2426 if (keywstate
>= 256 && keywstate
< 5120)
2427 keywstate
= XKeysymToKeycode(dpy
, (KeySym
)keywstate
);
2429 if (event
->keycode
!= 0) { /* Only for actual key events */
2431 /* Get keyboard input method */
2433 xim
= XOpenIM(dpy
, 0, 0, 0);
2434 xic
= XCreateIC(xim
,
2435 XNInputStyle
, XIMPreeditNothing
| XIMStatusNothing
,
2436 XNClientWindow
, areawin
->window
,
2437 XNFocusWindow
, areawin
->window
,
2442 /* Do a UTF-8 code lookup */
2443 Xutf8LookupString(xic
, event
, buffer
, 15, &keysym
, &status
);
2444 /* Convert a UTF-8 code to a known encoding */
2445 utf8enc
= utf8_reverse_lookup(buffer
);
2446 if ((utf8enc
!= -1) && (utf8enc
!= (keywstate
& 0xff))) keywstate
= utf8enc
;
2449 /* ASCII values already come upper/lowercase; we only want to register */
2450 /* a Shift key if it's a non-ASCII key or another modifier is in effect */
2452 keywstate
|= (((LockMask
| ControlMask
| Mod1Mask
) & event
->state
) << 16);
2453 if (keywstate
> 255) keywstate
|= ((ShiftMask
& event
->state
) << 16);
2455 /* Treat button events and key events in the same way by setting */
2456 /* a key state for buttons */
2458 if (keypressed
== 0)
2459 keywstate
|= (((Button1Mask
| Button2Mask
| Button3Mask
| Button4Mask
|
2460 Button5Mask
| ShiftMask
)
2461 & event
->state
) << 16);
2466 /*------------------------*/
2467 /* Handle keyboard inputs */
2468 /*------------------------*/
2470 void keyhandler(xcWidget w
, caddr_t clientdata
, XKeyEvent
*event
)
2472 int keywstate
; /* KeySym with prepended state information */
2474 UNUSED(w
); UNUSED(clientdata
);
2477 if (popups
> 0) return;
2479 if (popups
> 0 && help_up
== 0) return;
2482 if ((event
->type
== KeyRelease
) || (event
->type
== ButtonRelease
)) {
2484 /* Register a "tap" event if a key or button was released */
2485 /* while a timeout event is pending. */
2487 if (areawin
->time_id
!= 0) {
2488 xcRemoveTimeOut(areawin
->time_id
);
2489 areawin
->time_id
= 0;
2490 keywstate
= getkeysignature(event
);
2491 eventdispatch(keywstate
, areawin
->save
.x
, areawin
->save
.y
);
2494 keywstate
= getkeysignature(event
);
2495 if ((pressmode
!= 0) && (keywstate
== pressmode
)) {
2496 /* Events that require hold & drag (namely, MOVE_MODE) */
2497 /* must be resolved here. Call finish_op() to ensure */
2498 /* that we restore xcircuit to a state of sanity. */
2500 finish_op(XCF_Finish
, event
->x
, event
->y
);
2502 if (areawin
->redraw_needed
)
2503 drawarea(NULL
, NULL
, NULL
);
2505 return; /* Ignore all other release events */
2509 /* Check if any bindings match key/button "hold". If so, then start */
2510 /* the timer and wait for key release or timeout. */
2513 keywstate
= getkeysignature(event
);
2514 if ((keywstate
!= -1) && (xobjs
.hold
== TRUE
)) {
2516 /* Establish whether a HOLD modifier binding would apply in */
2517 /* the current eventmode. If so, set the HOLD timer. */
2519 func
= boundfunction(areawin
->area
, keywstate
| HOLD_MASK
, NULL
);
2521 areawin
->save
.x
= event
->x
;
2522 areawin
->save
.y
= event
->y
;
2523 areawin
->time_id
= xcAddTimeOut(app
, PRESSTIME
,
2524 makepress
, (ClientData
)((pointertype
)keywstate
));
2529 eventdispatch(keywstate
, event
->x
, event
->y
);
2533 /*--------------------------------*/
2534 /* Set snap spacing from keyboard */
2535 /*--------------------------------*/
2537 void setsnap(short direction
)
2539 float oldsnap
= xobjs
.pagelist
[areawin
->page
]->snapspace
;
2542 if (direction
> 0) xobjs
.pagelist
[areawin
->page
]->snapspace
*= 2;
2545 xobjs
.pagelist
[areawin
->page
]->snapspace
/= 2;
2547 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2548 Wprintf("Snap space at minimum value of %s", buffer
);
2551 if (xobjs
.pagelist
[areawin
->page
]->snapspace
!= oldsnap
) {
2552 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2553 Wprintf("Snap spacing set to %s", buffer
);
2554 areawin
->redraw_needed
= True
;
2555 drawarea(NULL
, NULL
, NULL
);
2559 /*-----------------------------------------*/
2560 /* Reposition an object onto the snap grid */
2561 /*-----------------------------------------*/
2566 Boolean preselected
;
2568 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
2569 if (!checkselect(ALL_TYPES
)) return;
2570 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
2571 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
2572 + areawin
->selects
; selectobj
++) {
2573 easydraw(*selectobj
, DOFORALL
);
2574 switch(SELECTTYPE(selectobj
)) {
2576 objinstptr snapobj
= SELTOOBJINST(selectobj
);
2578 u2u_snap(&snapobj
->position
);
2581 graphicptr snapg
= SELTOGRAPHIC(selectobj
);
2583 u2u_snap(&snapg
->position
);
2586 labelptr snaplabel
= SELTOLABEL(selectobj
);
2588 u2u_snap(&snaplabel
->position
);
2591 polyptr snappoly
= SELTOPOLY(selectobj
);
2592 pointlist snappoint
;
2594 for (snappoint
= snappoly
->points
; snappoint
< snappoly
->points
+
2595 snappoly
->number
; snappoint
++)
2596 u2u_snap(snappoint
);
2599 arcptr snaparc
= SELTOARC(selectobj
);
2601 u2u_snap(&snaparc
->position
);
2602 if (areawin
->snapto
) {
2603 snaparc
->radius
= (snaparc
->radius
/
2604 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2605 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2606 snaparc
->yaxis
= (snaparc
->yaxis
/
2607 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2608 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2613 splineptr snapspline
= SELTOSPLINE(selectobj
);
2616 for (i
= 0; i
< 4; i
++)
2617 u2u_snap(&snapspline
->ctrl
[i
]);
2618 calcspline(snapspline
);
2621 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
2622 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
2623 easydraw(*selectobj
, DOFORALL
);
2626 select_invalidate_netlist();
2627 if (eventmode
== NORMAL_MODE
)
2632 /*----------------------------------------------*/
2633 /* Routines to print the cursor position */
2634 /*----------------------------------------------*/
2636 /*----------------------------------------------*/
2637 /* fast integer power-of-10 routine */
2638 /*----------------------------------------------*/
2646 case 0: return 1; break;
2647 case 1: return 10; break;
2648 case 2: return 100; break;
2649 case 3: return 1000; break;
2652 for (i
= 1; i
< a
+ 1; i
++) istr
[i
] = '0';
2659 /*--------------------------------------------------*/
2660 /* find greatest common factor between two integers */
2661 /*--------------------------------------------------*/
2663 int calcgcf(int a
, int b
)
2667 if ((mod
= a
% b
) == 0) return (b
);
2668 else return (calcgcf(b
, mod
));
2671 /*--------------------------------------------------------------*/
2672 /* generate a fraction from a float, if possible */
2673 /* fraction returned as a string (must be allocated beforehand) */
2674 /*--------------------------------------------------------------*/
2676 void fraccalc(float xyval
, char *fstr
)
2679 int ip
, mant
, divisor
, denom
, numer
, rpart
;
2681 char num
[10], *nptr
= &num
[2], *sptr
;
2684 fp
= fabs(xyval
- ip
);
2686 /* write fractional part and grab mantissa as integer */
2688 sprintf(num
, "%1.7f", fp
);
2689 num
[8] = '\0'; /* no rounding up! */
2690 sscanf(nptr
, "%d", &mant
);
2692 if (mant
!= 0) { /* search for repeating substrings */
2693 for (i
= 1; i
<= 3; i
++) {
2696 while ((sptr
= nptr
- rept
* i
) >= &num
[2]) {
2697 for (t
= 0; t
< i
; t
++)
2698 if (*(sptr
+ t
) != *(nptr
+ t
)) break;
2702 if (rept
> 1) break;
2705 sscanf(nptr
, "%d", &rpart
); /* rpart is repeating part of mantissa */
2706 if (i
> 3 || rpart
== 0) { /* no repeat */
2707 divisor
= calcgcf(1000000, mant
);
2708 denom
= 1000000 / divisor
;
2714 sscanf(&num
[2], "%d", &z
);
2716 mant
= z
* p
+ rpart
;
2717 fd
= ipow10(nptr
- &num
[2]) * p
;
2719 divisor
= calcgcf(fd
, mant
);
2720 denom
= fd
/ divisor
;
2722 numer
= mant
/ divisor
;
2724 sprintf(fstr
, "%5.3f", xyval
);
2726 sprintf(fstr
, "%hd/%hd", (xyval
> 0) ? numer
: -numer
, denom
);
2728 sprintf(fstr
, "%hd %hd/%hd", ip
, numer
, denom
);
2730 else sprintf(fstr
, "%hd", ip
);
2733 /*------------------------------------------------------------------------------*/
2734 /* Print the position of the cursor in the upper right-hand message window */
2735 /*------------------------------------------------------------------------------*/
2737 void printpos(short xval
, short yval
)
2740 float oscale
, iscale
= (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
/
2741 (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
;
2744 XPoint
*tpoint
, *npoint
;
2748 /* For polygons, print the length (last line of a wire or polygon) or */
2749 /* length and width (box only) */
2751 if (eventmode
== BOX_MODE
|| eventmode
== EPOLY_MODE
|| eventmode
== WIRE_MODE
) {
2752 polyptr lwire
= (eventmode
== BOX_MODE
) ? TOPOLY(ENDPART
) : TOPOLY(EDITPART
);
2753 if ((eventmode
== EPOLY_MODE
) && (lwire
->number
> 2)) {
2754 /* sanity check on edit cycle */
2755 cycle
= (lwire
->cycle
) ? lwire
->cycle
->number
: -1;
2756 if (cycle
< 0 || cycle
>= lwire
->number
) {
2757 advancecycle((genericptr
*)(&lwire
), 0);
2760 tpoint
= lwire
->points
+ cycle
;
2761 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, 1);
2762 llen
= wirelength(tpoint
, npoint
);
2763 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, -1);
2764 lwid
= wirelength(tpoint
, npoint
);
2766 if (lwire
->style
& UNCLOSED
) { /* unclosed polys */
2769 else if (cycle
== lwire
->number
- 1) {
2774 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2780 else if (eventmode
== BOX_MODE
) {
2781 tpoint
= lwire
->points
;
2782 npoint
= lwire
->points
+ 1;
2783 llen
= wirelength(tpoint
, npoint
);
2784 npoint
= lwire
->points
+ 3;
2785 lwid
= wirelength(tpoint
, npoint
);
2786 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2794 tpoint
= lwire
->points
+ lwire
->number
- 1;
2795 llen
= wirelength(tpoint
- 1, tpoint
);
2799 else if (eventmode
== ARC_MODE
|| eventmode
== EARC_MODE
) {
2800 arcptr larc
= (eventmode
== ARC_MODE
) ? TOARC(ENDPART
) : TOARC(EDITPART
);
2801 llen
= larc
->radius
;
2802 if (abs(larc
->radius
) != larc
->yaxis
) {
2810 switch (xobjs
.pagelist
[areawin
->page
]->coordstyle
) {
2812 sprintf(_STR
, "%g, %g", xval
* iscale
, yval
* iscale
);
2813 sptr
= _STR
+ strlen(_STR
);
2816 sprintf(sptr
, " (%g x %g)", llen
* iscale
, lwid
* iscale
);
2818 sprintf(sptr
, " (length %g)", llen
* iscale
);
2822 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2823 f1
= ((float)(xval
) * iscale
* oscale
) / 72.0;
2824 f2
= ((float)(yval
) * iscale
* oscale
) / 72.0;
2825 sprintf(_STR
, "%5.3f, %5.3f in", f1
, f2
);
2826 sptr
= _STR
+ strlen(_STR
);
2828 f1
= ((float)(llen
) * iscale
* oscale
) / 72.0;
2830 f2
= ((float)(lwid
) * iscale
* oscale
) / 72.0;
2831 sprintf(sptr
, " (%5.3f x %5.3f in)", f1
, f2
);
2834 sprintf(sptr
, " (length %5.3f in)", f1
);
2838 char fstr1
[30], fstr2
[30];
2840 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2841 fraccalc((((float)(xval
) * iscale
* oscale
) / 72.0), fstr1
);
2842 fraccalc((((float)(yval
) * iscale
* oscale
) / 72.0), fstr2
);
2843 sprintf(_STR
, "%s, %s in", fstr1
, fstr2
);
2844 sptr
= _STR
+ strlen(_STR
);
2846 fraccalc((((float)(llen
) * iscale
* oscale
) / 72.0), fstr1
);
2848 fraccalc((((float)(lwid
) * iscale
* oscale
) / 72.0), fstr2
);
2849 sprintf(sptr
, " (%s x %s in)", fstr1
, fstr2
);
2852 sprintf(sptr
, " (length %s in)", fstr1
);
2856 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* CMSCALE
;
2857 f1
= ((float)(xval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2858 f2
= ((float)(yval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2859 sprintf(_STR
, "%5.3f, %5.3f cm", f1
, f2
);
2860 sptr
= _STR
+ strlen(_STR
);
2862 f1
= ((float)(llen
) * iscale
* oscale
) / IN_CM_CONVERT
;
2864 f2
= ((float)(lwid
) * iscale
* oscale
) / IN_CM_CONVERT
;
2865 sprintf(sptr
, " (%5.3f x %5.3f cm)", f1
, f2
);
2868 sprintf(sptr
, " (length %5.3f cm)", f1
);
2875 /*---------------------------------------------------*/
2876 /* Find nearest point of intersection of the cursor */
2877 /* position to a wire and move there. */
2878 /*---------------------------------------------------*/
2880 void findwirex(XPoint
*endpt1
, XPoint
*endpt2
, XPoint
*userpt
,
2881 XPoint
*newpos
, float *rot
)
2886 xsq
= sqwirelen(endpt1
, endpt2
);
2887 ysq
= sqwirelen(endpt1
, userpt
);
2888 zsq
= sqwirelen(endpt2
, userpt
);
2889 frac
= 0.5 + (float)(ysq
- zsq
) / (float)(xsq
<< 1);
2890 if (frac
> 1) frac
= 1;
2891 else if (frac
< 0) frac
= 0;
2892 newpos
->x
= endpt1
->x
+ (int)((endpt2
->x
- endpt1
->x
) * frac
);
2893 newpos
->y
= endpt1
->y
+ (int)((endpt2
->y
- endpt1
->y
) * frac
);
2895 *rot
= 180.0 + INVRFAC
* atan2((double)(endpt1
->x
-
2896 endpt2
->x
), (double)(endpt1
->y
- endpt2
->y
));
2899 /*----------------------------------------------------------------*/
2900 /* Find the closest point of attachment from the pointer position */
2901 /* to the "attachto" element. */
2902 /*----------------------------------------------------------------*/
2904 void findattach(XPoint
*newpos
, float *rot
, XPoint
*userpt
)
2906 XPoint
*endpt1
, *endpt2
;
2911 if (rot
) locrot
= *rot
;
2913 /* find point of intersection and slope */
2915 if (SELECTTYPE(&areawin
->attachto
) == ARC
) {
2916 arcptr aarc
= SELTOARC(&areawin
->attachto
);
2918 tmpang
= atan2((double)(userpt
->y
- aarc
->position
.y
) * (double)
2919 (abs(aarc
->radius
)), (double)(userpt
->x
- aarc
->position
.x
) *
2920 (double)aarc
->yaxis
);
2922 /* don't follow the arc beyond its endpoints */
2924 tmpdeg
= (float)(tmpang
* INVRFAC
);
2925 if (tmpdeg
< 0) tmpdeg
+= 360;
2926 if (((aarc
->angle2
> 360) && (tmpdeg
> aarc
->angle2
- 360) &&
2927 (tmpdeg
< aarc
->angle1
)) ||
2928 ((aarc
->angle1
< 0) && (tmpdeg
> aarc
->angle2
) &&
2929 (tmpdeg
< aarc
->angle1
+ 360)) ||
2930 ((aarc
->angle1
>= 0) && (aarc
->angle2
<= 360) && ((tmpdeg
2931 > aarc
->angle2
) || (tmpdeg
< aarc
->angle1
)))) {
2932 float testd1
= aarc
->angle1
- tmpdeg
;
2933 float testd2
= tmpdeg
- aarc
->angle2
;
2934 if (testd1
< 0) testd1
+= 360;
2935 if (testd2
< 0) testd2
+= 360;
2937 /* if arc is closed, attach to the line between the endpoints */
2939 if (!(aarc
->style
& UNCLOSED
)) {
2941 tmpang
= (double) aarc
->angle1
/ INVRFAC
;
2942 end1
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2943 end1
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2944 tmpang
= (double) aarc
->angle2
/ INVRFAC
;
2945 end2
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2946 end2
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2947 findwirex(&end1
, &end2
, userpt
, newpos
, &locrot
);
2948 if (rot
) *rot
= locrot
;
2952 tmpang
= (double)((testd1
< testd2
) ? aarc
->angle1
: aarc
->angle2
)
2956 /* get position in user coordinates nearest to the intersect pt */
2958 newpos
->x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2959 newpos
->y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2961 /* rotation of object is normal to the curve of the ellipse */
2964 *rot
= 90.0 - INVRFAC
* tmpang
;
2965 if (*rot
< 0.0) *rot
+= 360.0;
2968 else if (SELECTTYPE(&areawin
->attachto
) == SPLINE
) {
2969 splineptr aspline
= SELTOSPLINE(&areawin
->attachto
);
2970 frac
= findsplinemin(aspline
, userpt
);
2971 findsplinepos(aspline
, frac
, newpos
, &locrot
);
2972 if (rot
) *rot
= locrot
;
2974 else if (SELECTTYPE(&areawin
->attachto
) == OBJINST
) {
2976 objinstptr ainst
= SELTOOBJINST(&areawin
->attachto
);
2977 objectptr aobj
= ainst
->thisobject
;
2979 long testdist
, mindist
= 1e8
;
2982 /* In case instance has no pin labels, we will attach to */
2983 /* the instance's own origin. */
2985 mdpoint
.x
= mdpoint
.y
= 0;
2986 ReferencePosition(ainst
, &mdpoint
, newpos
);
2988 /* Find the nearest pin label in the object instance and attach to it */
2989 for (ggen
= aobj
->plist
; ggen
< aobj
->plist
+ aobj
->parts
; ggen
++) {
2990 if (ELEMENTTYPE(*ggen
) == LABEL
) {
2991 labelptr alab
= TOLABEL(ggen
);
2992 if (alab
->pin
== LOCAL
|| alab
->pin
== GLOBAL
) {
2993 ReferencePosition(ainst
, &alab
->position
, &mdpoint
);
2994 testdist
= sqwirelen(&mdpoint
, userpt
);
2995 if (testdist
< mindist
) {
3003 else if (SELECTTYPE(&areawin
->attachto
) == LABEL
) {
3004 /* Only one choice: Attach to the label position */
3005 labelptr alabel
= SELTOLABEL(&areawin
->attachto
);
3006 newpos
->x
= alabel
->position
.x
;
3007 newpos
->y
= alabel
->position
.y
;
3009 else if (SELECTTYPE(&areawin
->attachto
) == POLYGON
) {
3010 polyptr apoly
= SELTOPOLY(&areawin
->attachto
);
3011 XPoint
*testpt
, *minpt
, *nxtpt
;
3012 long mindist
= 1e8
, testdist
;
3013 minpt
= nxtpt
= apoly
->points
; /* so variables aren't uninitialized */
3014 for (testpt
= apoly
->points
; testpt
< apoly
->points
+
3015 apoly
->number
- 1; testpt
++) {
3016 testdist
= finddist(testpt
, testpt
+ 1, userpt
);
3017 if (testdist
< mindist
) {
3023 if (!(apoly
->style
& UNCLOSED
)) {
3024 testdist
= finddist(testpt
, apoly
->points
, userpt
);
3025 if (testdist
< mindist
) {
3028 nxtpt
= apoly
->points
;
3033 findwirex(endpt1
, endpt2
, userpt
, newpos
, &locrot
);
3034 if (rot
) *rot
= locrot
;
3038 /*--------------------------------------------*/
3039 /* Find closest point in a path to the cursor */
3040 /*--------------------------------------------*/
3042 XPoint
*pathclosepoint(pathptr dragpath
, XPoint
*newpos
)
3047 int mdist
= 1000000, tdist
;
3049 for (cpoint
= dragpath
->plist
; cpoint
< dragpath
->plist
+ dragpath
->parts
;
3051 switch(ELEMENTTYPE(*cpoint
)) {
3053 tdist
= wirelength(&(TOARC(cpoint
)->position
), newpos
);
3054 if (tdist
< mdist
) {
3056 rpoint
= &(TOARC(cpoint
)->position
);
3060 mpoint
= closepoint(TOPOLY(cpoint
), newpos
);
3061 tdist
= wirelength(TOPOLY(cpoint
)->points
+ mpoint
, newpos
);
3062 if (tdist
< mdist
) {
3064 rpoint
= TOPOLY(cpoint
)->points
+ mpoint
;
3068 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[0]), newpos
);
3069 if (tdist
< mdist
) {
3071 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[0]);
3073 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[3]), newpos
);
3074 if (tdist
< mdist
) {
3076 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[3]);
3084 /*-------------------------------------------*/
3085 /* Drag a selected element around the screen */
3086 /*-------------------------------------------*/
3088 void drag(int x
, int y
)
3091 Boolean eventcheck
= False
;
3093 short deltax
, deltay
;
3099 /* flush out multiple pointermotion events from the event queue */
3100 /* use only the last motion event */
3101 while (XCheckWindowEvent(dpy
, areawin
->window
, PointerMotionMask
|
3102 Button1MotionMask
, &again
) == True
) eventcheck
= True
;
3104 XButtonEvent
*event
= (XButtonEvent
*)(&again
);
3105 locx
= (int)event
->x
;
3106 locy
= (int)event
->y
;
3109 /* Determine if this event is supposed to be handled by */
3110 /* trackselarea(), or whether we should not be here at all */
3111 /* (button press and mouse movement in an unsupported mode) */
3113 if (eventmode
== SELAREA_MODE
) {
3117 else if (eventmode
== RESCALE_MODE
) {
3121 else if (eventmode
== PAN_MODE
) {
3122 trackpan(locx
, locy
);
3125 else if (eventmode
!= CATMOVE_MODE
&& eventmode
!= MOVE_MODE
3126 && eventmode
!= COPY_MODE
)
3129 snap(locx
, locy
, &userpt
);
3130 deltax
= userpt
.x
- areawin
->save
.x
;
3131 deltay
= userpt
.y
- areawin
->save
.y
;
3132 if (deltax
== 0 && deltay
== 0) return;
3134 areawin
->save
.x
= userpt
.x
;
3135 areawin
->save
.y
= userpt
.y
;
3137 /* set up the graphics state for moving a selected object */
3139 XTopSetForeground(SELECTCOLOR
);
3141 placeselects(deltax
, deltay
, &userpt
);
3143 /* restore graphics state */
3145 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
3147 /* print the position and other useful measurements */
3149 printpos(userpt
.x
, userpt
.y
);
3152 /*------------------------------------------------------*/
3153 /* Wrapper for drag() for xlib callback compatibility. */
3154 /*------------------------------------------------------*/
3156 void xlib_drag(xcWidget w
, caddr_t clientdata
, XEvent
*event
)
3158 XButtonEvent
*bevent
= (XButtonEvent
*)event
;
3159 UNUSED(w
); UNUSED(clientdata
);
3161 drag(bevent
->x
, bevent
->y
);
3162 if (areawin
->redraw_needed
)
3163 drawarea(NULL
, NULL
, NULL
);
3166 /*----------------------------------------------*/
3167 /* Rotate an element of a path */
3168 /*----------------------------------------------*/
3170 void elemrotate(genericptr
*genobj
, float direction
, XPoint
*position
)
3172 XPoint negpt
, *newpts
= (XPoint
*)NULL
;
3174 negpt
.x
= -position
->x
;
3175 negpt
.y
= -position
->y
;
3177 switch(ELEMENTTYPE(*genobj
)) {
3179 arcptr rotatearc
= TOARC(genobj
);
3180 rotatearc
->angle1
-= direction
;
3181 rotatearc
->angle2
-= direction
;
3182 if (rotatearc
->angle1
>= 360) {
3183 rotatearc
->angle1
-= 360;
3184 rotatearc
->angle2
-= 360;
3186 else if (rotatearc
->angle2
<= 0) {
3187 rotatearc
->angle1
+= 360;
3188 rotatearc
->angle2
+= 360;
3190 newpts
= (XPoint
*)malloc(sizeof(XPoint
));
3191 UTransformPoints(&rotatearc
->position
, newpts
, 1, negpt
, 1.0, 0);
3192 UTransformPoints(newpts
, &rotatearc
->position
, 1, *position
,
3198 splineptr rotatespline
= TOSPLINE(genobj
);
3199 newpts
= (XPoint
*)malloc(4 * sizeof(XPoint
));
3200 UTransformPoints(rotatespline
->ctrl
, newpts
, 4, negpt
, 1.0, 0);
3201 UTransformPoints(newpts
, rotatespline
->ctrl
, 4, *position
,
3203 calcspline(rotatespline
);
3207 polyptr rotatepoly
= TOPOLY(genobj
);
3208 newpts
= (XPoint
*)malloc(rotatepoly
->number
* sizeof(XPoint
));
3209 UTransformPoints(rotatepoly
->points
, newpts
, rotatepoly
->number
,
3211 UTransformPoints(newpts
, rotatepoly
->points
, rotatepoly
->number
,
3212 *position
, 1.0, direction
);
3215 if (newpts
) free(newpts
);
3218 /*------------------------------------------------------*/
3219 /* Rotate an element or group of elements */
3220 /* Objects and labels, if selected singly, rotate */
3221 /* about their position point. All other elements, */
3222 /* and groups, rotate about the cursor point. */
3223 /*------------------------------------------------------*/
3225 void elementrotate(float direction
, XPoint
*position
)
3227 short *selectobj
; /* , ld; (jdk) */
3228 Boolean single
= False
;
3229 Boolean need_refresh
= False
;
3230 Boolean preselected
;
3231 XPoint newpt
, negpt
;
3233 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3234 if (!checkselect(ALL_TYPES
)) return;
3235 if (areawin
->selects
== 1) single
= True
;
3237 negpt
.x
= -position
->x
;
3238 negpt
.y
= -position
->y
;
3240 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3241 + areawin
->selects
; selectobj
++) {
3243 /* erase the element */
3244 if (!need_refresh
) {
3245 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
3246 easydraw(*selectobj
, DOFORALL
);
3249 switch(SELECTTYPE(selectobj
)) {
3252 objinstptr rotateobj
= SELTOOBJINST(selectobj
);
3254 if (is_library(topobject
) >= 0 && !is_virtual(rotateobj
)) break;
3255 rotateobj
->rotation
+= direction
;
3256 while (rotateobj
->rotation
>= 360) rotateobj
->rotation
-= 360;
3257 while (rotateobj
->rotation
<= 0) rotateobj
->rotation
+= 360;
3259 UTransformPoints(&rotateobj
->position
, &newpt
, 1, negpt
, 1.0, 0);
3260 UTransformPoints(&newpt
, &rotateobj
->position
, 1, *position
,
3266 labelptr rotatetext
= SELTOLABEL(selectobj
);
3268 rotatetext
->rotation
+= direction
;
3269 while (rotatetext
->rotation
>= 360) rotatetext
->rotation
-= 360;
3270 while (rotatetext
->rotation
<= 0) rotatetext
->rotation
+= 360;
3272 UTransformPoints(&rotatetext
->position
, &newpt
, 1, negpt
, 1.0, 0);
3273 UTransformPoints(&newpt
, &rotatetext
->position
, 1, *position
,
3279 graphicptr rotateg
= SELTOGRAPHIC(selectobj
);
3281 rotateg
->rotation
+= direction
;
3282 while (rotateg
->rotation
>= 360) rotateg
->rotation
-= 360;
3283 while (rotateg
->rotation
<= 0) rotateg
->rotation
+= 360;
3285 rotateg
->valid
= FALSE
;
3286 #endif /* !HAVE_CAIRO */
3288 UTransformPoints(&rotateg
->position
, &newpt
, 1, negpt
, 1.0, 0);
3289 UTransformPoints(&newpt
, &rotateg
->position
, 1, *position
,
3292 need_refresh
= True
;
3295 case POLYGON
: case ARC
: case SPLINE
:{
3296 genericptr
*genpart
= topobject
->plist
+ *selectobj
;
3297 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3299 elemrotate(genpart
, direction
, position
);
3303 genericptr
*genpart
;
3304 pathptr rotatepath
= SELTOPATH(selectobj
);
3306 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3308 for (genpart
= rotatepath
->plist
; genpart
< rotatepath
->plist
3309 + rotatepath
->parts
; genpart
++)
3310 elemrotate(genpart
, direction
, position
);
3314 /* redisplay the element */
3315 if (preselected
|| ((eventmode
!= NORMAL_MODE
) && !need_refresh
)) {
3316 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
3317 easydraw(*selectobj
, DOFORALL
);
3321 /* This takes care of all selected instances and labels in one go, */
3322 /* because we only need to know the origin and amount of rotation. */
3324 if (eventmode
!= COPY_MODE
)
3325 register_for_undo(XCF_Rotate
, UNDO_MORE
, areawin
->topinstance
,
3326 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
,
3329 /* New rule (6/15/07) to be applied generally: If objects were */
3330 /* selected prior to calling elementrotate() and similar functions, */
3331 /* leave them selected upon exit. Otherwise, deselect them. */
3333 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
3337 if (eventmode
== CATALOG_MODE
) {
3339 if ((libnum
= is_library(topobject
)) >= 0) {
3340 composelib(libnum
+ LIBRARY
);
3341 need_refresh
= TRUE
;
3345 pwriteback(areawin
->topinstance
);
3346 calcbbox(areawin
->topinstance
);
3349 if (need_refresh
) drawarea(NULL
, NULL
, NULL
);
3352 /*----------------------------------------------*/
3353 /* Rescale the current edit element to the */
3354 /* dimensions of the rescale box. */
3355 /*----------------------------------------------*/
3357 void elementrescale(float newscale
)
3365 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3366 + areawin
->selects
; selectobj
++) {
3367 switch (SELECTTYPE(selectobj
)) {
3369 sclab
= SELTOLABEL(selectobj
);
3370 oldsize
= sclab
->scale
;
3371 sclab
->scale
= newscale
;
3374 scinst
= SELTOOBJINST(selectobj
);
3375 oldsize
= scinst
->scale
;
3376 scinst
->scale
= newscale
;
3379 scgraph
= SELTOGRAPHIC(selectobj
);
3380 oldsize
= scgraph
->scale
;
3381 scgraph
->scale
= newscale
;
3384 register_for_undo(XCF_Rescale
, UNDO_MORE
, areawin
->topinstance
,
3385 SELTOGENERIC(selectobj
), (double)oldsize
);
3387 calcbbox(areawin
->topinstance
);
3390 /*-------------------------------------------------*/
3391 /* Edit an element in an element-dependent fashion */
3392 /*-------------------------------------------------*/
3394 void edit(int x
, int y
)
3398 if (areawin
->selects
== 0) {
3399 Boolean saveredraw
= areawin
->redraw_needed
;
3400 selectobj
= select_element(ALL_TYPES
);
3401 areawin
->redraw_needed
= saveredraw
;
3404 selectobj
= areawin
->selectlist
;
3405 if (areawin
->selects
== 0)
3407 else if (areawin
->selects
!= 1) { /* Multiple object edit */
3409 short *selectlist
, selrefno
;
3410 Boolean save_redraw
= areawin
->redraw_needed
;
3412 /* Find the closest part to use as a reference */
3413 selnum
= areawin
->selects
;
3414 selectlist
= areawin
->selectlist
;
3415 areawin
->selects
= 0;
3416 areawin
->selectlist
= NULL
;
3417 selectobj
= select_element(ALL_TYPES
);
3418 if (selectobj
!= NULL
)
3419 selrefno
= *selectobj
;
3423 areawin
->selects
= selnum
;
3424 areawin
->selectlist
= selectlist
;
3425 areawin
->redraw_needed
= save_redraw
;
3426 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3427 + areawin
->selects
; selectobj
++) {
3428 if (*selectobj
== selrefno
) break;
3430 if (selectobj
== areawin
->selectlist
+ areawin
->selects
) {
3431 Wprintf("Put cursor close to the reference element.");
3435 /* Shuffle the reference element to the beginning of the select list */
3436 *selectobj
= *(areawin
->selectlist
);
3437 *(areawin
->selectlist
) = selrefno
;
3438 selectobj
= areawin
->selectlist
;
3441 switch(SELECTTYPE(selectobj
)) {
3443 labelptr
*lastlabel
= (labelptr
*)EDITPART
;
3448 /* save the old string, including parameters */
3449 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3452 /* fill any NULL instance parameters with the default value */
3453 copyparams(areawin
->topinstance
, areawin
->topinstance
);
3455 /* place text cursor line at point nearest the cursor */
3456 /* unless textend is set. . . */
3458 if (areawin
->textend
== 0) {
3459 TextLinesInfo tlinfo
;
3461 tlinfo
.tbreak
= NULL
;
3462 tlinfo
.padding
= NULL
;
3464 window_to_user(x
, y
, &areawin
->save
);
3465 InvTransformPoints(&areawin
->save
, &tmppt
, 1, (*lastlabel
)->position
,
3466 (*lastlabel
)->scale
, (*lastlabel
)->rotation
);
3467 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3468 tmppt
.x
+= ((*lastlabel
)->anchor
& NOTLEFT
?
3469 ((*lastlabel
)->anchor
& RIGHT
? tmpext
.maxwidth
3470 : tmpext
.maxwidth
>> 1) : 0);
3471 tmppt
.y
+= ((*lastlabel
)->anchor
& NOTBOTTOM
?
3472 ((*lastlabel
)->anchor
& TOP
? tmpext
.ascent
:
3473 (tmpext
.ascent
+ tmpext
.base
) >> 1) : tmpext
.base
);
3474 if ((*lastlabel
)->pin
)
3475 pinadjust((*lastlabel
)->anchor
, &tmppt
.x
, NULL
, -1);
3477 /* Where tbreak is passed to ULength, the character position */
3478 /* is returned in the TextLinesInfo dostop field. */
3479 tlinfo
.tbreak
= &tmppt
;
3480 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3481 areawin
->textpos
= tlinfo
.dostop
;
3483 if (tlinfo
.padding
!= NULL
) free(tlinfo
.padding
);
3486 /* find current font */
3488 curfont
= findcurfont(areawin
->textpos
, (*lastlabel
)->string
,
3489 areawin
->topinstance
);
3491 /* change menu buttons accordingly */
3493 setfontmarks(curfont
, (*lastlabel
)->anchor
);
3495 if (eventmode
== CATALOG_MODE
) {
3496 /* CATTEXT_MODE may show an otherwise hidden library namespace */
3497 undrawtext(*lastlabel
);
3498 eventmode
= CATTEXT_MODE
;
3499 redrawtext(*lastlabel
);
3500 areawin
->redraw_needed
= False
; /* ignore prev. redraw requests */
3501 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3504 eventmode
= ETEXT_MODE
;
3505 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3508 XDefineCursor(dpy
, areawin
->window
, TEXTPTR
);
3510 /* write the text at the bottom */
3512 charreport(*lastlabel
);
3516 case POLYGON
: case ARC
: case SPLINE
: case PATH
:
3517 window_to_user(x
, y
, &areawin
->save
);
3518 pathedit(*(EDITPART
));
3521 case OBJINST
: case GRAPHIC
:
3522 if (areawin
->selects
== 1)
3526 XDefineCursor (dpy
, areawin
->window
, EDCURSOR
);
3529 /*----------------------------------------------------------------------*/
3530 /* edit() routine for path-type elements (polygons, splines, arcs, and */
3532 /*----------------------------------------------------------------------*/
3534 void pathedit(genericptr editpart
)
3536 splineptr lastspline
= NULL
;
3538 polyptr lastpoly
= NULL
;
3545 /* Find and set constrained edit points on all elements. Register */
3546 /* each element with the undo mechanism. */
3548 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
3549 areawin
->selects
; eselect
++) {
3550 switch (SELECTTYPE(eselect
)) {
3552 findconstrained(SELTOPOLY(eselect
));
3555 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3556 SELTOGENERIC(eselect
));
3561 switch(ELEMENTTYPE(editpart
)) {
3563 genericptr
*ggen
, *savegen
= NULL
;
3564 int mincycle
, dist
, mindist
= 1e6
;
3566 lastpath
= (pathptr
)editpart
;
3567 havecycle
= (checkcycle(editpart
, 0) >= 0) ? True
: False
;
3569 /* determine which point of the path is closest to the cursor */
3570 for (ggen
= lastpath
->plist
; ggen
< lastpath
->plist
+ lastpath
->parts
;
3572 switch (ELEMENTTYPE(*ggen
)) {
3574 lastpoly
= TOPOLY(ggen
);
3575 cycle
= closepoint(lastpoly
, &areawin
->save
);
3576 dist
= wirelength(lastpoly
->points
+ cycle
, &areawin
->save
);
3579 lastspline
= TOSPLINE(ggen
);
3580 cycle
= (wirelength(&lastspline
->ctrl
[0],
3581 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3582 &areawin
->save
)) ? 0 : 3;
3583 dist
= wirelength(&lastspline
->ctrl
[cycle
], &areawin
->save
);
3586 if (dist
< mindist
) {
3592 if (savegen
== NULL
) return; /* something went terribly wrong */
3593 switch (ELEMENTTYPE(*savegen
)) {
3595 lastpoly
= TOPOLY(savegen
);
3596 addcycle(savegen
, mincycle
, 0);
3597 savept
= lastpoly
->points
+ mincycle
;
3598 makerefcycle(lastpoly
->cycle
, mincycle
);
3599 findconstrained(lastpoly
);
3602 lastspline
= TOSPLINE(savegen
);
3603 addcycle(savegen
, mincycle
, 0);
3604 savept
= &lastspline
->ctrl
[mincycle
];
3605 makerefcycle(lastspline
->cycle
, mincycle
);
3608 updatepath(lastpath
);
3610 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3611 (genericptr
)lastpath
);
3612 patheditpush(lastpath
);
3613 areawin
->origin
= areawin
->save
;
3616 path_mode_draw(xcDRAW_INIT
, lastpath
);
3618 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3619 (xcEventHandler
)trackelement
, NULL
);
3620 eventmode
= EPATH_MODE
;
3621 printpos(savept
->x
, savept
->y
);
3626 lastpoly
= (polyptr
)editpart
;
3628 /* Determine which point of polygon is closest to cursor */
3629 cycle
= closepoint(lastpoly
, &areawin
->save
);
3630 havecycle
= (lastpoly
->cycle
== NULL
) ? False
: True
;
3631 addcycle(&editpart
, cycle
, 0);
3632 savept
= lastpoly
->points
+ cycle
;
3633 makerefcycle(lastpoly
->cycle
, cycle
);
3635 findconstrained(lastpoly
);
3636 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3637 (genericptr
)lastpoly
);
3640 /* Push onto the editstack */
3641 polyeditpush(lastpoly
);
3643 /* remember our postion for pointer restore */
3644 areawin
->origin
= areawin
->save
;
3648 poly_mode_draw(xcDRAW_INIT
, lastpoly
);
3650 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3651 (xcEventHandler
)trackelement
, NULL
);
3652 eventmode
= EPOLY_MODE
;
3653 printeditbindings();
3654 printpos(savept
->x
, savept
->y
);
3659 lastspline
= (splineptr
)editpart
;
3661 /* find which point is closest to the cursor */
3663 cycle
= (wirelength(&lastspline
->ctrl
[0],
3664 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3665 &areawin
->save
)) ? 0 : 3;
3666 havecycle
= (lastspline
->cycle
== NULL
) ? False
: True
;
3667 addcycle(&editpart
, cycle
, 0);
3668 makerefcycle(lastspline
->cycle
, cycle
);
3669 curpt
= &lastspline
->ctrl
[cycle
];
3671 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3672 (genericptr
)lastspline
);
3674 /* Push onto the editstack */
3675 splineeditpush(lastspline
);
3677 /* remember our postion for pointer restore */
3678 areawin
->origin
= areawin
->save
;
3682 spline_mode_draw(xcDRAW_INIT
, lastspline
);
3683 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3684 (xcEventHandler
)trackelement
, NULL
);
3685 eventmode
= ESPLINE_MODE
;
3689 float tmpratio
, tlen
;
3691 lastarc
= (arcptr
)editpart
;
3693 /* find a part of the arc close to the pointer */
3695 tlen
= (float)wirelength(&areawin
->save
, &(lastarc
->position
));
3696 tmpratio
= (float)(abs(lastarc
->radius
)) / tlen
;
3697 curpt
.x
= lastarc
->position
.x
+ tmpratio
* (areawin
->save
.x
3698 - lastarc
->position
.x
);
3699 tmpratio
= (float)lastarc
->yaxis
/ tlen
;
3700 curpt
.y
= lastarc
->position
.y
+ tmpratio
* (areawin
->save
.y
3701 - lastarc
->position
.y
);
3702 addcycle(&editpart
, 0, 0);
3703 saveratio
= (double)(lastarc
->yaxis
) / (double)(abs(lastarc
->radius
));
3705 /* Push onto the editstack */
3706 arceditpush(lastarc
);
3707 areawin
->origin
= areawin
->save
;
3711 areawin
->save
.x
= curpt
.x
; /* for redrawing dotted edit line */
3712 areawin
->save
.y
= curpt
.y
;
3713 arc_mode_draw(xcDRAW_INIT
, lastarc
);
3714 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3715 (xcEventHandler
)trackarc
, NULL
);
3716 eventmode
= EARC_MODE
;
3717 printpos(curpt
.x
, curpt
.y
);
3722 /*------------------------------------------------------*/
3723 /* Raise an element to the top of the list */
3724 /*------------------------------------------------------*/
3726 void xc_top(short *selectno
, short *orderlist
)
3729 genericptr
*raiseobj
, *genobj
, temp
;
3731 raiseobj
= topobject
->plist
+ *selectno
;
3734 for (genobj
= topobject
->plist
+ *selectno
; genobj
<
3735 topobject
->plist
+ topobject
->parts
- 1; genobj
++) {
3736 *genobj
= *(genobj
+ 1);
3737 *(orderlist
+ i
) = *(orderlist
+ i
+ 1);
3740 *(topobject
->plist
+ topobject
->parts
- 1) = temp
;
3741 *(orderlist
+ topobject
->parts
- 1) = *selectno
;
3742 *selectno
= topobject
->parts
- 1;
3745 /*------------------------------------------------------*/
3746 /* Lower an element to the bottom of the list */
3747 /*------------------------------------------------------*/
3749 void xc_bottom(short *selectno
, short *orderlist
)
3752 genericptr
*lowerobj
, *genobj
, temp
;
3754 lowerobj
= topobject
->plist
+ *selectno
;
3757 for (genobj
= topobject
->plist
+ *selectno
;
3758 genobj
> topobject
->plist
; genobj
--) {
3759 *genobj
= *(genobj
- 1);
3760 *(orderlist
+ i
) = *(orderlist
+ i
- 1);
3764 *orderlist
= *selectno
;
3768 /*--------------------------------------------------------------*/
3769 /* Raise all selected elements by one position in the list */
3770 /*--------------------------------------------------------------*/
3774 short *sel
, topsel
, maxsel
, *topidx
, limit
, *orderlist
, i
;
3775 genericptr
*raiseobj
, temp
;
3777 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3778 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3780 /* Find topmost element in the select list */
3782 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3784 if (*sel
> maxsel
) {
3789 if (maxsel
== -1) return; /* Error condition */
3792 limit
= topobject
->parts
- 1;
3795 /* Exchange the topmost element with the one above it */
3796 if (topsel
< limit
) {
3797 raiseobj
= topobject
->plist
+ topsel
;
3799 *raiseobj
= *(raiseobj
+ 1);
3800 *(raiseobj
+ 1) = temp
;
3802 i
= *(orderlist
+ topsel
);
3803 *(orderlist
+ topsel
) = *(orderlist
+ topsel
+ 1);
3804 *(orderlist
+ topsel
+ 1) = i
;
3809 /* Find next topmost element */
3811 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3813 if (*sel
< maxsel
) {
3814 if (*sel
> topsel
) {
3820 if (topsel
== -1) break; /* No more elements to raise */
3823 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3827 /*--------------------------------------------------------------*/
3828 /* Lower all selected elements by one position in the list */
3829 /*--------------------------------------------------------------*/
3833 short *sel
, botsel
, minsel
, *botidx
, limit
, *orderlist
, i
;
3834 genericptr
*lowerobj
, temp
;
3836 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3837 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3839 /* Find bottommost element in the select list */
3840 minsel
= topobject
->parts
;
3841 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3843 if (*sel
< minsel
) {
3848 if (minsel
== topobject
->parts
) return; /* Error condition */
3854 /* Exchange the topmost element with the one below it */
3855 if (botsel
> limit
) {
3856 lowerobj
= topobject
->plist
+ botsel
;
3858 *lowerobj
= *(lowerobj
- 1);
3859 *(lowerobj
- 1) = temp
;
3861 i
= *(orderlist
+ botsel
);
3862 *(orderlist
+ botsel
) = *(orderlist
+ botsel
- 1);
3863 *(orderlist
+ botsel
- 1) = i
;
3868 /* Find next topmost element */
3869 botsel
= topobject
->parts
;
3870 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3872 if (*sel
> minsel
) {
3873 if (*sel
< botsel
) {
3879 if (botsel
== topobject
->parts
) break; /* No more elements to raise */
3882 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3886 /*------------------------------------------------------*/
3887 /* Generate a virtual copy of an object instance in the */
3888 /* user library. This is like the library virtual copy */
3889 /* except that it allows the user to generate a library */
3890 /* copy of an existing instance, without having to make */
3891 /* a copy of the master library instance and edit it. */
3892 /* copyvirtual() also allows the library virtual */
3893 /* instance to take on a specific rotation or flip */
3894 /* value, which cannot be done with the library virtual */
3895 /* copy function. */
3896 /*------------------------------------------------------*/
3900 short *selectno
, created
= 0;
3901 objinstptr vcpobj
, libinst
;
3903 for (selectno
= areawin
->selectlist
; selectno
< areawin
->selectlist
+
3904 areawin
->selects
; selectno
++) {
3905 if (SELECTTYPE(selectno
) == OBJINST
) {
3906 vcpobj
= SELTOOBJINST(selectno
);
3907 libinst
= addtoinstlist(USERLIB
- LIBRARY
, vcpobj
->thisobject
, TRUE
);
3908 instcopy(libinst
, vcpobj
);
3913 Wprintf("No object instances selected for virtual copy!");
3917 composelib(USERLIB
);
3921 /*------------------------------------------------------*/
3922 /* Exchange the list position (drawing order) of two */
3923 /* elements, or move the position of one element to the */
3924 /* top or bottom. */
3925 /*------------------------------------------------------*/
3929 short *selectno
, *orderlist
, i
;
3930 genericptr
*exchobj
, *exchobj2
, temp
;
3931 Boolean preselected
;
3933 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3934 if (!checkselect(ALL_TYPES
)) {
3935 Wprintf("Select 1 or 2 objects");
3939 selectno
= areawin
->selectlist
;
3940 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3941 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3943 if (areawin
->selects
== 1) { /* lower if on top; raise otherwise */
3944 if (*selectno
== topobject
->parts
- 1)
3945 xc_bottom(selectno
, orderlist
);
3947 xc_top(selectno
, orderlist
);
3949 else { /* exchange the two objects */
3950 exchobj
= topobject
->plist
+ *selectno
;
3951 exchobj2
= topobject
->plist
+ *(selectno
+ 1);
3954 *exchobj
= *exchobj2
;
3957 i
= *(orderlist
+ *selectno
);
3958 *(orderlist
+ *selectno
) = *(orderlist
+ *(selectno
+ 1));
3959 *(orderlist
+ *(selectno
+ 1)) = i
;
3961 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
3962 orderlist
, topobject
->parts
);
3964 incr_changes(topobject
);
3967 drawarea(NULL
, NULL
, NULL
);
3970 /*--------------------------------------------------------*/
3971 /* Flip an element horizontally (POLYGON, ARC, or SPLINE) */
3972 /*--------------------------------------------------------*/
3974 void elhflip(genericptr
*genobj
, short x
)
3976 switch(ELEMENTTYPE(*genobj
)) {
3978 polyptr flippoly
= TOPOLY(genobj
);
3980 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
3981 flippoly
->number
; ppoint
++)
3982 ppoint
->x
= (x
<< 1) - ppoint
->x
;
3986 arcptr fliparc
= TOARC(genobj
);
3987 float tmpang
= 180 - fliparc
->angle1
;
3988 fliparc
->angle1
= 180 - fliparc
->angle2
;
3989 fliparc
->angle2
= tmpang
;
3990 if (fliparc
->angle2
< 0) {
3991 fliparc
->angle1
+= 360;
3992 fliparc
->angle2
+= 360;
3994 fliparc
->radius
= -fliparc
->radius
;
3995 fliparc
->position
.x
= (x
<< 1) - fliparc
->position
.x
;
4000 splineptr flipspline
= TOSPLINE(genobj
);
4002 for (i
= 0; i
< 4; i
++)
4003 flipspline
->ctrl
[i
].x
= (x
<< 1) - flipspline
->ctrl
[i
].x
;
4004 calcspline(flipspline
);
4009 /*--------------------------------------------------------*/
4010 /* Flip an element vertically (POLYGON, ARC, or SPLINE) */
4011 /*--------------------------------------------------------*/
4013 void elvflip(genericptr
*genobj
, short y
)
4015 switch(ELEMENTTYPE(*genobj
)) {
4018 polyptr flippoly
= TOPOLY(genobj
);
4021 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
4022 flippoly
->number
; ppoint
++)
4023 ppoint
->y
= (y
<< 1) - ppoint
->y
;
4027 arcptr fliparc
= TOARC(genobj
);
4028 float tmpang
= 360 - fliparc
->angle1
;
4029 fliparc
->angle1
= 360 - fliparc
->angle2
;
4030 fliparc
->angle2
= tmpang
;
4031 if (fliparc
->angle1
>= 360) {
4032 fliparc
->angle1
-= 360;
4033 fliparc
->angle2
-= 360;
4035 fliparc
->radius
= -fliparc
->radius
;
4036 fliparc
->position
.y
= (y
<< 1) - fliparc
->position
.y
;
4041 splineptr flipspline
= TOSPLINE(genobj
);
4043 for (i
= 0; i
< 4; i
++)
4044 flipspline
->ctrl
[i
].y
= (y
<< 1) - flipspline
->ctrl
[i
].y
;
4045 calcspline(flipspline
);
4050 /*------------------------------------------------------*/
4051 /* Horizontally flip an element */
4052 /*------------------------------------------------------*/
4054 void elementflip(XPoint
*position
)
4057 Boolean single
= False
;
4058 Boolean preselected
;
4060 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4061 if (!checkselect(ALL_TYPES
)) return;
4062 if (areawin
->selects
== 1) single
= True
;
4064 if (eventmode
!= COPY_MODE
)
4065 register_for_undo(XCF_Flip_X
, UNDO_MORE
, areawin
->topinstance
,
4066 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4068 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4069 + areawin
->selects
; selectobj
++) {
4071 /* erase the object */
4072 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4073 easydraw(*selectobj
, DOFORALL
);
4075 switch(SELECTTYPE(selectobj
)) {
4077 labelptr fliplab
= SELTOLABEL(selectobj
);
4078 if ((fliplab
->anchor
& (RIGHT
| NOTLEFT
)) != NOTLEFT
)
4079 fliplab
->anchor
^= (RIGHT
| NOTLEFT
);
4081 fliplab
->position
.x
= (position
->x
<< 1) - fliplab
->position
.x
;
4084 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4085 flipg
->scale
= -flipg
->scale
;
4087 flipg
->valid
= FALSE
;
4088 #endif /* !HAVE_CAIRO */
4090 flipg
->position
.x
= (position
->x
<< 1) - flipg
->position
.x
;
4093 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4094 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4095 flipobj
->scale
= -flipobj
->scale
;
4097 flipobj
->position
.x
= (position
->x
<< 1) - flipobj
->position
.x
;
4099 case POLYGON
: case ARC
: case SPLINE
:
4100 elhflip(topobject
->plist
+ *selectobj
, position
->x
);
4103 genericptr
*genpart
;
4104 pathptr flippath
= SELTOPATH(selectobj
);
4106 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4107 + flippath
->parts
; genpart
++)
4108 elhflip(genpart
, position
->x
);
4112 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4113 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4114 easydraw(*selectobj
, DOFORALL
);
4117 select_invalidate_netlist();
4118 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4122 if (eventmode
== NORMAL_MODE
)
4123 incr_changes(topobject
);
4124 if (eventmode
== CATALOG_MODE
) {
4126 if ((libnum
= is_library(topobject
)) >= 0) {
4127 composelib(libnum
+ LIBRARY
);
4128 drawarea(NULL
, NULL
, NULL
);
4132 pwriteback(areawin
->topinstance
);
4133 calcbbox(areawin
->topinstance
);
4137 /*----------------------------------------------*/
4138 /* Vertically flip an element */
4139 /*----------------------------------------------*/
4141 void elementvflip(XPoint
*position
)
4144 /*short fsign; (jdk) */
4145 Boolean preselected
;
4146 Boolean single
= False
;
4148 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4149 if (!checkselect(ALL_TYPES
)) return;
4150 if (areawin
->selects
== 1) single
= True
;
4152 if (eventmode
!= COPY_MODE
)
4153 register_for_undo(XCF_Flip_Y
, UNDO_MORE
, areawin
->topinstance
,
4154 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4156 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4157 + areawin
->selects
; selectobj
++) {
4159 /* erase the object */
4160 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4161 easydraw(*selectobj
, DOFORALL
);
4163 switch(SELECTTYPE(selectobj
)) {
4165 labelptr fliplab
= SELTOLABEL(selectobj
);
4166 if ((fliplab
->anchor
& (TOP
| NOTBOTTOM
)) != NOTBOTTOM
)
4167 fliplab
->anchor
^= (TOP
| NOTBOTTOM
);
4169 fliplab
->position
.y
= (position
->y
<< 1) - fliplab
->position
.y
;
4172 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4174 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4175 flipobj
->scale
= -(flipobj
->scale
);
4176 flipobj
->rotation
+= 180;
4177 while (flipobj
->rotation
>= 360) flipobj
->rotation
-= 360;
4179 flipobj
->position
.y
= (position
->y
<< 1) - flipobj
->position
.y
;
4182 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4184 flipg
->scale
= -(flipg
->scale
);
4185 flipg
->rotation
+= 180;
4186 while (flipg
->rotation
>= 360) flipg
->rotation
-= 360;
4188 flipg
->position
.y
= (position
->y
<< 1) - flipg
->position
.y
;
4190 case POLYGON
: case ARC
: case SPLINE
:
4191 elvflip(topobject
->plist
+ *selectobj
, position
->y
);
4194 genericptr
*genpart
;
4195 pathptr flippath
= SELTOPATH(selectobj
);
4197 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4198 + flippath
->parts
; genpart
++)
4199 elvflip(genpart
, position
->y
);
4202 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4203 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4204 easydraw(*selectobj
, DOFORALL
);
4207 select_invalidate_netlist();
4208 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4211 if (eventmode
== NORMAL_MODE
) {
4212 incr_changes(topobject
);
4214 if (eventmode
== CATALOG_MODE
) {
4216 if ((libnum
= is_library(topobject
)) >= 0) {
4217 composelib(libnum
+ LIBRARY
);
4218 drawarea(NULL
, NULL
, NULL
);
4222 pwriteback(areawin
->topinstance
);
4223 calcbbox(areawin
->topinstance
);
4227 /*----------------------------------------*/
4228 /* ButtonPress handler during delete mode */
4229 /*----------------------------------------*/
4231 void deletebutton(int x
, int y
)
4233 UNUSED(x
); UNUSED(y
);
4235 if (checkselect(ALL_TYPES
)) {
4236 standard_element_delete(ERASE
);
4237 calcbbox(areawin
->topinstance
);
4239 setoptionmenu(); /* Return GUI check/radio boxes to default */
4242 /*----------------------------------------------------------------------*/
4243 /* Process of element deletion. Remove one element from the indicated */
4245 /*----------------------------------------------------------------------*/
4247 void delete_one_element(objinstptr thisinstance
, genericptr thiselement
)
4249 objectptr thisobject
;
4251 Boolean pinchange
= False
;
4253 thisobject
= thisinstance
->thisobject
;
4255 /* The netlist contains pointers to elements which no longer */
4256 /* exist on the page, so we should remove them from the netlist. */
4258 if (RemoveFromNetlist(thisobject
, thiselement
)) pinchange
= True
;
4259 for (genobj
= thisobject
->plist
; genobj
< thisobject
->plist
4260 + thisobject
->parts
; genobj
++)
4261 if (*genobj
== thiselement
)
4264 if (genobj
== thisobject
->plist
+ thisobject
->parts
) return;
4266 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4267 *(genobj
- 1) = *genobj
;
4268 thisobject
->parts
--;
4270 if (pinchange
) setobjecttype(thisobject
);
4271 incr_changes(thisobject
);
4272 calcbbox(thisinstance
);
4273 invalidate_netlist(thisobject
);
4274 /* freenetlist(thisobject); */
4277 /*----------------------------------------------------------------------*/
4278 /* Process of element deletion. Remove everything in the selection */
4279 /* list from the indicated object, and return a new object containing */
4280 /* only the deleted elements. */
4282 /* if drawmode is DRAW, we erase the objects as we remove them. */
4284 /* Note that if "slist" is areawin->selectlist, it is freed by this */
4285 /* routine (calls freeselects()), but not otherwise. */
4286 /*----------------------------------------------------------------------*/
4288 objectptr
delete_element(objinstptr thisinstance
, short *slist
, int selects
,
4292 objectptr delobj
, thisobject
;
4294 Boolean pinchange
= False
;
4296 if (slist
== NULL
|| selects
== 0) return NULL
;
4298 thisobject
= thisinstance
->thisobject
;
4300 delobj
= (objectptr
) malloc(sizeof(object
));
4304 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4307 for (selectobj
= slist
; selectobj
< slist
+ selects
; selectobj
++) {
4308 genobj
= thisobject
->plist
+ *selectobj
;
4309 if (drawmode
) easydraw(*selectobj
, DOFORALL
);
4311 *(delobj
->plist
+ delobj
->parts
) = *genobj
;
4314 /* The netlist contains pointers to elements which no longer */
4315 /* exist on the page, so we should remove them from the netlist. */
4317 if (RemoveFromNetlist(thisobject
, *genobj
)) pinchange
= True
;
4318 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4319 *(genobj
- 1) = *genobj
;
4320 thisobject
->parts
--;
4321 reviseselect(slist
, selects
, selectobj
);
4323 if (pinchange
) setobjecttype(thisobject
);
4325 if (slist
== areawin
->selectlist
)
4328 calcbbox(thisinstance
);
4329 /* freenetlist(thisobject); */
4332 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
4333 drawarea(NULL
, NULL
, NULL
);
4338 /*----------------------------------------------------------------------*/
4339 /* Wrapper for delete_element(). Remember this deletion for the undo */
4341 /*----------------------------------------------------------------------*/
4343 void standard_element_delete(short drawmode
)
4347 /* register_for_undo(XCF_Select, UNDO_MORE, areawin->topinstance, */
4348 /* areawin->selectlist, areawin->selects); */
4349 select_invalidate_netlist();
4350 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4351 areawin
->selects
, drawmode
);
4352 register_for_undo(XCF_Delete
, UNDO_DONE
, areawin
->topinstance
,
4353 delobj
, (int)drawmode
);
4354 incr_changes(topobject
); /* Treat as one change */
4357 /*----------------------------------------------------------------------*/
4358 /* Another wrapper for delete_element(), in which we do not save the */
4359 /* deletion as an undo event. However, the returned object is saved */
4360 /* on areawin->editstack, so that the objects can be grabbed. This */
4361 /* allows objects to be carried across pages and through the hierarchy. */
4362 /*----------------------------------------------------------------------*/
4364 void delete_for_xfer(short drawmode
, short *slist
, int selects
)
4367 reset(areawin
->editstack
, DESTROY
);
4368 areawin
->editstack
= delete_element(areawin
->topinstance
,
4369 slist
, selects
, drawmode
);
4373 /*----------------------------------------------------------------------*/
4374 /* Yet another wrapper for delete_element(), in which we destroy the */
4375 /* object returned and free all associated memory. */
4376 /*----------------------------------------------------------------------*/
4378 void delete_noundo(short drawmode
)
4382 select_invalidate_netlist();
4383 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4384 areawin
->selects
, drawmode
);
4386 if (delobj
!= NULL
) reset(delobj
, DESTROY
);
4389 /*----------------------------------------------------------------------*/
4390 /* Undelete last deleted elements and return a selectlist of the */
4391 /* elements. If "olist" is non-NULL, then the undeleted elements are */
4392 /* placed into the object of thisinstance in the order given by olist, */
4393 /* and a copy of olist is returned. If "olist" is NULL, then the */
4394 /* undeleted elements are placed at the end of thisinstance->thisobject */
4395 /* ->plist, and a new selection list is returned. If "olist" is non- */
4396 /* NULL, then the size of olist had better match the number of objects */
4397 /* in delobj! It is up to the calling routine to check this. */
4398 /*----------------------------------------------------------------------*/
4400 short *xc_undelete(objinstptr thisinstance
, objectptr delobj
, short mode
,
4403 objectptr thisobject
;
4405 short *slist
, count
, i
; /* position; (jdk) */
4407 thisobject
= thisinstance
->thisobject
;
4408 slist
= (short *)malloc(delobj
->parts
* sizeof(short));
4411 for (regen
= delobj
->plist
; regen
< delobj
->plist
+ delobj
->parts
; regen
++) {
4412 PLIST_INCR(thisobject
);
4413 if (olist
== NULL
) {
4414 *(slist
+ count
) = thisobject
->parts
;
4415 *(topobject
->plist
+ topobject
->parts
) = *regen
;
4418 *(slist
+ count
) = *(olist
+ count
);
4419 for (i
= thisobject
->parts
; i
> *(olist
+ count
); i
--)
4420 *(thisobject
->plist
+ i
) = *(thisobject
->plist
+ i
- 1);
4421 *(thisobject
->plist
+ i
) = *regen
;
4423 thisobject
->parts
++;
4425 XTopSetForeground((*regen
)->color
);
4426 easydraw(*(slist
+ count
), DEFAULTCOLOR
);
4430 /* If the element has passed parameters (eparam), then we have to */
4431 /* check if the key exists in the new parent object. If not, */
4432 /* delete the parameter. */
4434 if ((*regen
)->passed
) {
4435 eparamptr nextepp
, epp
= (*regen
)->passed
;
4436 while (epp
!= NULL
) {
4437 nextepp
= epp
->next
;
4438 if (!match_param(thisobject
, epp
->key
)) {
4439 if (epp
== (*regen
)->passed
) (*regen
)->passed
= nextepp
;
4440 free_element_param(*regen
, epp
);
4446 /* Likewise, string parameters must be checked in labels because */
4447 /* they act like element parameters. */
4449 if (IS_LABEL(*regen
)) {
4450 labelptr glab
= TOLABEL(regen
);
4451 stringpart
*gstr
, *lastpart
= NULL
;
4452 for (gstr
= glab
->string
; gstr
!= NULL
; gstr
= lastpart
->nextpart
) {
4453 if (gstr
->type
== PARAM_START
) {
4454 if (!match_param(thisobject
, gstr
->data
.string
)) {
4455 free(gstr
->data
.string
);
4457 lastpart
->nextpart
= gstr
->nextpart
;
4459 glab
->string
= gstr
->nextpart
;
4461 gstr
= (lastpart
) ? lastpart
: glab
->string
;
4468 incr_changes(thisobject
); /* treat as one change */
4469 calcbbox(thisinstance
);
4471 /* flush the delete buffer but don't delete the elements */
4472 reset(delobj
, SAVE
);
4474 if (delobj
!= areawin
->editstack
) free(delobj
);
4479 /*----------------------------*/
4480 /* select save object handler */
4481 /*----------------------------*/
4483 void printname(objectptr curobject
)
4485 char editstr
[10], pagestr
[10];
4490 Dimension swidth
, swidth2
, sarea
;
4492 char *sptr
= tmpname
;
4495 /* print full string to make message widget proper size */
4497 strcpy(editstr
, ((ispage
= is_page(curobject
)) >= 0) ? "Editing: " : "");
4498 strcpy(editstr
, (is_library(curobject
) >= 0) ? "Library: " : "");
4499 if (strstr(curobject
->name
, "Page") == NULL
&& (ispage
>= 0))
4500 sprintf(pagestr
, " (p. %d)", areawin
->page
+ 1);
4503 W2printf("%s%s%s", editstr
, curobject
->name
, pagestr
);
4505 /* Tcl doesn't update width changes immediately. . . what to do? */
4506 /* (i.e., Tk_Width(message2) gives the original width) */
4509 XtSetArg(wargs
[0], XtNwidth
, &sarea
);
4510 XtGetValues(message2
, wargs
, 1);
4512 /* in the remote case that the string is longer than message widget, */
4513 /* truncate the string and denote the truncation with an ellipsis (...) */
4515 strcpy(tmpname
, curobject
->name
);
4516 swidth2
= XTextWidth(appdata
.xcfont
, editstr
, strlen(editstr
));
4517 swidth
= XTextWidth(appdata
.xcfont
, tmpname
, strlen(tmpname
));
4519 if ((swidth
+ swidth2
) > sarea
) {
4521 while ((swidth
+ swidth2
) > sarea
) {
4523 swidth
= XTextWidth(appdata
.xcfont
, sptr
, strlen(sptr
));
4525 for(ip
= sptr
; ip
< sptr
+ 3 && *ip
!= '\0'; ip
++) *ip
= '.';
4527 W2printf("Editing: %s", sptr
);
4532 /*--------------------------------------------------------------*/
4533 /* Make sure that a string does not conflict with postscript */
4534 /* names (commands and definitions found in xcircps2.pro). */
4536 /* Return value is NULL if no change was made. Otherwise, the */
4537 /* return value is an allocated string. */
4538 /*--------------------------------------------------------------*/
4540 char *checkvalidname(char *teststring
, objectptr newobj
)
4543 short dupl
; /* flag a duplicate string */
4545 char *sptr
, *pptr
, *cptr
;
4549 /* Try not to allocate memory unless necessary */
4556 if (newobj
!= NULL
) {
4557 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4558 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4559 libobj
= xobjs
.userlibs
[i
].library
+ j
;
4561 if (*libobj
== newobj
) continue;
4562 if (!strcmp(pptr
, (*libobj
)->name
)) {
4564 /* Prepend an underscore to the object name. If the */
4565 /* object has no technology, create a null technology */
4566 /* name. Otherwise, the technology remains the same */
4567 /* but the object name gets the prepended underscore. */
4569 if ((cptr
= strstr(pptr
, "::")) == NULL
) {
4570 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 4);
4571 sprintf(pptr
, "::_%s", (*libobj
)->name
);
4574 int offset
= cptr
- pptr
+ 2;
4576 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 2);
4578 pptr
= (char *)realloc(pptr
, strlen((*libobj
)->name
) + 2);
4579 sprintf(pptr
, "%s", (*libobj
)->name
);
4580 sprintf(pptr
+ offset
, "_%s", (*libobj
)->name
+ offset
);
4587 /* If we're in the middle of a file load, the name cannot be */
4588 /* the same as an alias, either. */
4590 if (aliastop
!= NULL
) {
4591 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
4592 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
) {
4593 if (!strcmp(pptr
, sref
->alias
)) {
4595 pptr
= (char *)malloc(strlen(sref
->alias
) + 2);
4597 pptr
= (char *)realloc(pptr
, strlen(sref
->alias
) + 2);
4598 sprintf(pptr
, "_%s", sref
->alias
);
4606 } while (dupl
== 1);
4608 return (pptr
== sptr
) ? NULL
: pptr
;
4611 /*--------------------------------------------------------------*/
4612 /* Make sure that name for new object does not conflict with */
4613 /* existing object definitions */
4615 /* Return: True if name required change, False otherwise */
4616 /*--------------------------------------------------------------*/
4618 Boolean
checkname(objectptr newobj
)
4622 /* Check for empty string */
4623 if (strlen(newobj
->name
) == 0) {
4624 Wprintf("Blank object name changed to default");
4625 sprintf(newobj
->name
, "user_object");
4628 pptr
= checkvalidname(newobj
->name
, newobj
);
4630 /* Change name if necessary to avoid naming conflicts */
4632 Wprintf("Created new object %s", newobj
->name
);
4636 Wprintf("Changed name from %s to %s to avoid conflict with "
4637 "existing object", newobj
->name
, pptr
);
4639 strncpy(newobj
->name
, pptr
, 79);
4645 /*------------------------------------------------------------*/
4646 /* Find the object "dot" in the builtin library, if it exists */
4647 /*------------------------------------------------------------*/
4655 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4656 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4657 dotobj
= *(xobjs
.userlibs
[i
].library
+ j
);
4658 name
= dotobj
->name
;
4659 if ((pptr
= strstr(name
, "::")) != NULL
) name
= pptr
+ 2;
4660 if (!strcmp(name
, "dot")) {
4665 return (objectptr
)NULL
;
4668 /*--------------------------------------*/
4669 /* Add value origin to all points */
4670 /*--------------------------------------*/
4672 void movepoints(genericptr
*ssgen
, short deltax
, short deltay
)
4674 switch(ELEMENTTYPE(*ssgen
)) {
4676 fpointlist sspoints
;
4677 TOARC(ssgen
)->position
.x
+= deltax
;
4678 TOARC(ssgen
)->position
.y
+= deltay
;
4679 for (sspoints
= TOARC(ssgen
)->points
; sspoints
< TOARC(ssgen
)->points
+
4680 TOARC(ssgen
)->number
; sspoints
++) {
4681 sspoints
->x
+= deltax
;
4682 sspoints
->y
+= deltay
;
4688 for (sspoints
= TOPOLY(ssgen
)->points
; sspoints
< TOPOLY(ssgen
)->points
+
4689 TOPOLY(ssgen
)->number
; sspoints
++) {
4690 sspoints
->x
+= deltax
;
4691 sspoints
->y
+= deltay
;
4696 fpointlist sspoints
;
4698 for (sspoints
= TOSPLINE(ssgen
)->points
; sspoints
<
4699 TOSPLINE(ssgen
)->points
+ INTSEGS
; sspoints
++) {
4700 sspoints
->x
+= deltax
;
4701 sspoints
->y
+= deltay
;
4703 for (j
= 0; j
< 4; j
++) {
4704 TOSPLINE(ssgen
)->ctrl
[j
].x
+= deltax
;
4705 TOSPLINE(ssgen
)->ctrl
[j
].y
+= deltay
;
4709 TOOBJINST(ssgen
)->position
.x
+= deltax
;
4710 TOOBJINST(ssgen
)->position
.y
+= deltay
;
4713 TOGRAPHIC(ssgen
)->position
.x
+= deltax
;
4714 TOGRAPHIC(ssgen
)->position
.y
+= deltay
;
4717 TOLABEL(ssgen
)->position
.x
+= deltax
;
4718 TOLABEL(ssgen
)->position
.y
+= deltay
;
4723 /*----------------------------------------------------------------------*/
4724 /* Add value origin to all edited points, according to edit flags */
4725 /*----------------------------------------------------------------------*/
4727 void editpoints(genericptr
*ssgen
, short deltax
, short deltay
)
4731 splineptr editspline
;
4732 short cycle
, cpoint
;
4737 switch(ELEMENTTYPE(*ssgen
)) {
4739 editpoly
= TOPOLY(ssgen
);
4740 if (editpoly
->cycle
== NULL
)
4741 movepoints(ssgen
, deltax
, deltay
);
4743 for (cptr
= editpoly
->cycle
;; cptr
++) {
4744 cycle
= cptr
->number
;
4745 curpt
= editpoly
->points
+ cycle
;
4746 if (cptr
->flags
& EDITX
) curpt
->x
+= deltax
;
4747 if (cptr
->flags
& EDITY
) curpt
->y
+= deltay
;
4748 if (cptr
->flags
& LASTENTRY
) break;
4755 editspline
= TOSPLINE(ssgen
);
4756 if (editspline
->cycle
== NULL
)
4757 movepoints(ssgen
, deltax
, deltay
);
4759 for (cptr
= editspline
->cycle
;; cptr
++) {
4760 cycle
= cptr
->number
;
4761 if (cycle
== 0 || cycle
== 3) {
4762 cpoint
= (cycle
== 0) ? 1 : 2;
4763 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cpoint
].x
+= deltax
;
4764 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cpoint
].y
+= deltay
;
4766 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cycle
].x
+= deltax
;
4767 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cycle
].y
+= deltay
;
4768 if (cptr
->flags
& ANTIXY
) {
4769 editspline
->ctrl
[cycle
].x
-= deltax
;
4770 editspline
->ctrl
[cycle
].y
-= deltay
;
4772 if (cptr
->flags
& LASTENTRY
) break;
4776 calcspline(editspline
);
4780 editpath
= TOPATH(ssgen
);
4781 if (checkcycle(*ssgen
, 0) < 0) {
4782 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4784 movepoints(ggen
, deltax
, deltay
);
4787 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4789 if (checkcycle(*ggen
, 0) >= 0)
4790 editpoints(ggen
, deltax
, deltay
);
4796 movepoints(ssgen
, deltax
, deltay
);
4804 void xlib_makeobject(xcWidget w
, caddr_t nulldata
)
4806 UNUSED(w
); UNUSED(nulldata
);
4808 domakeobject(-1, (char *)_STR2
, FALSE
);
4811 #endif /* !TCL_WRAPPER */
4813 /*--------------------------------------------------------------*/
4814 /* Set the name for a new user-defined object and make the */
4815 /* object. If "forceempty" is true, we allow creation of a new */
4816 /* object with no elements (normally would be used only from a */
4817 /* script, where an object is being constructed automatically). */
4818 /*--------------------------------------------------------------*/
4820 objinstptr
domakeobject(int libnum
, char *name
, Boolean forceempty
)
4823 objinstptr
*newinst
;
4825 oparamptr ops
, newop
;
4826 eparamptr epp
, newepp
;
4829 short loclibnum
= libnum
;
4831 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
4833 /* make room for new entry in library list */
4835 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
4836 realloc(xobjs
.userlibs
[loclibnum
].library
,
4837 (xobjs
.userlibs
[loclibnum
].number
+ 1) * sizeof(objectptr
));
4839 newobj
= xobjs
.userlibs
[loclibnum
].library
+ xobjs
.userlibs
[loclibnum
].number
;
4841 *newobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4842 areawin
->selects
, NORMAL
);
4844 if (*newobj
== NULL
) {
4847 if (!forceempty
) return NULL
;
4849 /* Create a new (empty) object */
4851 initobj
= (objectptr
) malloc(sizeof(object
));
4856 invalidate_netlist(topobject
);
4857 xobjs
.userlibs
[loclibnum
].number
++;
4859 /* Create the instance of this object so we can compute a bounding box */
4861 NEW_OBJINST(newinst
, topobject
);
4862 instancedefaults(*newinst
, *newobj
, 0, 0);
4865 /* find closest snap point to bbox center and make this the obj. center */
4867 if (areawin
->center
) {
4868 origin
.x
= (*newobj
)->bbox
.lowerleft
.x
+ (*newobj
)->bbox
.width
/ 2;
4869 origin
.y
= (*newobj
)->bbox
.lowerleft
.y
+ (*newobj
)->bbox
.height
/ 2;
4872 origin
.x
= origin
.y
= 0;
4875 instancedefaults(*newinst
, *newobj
, origin
.x
, origin
.y
);
4877 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4879 switch(ELEMENTTYPE(*ssgen
)) {
4882 TOOBJINST(ssgen
)->position
.x
-= origin
.x
;
4883 TOOBJINST(ssgen
)->position
.y
-= origin
.y
;
4887 TOGRAPHIC(ssgen
)->position
.x
-= origin
.x
;
4888 TOGRAPHIC(ssgen
)->position
.y
-= origin
.y
;
4892 TOLABEL(ssgen
)->position
.x
-= origin
.x
;
4893 TOLABEL(ssgen
)->position
.y
-= origin
.y
;
4897 genericptr
*pathlist
;
4898 for (pathlist
= TOPATH(ssgen
)->plist
; pathlist
< TOPATH(ssgen
)->plist
4899 + TOPATH(ssgen
)->parts
; pathlist
++) {
4900 movepoints(pathlist
, -origin
.x
, -origin
.y
);
4905 movepoints(ssgen
, -origin
.x
, -origin
.y
);
4910 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4912 for (epp
= (*ssgen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
4913 ops
= match_param(topobject
, epp
->key
);
4914 newop
= copyparameter(ops
);
4915 newop
->next
= (*newobj
)->params
;
4916 (*newobj
)->params
= newop
;
4918 /* Generate an indirect parameter reference from child to parent */
4919 newepp
= make_new_eparam(epp
->key
);
4920 newepp
->flags
|= P_INDIRECT
;
4921 newepp
->pdata
.refkey
= strdup(epp
->key
);
4922 newepp
->next
= (*newinst
)->passed
;
4923 (*newinst
)->passed
= newepp
;
4925 if (IS_LABEL(*ssgen
)) {
4926 /* Also need to check for substring parameters in labels */
4927 for (sptr
= TOLABEL(ssgen
)->string
; sptr
!= NULL
; sptr
= sptr
->nextpart
) {
4928 if (sptr
->type
== PARAM_START
) {
4929 ops
= match_param(topobject
, sptr
->data
.string
);
4931 newop
= copyparameter(ops
);
4932 newop
->next
= (*newobj
)->params
;
4933 (*newobj
)->params
= newop
;
4936 /* Generate an indirect parameter reference from child to parent */
4937 newepp
= make_new_eparam(sptr
->data
.string
);
4938 newepp
->flags
|= P_INDIRECT
;
4939 newepp
->pdata
.refkey
= strdup(sptr
->data
.string
);
4940 newepp
->next
= (*newinst
)->passed
;
4941 (*newinst
)->passed
= newepp
;
4947 /* any parameters in the top-level object that used by the selected */
4948 /* elements must be copied into the new object. */
4950 /* put new object back into place */
4952 (*newobj
)->hidden
= False
;
4953 (*newobj
)->schemtype
= SYMBOL
;
4956 incr_changes(*newobj
);
4958 /* (netlist invalidation was taken care of by delete_element() */
4959 /* Also, incr_changes(topobject) was done by delete_element()) */
4961 XTopSetForeground((*newinst
)->color
);
4962 UDrawObject(*newinst
, SINGLE
, (*newinst
)->color
,
4963 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
4966 /* Copy name into object and check for conflicts */
4968 strcpy((*newobj
)->name
, name
);
4971 /* register the technology and mark the technology as not saved */
4972 AddObjectTechnology(*newobj
);
4974 /* generate library instance for this object (bounding box */
4975 /* should be default, so don't do calcbbox() on it) */
4977 addtoinstlist(loclibnum
, *newobj
, FALSE
);
4979 /* recompile the user catalog and reset view bounds */
4981 composelib(loclibnum
+ LIBRARY
);
4982 centerview(xobjs
.libtop
[loclibnum
+ LIBRARY
]);
4989 /*-------------------------------------------*/
4990 /* Make a user object from selected elements */
4991 /*-------------------------------------------*/
4993 void selectsave(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
4995 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
4996 UNUSED(clientdata
); UNUSED(calldata
);
4998 if (areawin
->selects
== 0) return; /* nothing was selected */
5000 /* Get a name for the new object */
5002 eventmode
= NORMAL_MODE
;
5003 popdata
->dataptr
= NULL
;
5004 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
5005 popupprompt(w
, "Enter name for new object:", "\0", xlib_makeobject
, popdata
, NULL
);
5010 /*-----------------------------*/
5011 /* Edit-stack support routines */
5012 /*-----------------------------*/
5014 void arceditpush(arcptr lastarc
)
5018 NEW_ARC(newarc
, areawin
->editstack
);
5019 arccopy(*newarc
, lastarc
);
5020 copycycles(&((*newarc
)->cycle
), &(lastarc
->cycle
));
5023 /*--------------------------------------*/
5025 void splineeditpush(splineptr lastspline
)
5027 splineptr
*newspline
;
5029 NEW_SPLINE(newspline
, areawin
->editstack
);
5030 splinecopy(*newspline
, lastspline
);
5033 /*--------------------------------------*/
5035 void polyeditpush(polyptr lastpoly
)
5039 NEW_POLY(newpoly
, areawin
->editstack
);
5040 polycopy(*newpoly
, lastpoly
);
5043 /*--------------------------------------*/
5045 void patheditpush(pathptr lastpath
)
5049 NEW_PATH(newpath
, areawin
->editstack
);
5050 pathcopy(*newpath
, lastpath
);
5053 /*-----------------------------*/
5054 /* Copying support routines */
5055 /*-----------------------------*/
5057 pointlist
copypoints(pointlist points
, int number
)
5059 pointlist rpoints
, cpoints
, newpoints
;
5061 rpoints
= (pointlist
) malloc(number
* sizeof(XPoint
));
5062 for (newpoints
= rpoints
, cpoints
= points
;
5063 newpoints
< rpoints
+ number
;
5064 newpoints
++, cpoints
++) {
5065 newpoints
->x
= cpoints
->x
;
5066 newpoints
->y
= cpoints
->y
;
5071 /*------------------------------------------*/
5073 void graphiccopy(graphicptr newg
, graphicptr copyg
)
5078 newg
->source
= copyg
->source
;
5079 newg
->position
.x
= copyg
->position
.x
;
5080 newg
->position
.y
= copyg
->position
.y
;
5081 newg
->rotation
= copyg
->rotation
;
5082 newg
->scale
= copyg
->scale
;
5083 newg
->color
= copyg
->color
;
5084 newg
->passed
= NULL
;
5085 copyalleparams((genericptr
)newg
, (genericptr
)copyg
);
5087 newg
->valid
= FALSE
;
5088 newg
->target
= NULL
;
5089 newg
->clipmask
= (Pixmap
)NULL
;
5090 #endif /* HAVE_CAIRO */
5092 /* Update the refcount of the source image */
5093 for (i
= 0; i
< xobjs
.images
; i
++) {
5094 iptr
= xobjs
.imagelist
+ i
;
5095 if (iptr
->image
== newg
->source
) {
5102 /*------------------------------------------*/
5104 void labelcopy(labelptr newtext
, labelptr copytext
)
5106 newtext
->string
= stringcopy(copytext
->string
);
5107 newtext
->position
.x
= copytext
->position
.x
;
5108 newtext
->position
.y
= copytext
->position
.y
;
5109 newtext
->rotation
= copytext
->rotation
;
5110 newtext
->scale
= copytext
->scale
;
5111 newtext
->anchor
= copytext
->anchor
;
5112 newtext
->color
= copytext
->color
;
5113 newtext
->passed
= NULL
;
5114 newtext
->cycle
= NULL
;
5115 copyalleparams((genericptr
)newtext
, (genericptr
)copytext
);
5116 newtext
->pin
= copytext
->pin
;
5119 /*------------------------------------------*/
5121 void arccopy(arcptr newarc
, arcptr copyarc
)
5123 newarc
->style
= copyarc
->style
;
5124 newarc
->color
= copyarc
->color
;
5125 newarc
->position
.x
= copyarc
->position
.x
;
5126 newarc
->position
.y
= copyarc
->position
.y
;
5127 newarc
->radius
= copyarc
->radius
;
5128 newarc
->yaxis
= copyarc
->yaxis
;
5129 newarc
->angle1
= copyarc
->angle1
;
5130 newarc
->angle2
= copyarc
->angle2
;
5131 newarc
->width
= copyarc
->width
;
5132 newarc
->passed
= NULL
;
5133 newarc
->cycle
= NULL
;
5134 copyalleparams((genericptr
)newarc
, (genericptr
)copyarc
);
5138 /*------------------------------------------*/
5140 void polycopy(polyptr newpoly
, polyptr copypoly
)
5142 newpoly
->style
= copypoly
->style
;
5143 newpoly
->color
= copypoly
->color
;
5144 newpoly
->width
= copypoly
->width
;
5145 newpoly
->number
= copypoly
->number
;
5146 copycycles(&(newpoly
->cycle
), &(copypoly
->cycle
));
5147 newpoly
->points
= copypoints(copypoly
->points
, copypoly
->number
);
5149 newpoly
->passed
= NULL
;
5150 copyalleparams((genericptr
)newpoly
, (genericptr
)copypoly
);
5153 /*------------------------------------------*/
5155 void splinecopy(splineptr newspline
, splineptr copyspline
)
5159 newspline
->style
= copyspline
->style
;
5160 newspline
->color
= copyspline
->color
;
5161 newspline
->width
= copyspline
->width
;
5162 copycycles(&(newspline
->cycle
), &(copyspline
->cycle
));
5163 for (i
= 0; i
< 4; i
++) {
5164 newspline
->ctrl
[i
].x
= copyspline
->ctrl
[i
].x
;
5165 newspline
->ctrl
[i
].y
= copyspline
->ctrl
[i
].y
;
5167 for (i
= 0; i
< INTSEGS
; i
++) {
5168 newspline
->points
[i
].x
= copyspline
->points
[i
].x
;
5169 newspline
->points
[i
].y
= copyspline
->points
[i
].y
;
5171 newspline
->passed
= NULL
;
5172 copyalleparams((genericptr
)newspline
, (genericptr
)copyspline
);
5175 /*----------------------------------------------*/
5177 /*----------------------------------------------*/
5179 void pathcopy(pathptr newpath
, pathptr copypath
)
5182 splineptr
*newspline
, copyspline
;
5183 polyptr
*newpoly
, copypoly
;
5185 newpath
->style
= copypath
->style
;
5186 newpath
->color
= copypath
->color
;
5187 newpath
->width
= copypath
->width
;
5189 newpath
->passed
= NULL
;
5190 copyalleparams((genericptr
)newpath
, (genericptr
)copypath
);
5191 newpath
->plist
= (genericptr
*)malloc(copypath
->parts
* sizeof(genericptr
));
5193 for (ggen
= copypath
->plist
; ggen
< copypath
->plist
+ copypath
->parts
; ggen
++) {
5194 switch (ELEMENTTYPE(*ggen
)) {
5196 copypoly
= TOPOLY(ggen
);
5197 NEW_POLY(newpoly
, newpath
);
5198 polycopy(*newpoly
, copypoly
);
5201 copyspline
= TOSPLINE(ggen
);
5202 NEW_SPLINE(newspline
, newpath
);
5203 splinecopy(*newspline
, copyspline
);
5209 /*--------------------------------------------------------------*/
5210 /* Copy an object instance */
5211 /*--------------------------------------------------------------*/
5213 void instcopy(objinstptr newobj
, objinstptr copyobj
)
5215 newobj
->position
.x
= copyobj
->position
.x
;
5216 newobj
->position
.y
= copyobj
->position
.y
;
5217 newobj
->rotation
= copyobj
->rotation
;
5218 newobj
->scale
= copyobj
->scale
;
5219 newobj
->style
= copyobj
->style
;
5220 newobj
->thisobject
= copyobj
->thisobject
;
5221 newobj
->color
= copyobj
->color
;
5222 newobj
->bbox
.lowerleft
.x
= copyobj
->bbox
.lowerleft
.x
;
5223 newobj
->bbox
.lowerleft
.y
= copyobj
->bbox
.lowerleft
.y
;
5224 newobj
->bbox
.width
= copyobj
->bbox
.width
;
5225 newobj
->bbox
.height
= copyobj
->bbox
.height
;
5227 newobj
->passed
= NULL
;
5228 copyalleparams((genericptr
)newobj
, (genericptr
)copyobj
);
5230 newobj
->params
= NULL
;
5231 copyparams(newobj
, copyobj
);
5233 /* If the parameters are the same, the bounding box should be, too. */
5234 if (copyobj
->schembbox
!= NULL
) {
5235 newobj
->schembbox
= (BBox
*)malloc(sizeof(BBox
));
5236 newobj
->schembbox
->lowerleft
.x
= copyobj
->schembbox
->lowerleft
.x
;
5237 newobj
->schembbox
->lowerleft
.y
= copyobj
->schembbox
->lowerleft
.y
;
5238 newobj
->schembbox
->width
= copyobj
->schembbox
->width
;
5239 newobj
->schembbox
->height
= copyobj
->schembbox
->height
;
5242 newobj
->schembbox
= NULL
;
5245 /*--------------------------------------------------------------*/
5246 /* The method for removing objects from a list is to add the */
5247 /* value REMOVE_TAG to the type of each object needing to be */
5248 /* removed, and then calling this routine. */
5249 /*--------------------------------------------------------------*/
5251 void delete_tagged(objinstptr thisinst
) {
5252 Boolean tagged
= True
;
5253 objectptr thisobject
, delobj
;
5257 thisobject
= thisinst
->thisobject
;
5261 for (stmp
= 0; stmp
< thisobject
->parts
; stmp
++) {
5262 pgen
= thisobject
->plist
+ stmp
;
5263 if ((*pgen
)->type
& REMOVE_TAG
) {
5264 (*pgen
)->type
&= (~REMOVE_TAG
);
5267 delobj
= delete_element(thisinst
, &stmp
, 1, 0);
5268 register_for_undo(XCF_Delete
, UNDO_MORE
, thisinst
, delobj
, 0);
5270 /* If we destroy elements in the current window, we need to */
5271 /* make sure that the selection list is updated appropriately. */
5273 if ((thisobject
== topobject
) && (areawin
->selects
> 0)) {
5274 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5275 areawin
->selects
; sobj
++)
5276 if (*sobj
> stmp
) (*sobj
)--;
5279 /* Also ensure that this element is not referenced in any */
5280 /* netlist. If it is, remove it and mark the netlist as */
5283 remove_netlist_element(thisobject
, *pgen
);
5287 undo_finish_series();
5290 /*-----------------------------------------------------------------*/
5291 /* For copying: Check if an object is about to be placed directly */
5292 /* on top of the same object. If so, delete the one underneath. */
5293 /*-----------------------------------------------------------------*/
5298 genericptr
*sgen
, *pgen
;
5299 Boolean tagged
= False
;
5301 /* Work through the select list */
5303 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5304 areawin
->selects
; sobj
++) {
5305 sgen
= topobject
->plist
+ (*sobj
);
5307 /* For each object being copied, compare it against every object */
5308 /* on the current page (except self). Flag if it's the same. */
5310 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+ topobject
->parts
;
5312 if (pgen
== sgen
) continue;
5313 if (compare_single(sgen
, pgen
)) {
5314 /* Make sure that this object is not part of the selection, */
5315 /* else chaos will reign. */
5316 for (cobj
= areawin
->selectlist
; cobj
< areawin
->selectlist
+
5317 areawin
->selects
; cobj
++) {
5318 if (pgen
== topobject
->plist
+ (*cobj
)) break;
5320 /* Tag it for future deletion and prevent further compares */
5321 if (cobj
== areawin
->selectlist
+ areawin
->selects
) {
5323 (*pgen
)->type
|= REMOVE_TAG
;
5329 /* Delete the tagged elements */
5330 Wprintf("Duplicate object deleted");
5331 delete_tagged(areawin
->topinstance
);
5332 incr_changes(topobject
);
5336 /*--------------------------------------------------------------*/
5337 /* Direct placement of elements. Assumes that the selectlist */
5338 /* contains all the elements to be positioned. "deltax" and */
5339 /* "deltay" are relative x and y positions to move the */
5341 /*--------------------------------------------------------------*/
5343 void placeselects(short deltax
, short deltay
, XPoint
*userpt
)
5346 XPoint newpos
, *ppt
;
5353 doattach
= ((userpt
== NULL
) || (areawin
->attachto
< 0)) ? FALSE
: TRUE
;
5355 /* under attachto condition, keep element attached to */
5356 /* the attachto element. */
5358 if (doattach
) findattach(&newpos
, &rot
, userpt
);
5362 areawin
->clipped
= -1; /* Prevent clipping */
5363 #endif /* HAVE_CAIRO */
5365 for (dragselect
= areawin
->selectlist
; dragselect
< areawin
->selectlist
5366 + areawin
->selects
; dragselect
++) {
5368 switch(SELECTTYPE(dragselect
)) {
5370 objinstptr draginst
= SELTOOBJINST(dragselect
);
5373 draginst
->position
.x
= newpos
.x
;
5374 draginst
->position
.y
= newpos
.y
;
5375 while (rot
>= 360.0) rot
-= 360.0;
5376 while (rot
< 0.0) rot
+= 360.0;
5377 draginst
->rotation
= rot
;
5380 draginst
->position
.x
+= deltax
;
5381 draginst
->position
.y
+= deltay
;
5386 graphicptr dragg
= SELTOGRAPHIC(dragselect
);
5387 dragg
->position
.x
+= deltax
;
5388 dragg
->position
.y
+= deltay
;
5391 labelptr draglabel
= SELTOLABEL(dragselect
);
5393 draglabel
->position
.x
= newpos
.x
;
5394 draglabel
->position
.y
= newpos
.y
;
5395 draglabel
->rotation
= rot
;
5398 draglabel
->position
.x
+= deltax
;
5399 draglabel
->position
.y
+= deltay
;
5403 pathptr dragpath
= SELTOPATH(dragselect
);
5404 genericptr
*pathlist
;
5407 XPoint
*pdelta
= pathclosepoint(dragpath
, &newpos
);
5408 deltax
= newpos
.x
- pdelta
->x
;
5409 deltay
= newpos
.y
- pdelta
->y
;
5411 for (pathlist
= dragpath
->plist
; pathlist
< dragpath
->plist
5412 + dragpath
->parts
; pathlist
++) {
5413 movepoints(pathlist
, deltax
, deltay
);
5417 polyptr dragpoly
= SELTOPOLY(dragselect
);
5418 pointlist dragpoints
;
5420 /* if (dragpoly->cycle != NULL) continue; */
5422 closest
= closepoint(dragpoly
, &newpos
);
5423 deltax
= newpos
.x
- dragpoly
->points
[closest
].x
;
5424 deltay
= newpos
.y
- dragpoly
->points
[closest
].y
;
5426 for (dragpoints
= dragpoly
->points
; dragpoints
< dragpoly
->points
5427 + dragpoly
->number
; dragpoints
++) {
5428 dragpoints
->x
+= deltax
;
5429 dragpoints
->y
+= deltay
;
5433 splineptr dragspline
= SELTOSPLINE(dragselect
);
5435 fpointlist dragpoints
;
5437 /* if (dragspline->cycle != NULL) continue; */
5439 closest
= (wirelength(&dragspline
->ctrl
[0], &newpos
)
5440 > wirelength(&dragspline
->ctrl
[3], &newpos
)) ? 3 : 0;
5441 deltax
= newpos
.x
- dragspline
->ctrl
[closest
].x
;
5442 deltay
= newpos
.y
- dragspline
->ctrl
[closest
].y
;
5444 for (dragpoints
= dragspline
->points
; dragpoints
< dragspline
->
5445 points
+ INTSEGS
; dragpoints
++) {
5446 dragpoints
->x
+= deltax
;
5447 dragpoints
->y
+= deltay
;
5449 for (j
= 0; j
< 4; j
++) {
5450 dragspline
->ctrl
[j
].x
+= deltax
;
5451 dragspline
->ctrl
[j
].y
+= deltay
;
5455 arcptr dragarc
= SELTOARC(dragselect
);
5456 fpointlist dragpoints
;
5459 deltax
= newpos
.x
- dragarc
->position
.x
;
5460 deltay
= newpos
.y
- dragarc
->position
.y
;
5462 dragarc
->position
.x
+= deltax
;
5463 dragarc
->position
.y
+= deltay
;
5464 for (dragpoints
= dragarc
->points
; dragpoints
< dragarc
->
5465 points
+ dragarc
->number
; dragpoints
++) {
5466 dragpoints
->x
+= deltax
;
5467 dragpoints
->y
+= deltay
;
5473 if (areawin
->pinattach
) {
5474 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
5475 topobject
->parts
; pgen
++) {
5476 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
5477 cpoly
= TOPOLY(pgen
);
5478 if (cpoly
->cycle
!= NULL
) {
5479 ppt
= cpoly
->points
+ cpoly
->cycle
->number
;
5480 newpos
.x
= ppt
->x
+ deltax
;
5481 newpos
.y
= ppt
->y
+ deltay
;
5482 if (areawin
->manhatn
)
5483 manhattanize(&newpos
, cpoly
, cpoly
->cycle
->number
, FALSE
);
5491 move_mode_draw(xcDRAW_EDIT
, NULL
);
5494 areawin
->clipped
= 0;
5495 #endif /* HAVE_CAIRO */
5498 /*----------------------------------------------------------------------*/
5499 /* Copy handler. Assumes that the selectlist contains the elements */
5500 /* to be copied, and that the initial position of the copy is held */
5501 /* in areawin->save. */
5502 /*----------------------------------------------------------------------*/
5508 if (!checkselect_draw(ALL_TYPES
, True
)) return;
5509 u2u_snap(&areawin
->save
);
5510 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
5511 + areawin
->selects
; selectobj
++) {
5513 /* Cycles will not be used for copy mode: remove them */
5514 removecycle(topobject
->plist
+ (*selectobj
));
5516 switch(SELECTTYPE(selectobj
)) {
5517 case LABEL
: { /* copy label */
5518 labelptr copytext
= SELTOLABEL(selectobj
);
5521 NEW_LABEL(newtext
, topobject
);
5522 labelcopy(*newtext
, copytext
);
5524 case OBJINST
: { /* copy object instance */
5525 objinstptr copyobj
= SELTOOBJINST(selectobj
);
5527 NEW_OBJINST(newobj
, topobject
);
5528 instcopy(*newobj
, copyobj
);
5530 case GRAPHIC
: { /* copy graphic instance */
5531 graphicptr copyg
= SELTOGRAPHIC(selectobj
);
5533 NEW_GRAPHIC(newg
, topobject
);
5534 graphiccopy(*newg
, copyg
);
5536 case PATH
: { /* copy path */
5537 pathptr copypath
= SELTOPATH(selectobj
);
5539 NEW_PATH(newpath
, topobject
);
5540 pathcopy(*newpath
, copypath
);
5542 case ARC
: { /* copy arc */
5543 arcptr copyarc
= SELTOARC(selectobj
);
5545 NEW_ARC(newarc
, topobject
);
5546 arccopy(*newarc
, copyarc
);
5548 case POLYGON
: { /* copy polygons */
5549 polyptr copypoly
= SELTOPOLY(selectobj
);
5551 NEW_POLY(newpoly
, topobject
);
5552 polycopy(*newpoly
, copypoly
);
5554 case SPLINE
: { /* copy spline */
5555 splineptr copyspline
= SELTOSPLINE(selectobj
);
5556 splineptr
*newspline
;
5557 NEW_SPLINE(newspline
, topobject
);
5558 splinecopy(*newspline
, copyspline
);
5562 /* change selection from the old to the new object */
5564 *selectobj
= topobject
->parts
- 1;
5568 /*--------------------------------------------------------------*/
5569 /* Function which initiates interactive placement of copied */
5571 /*--------------------------------------------------------------*/
5575 if (areawin
->selects
> 0) {
5576 move_mode_draw(xcDRAW_INIT
, NULL
);
5577 if (eventmode
== NORMAL_MODE
) {
5578 XDefineCursor(dpy
, areawin
->window
, COPYCURSOR
);
5579 eventmode
= COPY_MODE
;
5581 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
5582 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5584 XtAddEventHandler(areawin
->area
, PointerMotionMask
|
5585 ButtonMotionMask
, False
, (XtEventHandler
)xlib_drag
,
5589 select_invalidate_netlist();
5593 /*-----------------------------------------------------------*/
5594 /* Copy handler for copying from a button push or key event. */
5595 /*-----------------------------------------------------------*/
5597 void copy_op(int op
, int x
, int y
)
5599 if (op
== XCF_Copy
) {
5600 window_to_user(x
, y
, &areawin
->save
);
5601 createcopies(); /* This function does all the hard work */
5602 copydrag(); /* Start interactive placement */
5605 eventmode
= NORMAL_MODE
;
5606 areawin
->attachto
= -1;
5609 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5610 ButtonMotionMask
, False
, (xcEventHandler
)xctk_drag
,
5613 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5614 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5617 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5618 u2u_snap(&areawin
->save
);
5619 if (op
== XCF_Cancel
) {
5620 move_mode_draw(xcDRAW_EMPTY
, NULL
);
5621 delete_noundo(NORMAL
);
5623 else if (op
== XCF_Finish_Copy
) {
5624 move_mode_draw(xcDRAW_FINAL
, NULL
);
5625 /* If selected objects are the only ones on the page, */
5626 /* then do a full bbox calculation. */
5627 if (topobject
->parts
== areawin
->selects
)
5628 calcbbox(areawin
->topinstance
);
5632 register_for_undo(XCF_Copy
, UNDO_MORE
, areawin
->topinstance
,
5633 areawin
->selectlist
, areawin
->selects
);
5635 incr_changes(topobject
);
5637 else { /* XCF_Continue_Copy */
5638 move_mode_draw(xcDRAW_FINAL
, NULL
);
5639 if (topobject
->parts
== areawin
->selects
)
5640 calcbbox(areawin
->topinstance
);
5644 register_for_undo(XCF_Copy
, UNDO_DONE
, areawin
->topinstance
,
5645 areawin
->selectlist
, areawin
->selects
);
5647 copydrag(); /* Start interactive placement again */
5648 incr_changes(topobject
);
5653 /*----------------------------------------------*/
5654 /* Check for more than one button being pressed */
5655 /*----------------------------------------------*/
5657 Boolean
checkmultiple(XButtonEvent
*event
)
5659 int state
= Button1Mask
| Button2Mask
| Button3Mask
|
5660 Button4Mask
| Button5Mask
;
5661 state
&= event
->state
;
5662 /* ((x - 1) & x) is always non-zero if x has more than one bit set */
5663 return (((state
- 1) & state
) == 0) ? False
: True
;
5666 /*----------------------------------------------------------------------*/
5667 /* Operation continuation---dependent upon the ongoing operation. */
5668 /* This operation only pertains to a few event modes for which */
5669 /* continuation of action makes sense---drawing wires (polygons), and */
5670 /* editing polygons, arcs, splines, and paths. */
5671 /*----------------------------------------------------------------------*/
5673 void continue_op(int op
, int x
, int y
)
5677 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5678 window_to_user(x
, y
, &areawin
->save
);
5681 printpos(ppos
.x
, ppos
.y
);
5690 case(EPATH_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5691 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5692 path_op(*(EDITPART
), op
, x
, y
);
5695 inst_op(*(EDITPART
), op
, x
, y
);
5698 finish_op(XCF_Finish_Element
, x
, y
);
5705 /*--------------------------------------------------------------*/
5706 /* Finish or cancel an operation. This forces a return to */
5707 /* "normal" mode, with whatever other side effects are caused */
5708 /* by the operation. */
5709 /*--------------------------------------------------------------*/
5711 void finish_op(int op
, int x
, int y
)
5715 XPoint snappt
, boxpts
[4];
5718 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5719 window_to_user(x
, y
, &areawin
->save
);
5722 case(EPATH_MODE
): case(BOX_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5723 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5724 path_op(*(EDITPART
), op
, x
, y
);
5728 inst_op(*(EDITPART
), op
, x
, y
);
5731 case (FONTCAT_MODE
):
5732 case (EFONTCAT_MODE
):
5733 fontcat_op(op
, x
, y
);
5734 eventmode
= (eventmode
== FONTCAT_MODE
) ? TEXT_MODE
: ETEXT_MODE
;
5735 text_mode_draw(xcDRAW_INIT
, TOLABEL(EDITPART
));
5736 XDefineCursor (dpy
, areawin
->window
, TEXTPTR
);
5741 catalog_op(op
, x
, y
);
5753 curlabel
= TOLABEL(EDITPART
);
5754 if (op
== XCF_Cancel
) {
5755 redrawtext(curlabel
);
5756 areawin
->redraw_needed
= False
; /* ignore previous requests */
5757 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5758 freelabel(curlabel
->string
);
5764 singlebbox(EDITPART
);
5765 incr_changes(topobject
);
5766 select_invalidate_netlist();
5767 text_mode_draw(xcDRAW_FINAL
, curlabel
);
5769 setdefaultfontmarks();
5770 eventmode
= NORMAL_MODE
;
5773 case(ETEXT_MODE
): case(CATTEXT_MODE
):
5774 curlabel
= TOLABEL(EDITPART
);
5775 if (op
== XCF_Cancel
) {
5776 /* restore the original text */
5777 undrawtext(curlabel
);
5778 undo_finish_series();
5780 redrawtext(curlabel
);
5781 areawin
->redraw_needed
= False
; /* ignore previous requests */
5782 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5783 if (eventmode
== CATTEXT_MODE
) eventmode
= CATALOG_MODE
;
5785 setdefaultfontmarks();
5787 else textreturn(); /* Generate "return" key character */
5788 areawin
->textend
= 0;
5792 u2u_snap(&areawin
->save
);
5794 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5795 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5797 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5798 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5801 if (op
== XCF_Cancel
) {
5802 /* Just regenerate the library where we started */
5803 if (areawin
->selects
>= 1) {
5804 objinstptr selinst
= SELTOOBJINST(areawin
->selectlist
);
5805 libnum
= libfindobject(selinst
->thisobject
, NULL
);
5807 composelib(libnum
+ LIBRARY
);
5814 eventmode
= CATALOG_MODE
;
5815 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5819 u2u_snap(&areawin
->save
);
5821 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5822 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5824 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5825 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5828 if (op
== XCF_Cancel
) {
5829 /* If we came from the library with an object instance, in */
5830 /* MOVE_MODE, then "cancel" should delete the element. */
5831 /* Otherwise, put the position of the element back to what */
5832 /* it was before we started the move. The difference is */
5833 /* indicated by the value of areawin->editpart. */
5835 if ((areawin
->selects
> 0) && (*areawin
->selectlist
== topobject
->parts
))
5836 delete_noundo(NORMAL
);
5838 placeselects(areawin
->origin
.x
- areawin
->save
.x
,
5839 areawin
->origin
.y
- areawin
->save
.y
, NULL
);
5841 drawarea(NULL
, NULL
, NULL
);
5844 if (areawin
->selects
> 0) {
5845 register_for_undo(XCF_Move
,
5846 /* (was_preselected) ? UNDO_DONE : UNDO_MORE, */
5848 areawin
->topinstance
,
5849 (int)(areawin
->save
.x
- areawin
->origin
.x
),
5850 (int)(areawin
->save
.y
- areawin
->origin
.y
));
5851 pwriteback(areawin
->topinstance
);
5852 incr_changes(topobject
);
5853 select_invalidate_netlist();
5854 unselect_all(); /* The way it used to be. . . */
5857 /* full calc needed: move may shrink bbox */
5858 calcbbox(areawin
->topinstance
);
5860 /* if (!was_preselected) clearselects(); */
5862 areawin
->attachto
= -1;
5868 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5869 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5871 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5872 ButtonMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5875 rescale_mode_draw(xcDRAW_FINAL
, NULL
);
5876 if (op
!= XCF_Cancel
) {
5877 XPoint newpoints
[5];
5878 fscale
= UGetRescaleBox(&areawin
->save
, newpoints
);
5880 elementrescale(fscale
);
5881 areawin
->redraw_needed
= True
;
5884 eventmode
= NORMAL_MODE
;
5888 selarea_mode_draw(xcDRAW_FINAL
, NULL
);
5891 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5892 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5894 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5895 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5898 /* Zero-width boxes act like a normal selection. Otherwise, */
5899 /* proceed with the area select. */
5901 if ((areawin
->origin
.x
== areawin
->save
.x
) &&
5902 (areawin
->origin
.y
== areawin
->save
.y
))
5903 select_add_element(ALL_TYPES
);
5905 boxpts
[0] = areawin
->origin
;
5906 boxpts
[1].x
= areawin
->save
.x
;
5907 boxpts
[1].y
= areawin
->origin
.y
;
5908 boxpts
[2] = areawin
->save
;
5909 boxpts
[3].x
= areawin
->origin
.x
;
5910 boxpts
[3].y
= areawin
->save
.y
;
5911 selectarea(topobject
, boxpts
, 0);
5916 u2u_snap(&areawin
->save
);
5919 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5920 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5922 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5923 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5926 areawin
->panx
= areawin
->pany
= 0;
5927 if (op
!= XCF_Cancel
)
5928 panbutton((u_int
) 5, (areawin
->width
>> 1) - (x
- areawin
->origin
.x
),
5929 (areawin
->height
>> 1) - (y
- areawin
->origin
.y
), 0);
5935 /* Remove any selections */
5936 if ((eventmode
== SELAREA_MODE
) || (eventmode
== PAN_MODE
)
5937 || (eventmode
== MOVE_MODE
))
5939 eventmode
= NORMAL_MODE
;
5940 areawin
->redraw_needed
= True
;
5942 else if (eventmode
!= MOVE_MODE
&& eventmode
!= EPATH_MODE
&&
5943 eventmode
!= EPOLY_MODE
&& eventmode
!= ARC_MODE
&&
5944 eventmode
!= EARC_MODE
&& eventmode
!= SPLINE_MODE
&&
5945 eventmode
!= ESPLINE_MODE
&& eventmode
!= WIRE_MODE
&&
5946 eventmode
!= ETEXT_MODE
&& eventmode
!= TEXT_MODE
) {
5950 if (eventmode
== NORMAL_MODE
) {
5952 /* Return any highlighted networks to normal */
5953 highlightnetlist(topobject
, areawin
->topinstance
, 0);
5955 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5958 snap(x
, y
, &snappt
);
5959 printpos(snappt
.x
, snappt
.y
);
5962 /*--------------------------------------------------------------*/
5963 /* Edit operations for instances. This is used to allow */
5964 /* numeric parameters to be adjusted from the hierarchical */
5965 /* level above, shielding the the unparameterized parts from */
5967 /*--------------------------------------------------------------*/
5969 void inst_op(genericptr editpart
, int op
, int x
, int y
)
5971 UNUSED(editpart
); UNUSED(op
); UNUSED(x
); UNUSED(y
);
5974 /*--------------------------------------------------------------*/
5975 /* Operations for path components */
5976 /*--------------------------------------------------------------*/
5978 void path_op(genericptr editpart
, int op
, int x
, int y
)
5981 splineptr newspline
;
5982 Boolean donecycles
= False
;
5983 UNUSED(x
); UNUSED(y
);
5985 /* Don't allow point cycling in a multi-part edit. */
5986 /* Allowing it is just confusing. Instead, we treat */
5987 /* button 1 (cycle) like button 2 (finish). */
5988 if (op
== XCF_Continue_Element
&& areawin
->selects
> 1)
5989 op
= XCF_Finish_Element
;
5991 switch(ELEMENTTYPE(editpart
)) {
5993 pathptr newpath
= (pathptr
)editpart
;
5994 short dotrack
= True
;
5997 areawin
->attachto
= -1;
5999 if (op
!= XCF_Continue_Element
) {
6002 if (op
== XCF_Continue_Element
) {
6003 nextpathcycle(newpath
, 1);
6004 patheditpush(newpath
);
6006 else if (op
== XCF_Finish_Element
) {
6007 path_mode_draw(xcDRAW_FINAL
, newpath
);
6008 incr_changes(topobject
);
6010 else { /* restore previous path from edit stack */
6011 free_single((genericptr
)newpath
);
6012 if (areawin
->editstack
->parts
> 0) {
6013 if (op
== XCF_Cancel
) {
6014 editpath
= TOPATH(areawin
->editstack
->plist
);
6015 pathcopy(newpath
, editpath
);
6016 reset(areawin
->editstack
, NORMAL
);
6019 editpath
= TOPATH(areawin
->editstack
->plist
+
6020 areawin
->editstack
->parts
- 1);
6021 pathcopy(newpath
, editpath
);
6022 free_single((genericptr
)editpath
);
6024 areawin
->editstack
->parts
--;
6026 if (areawin
->editstack
->parts
> 0) {
6028 nextpathcycle(newpath
, 1);
6029 path_mode_draw(xcDRAW_EDIT
, newpath
);
6033 user_to_window(areawin
->origin
, &warppt
);
6034 warppointer(warppt
.x
, warppt
.y
);
6035 path_mode_draw(xcDRAW_FINAL
, newpath
);
6039 path_mode_draw(xcDRAW_EMPTY
, newpath
);
6041 free_single((genericptr
)newpath
);
6045 pwriteback(areawin
->topinstance
);
6048 /* Free the editstack */
6049 reset(areawin
->editstack
, NORMAL
);
6050 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6051 (xcEventHandler
)trackelement
, NULL
);
6052 eventmode
= NORMAL_MODE
;
6058 if (eventmode
== BOX_MODE
) {
6061 newbox
= (polyptr
)editpart
;
6063 /* prevent length and/or width zero boxes */
6064 if (newbox
->points
->x
!= (newbox
->points
+ 2)->x
&& (newbox
->points
6065 + 1)->y
!= (newbox
->points
+ 3)->y
) {
6066 if (op
!= XCF_Cancel
) {
6067 poly_mode_draw(xcDRAW_FINAL
, newbox
);
6068 incr_changes(topobject
);
6069 if (!nonnetwork(newbox
)) invalidate_netlist(topobject
);
6070 register_for_undo(XCF_Box
, UNDO_MORE
, areawin
->topinstance
,
6074 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6075 free_single((genericptr
)newbox
);
6082 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6083 free_single((genericptr
)newbox
);
6088 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6089 (xcEventHandler
)trackbox
, NULL
);
6090 eventmode
= NORMAL_MODE
;
6092 else { /* EPOLY_MODE */
6094 short dotrack
= True
;
6096 newpoly
= (polyptr
)editpart
;
6097 areawin
->attachto
= -1;
6099 if (op
!= XCF_Continue_Element
) {
6103 if (op
== XCF_Continue_Element
) {
6104 nextpolycycle(&newpoly
, 1);
6105 polyeditpush(newpoly
);
6107 else if (op
== XCF_Finish_Element
) {
6109 /* Check for degenerate polygons (all points the same). */
6111 for (i
= 1; i
< newpoly
->number
; i
++)
6112 if ((newpoly
->points
[i
].x
!= newpoly
->points
[i
- 1].x
) ||
6113 (newpoly
->points
[i
].y
!= newpoly
->points
[i
- 1].y
))
6115 if (i
== newpoly
->number
) {
6116 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6117 /* Remove this polygon with the standard delete */
6118 /* method (saves polygon on undo stack). */
6119 newpoly
->type
|= REMOVE_TAG
;
6120 delete_tagged(areawin
->topinstance
);
6123 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6124 if (!nonnetwork(newpoly
)) invalidate_netlist(topobject
);
6125 incr_changes(topobject
);
6130 free_single((genericptr
)newpoly
);
6131 if (areawin
->editstack
->parts
> 0) {
6132 if (op
== XCF_Cancel
) {
6133 editpoly
= TOPOLY(areawin
->editstack
->plist
);
6134 polycopy(newpoly
, editpoly
);
6135 reset(areawin
->editstack
, NORMAL
);
6138 editpoly
= TOPOLY(areawin
->editstack
->plist
+
6139 areawin
->editstack
->parts
- 1);
6140 polycopy(newpoly
, editpoly
);
6141 free_single((genericptr
)editpoly
);
6143 areawin
->editstack
->parts
--;
6145 if (areawin
->editstack
->parts
> 0) {
6147 nextpolycycle(&newpoly
, -1);
6148 poly_mode_draw(xcDRAW_EDIT
, newpoly
);
6151 XcTopSetForeground(newpoly
->color
);
6152 user_to_window(areawin
->origin
, &warppt
);
6153 warppointer(warppt
.x
, warppt
.y
);
6154 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6158 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6163 pwriteback(areawin
->topinstance
);
6166 /* Free the editstack */
6167 reset(areawin
->editstack
, NORMAL
);
6169 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6170 (xcEventHandler
)trackelement
, NULL
);
6171 eventmode
= NORMAL_MODE
;
6178 arcptr newarc
, editarc
;
6179 short dotrack
= True
;
6181 newarc
= (arcptr
)editpart
;
6183 if (op
!= XCF_Continue_Element
) {
6187 if (op
== XCF_Continue_Element
) {
6188 nextarccycle(&newarc
, 1);
6189 arceditpush(newarc
);
6192 else if (op
== XCF_Finish_Element
) {
6195 if (newarc
->radius
!= 0 && newarc
->yaxis
!= 0 &&
6196 (newarc
->angle1
!= newarc
->angle2
)) {
6197 XTopSetForeground(newarc
->color
);
6198 incr_changes(topobject
);
6199 if (eventmode
== ARC_MODE
) {
6200 register_for_undo(XCF_Arc
, UNDO_MORE
, areawin
->topinstance
,
6203 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6207 /* Remove the record if the radius is zero. If we were */
6208 /* creating the arc, just delete it; it's as if it */
6209 /* never existed. If we were editing an arc, use the */
6210 /* standard delete method (saves arc on undo stack). */
6212 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6213 if (eventmode
== ARC_MODE
) {
6214 free_single((genericptr
)newarc
);
6219 newarc
->type
|= REMOVE_TAG
;
6220 delete_tagged(areawin
->topinstance
);
6224 else { /* Cancel: restore previous arc from edit stack */
6225 free_single((genericptr
)newarc
);
6226 if (areawin
->editstack
->parts
> 0) {
6227 if (op
== XCF_Cancel
) {
6228 editarc
= TOARC(areawin
->editstack
->plist
);
6229 arccopy(newarc
, editarc
);
6230 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6231 reset(areawin
->editstack
, NORMAL
);
6234 editarc
= TOARC(areawin
->editstack
->plist
+
6235 areawin
->editstack
->parts
- 1);
6236 arccopy(newarc
, editarc
);
6237 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6238 free_single((genericptr
)editarc
);
6240 areawin
->editstack
->parts
--;
6242 if (areawin
->editstack
->parts
> 0) {
6244 nextarccycle(&newarc
, -1);
6245 arc_mode_draw(xcDRAW_EDIT
, newarc
);
6248 if (eventmode
!= ARC_MODE
) {
6250 user_to_window(areawin
->origin
, &warppt
);
6251 warppointer(warppt
.x
, warppt
.y
);
6253 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6257 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6261 pwriteback(areawin
->topinstance
);
6264 /* Free the editstack */
6265 reset(areawin
->editstack
, NORMAL
);
6267 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6268 (xcEventHandler
)trackarc
, NULL
);
6269 eventmode
= NORMAL_MODE
;
6274 splineptr editspline
;
6275 short dotrack
= True
;
6277 newspline
= (splineptr
)editpart
;
6279 if (op
!= XCF_Continue_Element
) {
6283 if (op
== XCF_Continue_Element
) {
6284 /* Note: we work backwards through spline control points. */
6285 /* The reason is that when creating a spline, the sudden */
6286 /* move from the endpoint to the startpoint (forward */
6287 /* direction) is more disorienting than moving from the */
6288 /* endpoint to the endpoint's control point. */
6290 nextsplinecycle(&newspline
, -1);
6291 splineeditpush(newspline
);
6294 /* unlikely but possible to create zero-length splines */
6295 else if (newspline
->ctrl
[0].x
!= newspline
->ctrl
[3].x
||
6296 newspline
->ctrl
[0].x
!= newspline
->ctrl
[1].x
||
6297 newspline
->ctrl
[0].x
!= newspline
->ctrl
[2].x
||
6298 newspline
->ctrl
[0].y
!= newspline
->ctrl
[3].y
||
6299 newspline
->ctrl
[0].y
!= newspline
->ctrl
[1].y
||
6300 newspline
->ctrl
[0].y
!= newspline
->ctrl
[2].y
) {
6301 if (op
== XCF_Finish_Element
) {
6302 incr_changes(topobject
);
6303 if (eventmode
== SPLINE_MODE
) {
6304 register_for_undo(XCF_Spline
, UNDO_MORE
, areawin
->topinstance
,
6307 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6309 else { /* restore previous spline from edit stack */
6310 free_single((genericptr
)newspline
);
6311 if (areawin
->editstack
->parts
> 0) {
6312 if (op
== XCF_Cancel
) {
6313 editspline
= TOSPLINE(areawin
->editstack
->plist
);
6314 splinecopy(newspline
, editspline
);
6315 reset(areawin
->editstack
, NORMAL
);
6318 editspline
= TOSPLINE(areawin
->editstack
->plist
+
6319 areawin
->editstack
->parts
- 1);
6320 splinecopy(newspline
, editspline
);
6321 free_single((genericptr
)editspline
);
6323 areawin
->editstack
->parts
--;
6325 if (areawin
->editstack
->parts
> 0) {
6327 nextsplinecycle(&newspline
, 1);
6328 spline_mode_draw(xcDRAW_EDIT
, newspline
);
6331 if (eventmode
!= SPLINE_MODE
) {
6333 user_to_window(areawin
->origin
, &warppt
);
6334 warppointer(warppt
.x
, warppt
.y
);
6336 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6340 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6346 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6347 free_single((genericptr
)newspline
);
6351 pwriteback(areawin
->topinstance
);
6354 /* Free the editstack */
6355 reset(areawin
->editstack
, NORMAL
);
6357 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6358 (xcEventHandler
)trackelement
, NULL
);
6359 eventmode
= NORMAL_MODE
;
6364 calcbbox(areawin
->topinstance
);
6366 /* Multiple-element edit: Some items may have been moved as */
6367 /* opposed to edited, and should be registered here. To do */
6368 /* this correctly, we must first unselect the edited items, */
6369 /* then register the move for the remaining items. */
6374 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6375 areawin
->selects
; eselect
++)
6376 checkcycle(SELTOGENERIC(eselect
), 0);
6378 /* Remove all (remaining) cycles */
6379 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6380 areawin
->selects
; eselect
++)
6381 removecycle(SELTOGENERICPTR(eselect
));
6383 /* Remove edits from the undo stack when canceling */
6384 if (op
== XCF_Cancel
|| op
== XCF_Cancel_Last
) {
6385 if (xobjs
.undostack
&& (xobjs
.undostack
->type
== XCF_Edit
)) {
6386 undo_finish_series();
6393 /*-------------------------------------------------------*/
6394 /* Recalculate values for a drawing-area widget resizing */
6395 /*-------------------------------------------------------*/
6397 void resizearea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6403 int savewidth
= areawin
->width
, saveheight
= areawin
->height
;
6404 XCWindowData
*thiswin
;
6407 #endif /* !HAVE_CAIRO */
6408 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6410 if ((dpy
!= NULL
) && xcIsRealized(areawin
->area
)) {
6413 areawin
->width
= Tk_Width(w
);
6414 areawin
->height
= Tk_Height(w
);
6416 XtSetArg(wargs
[0], XtNwidth
, &areawin
->width
);
6417 XtSetArg(wargs
[1], XtNheight
, &areawin
->height
);
6418 XtGetValues(areawin
->area
, wargs
, 2);
6421 if (areawin
->width
!= savewidth
|| areawin
->height
!= saveheight
) {
6423 int maxwidth
= 0, maxheight
= 0;
6424 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6425 if (thiswin
->width
> maxwidth
) maxwidth
= thiswin
->width
;
6426 if (thiswin
->height
> maxheight
) maxheight
= thiswin
->height
;
6428 #if !defined(HAVE_CAIRO)
6429 if (dbuf
!= (Pixmap
)NULL
) XFreePixmap(dpy
, dbuf
);
6430 dbuf
= XCreatePixmap(dpy
, areawin
->window
, maxwidth
, maxheight
,
6431 DefaultDepthOfScreen(xcScreen(w
)));
6434 /* TODO: probably make this a generalized function call, which */
6435 /* should be handled depending on the surface in the xtgui.c, */
6436 /* xcwin32.c, etc. files. */
6437 /* For now only support xlib surface */
6438 cairo_xlib_surface_set_size(areawin
->surface
, areawin
->width
,
6441 if (areawin
->clipmask
!= (Pixmap
)NULL
) XFreePixmap(dpy
, areawin
->clipmask
);
6442 areawin
->clipmask
= XCreatePixmap(dpy
, areawin
->window
,
6443 maxwidth
, maxheight
, 1);
6445 if (areawin
->pbuf
!= (Pixmap
)NULL
) {
6446 XFreePixmap(dpy
, areawin
->pbuf
);
6447 areawin
->pbuf
= XCreatePixmap(dpy
, areawin
->window
,
6448 maxwidth
, maxheight
, 1);
6451 if (areawin
->cmgc
!= (GC
)NULL
) XFreeGC(dpy
, areawin
->cmgc
);
6452 values
.foreground
= 0;
6453 values
.background
= 0;
6454 areawin
->cmgc
= XCreateGC(dpy
, areawin
->clipmask
,
6455 GCForeground
| GCBackground
, &values
);
6456 #endif /* !HAVE_CAIRO */
6458 /* Clear fixed_pixmap */
6459 if (areawin
->fixed_pixmap
) {
6461 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6462 areawin
->fixed_pixmap
= NULL
;
6463 #else /* !HAVE_CAIRO */
6464 XFreePixmap(dpy
, areawin
->fixed_pixmap
);
6465 areawin
->fixed_pixmap
= (Pixmap
) NULL
;
6466 #endif /* !HAVE_CAIRO */
6471 /* Re-compose the directores to match the new dimensions */
6473 composelib(PAGELIB
);
6475 /* Re-center image in resized window */
6476 zoomview(NULL
, NULL
, NULL
);
6479 /* Flush all expose events from the buffer */
6480 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
) == True
);
6484 /*----------------------*/
6485 /* Draw the grids, etc. */
6486 /*----------------------*/
6489 void draw_grids(void)
6491 float x
, y
, spc
, spc2
, i
, j
, fpart
;
6492 float major_snapspace
, spc3
;
6494 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
6495 if (areawin
->gridon
&& spc
> 8) {
6496 fpart
= (float)(-areawin
->pcorner
.x
)
6497 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6498 x
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6499 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6500 fpart
= (float)(-areawin
->pcorner
.y
)
6501 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6502 y
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6503 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6505 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6506 for (i
= x
; i
< (float)areawin
->width
; i
+= spc
)
6507 DrawLine (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6508 0, (int)(i
+ 0.5), areawin
->height
);
6509 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc
)
6510 DrawLine (dpy
, areawin
->window
, areawin
->gc
, 0, (int)(j
- 0.5),
6511 areawin
->width
, (int)(j
- 0.5));
6514 if (areawin
->axeson
) {
6515 XPoint originpt
, zeropt
;
6516 zeropt
.x
= zeropt
.y
= 0;
6517 SetForeground(dpy
, areawin
->gc
, AXESCOLOR
);
6518 user_to_window(zeropt
, &originpt
);
6519 DrawLine(dpy
, areawin
->window
, areawin
->gc
, originpt
.x
, 0,
6520 originpt
.x
, areawin
->height
);
6521 DrawLine(dpy
, areawin
->window
, areawin
->gc
, 0, originpt
.y
,
6522 areawin
->width
, originpt
.y
);
6525 /* bounding box goes beneath everything except grid/axis lines */
6528 /* draw a little red dot at each snap-to point */
6530 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
6531 if (areawin
->snapto
&& spc2
> 8) {
6534 fpart
= (float)(-areawin
->pcorner
.x
)
6535 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6536 x2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6537 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6538 fpart
= (float)(-areawin
->pcorner
.y
)
6539 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6540 y2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6541 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6543 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6545 HDC hdc
= CreateCompatibleDC(NULL
);
6546 SelectObject(hdc
, Tk_GetHWND(areawin
->window
));
6548 SetForeground(dpy
, areawin
->gc
, SNAPCOLOR
);
6549 for (i
= x2
; i
< areawin
->width
; i
+= spc2
)
6550 for (j
= areawin
->height
- y2
; j
> 0; j
-= spc2
)
6551 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6552 SetPixelV(hdc
, (int)(i
+ 0.5), (int)(j
- 0.05), areawin
->gc
->foreground
);
6554 DrawPoint (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6556 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6562 /* Draw major snap points (code contributed by John Barry) */
6564 major_snapspace
= xobjs
.pagelist
[areawin
->page
]->gridspace
* 20;
6565 spc3
= major_snapspace
* areawin
->vscale
;
6567 fpart
= (float)(-areawin
->pcorner
.x
) / major_snapspace
;
6568 x
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6569 fpart
= (float)(-areawin
->pcorner
.y
) / major_snapspace
;
6570 y
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6572 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6573 for (i
= x
; i
< (float)areawin
->width
; i
+= spc3
) {
6574 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc3
) {
6575 XDrawArc(dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5) - 1,
6576 (int)(j
- 0.5) - 1, 2, 2, 0, 360*64);
6581 SetBackground(dpy
, areawin
->gc
, BACKGROUND
);
6583 #endif /* !HAVE_CAIRO */
6585 /*------------------------------------------------------*/
6586 /* Draw fixed parts of the primary graphics window */
6587 /*------------------------------------------------------*/
6589 void draw_fixed(void)
6591 Boolean old_ongoing
;
6594 #endif /* !HAVE_CAIRO */
6596 if (xobjs
.suspend
>= 0) return;
6597 old_ongoing
= areawin
->redraw_ongoing
;
6598 areawin
->redraw_ongoing
= True
;
6600 /* Set drawing context to fixed_pixmap */
6602 cairo_identity_matrix(areawin
->cr
);
6603 cairo_push_group(areawin
->cr
);
6604 #else /* HAVE_CAIRO */
6605 old_window
= areawin
->window
;
6606 areawin
->window
= areawin
->fixed_pixmap
;
6607 #endif /* HAVE_CAIRO */
6609 /* Clear background */
6611 if (xobjs
.pagelist
[areawin
->page
]->background
.name
!= (char *)NULL
) {
6615 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6616 cairo_paint(areawin
->cr
);
6617 #endif /* HAVE_GS */
6620 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6621 cairo_paint(areawin
->cr
);
6623 #else /* HAVE_CAIRO */
6624 if (xobjs
.pagelist
[areawin
->page
]->background
.name
== (char *)NULL
6625 || (copybackground() < 0)) {
6626 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6627 XFillRectangle(dpy
, areawin
->window
, areawin
->gc
, 0, 0, areawin
->width
,
6630 SetThinLineAttributes(dpy
, areawin
->gc
, 0, LineSolid
, CapRound
, JoinBevel
);
6631 #endif /* !HAVE_CAIRO */
6635 /* draw GRIDCOLOR lines for grid; mark axes in AXESCOLOR */
6637 if (eventmode
!= CATALOG_MODE
&& eventmode
!= ASSOC_MODE
6638 && eventmode
!= FONTCAT_MODE
&& eventmode
!= EFONTCAT_MODE
6639 && eventmode
!= CATMOVE_MODE
&& eventmode
!= CATTEXT_MODE
) {
6643 /* Determine the transformation matrix for the topmost object */
6644 /* and draw the hierarchy above the current edit object (if */
6645 /* "edit-in-place" is selected). */
6647 if (areawin
->editinplace
== True
) {
6648 if (areawin
->stack
!= NULL
) {
6649 pushlistptr lastlist
= NULL
, thislist
;
6652 UPushCTM(); /* save our current state */
6654 /* It's easiest if we first push the current page onto the stack, */
6655 /* then we don't need to treat the top-level page separately. We */
6656 /* pop it at the end. */
6657 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
6659 thislist
= areawin
->stack
;
6661 while ((thislist
!= NULL
) &&
6662 (is_library(thislist
->thisinst
->thisobject
) < 0)) {
6664 /* Invert the transformation matrix of the instance on the stack */
6665 /* to get the proper transformation matrix of the drawing one */
6666 /* up in the hierarchy. */
6669 UPreMultCTM(&mtmp
, thislist
->thisinst
->position
,
6670 thislist
->thisinst
->scale
, thislist
->thisinst
->rotation
);
6672 UPreMultCTMbyMat(DCTM
, &mtmp
);
6674 lastlist
= thislist
;
6675 thislist
= thislist
->next
;
6677 /* The following will be true for moves between schematics and symbols */
6678 if ((thislist
!= NULL
) && (thislist
->thisinst
->thisobject
->symschem
6679 == lastlist
->thisinst
->thisobject
))
6683 if (lastlist
!= NULL
) {
6684 pushlistptr stack
= NULL
;
6685 SetForeground(dpy
, areawin
->gc
, OFFBUTTONCOLOR
);
6686 UDrawObject(lastlist
->thisinst
, SINGLE
, DOFORALL
,
6687 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &stack
);
6688 /* This shouldn't happen, but just in case. . . */
6689 if (stack
) free_stack(&stack
);
6692 pop_stack(&areawin
->stack
); /* restore the original stack state */
6693 UPopCTM(); /* restore the original matrix state */
6698 /* draw all of the elements on the screen */
6700 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
6702 /* Initialize hierstack */
6703 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6704 UDrawObject(areawin
->topinstance
, TOPLEVEL
, FOREGROUND
,
6705 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &areawin
->hierstack
);
6706 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6709 if (areawin
->fixed_pixmap
)
6710 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6711 areawin
->fixed_pixmap
= cairo_pop_group(areawin
->cr
);
6712 #else /* HAVE_CAIRO */
6713 areawin
->window
= old_window
;
6714 #endif /* HAVE_CAIRO */
6715 areawin
->redraw_ongoing
= old_ongoing
;
6718 /*--------------------------------------*/
6719 /* Draw the primary graphics window */
6720 /*--------------------------------------*/
6722 void drawwindow(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6725 xcDrawType redrawtype
= xcDRAW_EDIT
;
6726 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6728 if (areawin
->area
== NULL
) return;
6729 if (!xcIsRealized(areawin
->area
)) return;
6730 if (xobjs
.suspend
>= 0) return;
6733 /* Make sure a fixed pixmap exists */
6734 if (!areawin
->fixed_pixmap
) {
6735 areawin
->fixed_pixmap
= XCreatePixmap(dpy
, areawin
->window
,
6736 areawin
->width
, areawin
->height
,
6737 DefaultDepthOfScreen(xcScreen(areawin
->area
)));
6739 #endif /* !HAVE_CAIRO */
6741 /* Sanity check---specifically to track down an error */
6742 if ((areawin
->selects
== 1) && *(areawin
->selectlist
) >= topobject
->parts
) {
6743 Wprintf("Internal error!");
6744 areawin
->selects
= 0;
6748 if (areawin
->redraw_needed
)
6749 redrawtype
= xcREDRAW_FORCED
;
6751 switch (eventmode
) {
6752 case ARC_MODE
: case EARC_MODE
:
6753 arc_mode_draw(redrawtype
, TOARC(EDITPART
));
6755 case SPLINE_MODE
: case ESPLINE_MODE
:
6756 spline_mode_draw(redrawtype
, TOSPLINE(EDITPART
));
6758 case BOX_MODE
: case EPOLY_MODE
: case WIRE_MODE
:
6759 poly_mode_draw(redrawtype
, TOPOLY(EDITPART
));
6762 path_mode_draw(redrawtype
, TOPATH(EDITPART
));
6764 case TEXT_MODE
: case CATTEXT_MODE
: case ETEXT_MODE
:
6765 text_mode_draw(redrawtype
, TOLABEL(EDITPART
));
6768 selarea_mode_draw(redrawtype
, NULL
);
6771 rescale_mode_draw(redrawtype
, NULL
);
6773 case CATMOVE_MODE
: case MOVE_MODE
: case COPY_MODE
:
6774 move_mode_draw(redrawtype
, NULL
);
6776 case ASSOC_MODE
: case EINST_MODE
: case FONTCAT_MODE
: case EFONTCAT_MODE
:
6777 case PAN_MODE
: case NORMAL_MODE
: case UNDO_MODE
: case CATALOG_MODE
:
6778 normal_mode_draw(redrawtype
, NULL
);
6781 /* flush out multiple expose/resize events from the event queue */
6782 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
));
6784 /* end by restoring graphics state */
6785 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
6787 areawin
->redraw_needed
= False
;
6790 /*----------------------------------------------------------------------*/
6791 /* Draw the current window (areawin). Check if other windows contain */
6792 /* the same object or one of its ancestors. If so, redraw them, too. */
6793 /*----------------------------------------------------------------------*/
6795 void drawarea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6797 XCWindowDataPtr thiswin
, focuswin
;
6799 if (xobjs
.suspend
>= 0) {
6800 if (xobjs
.suspend
== 0)
6801 xobjs
.suspend
= 1; /* Mark that a refresh is pending */
6807 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6808 if (thiswin
== focuswin
) continue;
6810 /* Note: need to check ancestry here, not just blindly redraw */
6811 /* all the windows all the time. */
6815 /* Don't respond to an expose event if the graphics context */
6816 /* has not yet been created. */
6817 if (areawin
->cr
!= NULL
)
6819 drawwindow(NULL
, NULL
, NULL
);
6822 drawwindow(w
, clientdata
, calldata
);
6825 /*-------------------------------------------------------------------------*/