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(event
, _STR
, 150, &keypressed
, NULL
);
2404 /* Ignore Shift, Control, Caps Lock, and Meta (Alt) keys */
2405 /* when pressed alone. */
2407 if (keypressed
== XK_Control_L
|| keypressed
== XK_Control_R
||
2408 keypressed
== XK_Alt_L
|| keypressed
== XK_Alt_R
||
2409 keypressed
== XK_Caps_Lock
|| keypressed
== XK_Shift_L
||
2410 keypressed
== XK_Shift_R
)
2413 /* Only keep key state information pertaining to Shift, Caps Lock, */
2414 /* Control, and Alt (Meta) */
2416 keywstate
= (keypressed
& 0xffff);
2418 /* Convert codes outside the character (0 - 255) range but within */
2419 /* the ISO-Latin1,...,9 encoding scheme (256-5120). X11 has unique */
2420 /* keysyms for each character, but the ISO-Latin encodings define */
2421 /* mappings to the 8-bit (256) character set. */
2423 if (keywstate
>= 256 && keywstate
< 5120)
2424 keywstate
= XKeysymToKeycode(dpy
, (KeySym
)keywstate
);
2426 if (event
->keycode
!= 0) { /* Only for actual key events */
2428 /* Get keyboard input method */
2430 xim
= XOpenIM(dpy
, 0, 0, 0);
2431 xic
= XCreateIC(xim
,
2432 XNInputStyle
, XIMPreeditNothing
| XIMStatusNothing
,
2433 XNClientWindow
, areawin
->window
,
2434 XNFocusWindow
, areawin
->window
,
2439 /* Do a UTF-8 code lookup */
2440 Xutf8LookupString(xic
, event
, buffer
, 15, &keysym
, &status
);
2441 /* Convert a UTF-8 code to a known encoding */
2442 utf8enc
= utf8_reverse_lookup(buffer
);
2443 if ((utf8enc
!= -1) && (utf8enc
!= (keywstate
& 0xff))) keywstate
= utf8enc
;
2446 /* ASCII values already come upper/lowercase; we only want to register */
2447 /* a Shift key if it's a non-ASCII key or another modifier is in effect */
2449 keywstate
|= (((LockMask
| ControlMask
| Mod1Mask
) & event
->state
) << 16);
2450 if (keywstate
> 255) keywstate
|= ((ShiftMask
& event
->state
) << 16);
2452 /* Treat button events and key events in the same way by setting */
2453 /* a key state for buttons */
2455 if (keypressed
== 0)
2456 keywstate
|= (((Button1Mask
| Button2Mask
| Button3Mask
| Button4Mask
|
2457 Button5Mask
| ShiftMask
)
2458 & event
->state
) << 16);
2463 /*------------------------*/
2464 /* Handle keyboard inputs */
2465 /*------------------------*/
2467 void keyhandler(xcWidget w
, caddr_t clientdata
, XKeyEvent
*event
)
2469 int keywstate
; /* KeySym with prepended state information */
2471 UNUSED(w
); UNUSED(clientdata
);
2474 if (popups
> 0) return;
2476 if (popups
> 0 && help_up
== 0) return;
2479 if ((event
->type
== KeyRelease
) || (event
->type
== ButtonRelease
)) {
2481 /* Register a "tap" event if a key or button was released */
2482 /* while a timeout event is pending. */
2484 if (areawin
->time_id
!= 0) {
2485 xcRemoveTimeOut(areawin
->time_id
);
2486 areawin
->time_id
= 0;
2487 keywstate
= getkeysignature(event
);
2488 eventdispatch(keywstate
, areawin
->save
.x
, areawin
->save
.y
);
2491 keywstate
= getkeysignature(event
);
2492 if ((pressmode
!= 0) && (keywstate
== pressmode
)) {
2493 /* Events that require hold & drag (namely, MOVE_MODE) */
2494 /* must be resolved here. Call finish_op() to ensure */
2495 /* that we restore xcircuit to a state of sanity. */
2497 finish_op(XCF_Finish
, event
->x
, event
->y
);
2499 if (areawin
->redraw_needed
)
2500 drawarea(NULL
, NULL
, NULL
);
2502 return; /* Ignore all other release events */
2506 /* Check if any bindings match key/button "hold". If so, then start */
2507 /* the timer and wait for key release or timeout. */
2510 keywstate
= getkeysignature(event
);
2511 if ((keywstate
!= -1) && (xobjs
.hold
== TRUE
)) {
2513 /* Establish whether a HOLD modifier binding would apply in */
2514 /* the current eventmode. If so, set the HOLD timer. */
2516 func
= boundfunction(areawin
->area
, keywstate
| HOLD_MASK
, NULL
);
2518 areawin
->save
.x
= event
->x
;
2519 areawin
->save
.y
= event
->y
;
2520 areawin
->time_id
= xcAddTimeOut(app
, PRESSTIME
,
2521 makepress
, (ClientData
)((pointertype
)keywstate
));
2526 eventdispatch(keywstate
, event
->x
, event
->y
);
2530 /*--------------------------------*/
2531 /* Set snap spacing from keyboard */
2532 /*--------------------------------*/
2534 void setsnap(short direction
)
2536 float oldsnap
= xobjs
.pagelist
[areawin
->page
]->snapspace
;
2539 if (direction
> 0) xobjs
.pagelist
[areawin
->page
]->snapspace
*= 2;
2542 xobjs
.pagelist
[areawin
->page
]->snapspace
/= 2;
2544 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2545 Wprintf("Snap space at minimum value of %s", buffer
);
2548 if (xobjs
.pagelist
[areawin
->page
]->snapspace
!= oldsnap
) {
2549 measurestr(xobjs
.pagelist
[areawin
->page
]->snapspace
, buffer
);
2550 Wprintf("Snap spacing set to %s", buffer
);
2551 areawin
->redraw_needed
= True
;
2552 drawarea(NULL
, NULL
, NULL
);
2556 /*-----------------------------------------*/
2557 /* Reposition an object onto the snap grid */
2558 /*-----------------------------------------*/
2563 Boolean preselected
;
2565 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
2566 if (!checkselect(ALL_TYPES
)) return;
2567 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
2568 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
2569 + areawin
->selects
; selectobj
++) {
2570 easydraw(*selectobj
, DOFORALL
);
2571 switch(SELECTTYPE(selectobj
)) {
2573 objinstptr snapobj
= SELTOOBJINST(selectobj
);
2575 u2u_snap(&snapobj
->position
);
2578 graphicptr snapg
= SELTOGRAPHIC(selectobj
);
2580 u2u_snap(&snapg
->position
);
2583 labelptr snaplabel
= SELTOLABEL(selectobj
);
2585 u2u_snap(&snaplabel
->position
);
2588 polyptr snappoly
= SELTOPOLY(selectobj
);
2589 pointlist snappoint
;
2591 for (snappoint
= snappoly
->points
; snappoint
< snappoly
->points
+
2592 snappoly
->number
; snappoint
++)
2593 u2u_snap(snappoint
);
2596 arcptr snaparc
= SELTOARC(selectobj
);
2598 u2u_snap(&snaparc
->position
);
2599 if (areawin
->snapto
) {
2600 snaparc
->radius
= (snaparc
->radius
/
2601 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2602 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2603 snaparc
->yaxis
= (snaparc
->yaxis
/
2604 xobjs
.pagelist
[areawin
->page
]->snapspace
) *
2605 xobjs
.pagelist
[areawin
->page
]->snapspace
;
2610 splineptr snapspline
= SELTOSPLINE(selectobj
);
2613 for (i
= 0; i
< 4; i
++)
2614 u2u_snap(&snapspline
->ctrl
[i
]);
2615 calcspline(snapspline
);
2618 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
2619 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
2620 easydraw(*selectobj
, DOFORALL
);
2623 select_invalidate_netlist();
2624 if (eventmode
== NORMAL_MODE
)
2629 /*----------------------------------------------*/
2630 /* Routines to print the cursor position */
2631 /*----------------------------------------------*/
2633 /*----------------------------------------------*/
2634 /* fast integer power-of-10 routine */
2635 /*----------------------------------------------*/
2643 case 0: return 1; break;
2644 case 1: return 10; break;
2645 case 2: return 100; break;
2646 case 3: return 1000; break;
2649 for (i
= 1; i
< a
+ 1; i
++) istr
[i
] = '0';
2656 /*--------------------------------------------------*/
2657 /* find greatest common factor between two integers */
2658 /*--------------------------------------------------*/
2660 int calcgcf(int a
, int b
)
2664 if ((mod
= a
% b
) == 0) return (b
);
2665 else return (calcgcf(b
, mod
));
2668 /*--------------------------------------------------------------*/
2669 /* generate a fraction from a float, if possible */
2670 /* fraction returned as a string (must be allocated beforehand) */
2671 /*--------------------------------------------------------------*/
2673 void fraccalc(float xyval
, char *fstr
)
2676 int ip
, mant
, divisor
, denom
, numer
, rpart
;
2678 char num
[10], *nptr
= &num
[2], *sptr
;
2681 fp
= fabs(xyval
- ip
);
2683 /* write fractional part and grab mantissa as integer */
2685 sprintf(num
, "%1.7f", fp
);
2686 num
[8] = '\0'; /* no rounding up! */
2687 sscanf(nptr
, "%d", &mant
);
2689 if (mant
!= 0) { /* search for repeating substrings */
2690 for (i
= 1; i
<= 3; i
++) {
2693 while ((sptr
= nptr
- rept
* i
) >= &num
[2]) {
2694 for (t
= 0; t
< i
; t
++)
2695 if (*(sptr
+ t
) != *(nptr
+ t
)) break;
2699 if (rept
> 1) break;
2702 sscanf(nptr
, "%d", &rpart
); /* rpart is repeating part of mantissa */
2703 if (i
> 3 || rpart
== 0) { /* no repeat */
2704 divisor
= calcgcf(1000000, mant
);
2705 denom
= 1000000 / divisor
;
2711 sscanf(&num
[2], "%d", &z
);
2713 mant
= z
* p
+ rpart
;
2714 fd
= ipow10(nptr
- &num
[2]) * p
;
2716 divisor
= calcgcf(fd
, mant
);
2717 denom
= fd
/ divisor
;
2719 numer
= mant
/ divisor
;
2721 sprintf(fstr
, "%5.3f", xyval
);
2723 sprintf(fstr
, "%hd/%hd", (xyval
> 0) ? numer
: -numer
, denom
);
2725 sprintf(fstr
, "%hd %hd/%hd", ip
, numer
, denom
);
2727 else sprintf(fstr
, "%hd", ip
);
2730 /*------------------------------------------------------------------------------*/
2731 /* Print the position of the cursor in the upper right-hand message window */
2732 /*------------------------------------------------------------------------------*/
2734 void printpos(short xval
, short yval
)
2737 float oscale
, iscale
= (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.y
/
2738 (float)xobjs
.pagelist
[areawin
->page
]->drawingscale
.x
;
2741 XPoint
*tpoint
, *npoint
;
2745 /* For polygons, print the length (last line of a wire or polygon) or */
2746 /* length and width (box only) */
2748 if (eventmode
== BOX_MODE
|| eventmode
== EPOLY_MODE
|| eventmode
== WIRE_MODE
) {
2749 polyptr lwire
= (eventmode
== BOX_MODE
) ? TOPOLY(ENDPART
) : TOPOLY(EDITPART
);
2750 if ((eventmode
== EPOLY_MODE
) && (lwire
->number
> 2)) {
2751 /* sanity check on edit cycle */
2752 cycle
= (lwire
->cycle
) ? lwire
->cycle
->number
: -1;
2753 if (cycle
< 0 || cycle
>= lwire
->number
) {
2754 advancecycle((genericptr
*)(&lwire
), 0);
2757 tpoint
= lwire
->points
+ cycle
;
2758 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, 1);
2759 llen
= wirelength(tpoint
, npoint
);
2760 npoint
= lwire
->points
+ checkcycle((genericptr
)lwire
, -1);
2761 lwid
= wirelength(tpoint
, npoint
);
2763 if (lwire
->style
& UNCLOSED
) { /* unclosed polys */
2766 else if (cycle
== lwire
->number
- 1) {
2771 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2777 else if (eventmode
== BOX_MODE
) {
2778 tpoint
= lwire
->points
;
2779 npoint
= lwire
->points
+ 1;
2780 llen
= wirelength(tpoint
, npoint
);
2781 npoint
= lwire
->points
+ 3;
2782 lwid
= wirelength(tpoint
, npoint
);
2783 if ((npoint
->y
- tpoint
->y
) == 0) { /* swap width and length */
2791 tpoint
= lwire
->points
+ lwire
->number
- 1;
2792 llen
= wirelength(tpoint
- 1, tpoint
);
2796 else if (eventmode
== ARC_MODE
|| eventmode
== EARC_MODE
) {
2797 arcptr larc
= (eventmode
== ARC_MODE
) ? TOARC(ENDPART
) : TOARC(EDITPART
);
2798 llen
= larc
->radius
;
2799 if (abs(larc
->radius
) != larc
->yaxis
) {
2807 switch (xobjs
.pagelist
[areawin
->page
]->coordstyle
) {
2809 sprintf(_STR
, "%g, %g", xval
* iscale
, yval
* iscale
);
2810 sptr
= _STR
+ strlen(_STR
);
2813 sprintf(sptr
, " (%g x %g)", llen
* iscale
, lwid
* iscale
);
2815 sprintf(sptr
, " (length %g)", llen
* iscale
);
2819 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2820 f1
= ((float)(xval
) * iscale
* oscale
) / 72.0;
2821 f2
= ((float)(yval
) * iscale
* oscale
) / 72.0;
2822 sprintf(_STR
, "%5.3f, %5.3f in", f1
, f2
);
2823 sptr
= _STR
+ strlen(_STR
);
2825 f1
= ((float)(llen
) * iscale
* oscale
) / 72.0;
2827 f2
= ((float)(lwid
) * iscale
* oscale
) / 72.0;
2828 sprintf(sptr
, " (%5.3f x %5.3f in)", f1
, f2
);
2831 sprintf(sptr
, " (length %5.3f in)", f1
);
2835 char fstr1
[30], fstr2
[30];
2837 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* INCHSCALE
;
2838 fraccalc((((float)(xval
) * iscale
* oscale
) / 72.0), fstr1
);
2839 fraccalc((((float)(yval
) * iscale
* oscale
) / 72.0), fstr2
);
2840 sprintf(_STR
, "%s, %s in", fstr1
, fstr2
);
2841 sptr
= _STR
+ strlen(_STR
);
2843 fraccalc((((float)(llen
) * iscale
* oscale
) / 72.0), fstr1
);
2845 fraccalc((((float)(lwid
) * iscale
* oscale
) / 72.0), fstr2
);
2846 sprintf(sptr
, " (%s x %s in)", fstr1
, fstr2
);
2849 sprintf(sptr
, " (length %s in)", fstr1
);
2853 oscale
= xobjs
.pagelist
[areawin
->page
]->outscale
* CMSCALE
;
2854 f1
= ((float)(xval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2855 f2
= ((float)(yval
) * iscale
* oscale
) / IN_CM_CONVERT
;
2856 sprintf(_STR
, "%5.3f, %5.3f cm", f1
, f2
);
2857 sptr
= _STR
+ strlen(_STR
);
2859 f1
= ((float)(llen
) * iscale
* oscale
) / IN_CM_CONVERT
;
2861 f2
= ((float)(lwid
) * iscale
* oscale
) / IN_CM_CONVERT
;
2862 sprintf(sptr
, " (%5.3f x %5.3f cm)", f1
, f2
);
2865 sprintf(sptr
, " (length %5.3f cm)", f1
);
2872 /*---------------------------------------------------*/
2873 /* Find nearest point of intersection of the cursor */
2874 /* position to a wire and move there. */
2875 /*---------------------------------------------------*/
2877 void findwirex(XPoint
*endpt1
, XPoint
*endpt2
, XPoint
*userpt
,
2878 XPoint
*newpos
, float *rot
)
2883 xsq
= sqwirelen(endpt1
, endpt2
);
2884 ysq
= sqwirelen(endpt1
, userpt
);
2885 zsq
= sqwirelen(endpt2
, userpt
);
2886 frac
= 0.5 + (float)(ysq
- zsq
) / (float)(xsq
<< 1);
2887 if (frac
> 1) frac
= 1;
2888 else if (frac
< 0) frac
= 0;
2889 newpos
->x
= endpt1
->x
+ (int)((endpt2
->x
- endpt1
->x
) * frac
);
2890 newpos
->y
= endpt1
->y
+ (int)((endpt2
->y
- endpt1
->y
) * frac
);
2892 *rot
= 180.0 + INVRFAC
* atan2((double)(endpt1
->x
-
2893 endpt2
->x
), (double)(endpt1
->y
- endpt2
->y
));
2896 /*----------------------------------------------------------------*/
2897 /* Find the closest point of attachment from the pointer position */
2898 /* to the "attachto" element. */
2899 /*----------------------------------------------------------------*/
2901 void findattach(XPoint
*newpos
, float *rot
, XPoint
*userpt
)
2903 XPoint
*endpt1
, *endpt2
;
2908 if (rot
) locrot
= *rot
;
2910 /* find point of intersection and slope */
2912 if (SELECTTYPE(&areawin
->attachto
) == ARC
) {
2913 arcptr aarc
= SELTOARC(&areawin
->attachto
);
2915 tmpang
= atan2((double)(userpt
->y
- aarc
->position
.y
) * (double)
2916 (abs(aarc
->radius
)), (double)(userpt
->x
- aarc
->position
.x
) *
2917 (double)aarc
->yaxis
);
2919 /* don't follow the arc beyond its endpoints */
2921 tmpdeg
= (float)(tmpang
* INVRFAC
);
2922 if (tmpdeg
< 0) tmpdeg
+= 360;
2923 if (((aarc
->angle2
> 360) && (tmpdeg
> aarc
->angle2
- 360) &&
2924 (tmpdeg
< aarc
->angle1
)) ||
2925 ((aarc
->angle1
< 0) && (tmpdeg
> aarc
->angle2
) &&
2926 (tmpdeg
< aarc
->angle1
+ 360)) ||
2927 ((aarc
->angle1
>= 0) && (aarc
->angle2
<= 360) && ((tmpdeg
2928 > aarc
->angle2
) || (tmpdeg
< aarc
->angle1
)))) {
2929 float testd1
= aarc
->angle1
- tmpdeg
;
2930 float testd2
= tmpdeg
- aarc
->angle2
;
2931 if (testd1
< 0) testd1
+= 360;
2932 if (testd2
< 0) testd2
+= 360;
2934 /* if arc is closed, attach to the line between the endpoints */
2936 if (!(aarc
->style
& UNCLOSED
)) {
2938 tmpang
= (double) aarc
->angle1
/ INVRFAC
;
2939 end1
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2940 end1
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2941 tmpang
= (double) aarc
->angle2
/ INVRFAC
;
2942 end2
.x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2943 end2
.y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2944 findwirex(&end1
, &end2
, userpt
, newpos
, &locrot
);
2945 if (rot
) *rot
= locrot
;
2949 tmpang
= (double)((testd1
< testd2
) ? aarc
->angle1
: aarc
->angle2
)
2953 /* get position in user coordinates nearest to the intersect pt */
2955 newpos
->x
= aarc
->position
.x
+ abs(aarc
->radius
) * cos(tmpang
);
2956 newpos
->y
= aarc
->position
.y
+ aarc
->yaxis
* sin(tmpang
);
2958 /* rotation of object is normal to the curve of the ellipse */
2961 *rot
= 90.0 - INVRFAC
* tmpang
;
2962 if (*rot
< 0.0) *rot
+= 360.0;
2965 else if (SELECTTYPE(&areawin
->attachto
) == SPLINE
) {
2966 splineptr aspline
= SELTOSPLINE(&areawin
->attachto
);
2967 frac
= findsplinemin(aspline
, userpt
);
2968 findsplinepos(aspline
, frac
, newpos
, &locrot
);
2969 if (rot
) *rot
= locrot
;
2971 else if (SELECTTYPE(&areawin
->attachto
) == OBJINST
) {
2973 objinstptr ainst
= SELTOOBJINST(&areawin
->attachto
);
2974 objectptr aobj
= ainst
->thisobject
;
2976 long testdist
, mindist
= 1e8
;
2979 /* In case instance has no pin labels, we will attach to */
2980 /* the instance's own origin. */
2982 mdpoint
.x
= mdpoint
.y
= 0;
2983 ReferencePosition(ainst
, &mdpoint
, newpos
);
2985 /* Find the nearest pin label in the object instance and attach to it */
2986 for (ggen
= aobj
->plist
; ggen
< aobj
->plist
+ aobj
->parts
; ggen
++) {
2987 if (ELEMENTTYPE(*ggen
) == LABEL
) {
2988 labelptr alab
= TOLABEL(ggen
);
2989 if (alab
->pin
== LOCAL
|| alab
->pin
== GLOBAL
) {
2990 ReferencePosition(ainst
, &alab
->position
, &mdpoint
);
2991 testdist
= sqwirelen(&mdpoint
, userpt
);
2992 if (testdist
< mindist
) {
3000 else if (SELECTTYPE(&areawin
->attachto
) == LABEL
) {
3001 /* Only one choice: Attach to the label position */
3002 labelptr alabel
= SELTOLABEL(&areawin
->attachto
);
3003 newpos
->x
= alabel
->position
.x
;
3004 newpos
->y
= alabel
->position
.y
;
3006 else if (SELECTTYPE(&areawin
->attachto
) == POLYGON
) {
3007 polyptr apoly
= SELTOPOLY(&areawin
->attachto
);
3008 XPoint
*testpt
, *minpt
, *nxtpt
;
3009 long mindist
= 1e8
, testdist
;
3010 minpt
= nxtpt
= apoly
->points
; /* so variables aren't uninitialized */
3011 for (testpt
= apoly
->points
; testpt
< apoly
->points
+
3012 apoly
->number
- 1; testpt
++) {
3013 testdist
= finddist(testpt
, testpt
+ 1, userpt
);
3014 if (testdist
< mindist
) {
3020 if (!(apoly
->style
& UNCLOSED
)) {
3021 testdist
= finddist(testpt
, apoly
->points
, userpt
);
3022 if (testdist
< mindist
) {
3025 nxtpt
= apoly
->points
;
3030 findwirex(endpt1
, endpt2
, userpt
, newpos
, &locrot
);
3031 if (rot
) *rot
= locrot
;
3035 /*--------------------------------------------*/
3036 /* Find closest point in a path to the cursor */
3037 /*--------------------------------------------*/
3039 XPoint
*pathclosepoint(pathptr dragpath
, XPoint
*newpos
)
3044 int mdist
= 1000000, tdist
;
3046 for (cpoint
= dragpath
->plist
; cpoint
< dragpath
->plist
+ dragpath
->parts
;
3048 switch(ELEMENTTYPE(*cpoint
)) {
3050 tdist
= wirelength(&(TOARC(cpoint
)->position
), newpos
);
3051 if (tdist
< mdist
) {
3053 rpoint
= &(TOARC(cpoint
)->position
);
3057 mpoint
= closepoint(TOPOLY(cpoint
), newpos
);
3058 tdist
= wirelength(TOPOLY(cpoint
)->points
+ mpoint
, newpos
);
3059 if (tdist
< mdist
) {
3061 rpoint
= TOPOLY(cpoint
)->points
+ mpoint
;
3065 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[0]), newpos
);
3066 if (tdist
< mdist
) {
3068 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[0]);
3070 tdist
= wirelength(&(TOSPLINE(cpoint
)->ctrl
[3]), newpos
);
3071 if (tdist
< mdist
) {
3073 rpoint
= &(TOSPLINE(cpoint
)->ctrl
[3]);
3081 /*-------------------------------------------*/
3082 /* Drag a selected element around the screen */
3083 /*-------------------------------------------*/
3085 void drag(int x
, int y
)
3088 Boolean eventcheck
= False
;
3090 short deltax
, deltay
;
3096 /* flush out multiple pointermotion events from the event queue */
3097 /* use only the last motion event */
3098 while (XCheckWindowEvent(dpy
, areawin
->window
, PointerMotionMask
|
3099 Button1MotionMask
, &again
) == True
) eventcheck
= True
;
3101 XButtonEvent
*event
= (XButtonEvent
*)(&again
);
3102 locx
= (int)event
->x
;
3103 locy
= (int)event
->y
;
3106 /* Determine if this event is supposed to be handled by */
3107 /* trackselarea(), or whether we should not be here at all */
3108 /* (button press and mouse movement in an unsupported mode) */
3110 if (eventmode
== SELAREA_MODE
) {
3114 else if (eventmode
== RESCALE_MODE
) {
3118 else if (eventmode
== PAN_MODE
) {
3119 trackpan(locx
, locy
);
3122 else if (eventmode
!= CATMOVE_MODE
&& eventmode
!= MOVE_MODE
3123 && eventmode
!= COPY_MODE
)
3126 snap(locx
, locy
, &userpt
);
3127 deltax
= userpt
.x
- areawin
->save
.x
;
3128 deltay
= userpt
.y
- areawin
->save
.y
;
3129 if (deltax
== 0 && deltay
== 0) return;
3131 areawin
->save
.x
= userpt
.x
;
3132 areawin
->save
.y
= userpt
.y
;
3134 /* set up the graphics state for moving a selected object */
3136 XTopSetForeground(SELECTCOLOR
);
3138 placeselects(deltax
, deltay
, &userpt
);
3140 /* restore graphics state */
3142 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
3144 /* print the position and other useful measurements */
3146 printpos(userpt
.x
, userpt
.y
);
3149 /*------------------------------------------------------*/
3150 /* Wrapper for drag() for xlib callback compatibility. */
3151 /*------------------------------------------------------*/
3153 void xlib_drag(xcWidget w
, caddr_t clientdata
, XEvent
*event
)
3155 XButtonEvent
*bevent
= (XButtonEvent
*)event
;
3156 UNUSED(w
); UNUSED(clientdata
);
3158 drag(bevent
->x
, bevent
->y
);
3159 if (areawin
->redraw_needed
)
3160 drawarea(NULL
, NULL
, NULL
);
3163 /*----------------------------------------------*/
3164 /* Rotate an element of a path */
3165 /*----------------------------------------------*/
3167 void elemrotate(genericptr
*genobj
, float direction
, XPoint
*position
)
3169 XPoint negpt
, *newpts
= (XPoint
*)NULL
;
3171 negpt
.x
= -position
->x
;
3172 negpt
.y
= -position
->y
;
3174 switch(ELEMENTTYPE(*genobj
)) {
3176 arcptr rotatearc
= TOARC(genobj
);
3177 rotatearc
->angle1
-= direction
;
3178 rotatearc
->angle2
-= direction
;
3179 if (rotatearc
->angle1
>= 360) {
3180 rotatearc
->angle1
-= 360;
3181 rotatearc
->angle2
-= 360;
3183 else if (rotatearc
->angle2
<= 0) {
3184 rotatearc
->angle1
+= 360;
3185 rotatearc
->angle2
+= 360;
3187 newpts
= (XPoint
*)malloc(sizeof(XPoint
));
3188 UTransformPoints(&rotatearc
->position
, newpts
, 1, negpt
, 1.0, 0);
3189 UTransformPoints(newpts
, &rotatearc
->position
, 1, *position
,
3195 splineptr rotatespline
= TOSPLINE(genobj
);
3196 newpts
= (XPoint
*)malloc(4 * sizeof(XPoint
));
3197 UTransformPoints(rotatespline
->ctrl
, newpts
, 4, negpt
, 1.0, 0);
3198 UTransformPoints(newpts
, rotatespline
->ctrl
, 4, *position
,
3200 calcspline(rotatespline
);
3204 polyptr rotatepoly
= TOPOLY(genobj
);
3205 newpts
= (XPoint
*)malloc(rotatepoly
->number
* sizeof(XPoint
));
3206 UTransformPoints(rotatepoly
->points
, newpts
, rotatepoly
->number
,
3208 UTransformPoints(newpts
, rotatepoly
->points
, rotatepoly
->number
,
3209 *position
, 1.0, direction
);
3212 if (newpts
) free(newpts
);
3215 /*------------------------------------------------------*/
3216 /* Rotate an element or group of elements */
3217 /* Objects and labels, if selected singly, rotate */
3218 /* about their position point. All other elements, */
3219 /* and groups, rotate about the cursor point. */
3220 /*------------------------------------------------------*/
3222 void elementrotate(float direction
, XPoint
*position
)
3224 short *selectobj
; /* , ld; (jdk) */
3225 Boolean single
= False
;
3226 Boolean need_refresh
= False
;
3227 Boolean preselected
;
3228 XPoint newpt
, negpt
;
3230 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3231 if (!checkselect(ALL_TYPES
)) return;
3232 if (areawin
->selects
== 1) single
= True
;
3234 negpt
.x
= -position
->x
;
3235 negpt
.y
= -position
->y
;
3237 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3238 + areawin
->selects
; selectobj
++) {
3240 /* erase the element */
3241 if (!need_refresh
) {
3242 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
3243 easydraw(*selectobj
, DOFORALL
);
3246 switch(SELECTTYPE(selectobj
)) {
3249 objinstptr rotateobj
= SELTOOBJINST(selectobj
);
3251 if (is_library(topobject
) >= 0 && !is_virtual(rotateobj
)) break;
3252 rotateobj
->rotation
+= direction
;
3253 while (rotateobj
->rotation
>= 360) rotateobj
->rotation
-= 360;
3254 while (rotateobj
->rotation
<= 0) rotateobj
->rotation
+= 360;
3256 UTransformPoints(&rotateobj
->position
, &newpt
, 1, negpt
, 1.0, 0);
3257 UTransformPoints(&newpt
, &rotateobj
->position
, 1, *position
,
3263 labelptr rotatetext
= SELTOLABEL(selectobj
);
3265 rotatetext
->rotation
+= direction
;
3266 while (rotatetext
->rotation
>= 360) rotatetext
->rotation
-= 360;
3267 while (rotatetext
->rotation
<= 0) rotatetext
->rotation
+= 360;
3269 UTransformPoints(&rotatetext
->position
, &newpt
, 1, negpt
, 1.0, 0);
3270 UTransformPoints(&newpt
, &rotatetext
->position
, 1, *position
,
3276 graphicptr rotateg
= SELTOGRAPHIC(selectobj
);
3278 rotateg
->rotation
+= direction
;
3279 while (rotateg
->rotation
>= 360) rotateg
->rotation
-= 360;
3280 while (rotateg
->rotation
<= 0) rotateg
->rotation
+= 360;
3282 rotateg
->valid
= FALSE
;
3283 #endif /* !HAVE_CAIRO */
3285 UTransformPoints(&rotateg
->position
, &newpt
, 1, negpt
, 1.0, 0);
3286 UTransformPoints(&newpt
, &rotateg
->position
, 1, *position
,
3289 need_refresh
= True
;
3292 case POLYGON
: case ARC
: case SPLINE
:{
3293 genericptr
*genpart
= topobject
->plist
+ *selectobj
;
3294 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3296 elemrotate(genpart
, direction
, position
);
3300 genericptr
*genpart
;
3301 pathptr rotatepath
= SELTOPATH(selectobj
);
3303 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3305 for (genpart
= rotatepath
->plist
; genpart
< rotatepath
->plist
3306 + rotatepath
->parts
; genpart
++)
3307 elemrotate(genpart
, direction
, position
);
3311 /* redisplay the element */
3312 if (preselected
|| ((eventmode
!= NORMAL_MODE
) && !need_refresh
)) {
3313 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
3314 easydraw(*selectobj
, DOFORALL
);
3318 /* This takes care of all selected instances and labels in one go, */
3319 /* because we only need to know the origin and amount of rotation. */
3321 if (eventmode
!= COPY_MODE
)
3322 register_for_undo(XCF_Rotate
, UNDO_MORE
, areawin
->topinstance
,
3323 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
,
3326 /* New rule (6/15/07) to be applied generally: If objects were */
3327 /* selected prior to calling elementrotate() and similar functions, */
3328 /* leave them selected upon exit. Otherwise, deselect them. */
3330 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
3334 if (eventmode
== CATALOG_MODE
) {
3336 if ((libnum
= is_library(topobject
)) >= 0) {
3337 composelib(libnum
+ LIBRARY
);
3338 need_refresh
= TRUE
;
3342 pwriteback(areawin
->topinstance
);
3343 calcbbox(areawin
->topinstance
);
3346 if (need_refresh
) drawarea(NULL
, NULL
, NULL
);
3349 /*----------------------------------------------*/
3350 /* Rescale the current edit element to the */
3351 /* dimensions of the rescale box. */
3352 /*----------------------------------------------*/
3354 void elementrescale(float newscale
)
3362 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3363 + areawin
->selects
; selectobj
++) {
3364 switch (SELECTTYPE(selectobj
)) {
3366 sclab
= SELTOLABEL(selectobj
);
3367 oldsize
= sclab
->scale
;
3368 sclab
->scale
= newscale
;
3371 scinst
= SELTOOBJINST(selectobj
);
3372 oldsize
= scinst
->scale
;
3373 scinst
->scale
= newscale
;
3376 scgraph
= SELTOGRAPHIC(selectobj
);
3377 oldsize
= scgraph
->scale
;
3378 scgraph
->scale
= newscale
;
3381 register_for_undo(XCF_Rescale
, UNDO_MORE
, areawin
->topinstance
,
3382 SELTOGENERIC(selectobj
), (double)oldsize
);
3384 calcbbox(areawin
->topinstance
);
3387 /*-------------------------------------------------*/
3388 /* Edit an element in an element-dependent fashion */
3389 /*-------------------------------------------------*/
3391 void edit(int x
, int y
)
3395 if (areawin
->selects
== 0) {
3396 Boolean saveredraw
= areawin
->redraw_needed
;
3397 selectobj
= select_element(ALL_TYPES
);
3398 areawin
->redraw_needed
= saveredraw
;
3401 selectobj
= areawin
->selectlist
;
3402 if (areawin
->selects
== 0)
3404 else if (areawin
->selects
!= 1) { /* Multiple object edit */
3406 short *selectlist
, selrefno
;
3407 Boolean save_redraw
= areawin
->redraw_needed
;
3409 /* Find the closest part to use as a reference */
3410 selnum
= areawin
->selects
;
3411 selectlist
= areawin
->selectlist
;
3412 areawin
->selects
= 0;
3413 areawin
->selectlist
= NULL
;
3414 selectobj
= select_element(ALL_TYPES
);
3415 if (selectobj
!= NULL
)
3416 selrefno
= *selectobj
;
3420 areawin
->selects
= selnum
;
3421 areawin
->selectlist
= selectlist
;
3422 areawin
->redraw_needed
= save_redraw
;
3423 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
3424 + areawin
->selects
; selectobj
++) {
3425 if (*selectobj
== selrefno
) break;
3427 if (selectobj
== areawin
->selectlist
+ areawin
->selects
) {
3428 Wprintf("Put cursor close to the reference element.");
3432 /* Shuffle the reference element to the beginning of the select list */
3433 *selectobj
= *(areawin
->selectlist
);
3434 *(areawin
->selectlist
) = selrefno
;
3435 selectobj
= areawin
->selectlist
;
3438 switch(SELECTTYPE(selectobj
)) {
3440 labelptr
*lastlabel
= (labelptr
*)EDITPART
;
3445 /* save the old string, including parameters */
3446 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3449 /* fill any NULL instance parameters with the default value */
3450 copyparams(areawin
->topinstance
, areawin
->topinstance
);
3452 /* place text cursor line at point nearest the cursor */
3453 /* unless textend is set. . . */
3455 if (areawin
->textend
== 0) {
3456 TextLinesInfo tlinfo
;
3458 tlinfo
.tbreak
= NULL
;
3459 tlinfo
.padding
= NULL
;
3461 window_to_user(x
, y
, &areawin
->save
);
3462 InvTransformPoints(&areawin
->save
, &tmppt
, 1, (*lastlabel
)->position
,
3463 (*lastlabel
)->scale
, (*lastlabel
)->rotation
);
3464 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3465 tmppt
.x
+= ((*lastlabel
)->anchor
& NOTLEFT
?
3466 ((*lastlabel
)->anchor
& RIGHT
? tmpext
.maxwidth
3467 : tmpext
.maxwidth
>> 1) : 0);
3468 tmppt
.y
+= ((*lastlabel
)->anchor
& NOTBOTTOM
?
3469 ((*lastlabel
)->anchor
& TOP
? tmpext
.ascent
:
3470 (tmpext
.ascent
+ tmpext
.base
) >> 1) : tmpext
.base
);
3471 if ((*lastlabel
)->pin
)
3472 pinadjust((*lastlabel
)->anchor
, &tmppt
.x
, NULL
, -1);
3474 /* Where tbreak is passed to ULength, the character position */
3475 /* is returned in the TextLinesInfo dostop field. */
3476 tlinfo
.tbreak
= &tmppt
;
3477 tmpext
= ULength(*lastlabel
, areawin
->topinstance
, &tlinfo
);
3478 areawin
->textpos
= tlinfo
.dostop
;
3480 if (tlinfo
.padding
!= NULL
) free(tlinfo
.padding
);
3483 /* find current font */
3485 curfont
= findcurfont(areawin
->textpos
, (*lastlabel
)->string
,
3486 areawin
->topinstance
);
3488 /* change menu buttons accordingly */
3490 setfontmarks(curfont
, (*lastlabel
)->anchor
);
3492 if (eventmode
== CATALOG_MODE
) {
3493 /* CATTEXT_MODE may show an otherwise hidden library namespace */
3494 undrawtext(*lastlabel
);
3495 eventmode
= CATTEXT_MODE
;
3496 redrawtext(*lastlabel
);
3497 areawin
->redraw_needed
= False
; /* ignore prev. redraw requests */
3498 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3501 eventmode
= ETEXT_MODE
;
3502 text_mode_draw(xcDRAW_INIT
, *lastlabel
);
3505 XDefineCursor(dpy
, areawin
->window
, TEXTPTR
);
3507 /* write the text at the bottom */
3509 charreport(*lastlabel
);
3513 case POLYGON
: case ARC
: case SPLINE
: case PATH
:
3514 window_to_user(x
, y
, &areawin
->save
);
3515 pathedit(*(EDITPART
));
3518 case OBJINST
: case GRAPHIC
:
3519 if (areawin
->selects
== 1)
3523 XDefineCursor (dpy
, areawin
->window
, EDCURSOR
);
3526 /*----------------------------------------------------------------------*/
3527 /* edit() routine for path-type elements (polygons, splines, arcs, and */
3529 /*----------------------------------------------------------------------*/
3531 void pathedit(genericptr editpart
)
3533 splineptr lastspline
= NULL
;
3535 polyptr lastpoly
= NULL
;
3542 /* Find and set constrained edit points on all elements. Register */
3543 /* each element with the undo mechanism. */
3545 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
3546 areawin
->selects
; eselect
++) {
3547 switch (SELECTTYPE(eselect
)) {
3549 findconstrained(SELTOPOLY(eselect
));
3552 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3553 SELTOGENERIC(eselect
));
3558 switch(ELEMENTTYPE(editpart
)) {
3560 genericptr
*ggen
, *savegen
= NULL
;
3561 int mincycle
, dist
, mindist
= 1e6
;
3563 lastpath
= (pathptr
)editpart
;
3564 havecycle
= (checkcycle(editpart
, 0) >= 0) ? True
: False
;
3566 /* determine which point of the path is closest to the cursor */
3567 for (ggen
= lastpath
->plist
; ggen
< lastpath
->plist
+ lastpath
->parts
;
3569 switch (ELEMENTTYPE(*ggen
)) {
3571 lastpoly
= TOPOLY(ggen
);
3572 cycle
= closepoint(lastpoly
, &areawin
->save
);
3573 dist
= wirelength(lastpoly
->points
+ cycle
, &areawin
->save
);
3576 lastspline
= TOSPLINE(ggen
);
3577 cycle
= (wirelength(&lastspline
->ctrl
[0],
3578 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3579 &areawin
->save
)) ? 0 : 3;
3580 dist
= wirelength(&lastspline
->ctrl
[cycle
], &areawin
->save
);
3583 if (dist
< mindist
) {
3589 if (savegen
== NULL
) return; /* something went terribly wrong */
3590 switch (ELEMENTTYPE(*savegen
)) {
3592 lastpoly
= TOPOLY(savegen
);
3593 addcycle(savegen
, mincycle
, 0);
3594 savept
= lastpoly
->points
+ mincycle
;
3595 makerefcycle(lastpoly
->cycle
, mincycle
);
3596 findconstrained(lastpoly
);
3599 lastspline
= TOSPLINE(savegen
);
3600 addcycle(savegen
, mincycle
, 0);
3601 savept
= &lastspline
->ctrl
[mincycle
];
3602 makerefcycle(lastspline
->cycle
, mincycle
);
3605 updatepath(lastpath
);
3607 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3608 (genericptr
)lastpath
);
3609 patheditpush(lastpath
);
3610 areawin
->origin
= areawin
->save
;
3613 path_mode_draw(xcDRAW_INIT
, lastpath
);
3615 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3616 (xcEventHandler
)trackelement
, NULL
);
3617 eventmode
= EPATH_MODE
;
3618 printpos(savept
->x
, savept
->y
);
3623 lastpoly
= (polyptr
)editpart
;
3625 /* Determine which point of polygon is closest to cursor */
3626 cycle
= closepoint(lastpoly
, &areawin
->save
);
3627 havecycle
= (lastpoly
->cycle
== NULL
) ? False
: True
;
3628 addcycle(&editpart
, cycle
, 0);
3629 savept
= lastpoly
->points
+ cycle
;
3630 makerefcycle(lastpoly
->cycle
, cycle
);
3632 findconstrained(lastpoly
);
3633 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3634 (genericptr
)lastpoly
);
3637 /* Push onto the editstack */
3638 polyeditpush(lastpoly
);
3640 /* remember our postion for pointer restore */
3641 areawin
->origin
= areawin
->save
;
3645 poly_mode_draw(xcDRAW_INIT
, lastpoly
);
3647 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3648 (xcEventHandler
)trackelement
, NULL
);
3649 eventmode
= EPOLY_MODE
;
3650 printeditbindings();
3651 printpos(savept
->x
, savept
->y
);
3656 lastspline
= (splineptr
)editpart
;
3658 /* find which point is closest to the cursor */
3660 cycle
= (wirelength(&lastspline
->ctrl
[0],
3661 &areawin
->save
) < wirelength(&lastspline
->ctrl
[3],
3662 &areawin
->save
)) ? 0 : 3;
3663 havecycle
= (lastspline
->cycle
== NULL
) ? False
: True
;
3664 addcycle(&editpart
, cycle
, 0);
3665 makerefcycle(lastspline
->cycle
, cycle
);
3666 curpt
= &lastspline
->ctrl
[cycle
];
3668 register_for_undo(XCF_Edit
, UNDO_MORE
, areawin
->topinstance
,
3669 (genericptr
)lastspline
);
3671 /* Push onto the editstack */
3672 splineeditpush(lastspline
);
3674 /* remember our postion for pointer restore */
3675 areawin
->origin
= areawin
->save
;
3679 spline_mode_draw(xcDRAW_INIT
, lastspline
);
3680 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3681 (xcEventHandler
)trackelement
, NULL
);
3682 eventmode
= ESPLINE_MODE
;
3686 float tmpratio
, tlen
;
3688 lastarc
= (arcptr
)editpart
;
3690 /* find a part of the arc close to the pointer */
3692 tlen
= (float)wirelength(&areawin
->save
, &(lastarc
->position
));
3693 tmpratio
= (float)(abs(lastarc
->radius
)) / tlen
;
3694 curpt
.x
= lastarc
->position
.x
+ tmpratio
* (areawin
->save
.x
3695 - lastarc
->position
.x
);
3696 tmpratio
= (float)lastarc
->yaxis
/ tlen
;
3697 curpt
.y
= lastarc
->position
.y
+ tmpratio
* (areawin
->save
.y
3698 - lastarc
->position
.y
);
3699 addcycle(&editpart
, 0, 0);
3700 saveratio
= (double)(lastarc
->yaxis
) / (double)(abs(lastarc
->radius
));
3702 /* Push onto the editstack */
3703 arceditpush(lastarc
);
3704 areawin
->origin
= areawin
->save
;
3708 areawin
->save
.x
= curpt
.x
; /* for redrawing dotted edit line */
3709 areawin
->save
.y
= curpt
.y
;
3710 arc_mode_draw(xcDRAW_INIT
, lastarc
);
3711 xcAddEventHandler(areawin
->area
, PointerMotionMask
, False
,
3712 (xcEventHandler
)trackarc
, NULL
);
3713 eventmode
= EARC_MODE
;
3714 printpos(curpt
.x
, curpt
.y
);
3719 /*------------------------------------------------------*/
3720 /* Raise an element to the top of the list */
3721 /*------------------------------------------------------*/
3723 void xc_top(short *selectno
, short *orderlist
)
3726 genericptr
*raiseobj
, *genobj
, temp
;
3728 raiseobj
= topobject
->plist
+ *selectno
;
3731 for (genobj
= topobject
->plist
+ *selectno
; genobj
<
3732 topobject
->plist
+ topobject
->parts
- 1; genobj
++) {
3733 *genobj
= *(genobj
+ 1);
3734 *(orderlist
+ i
) = *(orderlist
+ i
+ 1);
3737 *(topobject
->plist
+ topobject
->parts
- 1) = temp
;
3738 *(orderlist
+ topobject
->parts
- 1) = *selectno
;
3739 *selectno
= topobject
->parts
- 1;
3742 /*------------------------------------------------------*/
3743 /* Lower an element to the bottom of the list */
3744 /*------------------------------------------------------*/
3746 void xc_bottom(short *selectno
, short *orderlist
)
3749 genericptr
*lowerobj
, *genobj
, temp
;
3751 lowerobj
= topobject
->plist
+ *selectno
;
3754 for (genobj
= topobject
->plist
+ *selectno
;
3755 genobj
> topobject
->plist
; genobj
--) {
3756 *genobj
= *(genobj
- 1);
3757 *(orderlist
+ i
) = *(orderlist
+ i
- 1);
3761 *orderlist
= *selectno
;
3765 /*--------------------------------------------------------------*/
3766 /* Raise all selected elements by one position in the list */
3767 /*--------------------------------------------------------------*/
3771 short *sel
, topsel
, maxsel
, *topidx
, limit
, *orderlist
, i
;
3772 genericptr
*raiseobj
, temp
;
3774 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3775 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3777 /* Find topmost element in the select list */
3779 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3781 if (*sel
> maxsel
) {
3786 if (maxsel
== -1) return; /* Error condition */
3789 limit
= topobject
->parts
- 1;
3792 /* Exchange the topmost element with the one above it */
3793 if (topsel
< limit
) {
3794 raiseobj
= topobject
->plist
+ topsel
;
3796 *raiseobj
= *(raiseobj
+ 1);
3797 *(raiseobj
+ 1) = temp
;
3799 i
= *(orderlist
+ topsel
);
3800 *(orderlist
+ topsel
) = *(orderlist
+ topsel
+ 1);
3801 *(orderlist
+ topsel
+ 1) = i
;
3806 /* Find next topmost element */
3808 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3810 if (*sel
< maxsel
) {
3811 if (*sel
> topsel
) {
3817 if (topsel
== -1) break; /* No more elements to raise */
3820 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3824 /*--------------------------------------------------------------*/
3825 /* Lower all selected elements by one position in the list */
3826 /*--------------------------------------------------------------*/
3830 short *sel
, botsel
, minsel
, *botidx
, limit
, *orderlist
, i
;
3831 genericptr
*lowerobj
, temp
;
3833 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3834 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3836 /* Find bottommost element in the select list */
3837 minsel
= topobject
->parts
;
3838 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3840 if (*sel
< minsel
) {
3845 if (minsel
== topobject
->parts
) return; /* Error condition */
3851 /* Exchange the topmost element with the one below it */
3852 if (botsel
> limit
) {
3853 lowerobj
= topobject
->plist
+ botsel
;
3855 *lowerobj
= *(lowerobj
- 1);
3856 *(lowerobj
- 1) = temp
;
3858 i
= *(orderlist
+ botsel
);
3859 *(orderlist
+ botsel
) = *(orderlist
+ botsel
- 1);
3860 *(orderlist
+ botsel
- 1) = i
;
3865 /* Find next topmost element */
3866 botsel
= topobject
->parts
;
3867 for (sel
= areawin
->selectlist
; sel
< areawin
->selectlist
+ areawin
->selects
;
3869 if (*sel
> minsel
) {
3870 if (*sel
< botsel
) {
3876 if (botsel
== topobject
->parts
) break; /* No more elements to raise */
3879 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
, orderlist
,
3883 /*------------------------------------------------------*/
3884 /* Generate a virtual copy of an object instance in the */
3885 /* user library. This is like the library virtual copy */
3886 /* except that it allows the user to generate a library */
3887 /* copy of an existing instance, without having to make */
3888 /* a copy of the master library instance and edit it. */
3889 /* copyvirtual() also allows the library virtual */
3890 /* instance to take on a specific rotation or flip */
3891 /* value, which cannot be done with the library virtual */
3892 /* copy function. */
3893 /*------------------------------------------------------*/
3897 short *selectno
, created
= 0;
3898 objinstptr vcpobj
, libinst
;
3900 for (selectno
= areawin
->selectlist
; selectno
< areawin
->selectlist
+
3901 areawin
->selects
; selectno
++) {
3902 if (SELECTTYPE(selectno
) == OBJINST
) {
3903 vcpobj
= SELTOOBJINST(selectno
);
3904 libinst
= addtoinstlist(USERLIB
- LIBRARY
, vcpobj
->thisobject
, TRUE
);
3905 instcopy(libinst
, vcpobj
);
3910 Wprintf("No object instances selected for virtual copy!");
3914 composelib(USERLIB
);
3918 /*------------------------------------------------------*/
3919 /* Exchange the list position (drawing order) of two */
3920 /* elements, or move the position of one element to the */
3921 /* top or bottom. */
3922 /*------------------------------------------------------*/
3926 short *selectno
, *orderlist
, i
;
3927 genericptr
*exchobj
, *exchobj2
, temp
;
3928 Boolean preselected
;
3930 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
3931 if (!checkselect(ALL_TYPES
)) {
3932 Wprintf("Select 1 or 2 objects");
3936 selectno
= areawin
->selectlist
;
3937 orderlist
= (short *)malloc(topobject
->parts
* sizeof(short));
3938 for (i
= 0; i
< topobject
->parts
; i
++) *(orderlist
+ i
) = i
;
3940 if (areawin
->selects
== 1) { /* lower if on top; raise otherwise */
3941 if (*selectno
== topobject
->parts
- 1)
3942 xc_bottom(selectno
, orderlist
);
3944 xc_top(selectno
, orderlist
);
3946 else { /* exchange the two objects */
3947 exchobj
= topobject
->plist
+ *selectno
;
3948 exchobj2
= topobject
->plist
+ *(selectno
+ 1);
3951 *exchobj
= *exchobj2
;
3954 i
= *(orderlist
+ *selectno
);
3955 *(orderlist
+ *selectno
) = *(orderlist
+ *(selectno
+ 1));
3956 *(orderlist
+ *(selectno
+ 1)) = i
;
3958 register_for_undo(XCF_Reorder
, UNDO_MORE
, areawin
->topinstance
,
3959 orderlist
, topobject
->parts
);
3961 incr_changes(topobject
);
3964 drawarea(NULL
, NULL
, NULL
);
3967 /*--------------------------------------------------------*/
3968 /* Flip an element horizontally (POLYGON, ARC, or SPLINE) */
3969 /*--------------------------------------------------------*/
3971 void elhflip(genericptr
*genobj
, short x
)
3973 switch(ELEMENTTYPE(*genobj
)) {
3975 polyptr flippoly
= TOPOLY(genobj
);
3977 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
3978 flippoly
->number
; ppoint
++)
3979 ppoint
->x
= (x
<< 1) - ppoint
->x
;
3983 arcptr fliparc
= TOARC(genobj
);
3984 float tmpang
= 180 - fliparc
->angle1
;
3985 fliparc
->angle1
= 180 - fliparc
->angle2
;
3986 fliparc
->angle2
= tmpang
;
3987 if (fliparc
->angle2
< 0) {
3988 fliparc
->angle1
+= 360;
3989 fliparc
->angle2
+= 360;
3991 fliparc
->radius
= -fliparc
->radius
;
3992 fliparc
->position
.x
= (x
<< 1) - fliparc
->position
.x
;
3997 splineptr flipspline
= TOSPLINE(genobj
);
3999 for (i
= 0; i
< 4; i
++)
4000 flipspline
->ctrl
[i
].x
= (x
<< 1) - flipspline
->ctrl
[i
].x
;
4001 calcspline(flipspline
);
4006 /*--------------------------------------------------------*/
4007 /* Flip an element vertically (POLYGON, ARC, or SPLINE) */
4008 /*--------------------------------------------------------*/
4010 void elvflip(genericptr
*genobj
, short y
)
4012 switch(ELEMENTTYPE(*genobj
)) {
4015 polyptr flippoly
= TOPOLY(genobj
);
4018 for (ppoint
= flippoly
->points
; ppoint
< flippoly
->points
+
4019 flippoly
->number
; ppoint
++)
4020 ppoint
->y
= (y
<< 1) - ppoint
->y
;
4024 arcptr fliparc
= TOARC(genobj
);
4025 float tmpang
= 360 - fliparc
->angle1
;
4026 fliparc
->angle1
= 360 - fliparc
->angle2
;
4027 fliparc
->angle2
= tmpang
;
4028 if (fliparc
->angle1
>= 360) {
4029 fliparc
->angle1
-= 360;
4030 fliparc
->angle2
-= 360;
4032 fliparc
->radius
= -fliparc
->radius
;
4033 fliparc
->position
.y
= (y
<< 1) - fliparc
->position
.y
;
4038 splineptr flipspline
= TOSPLINE(genobj
);
4040 for (i
= 0; i
< 4; i
++)
4041 flipspline
->ctrl
[i
].y
= (y
<< 1) - flipspline
->ctrl
[i
].y
;
4042 calcspline(flipspline
);
4047 /*------------------------------------------------------*/
4048 /* Horizontally flip an element */
4049 /*------------------------------------------------------*/
4051 void elementflip(XPoint
*position
)
4054 Boolean single
= False
;
4055 Boolean preselected
;
4057 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4058 if (!checkselect(ALL_TYPES
)) return;
4059 if (areawin
->selects
== 1) single
= True
;
4061 if (eventmode
!= COPY_MODE
)
4062 register_for_undo(XCF_Flip_X
, UNDO_MORE
, areawin
->topinstance
,
4063 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4065 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4066 + areawin
->selects
; selectobj
++) {
4068 /* erase the object */
4069 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4070 easydraw(*selectobj
, DOFORALL
);
4072 switch(SELECTTYPE(selectobj
)) {
4074 labelptr fliplab
= SELTOLABEL(selectobj
);
4075 if ((fliplab
->anchor
& (RIGHT
| NOTLEFT
)) != NOTLEFT
)
4076 fliplab
->anchor
^= (RIGHT
| NOTLEFT
);
4078 fliplab
->position
.x
= (position
->x
<< 1) - fliplab
->position
.x
;
4081 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4082 flipg
->scale
= -flipg
->scale
;
4084 flipg
->valid
= FALSE
;
4085 #endif /* !HAVE_CAIRO */
4087 flipg
->position
.x
= (position
->x
<< 1) - flipg
->position
.x
;
4090 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4091 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4092 flipobj
->scale
= -flipobj
->scale
;
4094 flipobj
->position
.x
= (position
->x
<< 1) - flipobj
->position
.x
;
4096 case POLYGON
: case ARC
: case SPLINE
:
4097 elhflip(topobject
->plist
+ *selectobj
, position
->x
);
4100 genericptr
*genpart
;
4101 pathptr flippath
= SELTOPATH(selectobj
);
4103 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4104 + flippath
->parts
; genpart
++)
4105 elhflip(genpart
, position
->x
);
4109 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4110 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4111 easydraw(*selectobj
, DOFORALL
);
4114 select_invalidate_netlist();
4115 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4119 if (eventmode
== NORMAL_MODE
)
4120 incr_changes(topobject
);
4121 if (eventmode
== CATALOG_MODE
) {
4123 if ((libnum
= is_library(topobject
)) >= 0) {
4124 composelib(libnum
+ LIBRARY
);
4125 drawarea(NULL
, NULL
, NULL
);
4129 pwriteback(areawin
->topinstance
);
4130 calcbbox(areawin
->topinstance
);
4134 /*----------------------------------------------*/
4135 /* Vertically flip an element */
4136 /*----------------------------------------------*/
4138 void elementvflip(XPoint
*position
)
4141 /*short fsign; (jdk) */
4142 Boolean preselected
;
4143 Boolean single
= False
;
4145 preselected
= (areawin
->selects
> 0) ? TRUE
: FALSE
;
4146 if (!checkselect(ALL_TYPES
)) return;
4147 if (areawin
->selects
== 1) single
= True
;
4149 if (eventmode
!= COPY_MODE
)
4150 register_for_undo(XCF_Flip_Y
, UNDO_MORE
, areawin
->topinstance
,
4151 (eventmode
== MOVE_MODE
) ? &areawin
->origin
: position
);
4153 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
4154 + areawin
->selects
; selectobj
++) {
4156 /* erase the object */
4157 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4158 easydraw(*selectobj
, DOFORALL
);
4160 switch(SELECTTYPE(selectobj
)) {
4162 labelptr fliplab
= SELTOLABEL(selectobj
);
4163 if ((fliplab
->anchor
& (TOP
| NOTBOTTOM
)) != NOTBOTTOM
)
4164 fliplab
->anchor
^= (TOP
| NOTBOTTOM
);
4166 fliplab
->position
.y
= (position
->y
<< 1) - fliplab
->position
.y
;
4169 objinstptr flipobj
= SELTOOBJINST(selectobj
);
4171 if (is_library(topobject
) >= 0 && !is_virtual(flipobj
)) break;
4172 flipobj
->scale
= -(flipobj
->scale
);
4173 flipobj
->rotation
+= 180;
4174 while (flipobj
->rotation
>= 360) flipobj
->rotation
-= 360;
4176 flipobj
->position
.y
= (position
->y
<< 1) - flipobj
->position
.y
;
4179 graphicptr flipg
= SELTOGRAPHIC(selectobj
);
4181 flipg
->scale
= -(flipg
->scale
);
4182 flipg
->rotation
+= 180;
4183 while (flipg
->rotation
>= 360) flipg
->rotation
-= 360;
4185 flipg
->position
.y
= (position
->y
<< 1) - flipg
->position
.y
;
4187 case POLYGON
: case ARC
: case SPLINE
:
4188 elvflip(topobject
->plist
+ *selectobj
, position
->y
);
4191 genericptr
*genpart
;
4192 pathptr flippath
= SELTOPATH(selectobj
);
4194 for (genpart
= flippath
->plist
; genpart
< flippath
->plist
4195 + flippath
->parts
; genpart
++)
4196 elvflip(genpart
, position
->y
);
4199 if (preselected
|| (eventmode
!= NORMAL_MODE
)) {
4200 SetForeground(dpy
, areawin
->gc
, SELECTCOLOR
);
4201 easydraw(*selectobj
, DOFORALL
);
4204 select_invalidate_netlist();
4205 if (eventmode
== NORMAL_MODE
|| eventmode
== CATALOG_MODE
)
4208 if (eventmode
== NORMAL_MODE
) {
4209 incr_changes(topobject
);
4211 if (eventmode
== CATALOG_MODE
) {
4213 if ((libnum
= is_library(topobject
)) >= 0) {
4214 composelib(libnum
+ LIBRARY
);
4215 drawarea(NULL
, NULL
, NULL
);
4219 pwriteback(areawin
->topinstance
);
4220 calcbbox(areawin
->topinstance
);
4224 /*----------------------------------------*/
4225 /* ButtonPress handler during delete mode */
4226 /*----------------------------------------*/
4228 void deletebutton(int x
, int y
)
4230 UNUSED(x
); UNUSED(y
);
4232 if (checkselect(ALL_TYPES
)) {
4233 standard_element_delete(ERASE
);
4234 calcbbox(areawin
->topinstance
);
4236 setoptionmenu(); /* Return GUI check/radio boxes to default */
4239 /*----------------------------------------------------------------------*/
4240 /* Process of element deletion. Remove one element from the indicated */
4242 /*----------------------------------------------------------------------*/
4244 void delete_one_element(objinstptr thisinstance
, genericptr thiselement
)
4246 objectptr thisobject
;
4248 Boolean pinchange
= False
;
4250 thisobject
= thisinstance
->thisobject
;
4252 /* The netlist contains pointers to elements which no longer */
4253 /* exist on the page, so we should remove them from the netlist. */
4255 if (RemoveFromNetlist(thisobject
, thiselement
)) pinchange
= True
;
4256 for (genobj
= thisobject
->plist
; genobj
< thisobject
->plist
4257 + thisobject
->parts
; genobj
++)
4258 if (*genobj
== thiselement
)
4261 if (genobj
== thisobject
->plist
+ thisobject
->parts
) return;
4263 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4264 *(genobj
- 1) = *genobj
;
4265 thisobject
->parts
--;
4267 if (pinchange
) setobjecttype(thisobject
);
4268 incr_changes(thisobject
);
4269 calcbbox(thisinstance
);
4270 invalidate_netlist(thisobject
);
4271 /* freenetlist(thisobject); */
4274 /*----------------------------------------------------------------------*/
4275 /* Process of element deletion. Remove everything in the selection */
4276 /* list from the indicated object, and return a new object containing */
4277 /* only the deleted elements. */
4279 /* if drawmode is DRAW, we erase the objects as we remove them. */
4281 /* Note that if "slist" is areawin->selectlist, it is freed by this */
4282 /* routine (calls freeselects()), but not otherwise. */
4283 /*----------------------------------------------------------------------*/
4285 objectptr
delete_element(objinstptr thisinstance
, short *slist
, int selects
,
4289 objectptr delobj
, thisobject
;
4291 Boolean pinchange
= False
;
4293 if (slist
== NULL
|| selects
== 0) return NULL
;
4295 thisobject
= thisinstance
->thisobject
;
4297 delobj
= (objectptr
) malloc(sizeof(object
));
4301 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
4304 for (selectobj
= slist
; selectobj
< slist
+ selects
; selectobj
++) {
4305 genobj
= thisobject
->plist
+ *selectobj
;
4306 if (drawmode
) easydraw(*selectobj
, DOFORALL
);
4308 *(delobj
->plist
+ delobj
->parts
) = *genobj
;
4311 /* The netlist contains pointers to elements which no longer */
4312 /* exist on the page, so we should remove them from the netlist. */
4314 if (RemoveFromNetlist(thisobject
, *genobj
)) pinchange
= True
;
4315 for (++genobj
; genobj
< thisobject
->plist
+ thisobject
->parts
; genobj
++)
4316 *(genobj
- 1) = *genobj
;
4317 thisobject
->parts
--;
4318 reviseselect(slist
, selects
, selectobj
);
4320 if (pinchange
) setobjecttype(thisobject
);
4322 if (slist
== areawin
->selectlist
)
4325 calcbbox(thisinstance
);
4326 /* freenetlist(thisobject); */
4329 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
4330 drawarea(NULL
, NULL
, NULL
);
4335 /*----------------------------------------------------------------------*/
4336 /* Wrapper for delete_element(). Remember this deletion for the undo */
4338 /*----------------------------------------------------------------------*/
4340 void standard_element_delete(short drawmode
)
4344 /* register_for_undo(XCF_Select, UNDO_MORE, areawin->topinstance, */
4345 /* areawin->selectlist, areawin->selects); */
4346 select_invalidate_netlist();
4347 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4348 areawin
->selects
, drawmode
);
4349 register_for_undo(XCF_Delete
, UNDO_DONE
, areawin
->topinstance
,
4350 delobj
, (int)drawmode
);
4351 incr_changes(topobject
); /* Treat as one change */
4354 /*----------------------------------------------------------------------*/
4355 /* Another wrapper for delete_element(), in which we do not save the */
4356 /* deletion as an undo event. However, the returned object is saved */
4357 /* on areawin->editstack, so that the objects can be grabbed. This */
4358 /* allows objects to be carried across pages and through the hierarchy. */
4359 /*----------------------------------------------------------------------*/
4361 void delete_for_xfer(short drawmode
, short *slist
, int selects
)
4364 reset(areawin
->editstack
, DESTROY
);
4365 areawin
->editstack
= delete_element(areawin
->topinstance
,
4366 slist
, selects
, drawmode
);
4370 /*----------------------------------------------------------------------*/
4371 /* Yet another wrapper for delete_element(), in which we destroy the */
4372 /* object returned and free all associated memory. */
4373 /*----------------------------------------------------------------------*/
4375 void delete_noundo(short drawmode
)
4379 select_invalidate_netlist();
4380 delobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4381 areawin
->selects
, drawmode
);
4383 if (delobj
!= NULL
) reset(delobj
, DESTROY
);
4386 /*----------------------------------------------------------------------*/
4387 /* Undelete last deleted elements and return a selectlist of the */
4388 /* elements. If "olist" is non-NULL, then the undeleted elements are */
4389 /* placed into the object of thisinstance in the order given by olist, */
4390 /* and a copy of olist is returned. If "olist" is NULL, then the */
4391 /* undeleted elements are placed at the end of thisinstance->thisobject */
4392 /* ->plist, and a new selection list is returned. If "olist" is non- */
4393 /* NULL, then the size of olist had better match the number of objects */
4394 /* in delobj! It is up to the calling routine to check this. */
4395 /*----------------------------------------------------------------------*/
4397 short *xc_undelete(objinstptr thisinstance
, objectptr delobj
, short mode
,
4400 objectptr thisobject
;
4402 short *slist
, count
, i
; /* position; (jdk) */
4404 thisobject
= thisinstance
->thisobject
;
4405 slist
= (short *)malloc(delobj
->parts
* sizeof(short));
4408 for (regen
= delobj
->plist
; regen
< delobj
->plist
+ delobj
->parts
; regen
++) {
4409 PLIST_INCR(thisobject
);
4410 if (olist
== NULL
) {
4411 *(slist
+ count
) = thisobject
->parts
;
4412 *(topobject
->plist
+ topobject
->parts
) = *regen
;
4415 *(slist
+ count
) = *(olist
+ count
);
4416 for (i
= thisobject
->parts
; i
> *(olist
+ count
); i
--)
4417 *(thisobject
->plist
+ i
) = *(thisobject
->plist
+ i
- 1);
4418 *(thisobject
->plist
+ i
) = *regen
;
4420 thisobject
->parts
++;
4422 XTopSetForeground((*regen
)->color
);
4423 easydraw(*(slist
+ count
), DEFAULTCOLOR
);
4427 /* If the element has passed parameters (eparam), then we have to */
4428 /* check if the key exists in the new parent object. If not, */
4429 /* delete the parameter. */
4431 if ((*regen
)->passed
) {
4432 eparamptr nextepp
, epp
= (*regen
)->passed
;
4433 while (epp
!= NULL
) {
4434 nextepp
= epp
->next
;
4435 if (!match_param(thisobject
, epp
->key
)) {
4436 if (epp
== (*regen
)->passed
) (*regen
)->passed
= nextepp
;
4437 free_element_param(*regen
, epp
);
4443 /* Likewise, string parameters must be checked in labels because */
4444 /* they act like element parameters. */
4446 if (IS_LABEL(*regen
)) {
4447 labelptr glab
= TOLABEL(regen
);
4448 stringpart
*gstr
, *lastpart
= NULL
;
4449 for (gstr
= glab
->string
; gstr
!= NULL
; gstr
= lastpart
->nextpart
) {
4450 if (gstr
->type
== PARAM_START
) {
4451 if (!match_param(thisobject
, gstr
->data
.string
)) {
4452 free(gstr
->data
.string
);
4454 lastpart
->nextpart
= gstr
->nextpart
;
4456 glab
->string
= gstr
->nextpart
;
4458 gstr
= (lastpart
) ? lastpart
: glab
->string
;
4465 incr_changes(thisobject
); /* treat as one change */
4466 calcbbox(thisinstance
);
4468 /* flush the delete buffer but don't delete the elements */
4469 reset(delobj
, SAVE
);
4471 if (delobj
!= areawin
->editstack
) free(delobj
);
4476 /*----------------------------*/
4477 /* select save object handler */
4478 /*----------------------------*/
4480 void printname(objectptr curobject
)
4482 char editstr
[10], pagestr
[10];
4487 Dimension swidth
, swidth2
, sarea
;
4489 char *sptr
= tmpname
;
4492 /* print full string to make message widget proper size */
4494 strcpy(editstr
, ((ispage
= is_page(curobject
)) >= 0) ? "Editing: " : "");
4495 strcpy(editstr
, (is_library(curobject
) >= 0) ? "Library: " : "");
4496 if (strstr(curobject
->name
, "Page") == NULL
&& (ispage
>= 0))
4497 sprintf(pagestr
, " (p. %d)", areawin
->page
+ 1);
4500 W2printf("%s%s%s", editstr
, curobject
->name
, pagestr
);
4502 /* Tcl doesn't update width changes immediately. . . what to do? */
4503 /* (i.e., Tk_Width(message2) gives the original width) */
4506 XtSetArg(wargs
[0], XtNwidth
, &sarea
);
4507 XtGetValues(message2
, wargs
, 1);
4509 /* in the remote case that the string is longer than message widget, */
4510 /* truncate the string and denote the truncation with an ellipsis (...) */
4512 strcpy(tmpname
, curobject
->name
);
4513 swidth2
= XTextWidth(appdata
.xcfont
, editstr
, strlen(editstr
));
4514 swidth
= XTextWidth(appdata
.xcfont
, tmpname
, strlen(tmpname
));
4516 if ((swidth
+ swidth2
) > sarea
) {
4518 while ((swidth
+ swidth2
) > sarea
) {
4520 swidth
= XTextWidth(appdata
.xcfont
, sptr
, strlen(sptr
));
4522 for(ip
= sptr
; ip
< sptr
+ 3 && *ip
!= '\0'; ip
++) *ip
= '.';
4524 W2printf("Editing: %s", sptr
);
4529 /*--------------------------------------------------------------*/
4530 /* Make sure that a string does not conflict with postscript */
4531 /* names (commands and definitions found in xcircps2.pro). */
4533 /* Return value is NULL if no change was made. Otherwise, the */
4534 /* return value is an allocated string. */
4535 /*--------------------------------------------------------------*/
4537 char *checkvalidname(char *teststring
, objectptr newobj
)
4540 short dupl
; /* flag a duplicate string */
4542 char *sptr
, *pptr
, *cptr
;
4546 /* Try not to allocate memory unless necessary */
4553 if (newobj
!= NULL
) {
4554 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4555 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4556 libobj
= xobjs
.userlibs
[i
].library
+ j
;
4558 if (*libobj
== newobj
) continue;
4559 if (!strcmp(pptr
, (*libobj
)->name
)) {
4561 /* Prepend an underscore to the object name. If the */
4562 /* object has no technology, create a null technology */
4563 /* name. Otherwise, the technology remains the same */
4564 /* but the object name gets the prepended underscore. */
4566 if ((cptr
= strstr(pptr
, "::")) == NULL
) {
4567 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 4);
4568 sprintf(pptr
, "::_%s", (*libobj
)->name
);
4571 int offset
= cptr
- pptr
+ 2;
4573 pptr
= (char *)malloc(strlen((*libobj
)->name
) + 2);
4575 pptr
= (char *)realloc(pptr
, strlen((*libobj
)->name
) + 2);
4576 sprintf(pptr
, "%s", (*libobj
)->name
);
4577 sprintf(pptr
+ offset
, "_%s", (*libobj
)->name
+ offset
);
4584 /* If we're in the middle of a file load, the name cannot be */
4585 /* the same as an alias, either. */
4587 if (aliastop
!= NULL
) {
4588 for (aref
= aliastop
; aref
!= NULL
; aref
= aref
->next
) {
4589 for (sref
= aref
->aliases
; sref
!= NULL
; sref
= sref
->next
) {
4590 if (!strcmp(pptr
, sref
->alias
)) {
4592 pptr
= (char *)malloc(strlen(sref
->alias
) + 2);
4594 pptr
= (char *)realloc(pptr
, strlen(sref
->alias
) + 2);
4595 sprintf(pptr
, "_%s", sref
->alias
);
4603 } while (dupl
== 1);
4605 return (pptr
== sptr
) ? NULL
: pptr
;
4608 /*--------------------------------------------------------------*/
4609 /* Make sure that name for new object does not conflict with */
4610 /* existing object definitions */
4612 /* Return: True if name required change, False otherwise */
4613 /*--------------------------------------------------------------*/
4615 Boolean
checkname(objectptr newobj
)
4619 /* Check for empty string */
4620 if (strlen(newobj
->name
) == 0) {
4621 Wprintf("Blank object name changed to default");
4622 sprintf(newobj
->name
, "user_object");
4625 pptr
= checkvalidname(newobj
->name
, newobj
);
4627 /* Change name if necessary to avoid naming conflicts */
4629 Wprintf("Created new object %s", newobj
->name
);
4633 Wprintf("Changed name from %s to %s to avoid conflict with "
4634 "existing object", newobj
->name
, pptr
);
4636 strncpy(newobj
->name
, pptr
, 79);
4642 /*------------------------------------------------------------*/
4643 /* Find the object "dot" in the builtin library, if it exists */
4644 /*------------------------------------------------------------*/
4652 for (i
= 0; i
< xobjs
.numlibs
; i
++) {
4653 for (j
= 0; j
< xobjs
.userlibs
[i
].number
; j
++) {
4654 dotobj
= *(xobjs
.userlibs
[i
].library
+ j
);
4655 name
= dotobj
->name
;
4656 if ((pptr
= strstr(name
, "::")) != NULL
) name
= pptr
+ 2;
4657 if (!strcmp(name
, "dot")) {
4662 return (objectptr
)NULL
;
4665 /*--------------------------------------*/
4666 /* Add value origin to all points */
4667 /*--------------------------------------*/
4669 void movepoints(genericptr
*ssgen
, short deltax
, short deltay
)
4671 switch(ELEMENTTYPE(*ssgen
)) {
4673 fpointlist sspoints
;
4674 TOARC(ssgen
)->position
.x
+= deltax
;
4675 TOARC(ssgen
)->position
.y
+= deltay
;
4676 for (sspoints
= TOARC(ssgen
)->points
; sspoints
< TOARC(ssgen
)->points
+
4677 TOARC(ssgen
)->number
; sspoints
++) {
4678 sspoints
->x
+= deltax
;
4679 sspoints
->y
+= deltay
;
4685 for (sspoints
= TOPOLY(ssgen
)->points
; sspoints
< TOPOLY(ssgen
)->points
+
4686 TOPOLY(ssgen
)->number
; sspoints
++) {
4687 sspoints
->x
+= deltax
;
4688 sspoints
->y
+= deltay
;
4693 fpointlist sspoints
;
4695 for (sspoints
= TOSPLINE(ssgen
)->points
; sspoints
<
4696 TOSPLINE(ssgen
)->points
+ INTSEGS
; sspoints
++) {
4697 sspoints
->x
+= deltax
;
4698 sspoints
->y
+= deltay
;
4700 for (j
= 0; j
< 4; j
++) {
4701 TOSPLINE(ssgen
)->ctrl
[j
].x
+= deltax
;
4702 TOSPLINE(ssgen
)->ctrl
[j
].y
+= deltay
;
4706 TOOBJINST(ssgen
)->position
.x
+= deltax
;
4707 TOOBJINST(ssgen
)->position
.y
+= deltay
;
4710 TOGRAPHIC(ssgen
)->position
.x
+= deltax
;
4711 TOGRAPHIC(ssgen
)->position
.y
+= deltay
;
4714 TOLABEL(ssgen
)->position
.x
+= deltax
;
4715 TOLABEL(ssgen
)->position
.y
+= deltay
;
4720 /*----------------------------------------------------------------------*/
4721 /* Add value origin to all edited points, according to edit flags */
4722 /*----------------------------------------------------------------------*/
4724 void editpoints(genericptr
*ssgen
, short deltax
, short deltay
)
4728 splineptr editspline
;
4729 short cycle
, cpoint
;
4734 switch(ELEMENTTYPE(*ssgen
)) {
4736 editpoly
= TOPOLY(ssgen
);
4737 if (editpoly
->cycle
== NULL
)
4738 movepoints(ssgen
, deltax
, deltay
);
4740 for (cptr
= editpoly
->cycle
;; cptr
++) {
4741 cycle
= cptr
->number
;
4742 curpt
= editpoly
->points
+ cycle
;
4743 if (cptr
->flags
& EDITX
) curpt
->x
+= deltax
;
4744 if (cptr
->flags
& EDITY
) curpt
->y
+= deltay
;
4745 if (cptr
->flags
& LASTENTRY
) break;
4752 editspline
= TOSPLINE(ssgen
);
4753 if (editspline
->cycle
== NULL
)
4754 movepoints(ssgen
, deltax
, deltay
);
4756 for (cptr
= editspline
->cycle
;; cptr
++) {
4757 cycle
= cptr
->number
;
4758 if (cycle
== 0 || cycle
== 3) {
4759 cpoint
= (cycle
== 0) ? 1 : 2;
4760 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cpoint
].x
+= deltax
;
4761 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cpoint
].y
+= deltay
;
4763 if (cptr
->flags
& EDITX
) editspline
->ctrl
[cycle
].x
+= deltax
;
4764 if (cptr
->flags
& EDITY
) editspline
->ctrl
[cycle
].y
+= deltay
;
4765 if (cptr
->flags
& ANTIXY
) {
4766 editspline
->ctrl
[cycle
].x
-= deltax
;
4767 editspline
->ctrl
[cycle
].y
-= deltay
;
4769 if (cptr
->flags
& LASTENTRY
) break;
4773 calcspline(editspline
);
4777 editpath
= TOPATH(ssgen
);
4778 if (checkcycle(*ssgen
, 0) < 0) {
4779 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4781 movepoints(ggen
, deltax
, deltay
);
4784 for (ggen
= editpath
->plist
; ggen
< editpath
->plist
+ editpath
->parts
;
4786 if (checkcycle(*ggen
, 0) >= 0)
4787 editpoints(ggen
, deltax
, deltay
);
4793 movepoints(ssgen
, deltax
, deltay
);
4801 void xlib_makeobject(xcWidget w
, caddr_t nulldata
)
4803 UNUSED(w
); UNUSED(nulldata
);
4805 domakeobject(-1, (char *)_STR2
, FALSE
);
4808 #endif /* !TCL_WRAPPER */
4810 /*--------------------------------------------------------------*/
4811 /* Set the name for a new user-defined object and make the */
4812 /* object. If "forceempty" is true, we allow creation of a new */
4813 /* object with no elements (normally would be used only from a */
4814 /* script, where an object is being constructed automatically). */
4815 /*--------------------------------------------------------------*/
4817 objinstptr
domakeobject(int libnum
, char *name
, Boolean forceempty
)
4820 objinstptr
*newinst
;
4822 oparamptr ops
, newop
;
4823 eparamptr epp
, newepp
;
4826 short loclibnum
= libnum
;
4828 if (libnum
== -1) loclibnum
= USERLIB
- LIBRARY
;
4830 /* make room for new entry in library list */
4832 xobjs
.userlibs
[loclibnum
].library
= (objectptr
*)
4833 realloc(xobjs
.userlibs
[loclibnum
].library
,
4834 (xobjs
.userlibs
[loclibnum
].number
+ 1) * sizeof(objectptr
));
4836 newobj
= xobjs
.userlibs
[loclibnum
].library
+ xobjs
.userlibs
[loclibnum
].number
;
4838 *newobj
= delete_element(areawin
->topinstance
, areawin
->selectlist
,
4839 areawin
->selects
, NORMAL
);
4841 if (*newobj
== NULL
) {
4844 if (!forceempty
) return NULL
;
4846 /* Create a new (empty) object */
4848 initobj
= (objectptr
) malloc(sizeof(object
));
4853 invalidate_netlist(topobject
);
4854 xobjs
.userlibs
[loclibnum
].number
++;
4856 /* Create the instance of this object so we can compute a bounding box */
4858 NEW_OBJINST(newinst
, topobject
);
4859 instancedefaults(*newinst
, *newobj
, 0, 0);
4862 /* find closest snap point to bbox center and make this the obj. center */
4864 if (areawin
->center
) {
4865 origin
.x
= (*newobj
)->bbox
.lowerleft
.x
+ (*newobj
)->bbox
.width
/ 2;
4866 origin
.y
= (*newobj
)->bbox
.lowerleft
.y
+ (*newobj
)->bbox
.height
/ 2;
4869 origin
.x
= origin
.y
= 0;
4872 instancedefaults(*newinst
, *newobj
, origin
.x
, origin
.y
);
4874 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4876 switch(ELEMENTTYPE(*ssgen
)) {
4879 TOOBJINST(ssgen
)->position
.x
-= origin
.x
;
4880 TOOBJINST(ssgen
)->position
.y
-= origin
.y
;
4884 TOGRAPHIC(ssgen
)->position
.x
-= origin
.x
;
4885 TOGRAPHIC(ssgen
)->position
.y
-= origin
.y
;
4889 TOLABEL(ssgen
)->position
.x
-= origin
.x
;
4890 TOLABEL(ssgen
)->position
.y
-= origin
.y
;
4894 genericptr
*pathlist
;
4895 for (pathlist
= TOPATH(ssgen
)->plist
; pathlist
< TOPATH(ssgen
)->plist
4896 + TOPATH(ssgen
)->parts
; pathlist
++) {
4897 movepoints(pathlist
, -origin
.x
, -origin
.y
);
4902 movepoints(ssgen
, -origin
.x
, -origin
.y
);
4907 for (ssgen
= (*newobj
)->plist
; ssgen
< (*newobj
)->plist
+ (*newobj
)->parts
;
4909 for (epp
= (*ssgen
)->passed
; epp
!= NULL
; epp
= epp
->next
) {
4910 ops
= match_param(topobject
, epp
->key
);
4911 newop
= copyparameter(ops
);
4912 newop
->next
= (*newobj
)->params
;
4913 (*newobj
)->params
= newop
;
4915 /* Generate an indirect parameter reference from child to parent */
4916 newepp
= make_new_eparam(epp
->key
);
4917 newepp
->flags
|= P_INDIRECT
;
4918 newepp
->pdata
.refkey
= strdup(epp
->key
);
4919 newepp
->next
= (*newinst
)->passed
;
4920 (*newinst
)->passed
= newepp
;
4922 if (IS_LABEL(*ssgen
)) {
4923 /* Also need to check for substring parameters in labels */
4924 for (sptr
= TOLABEL(ssgen
)->string
; sptr
!= NULL
; sptr
= sptr
->nextpart
) {
4925 if (sptr
->type
== PARAM_START
) {
4926 ops
= match_param(topobject
, sptr
->data
.string
);
4928 newop
= copyparameter(ops
);
4929 newop
->next
= (*newobj
)->params
;
4930 (*newobj
)->params
= newop
;
4933 /* Generate an indirect parameter reference from child to parent */
4934 newepp
= make_new_eparam(sptr
->data
.string
);
4935 newepp
->flags
|= P_INDIRECT
;
4936 newepp
->pdata
.refkey
= strdup(sptr
->data
.string
);
4937 newepp
->next
= (*newinst
)->passed
;
4938 (*newinst
)->passed
= newepp
;
4944 /* any parameters in the top-level object that used by the selected */
4945 /* elements must be copied into the new object. */
4947 /* put new object back into place */
4949 (*newobj
)->hidden
= False
;
4950 (*newobj
)->schemtype
= SYMBOL
;
4953 incr_changes(*newobj
);
4955 /* (netlist invalidation was taken care of by delete_element() */
4956 /* Also, incr_changes(topobject) was done by delete_element()) */
4958 XTopSetForeground((*newinst
)->color
);
4959 UDrawObject(*newinst
, SINGLE
, (*newinst
)->color
,
4960 xobjs
.pagelist
[areawin
->page
]->wirewidth
, NULL
);
4963 /* Copy name into object and check for conflicts */
4965 strcpy((*newobj
)->name
, name
);
4968 /* register the technology and mark the technology as not saved */
4969 AddObjectTechnology(*newobj
);
4971 /* generate library instance for this object (bounding box */
4972 /* should be default, so don't do calcbbox() on it) */
4974 addtoinstlist(loclibnum
, *newobj
, FALSE
);
4976 /* recompile the user catalog and reset view bounds */
4978 composelib(loclibnum
+ LIBRARY
);
4979 centerview(xobjs
.libtop
[loclibnum
+ LIBRARY
]);
4986 /*-------------------------------------------*/
4987 /* Make a user object from selected elements */
4988 /*-------------------------------------------*/
4990 void selectsave(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
4992 buttonsave
*popdata
= (buttonsave
*)malloc(sizeof(buttonsave
));
4993 UNUSED(clientdata
); UNUSED(calldata
);
4995 if (areawin
->selects
== 0) return; /* nothing was selected */
4997 /* Get a name for the new object */
4999 eventmode
= NORMAL_MODE
;
5000 popdata
->dataptr
= NULL
;
5001 popdata
->button
= NULL
; /* indicates that no button is assc'd w/ the popup */
5002 popupprompt(w
, "Enter name for new object:", "\0", xlib_makeobject
, popdata
, NULL
);
5007 /*-----------------------------*/
5008 /* Edit-stack support routines */
5009 /*-----------------------------*/
5011 void arceditpush(arcptr lastarc
)
5015 NEW_ARC(newarc
, areawin
->editstack
);
5016 arccopy(*newarc
, lastarc
);
5017 copycycles(&((*newarc
)->cycle
), &(lastarc
->cycle
));
5020 /*--------------------------------------*/
5022 void splineeditpush(splineptr lastspline
)
5024 splineptr
*newspline
;
5026 NEW_SPLINE(newspline
, areawin
->editstack
);
5027 splinecopy(*newspline
, lastspline
);
5030 /*--------------------------------------*/
5032 void polyeditpush(polyptr lastpoly
)
5036 NEW_POLY(newpoly
, areawin
->editstack
);
5037 polycopy(*newpoly
, lastpoly
);
5040 /*--------------------------------------*/
5042 void patheditpush(pathptr lastpath
)
5046 NEW_PATH(newpath
, areawin
->editstack
);
5047 pathcopy(*newpath
, lastpath
);
5050 /*-----------------------------*/
5051 /* Copying support routines */
5052 /*-----------------------------*/
5054 pointlist
copypoints(pointlist points
, int number
)
5056 pointlist rpoints
, cpoints
, newpoints
;
5058 rpoints
= (pointlist
) malloc(number
* sizeof(XPoint
));
5059 for (newpoints
= rpoints
, cpoints
= points
;
5060 newpoints
< rpoints
+ number
;
5061 newpoints
++, cpoints
++) {
5062 newpoints
->x
= cpoints
->x
;
5063 newpoints
->y
= cpoints
->y
;
5068 /*------------------------------------------*/
5070 void graphiccopy(graphicptr newg
, graphicptr copyg
)
5075 newg
->source
= copyg
->source
;
5076 newg
->position
.x
= copyg
->position
.x
;
5077 newg
->position
.y
= copyg
->position
.y
;
5078 newg
->rotation
= copyg
->rotation
;
5079 newg
->scale
= copyg
->scale
;
5080 newg
->color
= copyg
->color
;
5081 newg
->passed
= NULL
;
5082 copyalleparams((genericptr
)newg
, (genericptr
)copyg
);
5084 newg
->valid
= FALSE
;
5085 newg
->target
= NULL
;
5086 newg
->clipmask
= (Pixmap
)NULL
;
5087 #endif /* HAVE_CAIRO */
5089 /* Update the refcount of the source image */
5090 for (i
= 0; i
< xobjs
.images
; i
++) {
5091 iptr
= xobjs
.imagelist
+ i
;
5092 if (iptr
->image
== newg
->source
) {
5099 /*------------------------------------------*/
5101 void labelcopy(labelptr newtext
, labelptr copytext
)
5103 newtext
->string
= stringcopy(copytext
->string
);
5104 newtext
->position
.x
= copytext
->position
.x
;
5105 newtext
->position
.y
= copytext
->position
.y
;
5106 newtext
->rotation
= copytext
->rotation
;
5107 newtext
->scale
= copytext
->scale
;
5108 newtext
->anchor
= copytext
->anchor
;
5109 newtext
->color
= copytext
->color
;
5110 newtext
->passed
= NULL
;
5111 newtext
->cycle
= NULL
;
5112 copyalleparams((genericptr
)newtext
, (genericptr
)copytext
);
5113 newtext
->pin
= copytext
->pin
;
5116 /*------------------------------------------*/
5118 void arccopy(arcptr newarc
, arcptr copyarc
)
5120 newarc
->style
= copyarc
->style
;
5121 newarc
->color
= copyarc
->color
;
5122 newarc
->position
.x
= copyarc
->position
.x
;
5123 newarc
->position
.y
= copyarc
->position
.y
;
5124 newarc
->radius
= copyarc
->radius
;
5125 newarc
->yaxis
= copyarc
->yaxis
;
5126 newarc
->angle1
= copyarc
->angle1
;
5127 newarc
->angle2
= copyarc
->angle2
;
5128 newarc
->width
= copyarc
->width
;
5129 newarc
->passed
= NULL
;
5130 newarc
->cycle
= NULL
;
5131 copyalleparams((genericptr
)newarc
, (genericptr
)copyarc
);
5135 /*------------------------------------------*/
5137 void polycopy(polyptr newpoly
, polyptr copypoly
)
5139 newpoly
->style
= copypoly
->style
;
5140 newpoly
->color
= copypoly
->color
;
5141 newpoly
->width
= copypoly
->width
;
5142 newpoly
->number
= copypoly
->number
;
5143 copycycles(&(newpoly
->cycle
), &(copypoly
->cycle
));
5144 newpoly
->points
= copypoints(copypoly
->points
, copypoly
->number
);
5146 newpoly
->passed
= NULL
;
5147 copyalleparams((genericptr
)newpoly
, (genericptr
)copypoly
);
5150 /*------------------------------------------*/
5152 void splinecopy(splineptr newspline
, splineptr copyspline
)
5156 newspline
->style
= copyspline
->style
;
5157 newspline
->color
= copyspline
->color
;
5158 newspline
->width
= copyspline
->width
;
5159 copycycles(&(newspline
->cycle
), &(copyspline
->cycle
));
5160 for (i
= 0; i
< 4; i
++) {
5161 newspline
->ctrl
[i
].x
= copyspline
->ctrl
[i
].x
;
5162 newspline
->ctrl
[i
].y
= copyspline
->ctrl
[i
].y
;
5164 for (i
= 0; i
< INTSEGS
; i
++) {
5165 newspline
->points
[i
].x
= copyspline
->points
[i
].x
;
5166 newspline
->points
[i
].y
= copyspline
->points
[i
].y
;
5168 newspline
->passed
= NULL
;
5169 copyalleparams((genericptr
)newspline
, (genericptr
)copyspline
);
5172 /*----------------------------------------------*/
5174 /*----------------------------------------------*/
5176 void pathcopy(pathptr newpath
, pathptr copypath
)
5179 splineptr
*newspline
, copyspline
;
5180 polyptr
*newpoly
, copypoly
;
5182 newpath
->style
= copypath
->style
;
5183 newpath
->color
= copypath
->color
;
5184 newpath
->width
= copypath
->width
;
5186 newpath
->passed
= NULL
;
5187 copyalleparams((genericptr
)newpath
, (genericptr
)copypath
);
5188 newpath
->plist
= (genericptr
*)malloc(copypath
->parts
* sizeof(genericptr
));
5190 for (ggen
= copypath
->plist
; ggen
< copypath
->plist
+ copypath
->parts
; ggen
++) {
5191 switch (ELEMENTTYPE(*ggen
)) {
5193 copypoly
= TOPOLY(ggen
);
5194 NEW_POLY(newpoly
, newpath
);
5195 polycopy(*newpoly
, copypoly
);
5198 copyspline
= TOSPLINE(ggen
);
5199 NEW_SPLINE(newspline
, newpath
);
5200 splinecopy(*newspline
, copyspline
);
5206 /*--------------------------------------------------------------*/
5207 /* Copy an object instance */
5208 /*--------------------------------------------------------------*/
5210 void instcopy(objinstptr newobj
, objinstptr copyobj
)
5212 newobj
->position
.x
= copyobj
->position
.x
;
5213 newobj
->position
.y
= copyobj
->position
.y
;
5214 newobj
->rotation
= copyobj
->rotation
;
5215 newobj
->scale
= copyobj
->scale
;
5216 newobj
->style
= copyobj
->style
;
5217 newobj
->thisobject
= copyobj
->thisobject
;
5218 newobj
->color
= copyobj
->color
;
5219 newobj
->bbox
.lowerleft
.x
= copyobj
->bbox
.lowerleft
.x
;
5220 newobj
->bbox
.lowerleft
.y
= copyobj
->bbox
.lowerleft
.y
;
5221 newobj
->bbox
.width
= copyobj
->bbox
.width
;
5222 newobj
->bbox
.height
= copyobj
->bbox
.height
;
5224 newobj
->passed
= NULL
;
5225 copyalleparams((genericptr
)newobj
, (genericptr
)copyobj
);
5227 newobj
->params
= NULL
;
5228 copyparams(newobj
, copyobj
);
5230 /* If the parameters are the same, the bounding box should be, too. */
5231 if (copyobj
->schembbox
!= NULL
) {
5232 newobj
->schembbox
= (BBox
*)malloc(sizeof(BBox
));
5233 newobj
->schembbox
->lowerleft
.x
= copyobj
->schembbox
->lowerleft
.x
;
5234 newobj
->schembbox
->lowerleft
.y
= copyobj
->schembbox
->lowerleft
.y
;
5235 newobj
->schembbox
->width
= copyobj
->schembbox
->width
;
5236 newobj
->schembbox
->height
= copyobj
->schembbox
->height
;
5239 newobj
->schembbox
= NULL
;
5242 /*--------------------------------------------------------------*/
5243 /* The method for removing objects from a list is to add the */
5244 /* value REMOVE_TAG to the type of each object needing to be */
5245 /* removed, and then calling this routine. */
5246 /*--------------------------------------------------------------*/
5248 void delete_tagged(objinstptr thisinst
) {
5249 Boolean tagged
= True
;
5250 objectptr thisobject
, delobj
;
5254 thisobject
= thisinst
->thisobject
;
5258 for (stmp
= 0; stmp
< thisobject
->parts
; stmp
++) {
5259 pgen
= thisobject
->plist
+ stmp
;
5260 if ((*pgen
)->type
& REMOVE_TAG
) {
5261 (*pgen
)->type
&= (~REMOVE_TAG
);
5264 delobj
= delete_element(thisinst
, &stmp
, 1, 0);
5265 register_for_undo(XCF_Delete
, UNDO_MORE
, thisinst
, delobj
, 0);
5267 /* If we destroy elements in the current window, we need to */
5268 /* make sure that the selection list is updated appropriately. */
5270 if ((thisobject
== topobject
) && (areawin
->selects
> 0)) {
5271 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5272 areawin
->selects
; sobj
++)
5273 if (*sobj
> stmp
) (*sobj
)--;
5276 /* Also ensure that this element is not referenced in any */
5277 /* netlist. If it is, remove it and mark the netlist as */
5280 remove_netlist_element(thisobject
, *pgen
);
5284 undo_finish_series();
5287 /*-----------------------------------------------------------------*/
5288 /* For copying: Check if an object is about to be placed directly */
5289 /* on top of the same object. If so, delete the one underneath. */
5290 /*-----------------------------------------------------------------*/
5295 genericptr
*sgen
, *pgen
;
5296 Boolean tagged
= False
;
5298 /* Work through the select list */
5300 for (sobj
= areawin
->selectlist
; sobj
< areawin
->selectlist
+
5301 areawin
->selects
; sobj
++) {
5302 sgen
= topobject
->plist
+ (*sobj
);
5304 /* For each object being copied, compare it against every object */
5305 /* on the current page (except self). Flag if it's the same. */
5307 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+ topobject
->parts
;
5309 if (pgen
== sgen
) continue;
5310 if (compare_single(sgen
, pgen
)) {
5311 /* Make sure that this object is not part of the selection, */
5312 /* else chaos will reign. */
5313 for (cobj
= areawin
->selectlist
; cobj
< areawin
->selectlist
+
5314 areawin
->selects
; cobj
++) {
5315 if (pgen
== topobject
->plist
+ (*cobj
)) break;
5317 /* Tag it for future deletion and prevent further compares */
5318 if (cobj
== areawin
->selectlist
+ areawin
->selects
) {
5320 (*pgen
)->type
|= REMOVE_TAG
;
5326 /* Delete the tagged elements */
5327 Wprintf("Duplicate object deleted");
5328 delete_tagged(areawin
->topinstance
);
5329 incr_changes(topobject
);
5333 /*--------------------------------------------------------------*/
5334 /* Direct placement of elements. Assumes that the selectlist */
5335 /* contains all the elements to be positioned. "deltax" and */
5336 /* "deltay" are relative x and y positions to move the */
5338 /*--------------------------------------------------------------*/
5340 void placeselects(short deltax
, short deltay
, XPoint
*userpt
)
5343 XPoint newpos
, *ppt
;
5350 doattach
= ((userpt
== NULL
) || (areawin
->attachto
< 0)) ? FALSE
: TRUE
;
5352 /* under attachto condition, keep element attached to */
5353 /* the attachto element. */
5355 if (doattach
) findattach(&newpos
, &rot
, userpt
);
5359 areawin
->clipped
= -1; /* Prevent clipping */
5360 #endif /* HAVE_CAIRO */
5362 for (dragselect
= areawin
->selectlist
; dragselect
< areawin
->selectlist
5363 + areawin
->selects
; dragselect
++) {
5365 switch(SELECTTYPE(dragselect
)) {
5367 objinstptr draginst
= SELTOOBJINST(dragselect
);
5370 draginst
->position
.x
= newpos
.x
;
5371 draginst
->position
.y
= newpos
.y
;
5372 while (rot
>= 360.0) rot
-= 360.0;
5373 while (rot
< 0.0) rot
+= 360.0;
5374 draginst
->rotation
= rot
;
5377 draginst
->position
.x
+= deltax
;
5378 draginst
->position
.y
+= deltay
;
5383 graphicptr dragg
= SELTOGRAPHIC(dragselect
);
5384 dragg
->position
.x
+= deltax
;
5385 dragg
->position
.y
+= deltay
;
5388 labelptr draglabel
= SELTOLABEL(dragselect
);
5390 draglabel
->position
.x
= newpos
.x
;
5391 draglabel
->position
.y
= newpos
.y
;
5392 draglabel
->rotation
= rot
;
5395 draglabel
->position
.x
+= deltax
;
5396 draglabel
->position
.y
+= deltay
;
5400 pathptr dragpath
= SELTOPATH(dragselect
);
5401 genericptr
*pathlist
;
5404 XPoint
*pdelta
= pathclosepoint(dragpath
, &newpos
);
5405 deltax
= newpos
.x
- pdelta
->x
;
5406 deltay
= newpos
.y
- pdelta
->y
;
5408 for (pathlist
= dragpath
->plist
; pathlist
< dragpath
->plist
5409 + dragpath
->parts
; pathlist
++) {
5410 movepoints(pathlist
, deltax
, deltay
);
5414 polyptr dragpoly
= SELTOPOLY(dragselect
);
5415 pointlist dragpoints
;
5417 /* if (dragpoly->cycle != NULL) continue; */
5419 closest
= closepoint(dragpoly
, &newpos
);
5420 deltax
= newpos
.x
- dragpoly
->points
[closest
].x
;
5421 deltay
= newpos
.y
- dragpoly
->points
[closest
].y
;
5423 for (dragpoints
= dragpoly
->points
; dragpoints
< dragpoly
->points
5424 + dragpoly
->number
; dragpoints
++) {
5425 dragpoints
->x
+= deltax
;
5426 dragpoints
->y
+= deltay
;
5430 splineptr dragspline
= SELTOSPLINE(dragselect
);
5432 fpointlist dragpoints
;
5434 /* if (dragspline->cycle != NULL) continue; */
5436 closest
= (wirelength(&dragspline
->ctrl
[0], &newpos
)
5437 > wirelength(&dragspline
->ctrl
[3], &newpos
)) ? 3 : 0;
5438 deltax
= newpos
.x
- dragspline
->ctrl
[closest
].x
;
5439 deltay
= newpos
.y
- dragspline
->ctrl
[closest
].y
;
5441 for (dragpoints
= dragspline
->points
; dragpoints
< dragspline
->
5442 points
+ INTSEGS
; dragpoints
++) {
5443 dragpoints
->x
+= deltax
;
5444 dragpoints
->y
+= deltay
;
5446 for (j
= 0; j
< 4; j
++) {
5447 dragspline
->ctrl
[j
].x
+= deltax
;
5448 dragspline
->ctrl
[j
].y
+= deltay
;
5452 arcptr dragarc
= SELTOARC(dragselect
);
5453 fpointlist dragpoints
;
5456 deltax
= newpos
.x
- dragarc
->position
.x
;
5457 deltay
= newpos
.y
- dragarc
->position
.y
;
5459 dragarc
->position
.x
+= deltax
;
5460 dragarc
->position
.y
+= deltay
;
5461 for (dragpoints
= dragarc
->points
; dragpoints
< dragarc
->
5462 points
+ dragarc
->number
; dragpoints
++) {
5463 dragpoints
->x
+= deltax
;
5464 dragpoints
->y
+= deltay
;
5470 if (areawin
->pinattach
) {
5471 for (pgen
= topobject
->plist
; pgen
< topobject
->plist
+
5472 topobject
->parts
; pgen
++) {
5473 if (ELEMENTTYPE(*pgen
) == POLYGON
) {
5474 cpoly
= TOPOLY(pgen
);
5475 if (cpoly
->cycle
!= NULL
) {
5476 ppt
= cpoly
->points
+ cpoly
->cycle
->number
;
5477 newpos
.x
= ppt
->x
+ deltax
;
5478 newpos
.y
= ppt
->y
+ deltay
;
5479 if (areawin
->manhatn
)
5480 manhattanize(&newpos
, cpoly
, cpoly
->cycle
->number
, FALSE
);
5488 move_mode_draw(xcDRAW_EDIT
, NULL
);
5491 areawin
->clipped
= 0;
5492 #endif /* HAVE_CAIRO */
5495 /*----------------------------------------------------------------------*/
5496 /* Copy handler. Assumes that the selectlist contains the elements */
5497 /* to be copied, and that the initial position of the copy is held */
5498 /* in areawin->save. */
5499 /*----------------------------------------------------------------------*/
5505 if (!checkselect_draw(ALL_TYPES
, True
)) return;
5506 u2u_snap(&areawin
->save
);
5507 for (selectobj
= areawin
->selectlist
; selectobj
< areawin
->selectlist
5508 + areawin
->selects
; selectobj
++) {
5510 /* Cycles will not be used for copy mode: remove them */
5511 removecycle(topobject
->plist
+ (*selectobj
));
5513 switch(SELECTTYPE(selectobj
)) {
5514 case LABEL
: { /* copy label */
5515 labelptr copytext
= SELTOLABEL(selectobj
);
5518 NEW_LABEL(newtext
, topobject
);
5519 labelcopy(*newtext
, copytext
);
5521 case OBJINST
: { /* copy object instance */
5522 objinstptr copyobj
= SELTOOBJINST(selectobj
);
5524 NEW_OBJINST(newobj
, topobject
);
5525 instcopy(*newobj
, copyobj
);
5527 case GRAPHIC
: { /* copy graphic instance */
5528 graphicptr copyg
= SELTOGRAPHIC(selectobj
);
5530 NEW_GRAPHIC(newg
, topobject
);
5531 graphiccopy(*newg
, copyg
);
5533 case PATH
: { /* copy path */
5534 pathptr copypath
= SELTOPATH(selectobj
);
5536 NEW_PATH(newpath
, topobject
);
5537 pathcopy(*newpath
, copypath
);
5539 case ARC
: { /* copy arc */
5540 arcptr copyarc
= SELTOARC(selectobj
);
5542 NEW_ARC(newarc
, topobject
);
5543 arccopy(*newarc
, copyarc
);
5545 case POLYGON
: { /* copy polygons */
5546 polyptr copypoly
= SELTOPOLY(selectobj
);
5548 NEW_POLY(newpoly
, topobject
);
5549 polycopy(*newpoly
, copypoly
);
5551 case SPLINE
: { /* copy spline */
5552 splineptr copyspline
= SELTOSPLINE(selectobj
);
5553 splineptr
*newspline
;
5554 NEW_SPLINE(newspline
, topobject
);
5555 splinecopy(*newspline
, copyspline
);
5559 /* change selection from the old to the new object */
5561 *selectobj
= topobject
->parts
- 1;
5565 /*--------------------------------------------------------------*/
5566 /* Function which initiates interactive placement of copied */
5568 /*--------------------------------------------------------------*/
5572 if (areawin
->selects
> 0) {
5573 move_mode_draw(xcDRAW_INIT
, NULL
);
5574 if (eventmode
== NORMAL_MODE
) {
5575 XDefineCursor(dpy
, areawin
->window
, COPYCURSOR
);
5576 eventmode
= COPY_MODE
;
5578 Tk_CreateEventHandler(areawin
->area
, PointerMotionMask
|
5579 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5581 XtAddEventHandler(areawin
->area
, PointerMotionMask
|
5582 ButtonMotionMask
, False
, (XtEventHandler
)xlib_drag
,
5586 select_invalidate_netlist();
5590 /*-----------------------------------------------------------*/
5591 /* Copy handler for copying from a button push or key event. */
5592 /*-----------------------------------------------------------*/
5594 void copy_op(int op
, int x
, int y
)
5596 if (op
== XCF_Copy
) {
5597 window_to_user(x
, y
, &areawin
->save
);
5598 createcopies(); /* This function does all the hard work */
5599 copydrag(); /* Start interactive placement */
5602 eventmode
= NORMAL_MODE
;
5603 areawin
->attachto
= -1;
5606 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5607 ButtonMotionMask
, False
, (xcEventHandler
)xctk_drag
,
5610 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5611 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5614 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5615 u2u_snap(&areawin
->save
);
5616 if (op
== XCF_Cancel
) {
5617 move_mode_draw(xcDRAW_EMPTY
, NULL
);
5618 delete_noundo(NORMAL
);
5620 else if (op
== XCF_Finish_Copy
) {
5621 move_mode_draw(xcDRAW_FINAL
, NULL
);
5622 /* If selected objects are the only ones on the page, */
5623 /* then do a full bbox calculation. */
5624 if (topobject
->parts
== areawin
->selects
)
5625 calcbbox(areawin
->topinstance
);
5629 register_for_undo(XCF_Copy
, UNDO_MORE
, areawin
->topinstance
,
5630 areawin
->selectlist
, areawin
->selects
);
5632 incr_changes(topobject
);
5634 else { /* XCF_Continue_Copy */
5635 move_mode_draw(xcDRAW_FINAL
, NULL
);
5636 if (topobject
->parts
== areawin
->selects
)
5637 calcbbox(areawin
->topinstance
);
5641 register_for_undo(XCF_Copy
, UNDO_DONE
, areawin
->topinstance
,
5642 areawin
->selectlist
, areawin
->selects
);
5644 copydrag(); /* Start interactive placement again */
5645 incr_changes(topobject
);
5650 /*----------------------------------------------*/
5651 /* Check for more than one button being pressed */
5652 /*----------------------------------------------*/
5654 Boolean
checkmultiple(XButtonEvent
*event
)
5656 int state
= Button1Mask
| Button2Mask
| Button3Mask
|
5657 Button4Mask
| Button5Mask
;
5658 state
&= event
->state
;
5659 /* ((x - 1) & x) is always non-zero if x has more than one bit set */
5660 return (((state
- 1) & state
) == 0) ? False
: True
;
5663 /*----------------------------------------------------------------------*/
5664 /* Operation continuation---dependent upon the ongoing operation. */
5665 /* This operation only pertains to a few event modes for which */
5666 /* continuation of action makes sense---drawing wires (polygons), and */
5667 /* editing polygons, arcs, splines, and paths. */
5668 /*----------------------------------------------------------------------*/
5670 void continue_op(int op
, int x
, int y
)
5674 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5675 window_to_user(x
, y
, &areawin
->save
);
5678 printpos(ppos
.x
, ppos
.y
);
5687 case(EPATH_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5688 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5689 path_op(*(EDITPART
), op
, x
, y
);
5692 inst_op(*(EDITPART
), op
, x
, y
);
5695 finish_op(XCF_Finish_Element
, x
, y
);
5702 /*--------------------------------------------------------------*/
5703 /* Finish or cancel an operation. This forces a return to */
5704 /* "normal" mode, with whatever other side effects are caused */
5705 /* by the operation. */
5706 /*--------------------------------------------------------------*/
5708 void finish_op(int op
, int x
, int y
)
5712 XPoint snappt
, boxpts
[4];
5715 if (eventmode
!= EARC_MODE
&& eventmode
!= ARC_MODE
) {
5716 window_to_user(x
, y
, &areawin
->save
);
5719 case(EPATH_MODE
): case(BOX_MODE
): case(EPOLY_MODE
): case (ARC_MODE
):
5720 case(EARC_MODE
): case(SPLINE_MODE
): case(ESPLINE_MODE
):
5721 path_op(*(EDITPART
), op
, x
, y
);
5725 inst_op(*(EDITPART
), op
, x
, y
);
5728 case (FONTCAT_MODE
):
5729 case (EFONTCAT_MODE
):
5730 fontcat_op(op
, x
, y
);
5731 eventmode
= (eventmode
== FONTCAT_MODE
) ? TEXT_MODE
: ETEXT_MODE
;
5732 text_mode_draw(xcDRAW_INIT
, TOLABEL(EDITPART
));
5733 XDefineCursor (dpy
, areawin
->window
, TEXTPTR
);
5738 catalog_op(op
, x
, y
);
5750 curlabel
= TOLABEL(EDITPART
);
5751 if (op
== XCF_Cancel
) {
5752 redrawtext(curlabel
);
5753 areawin
->redraw_needed
= False
; /* ignore previous requests */
5754 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5755 freelabel(curlabel
->string
);
5761 singlebbox(EDITPART
);
5762 incr_changes(topobject
);
5763 select_invalidate_netlist();
5764 text_mode_draw(xcDRAW_FINAL
, curlabel
);
5766 setdefaultfontmarks();
5767 eventmode
= NORMAL_MODE
;
5770 case(ETEXT_MODE
): case(CATTEXT_MODE
):
5771 curlabel
= TOLABEL(EDITPART
);
5772 if (op
== XCF_Cancel
) {
5773 /* restore the original text */
5774 undrawtext(curlabel
);
5775 undo_finish_series();
5777 redrawtext(curlabel
);
5778 areawin
->redraw_needed
= False
; /* ignore previous requests */
5779 text_mode_draw(xcDRAW_EMPTY
, curlabel
);
5780 if (eventmode
== CATTEXT_MODE
) eventmode
= CATALOG_MODE
;
5782 setdefaultfontmarks();
5784 else textreturn(); /* Generate "return" key character */
5785 areawin
->textend
= 0;
5789 u2u_snap(&areawin
->save
);
5791 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5792 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5794 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5795 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5798 if (op
== XCF_Cancel
) {
5799 /* Just regenerate the library where we started */
5800 if (areawin
->selects
>= 1) {
5801 objinstptr selinst
= SELTOOBJINST(areawin
->selectlist
);
5802 libnum
= libfindobject(selinst
->thisobject
, NULL
);
5804 composelib(libnum
+ LIBRARY
);
5811 eventmode
= CATALOG_MODE
;
5812 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5816 u2u_snap(&areawin
->save
);
5818 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5819 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5821 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5822 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5825 if (op
== XCF_Cancel
) {
5826 /* If we came from the library with an object instance, in */
5827 /* MOVE_MODE, then "cancel" should delete the element. */
5828 /* Otherwise, put the position of the element back to what */
5829 /* it was before we started the move. The difference is */
5830 /* indicated by the value of areawin->editpart. */
5832 if ((areawin
->selects
> 0) && (*areawin
->selectlist
== topobject
->parts
))
5833 delete_noundo(NORMAL
);
5835 placeselects(areawin
->origin
.x
- areawin
->save
.x
,
5836 areawin
->origin
.y
- areawin
->save
.y
, NULL
);
5838 drawarea(NULL
, NULL
, NULL
);
5841 if (areawin
->selects
> 0) {
5842 register_for_undo(XCF_Move
,
5843 /* (was_preselected) ? UNDO_DONE : UNDO_MORE, */
5845 areawin
->topinstance
,
5846 (int)(areawin
->save
.x
- areawin
->origin
.x
),
5847 (int)(areawin
->save
.y
- areawin
->origin
.y
));
5848 pwriteback(areawin
->topinstance
);
5849 incr_changes(topobject
);
5850 select_invalidate_netlist();
5851 unselect_all(); /* The way it used to be. . . */
5854 /* full calc needed: move may shrink bbox */
5855 calcbbox(areawin
->topinstance
);
5857 /* if (!was_preselected) clearselects(); */
5859 areawin
->attachto
= -1;
5865 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5866 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5868 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5869 ButtonMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5872 rescale_mode_draw(xcDRAW_FINAL
, NULL
);
5873 if (op
!= XCF_Cancel
) {
5874 XPoint newpoints
[5];
5875 fscale
= UGetRescaleBox(&areawin
->save
, newpoints
);
5877 elementrescale(fscale
);
5878 areawin
->redraw_needed
= True
;
5881 eventmode
= NORMAL_MODE
;
5885 selarea_mode_draw(xcDRAW_FINAL
, NULL
);
5888 Tk_DeleteEventHandler(areawin
->area
, ButtonMotionMask
|
5889 PointerMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5891 xcRemoveEventHandler(areawin
->area
, ButtonMotionMask
|
5892 PointerMotionMask
, FALSE
, (xcEventHandler
)xlib_drag
,
5895 /* Zero-width boxes act like a normal selection. Otherwise, */
5896 /* proceed with the area select. */
5898 if ((areawin
->origin
.x
== areawin
->save
.x
) &&
5899 (areawin
->origin
.y
== areawin
->save
.y
))
5900 select_add_element(ALL_TYPES
);
5902 boxpts
[0] = areawin
->origin
;
5903 boxpts
[1].x
= areawin
->save
.x
;
5904 boxpts
[1].y
= areawin
->origin
.y
;
5905 boxpts
[2] = areawin
->save
;
5906 boxpts
[3].x
= areawin
->origin
.x
;
5907 boxpts
[3].y
= areawin
->save
.y
;
5908 selectarea(topobject
, boxpts
, 0);
5913 u2u_snap(&areawin
->save
);
5916 Tk_DeleteEventHandler(areawin
->area
, PointerMotionMask
|
5917 ButtonMotionMask
, (Tk_EventProc
*)xctk_drag
, NULL
);
5919 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
|
5920 ButtonMotionMask
, False
, (xcEventHandler
)xlib_drag
,
5923 areawin
->panx
= areawin
->pany
= 0;
5924 if (op
!= XCF_Cancel
)
5925 panbutton((u_int
) 5, (areawin
->width
>> 1) - (x
- areawin
->origin
.x
),
5926 (areawin
->height
>> 1) - (y
- areawin
->origin
.y
), 0);
5932 /* Remove any selections */
5933 if ((eventmode
== SELAREA_MODE
) || (eventmode
== PAN_MODE
)
5934 || (eventmode
== MOVE_MODE
))
5936 eventmode
= NORMAL_MODE
;
5937 areawin
->redraw_needed
= True
;
5939 else if (eventmode
!= MOVE_MODE
&& eventmode
!= EPATH_MODE
&&
5940 eventmode
!= EPOLY_MODE
&& eventmode
!= ARC_MODE
&&
5941 eventmode
!= EARC_MODE
&& eventmode
!= SPLINE_MODE
&&
5942 eventmode
!= ESPLINE_MODE
&& eventmode
!= WIRE_MODE
&&
5943 eventmode
!= ETEXT_MODE
&& eventmode
!= TEXT_MODE
) {
5947 if (eventmode
== NORMAL_MODE
) {
5949 /* Return any highlighted networks to normal */
5950 highlightnetlist(topobject
, areawin
->topinstance
, 0);
5952 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
5955 snap(x
, y
, &snappt
);
5956 printpos(snappt
.x
, snappt
.y
);
5959 /*--------------------------------------------------------------*/
5960 /* Edit operations for instances. This is used to allow */
5961 /* numeric parameters to be adjusted from the hierarchical */
5962 /* level above, shielding the the unparameterized parts from */
5964 /*--------------------------------------------------------------*/
5966 void inst_op(genericptr editpart
, int op
, int x
, int y
)
5968 UNUSED(editpart
); UNUSED(op
); UNUSED(x
); UNUSED(y
);
5971 /*--------------------------------------------------------------*/
5972 /* Operations for path components */
5973 /*--------------------------------------------------------------*/
5975 void path_op(genericptr editpart
, int op
, int x
, int y
)
5978 splineptr newspline
;
5979 Boolean donecycles
= False
;
5980 UNUSED(x
); UNUSED(y
);
5982 /* Don't allow point cycling in a multi-part edit. */
5983 /* Allowing it is just confusing. Instead, we treat */
5984 /* button 1 (cycle) like button 2 (finish). */
5985 if (op
== XCF_Continue_Element
&& areawin
->selects
> 1)
5986 op
= XCF_Finish_Element
;
5988 switch(ELEMENTTYPE(editpart
)) {
5990 pathptr newpath
= (pathptr
)editpart
;
5991 short dotrack
= True
;
5994 areawin
->attachto
= -1;
5996 if (op
!= XCF_Continue_Element
) {
5999 if (op
== XCF_Continue_Element
) {
6000 nextpathcycle(newpath
, 1);
6001 patheditpush(newpath
);
6003 else if (op
== XCF_Finish_Element
) {
6004 path_mode_draw(xcDRAW_FINAL
, newpath
);
6005 incr_changes(topobject
);
6007 else { /* restore previous path from edit stack */
6008 free_single((genericptr
)newpath
);
6009 if (areawin
->editstack
->parts
> 0) {
6010 if (op
== XCF_Cancel
) {
6011 editpath
= TOPATH(areawin
->editstack
->plist
);
6012 pathcopy(newpath
, editpath
);
6013 reset(areawin
->editstack
, NORMAL
);
6016 editpath
= TOPATH(areawin
->editstack
->plist
+
6017 areawin
->editstack
->parts
- 1);
6018 pathcopy(newpath
, editpath
);
6019 free_single((genericptr
)editpath
);
6021 areawin
->editstack
->parts
--;
6023 if (areawin
->editstack
->parts
> 0) {
6025 nextpathcycle(newpath
, 1);
6026 path_mode_draw(xcDRAW_EDIT
, newpath
);
6030 user_to_window(areawin
->origin
, &warppt
);
6031 warppointer(warppt
.x
, warppt
.y
);
6032 path_mode_draw(xcDRAW_FINAL
, newpath
);
6036 path_mode_draw(xcDRAW_EMPTY
, newpath
);
6038 free_single((genericptr
)newpath
);
6042 pwriteback(areawin
->topinstance
);
6045 /* Free the editstack */
6046 reset(areawin
->editstack
, NORMAL
);
6047 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6048 (xcEventHandler
)trackelement
, NULL
);
6049 eventmode
= NORMAL_MODE
;
6055 if (eventmode
== BOX_MODE
) {
6058 newbox
= (polyptr
)editpart
;
6060 /* prevent length and/or width zero boxes */
6061 if (newbox
->points
->x
!= (newbox
->points
+ 2)->x
&& (newbox
->points
6062 + 1)->y
!= (newbox
->points
+ 3)->y
) {
6063 if (op
!= XCF_Cancel
) {
6064 poly_mode_draw(xcDRAW_FINAL
, newbox
);
6065 incr_changes(topobject
);
6066 if (!nonnetwork(newbox
)) invalidate_netlist(topobject
);
6067 register_for_undo(XCF_Box
, UNDO_MORE
, areawin
->topinstance
,
6071 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6072 free_single((genericptr
)newbox
);
6079 poly_mode_draw(xcDRAW_EMPTY
, newbox
);
6080 free_single((genericptr
)newbox
);
6085 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6086 (xcEventHandler
)trackbox
, NULL
);
6087 eventmode
= NORMAL_MODE
;
6089 else { /* EPOLY_MODE */
6091 short dotrack
= True
;
6093 newpoly
= (polyptr
)editpart
;
6094 areawin
->attachto
= -1;
6096 if (op
!= XCF_Continue_Element
) {
6100 if (op
== XCF_Continue_Element
) {
6101 nextpolycycle(&newpoly
, 1);
6102 polyeditpush(newpoly
);
6104 else if (op
== XCF_Finish_Element
) {
6106 /* Check for degenerate polygons (all points the same). */
6108 for (i
= 1; i
< newpoly
->number
; i
++)
6109 if ((newpoly
->points
[i
].x
!= newpoly
->points
[i
- 1].x
) ||
6110 (newpoly
->points
[i
].y
!= newpoly
->points
[i
- 1].y
))
6112 if (i
== newpoly
->number
) {
6113 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6114 /* Remove this polygon with the standard delete */
6115 /* method (saves polygon on undo stack). */
6116 newpoly
->type
|= REMOVE_TAG
;
6117 delete_tagged(areawin
->topinstance
);
6120 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6121 if (!nonnetwork(newpoly
)) invalidate_netlist(topobject
);
6122 incr_changes(topobject
);
6127 free_single((genericptr
)newpoly
);
6128 if (areawin
->editstack
->parts
> 0) {
6129 if (op
== XCF_Cancel
) {
6130 editpoly
= TOPOLY(areawin
->editstack
->plist
);
6131 polycopy(newpoly
, editpoly
);
6132 reset(areawin
->editstack
, NORMAL
);
6135 editpoly
= TOPOLY(areawin
->editstack
->plist
+
6136 areawin
->editstack
->parts
- 1);
6137 polycopy(newpoly
, editpoly
);
6138 free_single((genericptr
)editpoly
);
6140 areawin
->editstack
->parts
--;
6142 if (areawin
->editstack
->parts
> 0) {
6144 nextpolycycle(&newpoly
, -1);
6145 poly_mode_draw(xcDRAW_EDIT
, newpoly
);
6148 XcTopSetForeground(newpoly
->color
);
6149 user_to_window(areawin
->origin
, &warppt
);
6150 warppointer(warppt
.x
, warppt
.y
);
6151 poly_mode_draw(xcDRAW_FINAL
, newpoly
);
6155 poly_mode_draw(xcDRAW_EMPTY
, newpoly
);
6160 pwriteback(areawin
->topinstance
);
6163 /* Free the editstack */
6164 reset(areawin
->editstack
, NORMAL
);
6166 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6167 (xcEventHandler
)trackelement
, NULL
);
6168 eventmode
= NORMAL_MODE
;
6175 arcptr newarc
, editarc
;
6176 short dotrack
= True
;
6178 newarc
= (arcptr
)editpart
;
6180 if (op
!= XCF_Continue_Element
) {
6184 if (op
== XCF_Continue_Element
) {
6185 nextarccycle(&newarc
, 1);
6186 arceditpush(newarc
);
6189 else if (op
== XCF_Finish_Element
) {
6192 if (newarc
->radius
!= 0 && newarc
->yaxis
!= 0 &&
6193 (newarc
->angle1
!= newarc
->angle2
)) {
6194 XTopSetForeground(newarc
->color
);
6195 incr_changes(topobject
);
6196 if (eventmode
== ARC_MODE
) {
6197 register_for_undo(XCF_Arc
, UNDO_MORE
, areawin
->topinstance
,
6200 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6204 /* Remove the record if the radius is zero. If we were */
6205 /* creating the arc, just delete it; it's as if it */
6206 /* never existed. If we were editing an arc, use the */
6207 /* standard delete method (saves arc on undo stack). */
6209 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6210 if (eventmode
== ARC_MODE
) {
6211 free_single((genericptr
)newarc
);
6216 newarc
->type
|= REMOVE_TAG
;
6217 delete_tagged(areawin
->topinstance
);
6221 else { /* Cancel: restore previous arc from edit stack */
6222 free_single((genericptr
)newarc
);
6223 if (areawin
->editstack
->parts
> 0) {
6224 if (op
== XCF_Cancel
) {
6225 editarc
= TOARC(areawin
->editstack
->plist
);
6226 arccopy(newarc
, editarc
);
6227 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6228 reset(areawin
->editstack
, NORMAL
);
6231 editarc
= TOARC(areawin
->editstack
->plist
+
6232 areawin
->editstack
->parts
- 1);
6233 arccopy(newarc
, editarc
);
6234 copycycles(&(newarc
->cycle
), &(editarc
->cycle
));
6235 free_single((genericptr
)editarc
);
6237 areawin
->editstack
->parts
--;
6239 if (areawin
->editstack
->parts
> 0) {
6241 nextarccycle(&newarc
, -1);
6242 arc_mode_draw(xcDRAW_EDIT
, newarc
);
6245 if (eventmode
!= ARC_MODE
) {
6247 user_to_window(areawin
->origin
, &warppt
);
6248 warppointer(warppt
.x
, warppt
.y
);
6250 arc_mode_draw(xcDRAW_FINAL
, newarc
);
6254 arc_mode_draw(xcDRAW_EMPTY
, newarc
);
6258 pwriteback(areawin
->topinstance
);
6261 /* Free the editstack */
6262 reset(areawin
->editstack
, NORMAL
);
6264 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6265 (xcEventHandler
)trackarc
, NULL
);
6266 eventmode
= NORMAL_MODE
;
6271 splineptr editspline
;
6272 short dotrack
= True
;
6274 newspline
= (splineptr
)editpart
;
6276 if (op
!= XCF_Continue_Element
) {
6280 if (op
== XCF_Continue_Element
) {
6281 /* Note: we work backwards through spline control points. */
6282 /* The reason is that when creating a spline, the sudden */
6283 /* move from the endpoint to the startpoint (forward */
6284 /* direction) is more disorienting than moving from the */
6285 /* endpoint to the endpoint's control point. */
6287 nextsplinecycle(&newspline
, -1);
6288 splineeditpush(newspline
);
6291 /* unlikely but possible to create zero-length splines */
6292 else if (newspline
->ctrl
[0].x
!= newspline
->ctrl
[3].x
||
6293 newspline
->ctrl
[0].x
!= newspline
->ctrl
[1].x
||
6294 newspline
->ctrl
[0].x
!= newspline
->ctrl
[2].x
||
6295 newspline
->ctrl
[0].y
!= newspline
->ctrl
[3].y
||
6296 newspline
->ctrl
[0].y
!= newspline
->ctrl
[1].y
||
6297 newspline
->ctrl
[0].y
!= newspline
->ctrl
[2].y
) {
6298 if (op
== XCF_Finish_Element
) {
6299 incr_changes(topobject
);
6300 if (eventmode
== SPLINE_MODE
) {
6301 register_for_undo(XCF_Spline
, UNDO_MORE
, areawin
->topinstance
,
6304 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6306 else { /* restore previous spline from edit stack */
6307 free_single((genericptr
)newspline
);
6308 if (areawin
->editstack
->parts
> 0) {
6309 if (op
== XCF_Cancel
) {
6310 editspline
= TOSPLINE(areawin
->editstack
->plist
);
6311 splinecopy(newspline
, editspline
);
6312 reset(areawin
->editstack
, NORMAL
);
6315 editspline
= TOSPLINE(areawin
->editstack
->plist
+
6316 areawin
->editstack
->parts
- 1);
6317 splinecopy(newspline
, editspline
);
6318 free_single((genericptr
)editspline
);
6320 areawin
->editstack
->parts
--;
6322 if (areawin
->editstack
->parts
> 0) {
6324 nextsplinecycle(&newspline
, 1);
6325 spline_mode_draw(xcDRAW_EDIT
, newspline
);
6328 if (eventmode
!= SPLINE_MODE
) {
6330 user_to_window(areawin
->origin
, &warppt
);
6331 warppointer(warppt
.x
, warppt
.y
);
6333 spline_mode_draw(xcDRAW_FINAL
, newspline
);
6337 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6343 spline_mode_draw(xcDRAW_EMPTY
, newspline
);
6344 free_single((genericptr
)newspline
);
6348 pwriteback(areawin
->topinstance
);
6351 /* Free the editstack */
6352 reset(areawin
->editstack
, NORMAL
);
6354 xcRemoveEventHandler(areawin
->area
, PointerMotionMask
, False
,
6355 (xcEventHandler
)trackelement
, NULL
);
6356 eventmode
= NORMAL_MODE
;
6361 calcbbox(areawin
->topinstance
);
6363 /* Multiple-element edit: Some items may have been moved as */
6364 /* opposed to edited, and should be registered here. To do */
6365 /* this correctly, we must first unselect the edited items, */
6366 /* then register the move for the remaining items. */
6371 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6372 areawin
->selects
; eselect
++)
6373 checkcycle(SELTOGENERIC(eselect
), 0);
6375 /* Remove all (remaining) cycles */
6376 for (eselect
= areawin
->selectlist
; eselect
< areawin
->selectlist
+
6377 areawin
->selects
; eselect
++)
6378 removecycle(SELTOGENERICPTR(eselect
));
6380 /* Remove edits from the undo stack when canceling */
6381 if (op
== XCF_Cancel
|| op
== XCF_Cancel_Last
) {
6382 if (xobjs
.undostack
&& (xobjs
.undostack
->type
== XCF_Edit
)) {
6383 undo_finish_series();
6390 /*-------------------------------------------------------*/
6391 /* Recalculate values for a drawing-area widget resizing */
6392 /*-------------------------------------------------------*/
6394 void resizearea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6400 int savewidth
= areawin
->width
, saveheight
= areawin
->height
;
6401 XCWindowData
*thiswin
;
6404 #endif /* !HAVE_CAIRO */
6405 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6407 if ((dpy
!= NULL
) && xcIsRealized(areawin
->area
)) {
6410 areawin
->width
= Tk_Width(w
);
6411 areawin
->height
= Tk_Height(w
);
6413 XtSetArg(wargs
[0], XtNwidth
, &areawin
->width
);
6414 XtSetArg(wargs
[1], XtNheight
, &areawin
->height
);
6415 XtGetValues(areawin
->area
, wargs
, 2);
6418 if (areawin
->width
!= savewidth
|| areawin
->height
!= saveheight
) {
6420 int maxwidth
= 0, maxheight
= 0;
6421 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6422 if (thiswin
->width
> maxwidth
) maxwidth
= thiswin
->width
;
6423 if (thiswin
->height
> maxheight
) maxheight
= thiswin
->height
;
6425 #if !defined(HAVE_CAIRO)
6426 if (dbuf
!= (Pixmap
)NULL
) XFreePixmap(dpy
, dbuf
);
6427 dbuf
= XCreatePixmap(dpy
, areawin
->window
, maxwidth
, maxheight
,
6428 DefaultDepthOfScreen(xcScreen(w
)));
6431 /* TODO: probably make this a generalized function call, which */
6432 /* should be handled depending on the surface in the xtgui.c, */
6433 /* xcwin32.c, etc. files. */
6434 /* For now only support xlib surface */
6435 cairo_xlib_surface_set_size(areawin
->surface
, areawin
->width
,
6438 if (areawin
->clipmask
!= (Pixmap
)NULL
) XFreePixmap(dpy
, areawin
->clipmask
);
6439 areawin
->clipmask
= XCreatePixmap(dpy
, areawin
->window
,
6440 maxwidth
, maxheight
, 1);
6442 if (areawin
->pbuf
!= (Pixmap
)NULL
) {
6443 XFreePixmap(dpy
, areawin
->pbuf
);
6444 areawin
->pbuf
= XCreatePixmap(dpy
, areawin
->window
,
6445 maxwidth
, maxheight
, 1);
6448 if (areawin
->cmgc
!= (GC
)NULL
) XFreeGC(dpy
, areawin
->cmgc
);
6449 values
.foreground
= 0;
6450 values
.background
= 0;
6451 areawin
->cmgc
= XCreateGC(dpy
, areawin
->clipmask
,
6452 GCForeground
| GCBackground
, &values
);
6453 #endif /* !HAVE_CAIRO */
6455 /* Clear fixed_pixmap */
6456 if (areawin
->fixed_pixmap
) {
6458 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6459 areawin
->fixed_pixmap
= NULL
;
6460 #else /* !HAVE_CAIRO */
6461 XFreePixmap(dpy
, areawin
->fixed_pixmap
);
6462 areawin
->fixed_pixmap
= (Pixmap
) NULL
;
6463 #endif /* !HAVE_CAIRO */
6468 /* Re-compose the directores to match the new dimensions */
6470 composelib(PAGELIB
);
6472 /* Re-center image in resized window */
6473 zoomview(NULL
, NULL
, NULL
);
6476 /* Flush all expose events from the buffer */
6477 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
) == True
);
6481 /*----------------------*/
6482 /* Draw the grids, etc. */
6483 /*----------------------*/
6486 void draw_grids(void)
6488 float x
, y
, spc
, spc2
, i
, j
, fpart
;
6489 float major_snapspace
, spc3
;
6491 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
6492 if (areawin
->gridon
&& spc
> 8) {
6493 fpart
= (float)(-areawin
->pcorner
.x
)
6494 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6495 x
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6496 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6497 fpart
= (float)(-areawin
->pcorner
.y
)
6498 / xobjs
.pagelist
[areawin
->page
]->gridspace
;
6499 y
= xobjs
.pagelist
[areawin
->page
]->gridspace
*
6500 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6502 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6503 for (i
= x
; i
< (float)areawin
->width
; i
+= spc
)
6504 DrawLine (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6505 0, (int)(i
+ 0.5), areawin
->height
);
6506 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc
)
6507 DrawLine (dpy
, areawin
->window
, areawin
->gc
, 0, (int)(j
- 0.5),
6508 areawin
->width
, (int)(j
- 0.5));
6511 if (areawin
->axeson
) {
6512 XPoint originpt
, zeropt
;
6513 zeropt
.x
= zeropt
.y
= 0;
6514 SetForeground(dpy
, areawin
->gc
, AXESCOLOR
);
6515 user_to_window(zeropt
, &originpt
);
6516 DrawLine(dpy
, areawin
->window
, areawin
->gc
, originpt
.x
, 0,
6517 originpt
.x
, areawin
->height
);
6518 DrawLine(dpy
, areawin
->window
, areawin
->gc
, 0, originpt
.y
,
6519 areawin
->width
, originpt
.y
);
6522 /* bounding box goes beneath everything except grid/axis lines */
6525 /* draw a little red dot at each snap-to point */
6527 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
6528 if (areawin
->snapto
&& spc2
> 8) {
6531 fpart
= (float)(-areawin
->pcorner
.x
)
6532 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6533 x2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6534 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6535 fpart
= (float)(-areawin
->pcorner
.y
)
6536 / xobjs
.pagelist
[areawin
->page
]->snapspace
;
6537 y2
= xobjs
.pagelist
[areawin
->page
]->snapspace
*
6538 (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6540 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6542 HDC hdc
= CreateCompatibleDC(NULL
);
6543 SelectObject(hdc
, Tk_GetHWND(areawin
->window
));
6545 SetForeground(dpy
, areawin
->gc
, SNAPCOLOR
);
6546 for (i
= x2
; i
< areawin
->width
; i
+= spc2
)
6547 for (j
= areawin
->height
- y2
; j
> 0; j
-= spc2
)
6548 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6549 SetPixelV(hdc
, (int)(i
+ 0.5), (int)(j
- 0.05), areawin
->gc
->foreground
);
6551 DrawPoint (dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5),
6553 #if defined(TCL_WRAPPER) && defined(XC_WIN32)
6559 /* Draw major snap points (code contributed by John Barry) */
6561 major_snapspace
= xobjs
.pagelist
[areawin
->page
]->gridspace
* 20;
6562 spc3
= major_snapspace
* areawin
->vscale
;
6564 fpart
= (float)(-areawin
->pcorner
.x
) / major_snapspace
;
6565 x
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6566 fpart
= (float)(-areawin
->pcorner
.y
) / major_snapspace
;
6567 y
= major_snapspace
* (fpart
- (float)((int)fpart
)) * areawin
->vscale
;
6569 SetForeground(dpy
, areawin
->gc
, GRIDCOLOR
);
6570 for (i
= x
; i
< (float)areawin
->width
; i
+= spc3
) {
6571 for (j
= (float)areawin
->height
- y
; j
> 0; j
-= spc3
) {
6572 XDrawArc(dpy
, areawin
->window
, areawin
->gc
, (int)(i
+ 0.5) - 1,
6573 (int)(j
- 0.5) - 1, 2, 2, 0, 360*64);
6578 SetBackground(dpy
, areawin
->gc
, BACKGROUND
);
6580 #endif /* !HAVE_CAIRO */
6582 /*------------------------------------------------------*/
6583 /* Draw fixed parts of the primary graphics window */
6584 /*------------------------------------------------------*/
6586 void draw_fixed(void)
6588 Boolean old_ongoing
;
6591 #endif /* !HAVE_CAIRO */
6593 if (xobjs
.suspend
>= 0) return;
6594 old_ongoing
= areawin
->redraw_ongoing
;
6595 areawin
->redraw_ongoing
= True
;
6597 /* Set drawing context to fixed_pixmap */
6599 cairo_identity_matrix(areawin
->cr
);
6600 cairo_push_group(areawin
->cr
);
6601 #else /* HAVE_CAIRO */
6602 old_window
= areawin
->window
;
6603 areawin
->window
= areawin
->fixed_pixmap
;
6604 #endif /* HAVE_CAIRO */
6606 /* Clear background */
6608 if (xobjs
.pagelist
[areawin
->page
]->background
.name
!= (char *)NULL
) {
6612 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6613 cairo_paint(areawin
->cr
);
6614 #endif /* HAVE_GS */
6617 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6618 cairo_paint(areawin
->cr
);
6620 #else /* HAVE_CAIRO */
6621 if (xobjs
.pagelist
[areawin
->page
]->background
.name
== (char *)NULL
6622 || (copybackground() < 0)) {
6623 SetForeground(dpy
, areawin
->gc
, BACKGROUND
);
6624 XFillRectangle(dpy
, areawin
->window
, areawin
->gc
, 0, 0, areawin
->width
,
6627 SetThinLineAttributes(dpy
, areawin
->gc
, 0, LineSolid
, CapRound
, JoinBevel
);
6628 #endif /* !HAVE_CAIRO */
6632 /* draw GRIDCOLOR lines for grid; mark axes in AXESCOLOR */
6634 if (eventmode
!= CATALOG_MODE
&& eventmode
!= ASSOC_MODE
6635 && eventmode
!= FONTCAT_MODE
&& eventmode
!= EFONTCAT_MODE
6636 && eventmode
!= CATMOVE_MODE
&& eventmode
!= CATTEXT_MODE
) {
6640 /* Determine the transformation matrix for the topmost object */
6641 /* and draw the hierarchy above the current edit object (if */
6642 /* "edit-in-place" is selected). */
6644 if (areawin
->editinplace
== True
) {
6645 if (areawin
->stack
!= NULL
) {
6646 pushlistptr lastlist
= NULL
, thislist
;
6649 UPushCTM(); /* save our current state */
6651 /* It's easiest if we first push the current page onto the stack, */
6652 /* then we don't need to treat the top-level page separately. We */
6653 /* pop it at the end. */
6654 push_stack(&areawin
->stack
, areawin
->topinstance
, NULL
);
6656 thislist
= areawin
->stack
;
6658 while ((thislist
!= NULL
) &&
6659 (is_library(thislist
->thisinst
->thisobject
) < 0)) {
6661 /* Invert the transformation matrix of the instance on the stack */
6662 /* to get the proper transformation matrix of the drawing one */
6663 /* up in the hierarchy. */
6666 UPreMultCTM(&mtmp
, thislist
->thisinst
->position
,
6667 thislist
->thisinst
->scale
, thislist
->thisinst
->rotation
);
6669 UPreMultCTMbyMat(DCTM
, &mtmp
);
6671 lastlist
= thislist
;
6672 thislist
= thislist
->next
;
6674 /* The following will be true for moves between schematics and symbols */
6675 if ((thislist
!= NULL
) && (thislist
->thisinst
->thisobject
->symschem
6676 == lastlist
->thisinst
->thisobject
))
6680 if (lastlist
!= NULL
) {
6681 pushlistptr stack
= NULL
;
6682 SetForeground(dpy
, areawin
->gc
, OFFBUTTONCOLOR
);
6683 UDrawObject(lastlist
->thisinst
, SINGLE
, DOFORALL
,
6684 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &stack
);
6685 /* This shouldn't happen, but just in case. . . */
6686 if (stack
) free_stack(&stack
);
6689 pop_stack(&areawin
->stack
); /* restore the original stack state */
6690 UPopCTM(); /* restore the original matrix state */
6695 /* draw all of the elements on the screen */
6697 SetForeground(dpy
, areawin
->gc
, FOREGROUND
);
6699 /* Initialize hierstack */
6700 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6701 UDrawObject(areawin
->topinstance
, TOPLEVEL
, FOREGROUND
,
6702 xobjs
.pagelist
[areawin
->page
]->wirewidth
, &areawin
->hierstack
);
6703 if (areawin
->hierstack
) free_stack(&areawin
->hierstack
);
6706 if (areawin
->fixed_pixmap
)
6707 cairo_pattern_destroy(areawin
->fixed_pixmap
);
6708 areawin
->fixed_pixmap
= cairo_pop_group(areawin
->cr
);
6709 #else /* HAVE_CAIRO */
6710 areawin
->window
= old_window
;
6711 #endif /* HAVE_CAIRO */
6712 areawin
->redraw_ongoing
= old_ongoing
;
6715 /*--------------------------------------*/
6716 /* Draw the primary graphics window */
6717 /*--------------------------------------*/
6719 void drawwindow(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6722 xcDrawType redrawtype
= xcDRAW_EDIT
;
6723 UNUSED(w
); UNUSED(clientdata
); UNUSED(calldata
);
6725 if (areawin
->area
== NULL
) return;
6726 if (!xcIsRealized(areawin
->area
)) return;
6727 if (xobjs
.suspend
>= 0) return;
6730 /* Make sure a fixed pixmap exists */
6731 if (!areawin
->fixed_pixmap
) {
6732 areawin
->fixed_pixmap
= XCreatePixmap(dpy
, areawin
->window
,
6733 areawin
->width
, areawin
->height
,
6734 DefaultDepthOfScreen(xcScreen(areawin
->area
)));
6736 #endif /* !HAVE_CAIRO */
6738 /* Sanity check---specifically to track down an error */
6739 if ((areawin
->selects
== 1) && *(areawin
->selectlist
) >= topobject
->parts
) {
6740 Wprintf("Internal error!");
6741 areawin
->selects
= 0;
6745 if (areawin
->redraw_needed
)
6746 redrawtype
= xcREDRAW_FORCED
;
6748 switch (eventmode
) {
6749 case ARC_MODE
: case EARC_MODE
:
6750 arc_mode_draw(redrawtype
, TOARC(EDITPART
));
6752 case SPLINE_MODE
: case ESPLINE_MODE
:
6753 spline_mode_draw(redrawtype
, TOSPLINE(EDITPART
));
6755 case BOX_MODE
: case EPOLY_MODE
: case WIRE_MODE
:
6756 poly_mode_draw(redrawtype
, TOPOLY(EDITPART
));
6759 path_mode_draw(redrawtype
, TOPATH(EDITPART
));
6761 case TEXT_MODE
: case CATTEXT_MODE
: case ETEXT_MODE
:
6762 text_mode_draw(redrawtype
, TOLABEL(EDITPART
));
6765 selarea_mode_draw(redrawtype
, NULL
);
6768 rescale_mode_draw(redrawtype
, NULL
);
6770 case CATMOVE_MODE
: case MOVE_MODE
: case COPY_MODE
:
6771 move_mode_draw(redrawtype
, NULL
);
6773 case ASSOC_MODE
: case EINST_MODE
: case FONTCAT_MODE
: case EFONTCAT_MODE
:
6774 case PAN_MODE
: case NORMAL_MODE
: case UNDO_MODE
: case CATALOG_MODE
:
6775 normal_mode_draw(redrawtype
, NULL
);
6778 /* flush out multiple expose/resize events from the event queue */
6779 while (XCheckWindowEvent(dpy
, areawin
->window
, ExposureMask
, &discard
));
6781 /* end by restoring graphics state */
6782 SetForeground(dpy
, areawin
->gc
, areawin
->gccolor
);
6784 areawin
->redraw_needed
= False
;
6787 /*----------------------------------------------------------------------*/
6788 /* Draw the current window (areawin). Check if other windows contain */
6789 /* the same object or one of its ancestors. If so, redraw them, too. */
6790 /*----------------------------------------------------------------------*/
6792 void drawarea(xcWidget w
, caddr_t clientdata
, caddr_t calldata
)
6794 XCWindowDataPtr thiswin
, focuswin
;
6796 if (xobjs
.suspend
>= 0) {
6797 if (xobjs
.suspend
== 0)
6798 xobjs
.suspend
= 1; /* Mark that a refresh is pending */
6804 for (thiswin
= xobjs
.windowlist
; thiswin
!= NULL
; thiswin
= thiswin
->next
) {
6805 if (thiswin
== focuswin
) continue;
6807 /* Note: need to check ancestry here, not just blindly redraw */
6808 /* all the windows all the time. */
6812 /* Don't respond to an expose event if the graphics context */
6813 /* has not yet been created. */
6814 if (areawin
->cr
!= NULL
)
6816 drawwindow(NULL
, NULL
, NULL
);
6819 drawwindow(w
, clientdata
, calldata
);
6822 /*-------------------------------------------------------------------------*/