1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/select.c,v 1.26 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_SELECT_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "attr.e"
26 #include "auxtext.e"
27 #include "button.e"
28 #include "choice.e"
29 #include "cmd.e"
30 #include "color.e"
31 #include "cursor.e"
32 #include "dialog.e"
33 #include "drawing.e"
34 #include "dup.e"
35 #include "edit.e"
36 #include "exec.e"
37 #include "file.e"
38 #include "font.e"
39 #include "grid.e"
40 #include "group.e"
41 #include "http.e"
42 #include "mainloop.e"
43 #include "mark.e"
44 #include "menu.e"
45 #include "miniline.e"
46 #include "move.e"
47 #include "msg.e"
48 #include "names.e"
49 #include "navigate.e"
50 #include "obj.e"
51 #include "page.e"
52 #include "pin.e"
53 #include "poly.e"
54 #include "raster.e"
55 #include "rect.e"
56 #include "remote.e"
57 #include "ruler.e"
58 #include "scroll.e"
59 #include "select.e"
60 #include "setup.e"
61 #include "special.e"
62 #include "stk.e"
63 #include "stretch.e"
64 #include "strtbl.e"
65 #include "util.e"
66 
67 #define FORWARD 0
68 #define REVERSE 1
69 
70 int	selLtX=0, selLtY=0, selRbX=0, selRbY=0;
71 int	selObjLtX=0, selObjLtY=0, selObjRbX=0, selObjRbY=0;
72 int	selNoLockLtX=0, selNoLockLtY=0, selNoLockRbX=0, selNoLockRbY=0;
73 int	selNoLockObjLtX=0, selNoLockObjLtY=0;
74 int	selNoLockObjRbX=0, selNoLockObjRbY=0;
75 int	numObjSelected=0;
76 int	numObjLocked=0;
77 struct SelRec	*topSel=NULL, *botSel=NULL;
78 struct VSelRec	*topVSel=NULL, *botVSel=NULL;
79 
GetObjCurved(ObjPtr)80 int GetObjCurved(ObjPtr)
81    struct ObjRec *ObjPtr;
82 {
83    switch (ObjPtr->type) {
84    case OBJ_POLY: return ObjPtr->detail.p->curved;
85    case OBJ_POLYGON: return ObjPtr->detail.g->curved;
86    }
87 #ifdef _TGIF_DBG /* debug, do not translate */
88    TgAssert(FALSE, "Unexpected object type in GetObjCurved()", NULL);
89 #endif /* _TGIF_DBG */
90    return 0;
91 }
92 
SelectThisObject(ObjPtr)93 struct SelRec *SelectThisObject(ObjPtr)
94    struct ObjRec *ObjPtr;
95 {
96    struct SelRec *sel_ptr=(struct SelRec *)malloc(sizeof(struct SelRec));
97 
98    if (sel_ptr == NULL) FailAllocMessage();
99    memset(sel_ptr, 0, sizeof(struct SelRec));
100    sel_ptr->obj = ObjPtr;
101    return sel_ptr;
102 }
103 
CountSelectedVertices()104 int CountSelectedVertices()
105 {
106    struct VSelRec *vsel_ptr;
107    int count = 0;
108 
109    for (vsel_ptr=topVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->next) {
110       int curved=GetObjCurved(vsel_ptr->obj);
111 
112       if (curved == LT_STRUCT_SPLINE) {
113          /* can select at most one vertex for LT_STRUCT_SPLINE */
114          count++;
115       } else {
116          int n=vsel_ptr->n;
117 
118          count += n;
119          if (vsel_ptr->obj->type == OBJ_POLYGON) {
120             int i=0;
121 
122             for (i=0; i < n; i++) {
123                if (vsel_ptr->v_index[i] == 0) {
124                   count--;
125                   break;
126                }
127             }
128          }
129       }
130    }
131    return count;
132 }
133 
CalcBBox(X1,Y1,X2,Y2,LtX,LtY,RbX,RbY)134 void CalcBBox(X1, Y1, X2, Y2, LtX, LtY, RbX, RbY)
135    int X1, Y1, X2, Y2, * LtX, * LtY, * RbX, * RbY;
136 {
137    if (X1 < X2) {
138       if (Y1 < Y2) {
139          *LtX = X1; *LtY = Y1; *RbX = X2; *RbY = Y2;
140       } else {
141          *LtX = X1; *LtY = Y2; *RbX = X2; *RbY = Y1;
142       }
143    } else {
144       if (Y1 < Y2) {
145          *LtX = X2; *LtY = Y1; *RbX = X1; *RbY = Y2;
146       } else {
147          *LtX = X2; *LtY = Y2; *RbX = X1; *RbY = Y1;
148       }
149    }
150 }
151 
CalcVertexBBox(LtX,LtY,RbX,RbY)152 void CalcVertexBBox(LtX, LtY, RbX, RbY)
153    int *LtX, *LtY, *RbX, *RbY;
154 {
155    register int i, *x_ptr, *y_ptr;
156    struct VSelRec *vsel_ptr;
157 
158    *LtX = selRbX; *LtY = selRbY; *RbX = selLtX; *RbY = selLtY;
159 
160    for (vsel_ptr=topVSel; vsel_ptr!=NULL; vsel_ptr=vsel_ptr->next) {
161       for (i=0, x_ptr=vsel_ptr->x, y_ptr=vsel_ptr->y; i < vsel_ptr->n;
162             i++, x_ptr++, y_ptr++) {
163          if (*x_ptr < *LtX) *LtX = *x_ptr;
164          if (*y_ptr < *LtY) *LtY = *y_ptr;
165          if (*x_ptr > *RbX) *RbX = *x_ptr;
166          if (*y_ptr > *RbY) *RbY = *y_ptr;
167       }
168    }
169 }
170 
UnSelNonVertexObjs(highlight,no_locked_obj_only)171 void UnSelNonVertexObjs(highlight, no_locked_obj_only)
172    int highlight, no_locked_obj_only;
173 {
174    register struct ObjRec *obj_ptr;
175    register struct SelRec *sel_ptr, *prev_sel;
176 
177    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=prev_sel) {
178       prev_sel = sel_ptr->prev;
179       obj_ptr = sel_ptr->obj;
180 
181       if ((obj_ptr->type==OBJ_POLY || obj_ptr->type==OBJ_POLYGON) &&
182             (!no_locked_obj_only || !obj_ptr->locked)) {
183          continue;
184       }
185       if (highlight) HighLightAnObj(obj_ptr);
186 
187       if (sel_ptr->prev == NULL) {
188          topSel = sel_ptr->next;
189       } else {
190          sel_ptr->prev->next = sel_ptr->next;
191       }
192       if (sel_ptr->next == NULL) {
193          botSel = sel_ptr->prev;
194       } else {
195          sel_ptr->next->prev = sel_ptr->prev;
196       }
197       free(sel_ptr);
198    }
199 }
200 
FreeTopSel()201 void FreeTopSel()
202 {
203    struct SelRec *sel_ptr=topSel;
204 
205    topSel = topSel->next;
206    if (topSel != NULL) {
207       topSel->prev = NULL;
208    } else {
209       botSel = NULL;
210    }
211    free(sel_ptr);
212    numObjSelected--;
213    UpdSelBBox();
214 }
215 
JustFreeSel(pTopSel,pBotSel)216 void JustFreeSel(pTopSel, pBotSel)
217    struct SelRec *pTopSel, *pBotSel;
218 {
219    struct SelRec *pNextSel=NULL;
220 
221    for ( ; pTopSel != NULL; pTopSel=pNextSel) {
222       pNextSel = pTopSel->next;
223       free(pTopSel);
224    }
225 }
226 
UnlinkSel(pSel,ppTopSel,ppBotSel)227 void UnlinkSel(pSel, ppTopSel, ppBotSel)
228    struct SelRec *pSel, **ppTopSel, **ppBotSel;
229 {
230    if ((*ppTopSel) == pSel) {
231       (*ppTopSel) = pSel->next;
232    } else {
233       pSel->prev->next = pSel->next;
234    }
235    if ((*ppBotSel) == pSel) {
236       (*ppBotSel) = pSel->prev;
237    } else {
238       pSel->next->prev = pSel->prev;
239    }
240 }
241 
FindObjInSel(pObj,pTopSel,pBotSel)242 struct SelRec *FindObjInSel(pObj, pTopSel, pBotSel)
243    struct ObjRec *pObj;
244    struct SelRec *pTopSel, *pBotSel;
245 {
246    for ( ; pTopSel != NULL; pTopSel=pTopSel->next) {
247       if (pTopSel->obj == pObj) {
248          return pTopSel;
249       }
250    }
251    return NULL;
252 }
253 
PrependObjToSel(pObj,ppTopSel,ppBotSel)254 int PrependObjToSel(pObj, ppTopSel, ppBotSel)
255    struct ObjRec *pObj;
256    struct SelRec **ppTopSel, **ppBotSel;
257 {
258    int nReturn=TRUE;
259    struct SelRec *pSel=(struct SelRec *)malloc(sizeof(struct SelRec));
260 
261    if (pSel == NULL) {
262       FailAllocMessage();
263       nReturn = FALSE;
264    }
265    memset(pSel, 0, sizeof(struct SelRec));
266    pSel->obj = pObj;
267    pSel->next = (*ppTopSel);
268    pSel->prev = NULL;
269    if ((*ppTopSel) == NULL) {
270       (*ppBotSel) = pSel;
271    } else {
272       (*ppTopSel)->prev = pSel;
273    }
274    (*ppTopSel) = pSel;
275    return nReturn;
276 }
277 
AddObjIntoSel(pObj,pPrevSel,pNextSel,ppTopSel,ppBotSel)278 struct SelRec *AddObjIntoSel(pObj, pPrevSel, pNextSel, ppTopSel, ppBotSel)
279    struct ObjRec *pObj;
280    struct SelRec *pPrevSel, *pNextSel, **ppTopSel, **ppBotSel;
281 {
282    struct SelRec *pSel=(struct SelRec *)malloc(sizeof(struct SelRec));
283 
284    if (pSel == NULL) {
285       FailAllocMessage();
286       return NULL;
287    }
288    memset(pSel, 0, sizeof(struct SelRec));
289    pSel->obj = pObj;
290    pSel->next = pNextSel;
291    pSel->prev = pPrevSel;
292    if (pPrevSel == NULL) {
293       (*ppTopSel) = pSel;
294    } else {
295       pPrevSel->next = pSel;
296    }
297    if (pNextSel == NULL) {
298       (*ppBotSel) = pSel;
299    } else {
300       pNextSel->prev = pSel;
301    }
302    return pSel;
303 }
304 
JustRemoveAllVSel()305 void JustRemoveAllVSel()
306 {
307    register struct VSelRec *next_vsel;
308 
309    while (topVSel != NULL) {
310       next_vsel = topVSel->next;
311       free(topVSel->v_index);
312       free(topVSel->x);
313       free(topVSel->y);
314       free(topVSel);
315       topVSel = next_vsel;
316    }
317    botVSel = NULL;
318 }
319 
RemoveAllSel()320 void RemoveAllSel()
321 {
322    register struct SelRec *next_sel;
323    register struct VSelRec *next_vsel;
324 
325    while (topSel != NULL) {
326       next_sel = topSel->next;
327       free(topSel);
328       topSel = next_sel;
329    }
330    botSel = NULL;
331 
332    while (topVSel != NULL) {
333       next_vsel = topVSel->next;
334       free(topVSel->v_index);
335       free(topVSel->x);
336       free(topVSel->y);
337       free(topVSel);
338       topVSel = next_vsel;
339    }
340    botVSel = NULL;
341    numObjSelected = 0;
342 }
343 
FindObjAttrWithName(ObjPtr,AttrName)344 struct AttrRec *FindObjAttrWithName(ObjPtr, AttrName)
345    struct ObjRec *ObjPtr;
346    char *AttrName;
347    /* AttrName here must not contain '.' */
348 {
349    register struct AttrRec *attr_ptr;
350    struct AttrRec *found_attr=NULL;
351    int count=1, compare_name=(strchr(AttrName,'=') != NULL);
352 
353    if (ObjPtr == NULL) return NULL;
354 
355    for (attr_ptr=ObjPtr->fattr; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
356       if (compare_name) {
357          if (strcmp(attr_ptr->attr_name.s, AttrName) == 0) {
358             found_attr = attr_ptr;
359             break;
360          }
361       } else {
362          if (strcmp(attr_ptr->attr_value.s, AttrName) == 0) {
363             found_attr = attr_ptr;
364             break;
365          }
366       }
367    }
368    if (attr_ptr == NULL) return NULL;
369 
370    if (GetTextObjFirstStrSeg(found_attr->obj)->color == colorIndex) {
371       return found_attr;
372    }
373    for (attr_ptr=found_attr->next; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
374       if (compare_name) {
375          if (strcmp(attr_ptr->attr_name.s, AttrName) == 0) {
376             if (GetTextObjFirstStrSeg(attr_ptr->obj)->color == colorIndex) {
377                break;
378             } else if (GetTextObjFirstStrSeg(attr_ptr->obj)->color ==
379                   GetTextObjFirstStrSeg(found_attr->obj)->color) {
380                /* same color as found_attr's color, so don't increase count */
381             } else {
382                count++;
383             }
384          }
385       } else {
386          if (strcmp(attr_ptr->attr_value.s, AttrName) == 0) {
387             if (GetTextObjFirstStrSeg(attr_ptr->obj)->color == colorIndex) {
388                break;
389             } else if (GetTextObjFirstStrSeg(attr_ptr->obj)->color ==
390                   GetTextObjFirstStrSeg(found_attr->obj)->color) {
391                /* same color as found_attr's color, so don't increase count */
392             } else {
393                count++;
394             }
395          }
396       }
397    }
398    if (attr_ptr != NULL) {
399       found_attr = attr_ptr;
400    } else if (count != 1) {
401       sprintf(gszMsgBox, TgLoadCachedString(CSTID_CANT_FIND_ATTR_WITH_COLOR),
402             AttrName, colorMenuItems[colorIndex]);
403       Msg(gszMsgBox);
404       return NULL;
405    }
406    return found_attr;
407 }
408 
409 static
FindAVertex(XOff,YOff,VIndex,AbsX,AbsY)410 struct ObjRec *FindAVertex(XOff, YOff, VIndex, AbsX, AbsY)
411    int XOff, YOff, *VIndex, *AbsX, *AbsY;
412    /* XOff and YOff are screen offsets */
413 {
414    struct SelRec *sel_ptr;
415 
416    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
417       struct ObjRec *obj_ptr=sel_ptr->obj;
418       struct PolyRec *poly_ptr=NULL;
419       struct PolygonRec *polygon_ptr=NULL;
420       int n=0;
421       IntPoint *vs=NULL;
422 
423       if (obj_ptr->type != OBJ_POLY && obj_ptr->type != OBJ_POLYGON) continue;
424       if (!(XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
425             YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
426             XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
427             YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3)) {
428          continue;
429       }
430 
431       switch (obj_ptr->type) {
432       case OBJ_POLY:
433          poly_ptr = obj_ptr->detail.p;
434          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
435             n = poly_ptr->ssn;
436             vs = poly_ptr->ssvlist;
437          } else {
438             n = poly_ptr->n;
439             vs = poly_ptr->vlist;
440          }
441          if (PtInPolyMark(obj_ptr, XOff, YOff, n, vs, VIndex)) {
442             if (obj_ptr->ctm == NULL) {
443                *AbsX = vs[*VIndex].x;
444                *AbsY = vs[*VIndex].y;
445             } else {
446                int x, y;
447 
448                TransformPointThroughCTM( vs[*VIndex].x-obj_ptr->x,
449                      vs[*VIndex].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
450                *AbsX = x+obj_ptr->x;
451                *AbsY = y+obj_ptr->y;
452             }
453             return obj_ptr;
454          }
455          break;
456       case OBJ_POLYGON:
457          polygon_ptr = obj_ptr->detail.g;
458          if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
459             n = polygon_ptr->ssn;
460             vs = polygon_ptr->ssvlist;
461          } else {
462             n = polygon_ptr->n;
463             vs = polygon_ptr->vlist;
464          }
465          if (PtInPolyMark(obj_ptr, XOff, YOff, n, vs, VIndex)) {
466             if (obj_ptr->ctm == NULL) {
467                *AbsX = vs[*VIndex].x;
468                *AbsY = vs[*VIndex].y;
469             } else {
470                int x, y;
471 
472                TransformPointThroughCTM(vs[*VIndex].x-obj_ptr->x,
473                      vs[*VIndex].y-obj_ptr->y, obj_ptr->ctm, &x, &y);
474                *AbsX = x+obj_ptr->x;
475                *AbsY = y+obj_ptr->y;
476             }
477             return obj_ptr;
478          }
479          break;
480       }
481    }
482    return NULL;
483 }
484 
485 static
CandidatePortOwner(obj_ptr)486 int CandidatePortOwner(obj_ptr)
487    struct ObjRec *obj_ptr;
488 {
489    if (obj_ptr->type == OBJ_SYM || obj_ptr->type == OBJ_ICON) {
490       return TRUE;
491    } else if (obj_ptr->type == OBJ_GROUP) {
492       struct AttrRec *attr_ptr=FindAttrWithName(obj_ptr, "type=", NULL);
493 
494       if (attr_ptr != NULL && strcmp(attr_ptr->attr_value.s,
495             "tgBroadcastWire") == 0) {
496          return TRUE;
497       }
498    }
499    return FALSE;
500 }
501 
FindAnObj(XOff,YOff,OwnerObj,ConnectObj,ReturnedObjName)502 struct ObjRec *FindAnObj(XOff, YOff, OwnerObj, ConnectObj, ReturnedObjName)
503    int XOff, YOff;
504    struct ObjRec **OwnerObj, **ConnectObj;
505    char *ReturnedObjName;
506    /* XOff and YOff are screen offsets */
507 {
508    register struct ObjRec *obj_ptr;
509    register struct AttrRec *attr_ptr;
510    struct ObjRec *sub_obj, *returned_obj=NULL, *actual_obj=NULL;
511    struct ObjRec *owner_obj=NULL;
512    int found_attr=FALSE;
513 
514    if (OwnerObj != NULL) *OwnerObj = NULL;
515    if (ConnectObj != NULL) *ConnectObj = NULL;
516    if (ReturnedObjName != NULL) *ReturnedObjName = '\0';
517 
518    for (obj_ptr=topObj; returned_obj==NULL && obj_ptr!=NULL;
519          obj_ptr=obj_ptr->next) {
520       obj_ptr->tmp_child = NULL;
521       obj_ptr->tmp_parent = NULL;
522       if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
523          continue;
524       }
525       actual_obj = obj_ptr;
526       for (attr_ptr=obj_ptr->fattr; returned_obj==NULL && attr_ptr!=NULL;
527             attr_ptr=attr_ptr->next) {
528          if (attr_ptr->shown &&
529                XOff >= OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
530                YOff >= OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
531                XOff <= OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
532                YOff <= OFFSET_Y(attr_ptr->obj->bbox.rby)+3) {
533             owner_obj = obj_ptr;
534             returned_obj = attr_ptr->obj;
535             found_attr = TRUE;
536             break;
537          }
538       }
539       if (returned_obj != NULL) break;
540 
541       if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
542             YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
543             XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
544             YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
545          struct ObjRec *next_level_child=NULL, *visible_obj=NULL;
546 
547          switch (obj_ptr->type) {
548          case OBJ_TEXT:
549             if (FindGoodText(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
550             break;
551          case OBJ_XBM:
552             if (FindGoodXBm(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
553             break;
554          case OBJ_XPM:
555             if (FindGoodXPm(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
556             break;
557          case OBJ_BOX:
558             if (FindGoodBox(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
559             break;
560          case OBJ_OVAL:
561             if (FindGoodOval(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
562             break;
563          case OBJ_POLY:
564             if (FindGoodPoly(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
565             break;
566          case OBJ_POLYGON:
567             if (FindGoodPolygon(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
568             break;
569          case OBJ_ARC:
570             if (FindGoodArc(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
571             break;
572          case OBJ_RCBOX:
573             if (FindGoodRCBox(XOff,YOff,obj_ptr)) returned_obj = obj_ptr;
574             break;
575 
576          case OBJ_GROUP:
577          case OBJ_ICON:
578          case OBJ_SYM:
579             if (colorLayers) {
580                struct ObjRec *tmp_obj;
581 
582                for (tmp_obj=obj_ptr->detail.r->first; tmp_obj != NULL;
583                      tmp_obj=tmp_obj->next) {
584                   tmp_obj->tmp_parent = obj_ptr;
585                }
586             }
587             if (FindGoodObj(XOff, YOff, obj_ptr->detail.r->first, &sub_obj,
588                   &next_level_child)) {
589                obj_ptr->tmp_child = next_level_child;
590                if (sub_obj == NULL) {
591                   owner_obj = NULL;
592                   returned_obj = obj_ptr;
593                } else {
594                   owner_obj = obj_ptr;
595                   returned_obj = sub_obj;
596                }
597             }
598             break;
599          case OBJ_PIN:
600             visible_obj = GetPinObj(obj_ptr);
601             if (colorLayers) {
602                struct ObjRec *tmp_obj;
603 
604                for (tmp_obj=visible_obj->detail.r->first; tmp_obj != NULL;
605                      tmp_obj=tmp_obj->next) {
606                   tmp_obj->tmp_parent = visible_obj;
607                }
608             }
609             obj_ptr->tmp_child = visible_obj;
610             if (FindGoodObj(XOff, YOff, GetPinObj(obj_ptr), &sub_obj,
611                   &next_level_child)) {
612                visible_obj->tmp_child = next_level_child;
613                if (sub_obj == NULL) {
614                   owner_obj = NULL;
615                   returned_obj = obj_ptr;
616                } else {
617                   owner_obj = obj_ptr;
618                   returned_obj = sub_obj;
619                }
620             }
621             break;
622          }
623       }
624    }
625    if (ReturnedObjName != NULL) {
626       char *c_ptr;
627 
628       *ReturnedObjName = '\0';
629       c_ptr = ReturnedObjName;
630       if (returned_obj != NULL) {
631          struct ObjRec *prev_obj=NULL;
632          int see_sym_or_icon=FALSE;
633 
634          for (obj_ptr=actual_obj; obj_ptr != NULL; obj_ptr=obj_ptr->tmp_child) {
635             /* do not translate -- program constants */
636             if (connectingPortsFromInternalCommand) {
637                /* this is pretty much left for compatibility only */
638                if ((attr_ptr=FindObjAttrWithName(obj_ptr, "name=")) != NULL) {
639                   *c_ptr++ = '!';
640                   strcpy(c_ptr, attr_ptr->attr_value.s);
641                   c_ptr = &c_ptr[strlen(c_ptr)];
642                } else {
643                   if (prev_obj != NULL) prev_obj->tmp_child = NULL;
644                   break;
645                }
646             } else {
647                int just_seen_sym_or_icon=FALSE;
648 
649                if (!see_sym_or_icon) {
650                   if (CandidatePortOwner(obj_ptr)) {
651                      see_sym_or_icon = TRUE;
652                      just_seen_sym_or_icon = TRUE;
653                   }
654                }
655                if (see_sym_or_icon) {
656                   if ((attr_ptr=FindObjAttrWithName(obj_ptr, "name=")) ==
657                         NULL) {
658                      /* broken name is invalid */
659                      c_ptr = ReturnedObjName;
660                      if (prev_obj != NULL) prev_obj->tmp_child = NULL;
661                      break;
662                   } else if (BlankStr(attr_ptr->attr_value.s)) {
663                      /* do not translate -- program constants */
664                      *c_ptr++ = '!';
665                      strcpy(c_ptr, "(unknown)");
666                      c_ptr = &c_ptr[strlen(c_ptr)];
667                   } else {
668                      *c_ptr++ = '!';
669                      strcpy(c_ptr, attr_ptr->attr_value.s);
670                      c_ptr = &c_ptr[strlen(c_ptr)];
671                   }
672                   if (!just_seen_sym_or_icon && CandidatePortOwner(obj_ptr)) {
673                      obj_ptr->tmp_child = NULL;
674                      prev_obj = obj_ptr;
675                      break;
676                   }
677                }
678             }
679             prev_obj = obj_ptr;
680          }
681          if (ConnectObj != NULL) *ConnectObj = prev_obj;
682       }
683       if (c_ptr == ReturnedObjName) {
684          *ReturnedObjName = '\0';
685       } else {
686          *c_ptr = '\0';
687       }
688    }
689    if (OwnerObj != NULL) *OwnerObj = owner_obj;
690    return returned_obj;
691 }
692 
693 static
VertexAlreadySelected(ObjPtr,VIndex,VSelPtr)694 int VertexAlreadySelected(ObjPtr, VIndex, VSelPtr)
695    register struct ObjRec *ObjPtr;
696    int VIndex;
697    register struct VSelRec **VSelPtr;
698 {
699    register int i;
700 
701    for (*VSelPtr=topVSel; *VSelPtr != NULL; *VSelPtr=(*VSelPtr)->next) {
702       if ((*VSelPtr)->obj == ObjPtr) {
703          for (i = 0; i < (*VSelPtr)->n; i++) {
704             if ((*VSelPtr)->v_index[i] == VIndex) {
705                return TRUE;
706             }
707          }
708          return FALSE;
709       }
710    }
711    return FALSE;
712 }
713 
AlreadySelected(ObjPtr)714 struct SelRec *AlreadySelected(ObjPtr)
715    register struct ObjRec *ObjPtr;
716 {
717    register struct SelRec *sel_ptr;
718 
719    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
720       if (sel_ptr->obj == ObjPtr) {
721          return sel_ptr;
722       }
723    }
724    return NULL;
725 }
726 
AddSel(PrevPtr,NextPtr,SelPtr)727 void AddSel(PrevPtr, NextPtr, SelPtr)
728    struct SelRec *PrevPtr, *NextPtr, *SelPtr;
729    /* add SelPtr between PrevPtr and NextPtr */
730 {
731    SelPtr->prev = PrevPtr;
732    SelPtr->next = NextPtr;
733 
734    if (PrevPtr == NULL) {
735       topSel = SelPtr;
736    } else {
737       PrevPtr->next = SelPtr;
738    }
739    if (NextPtr == NULL) {
740       botSel = SelPtr;
741    } else {
742       NextPtr->prev = SelPtr;
743    }
744    numObjSelected++;
745 }
746 
AddNewSelObj(ObjPtr)747 void AddNewSelObj(ObjPtr)
748    register struct ObjRec *ObjPtr;
749 {
750    register struct ObjRec *obj_ptr=topObj;
751    register struct SelRec *sel_ptr=topSel, *new_sel_ptr;
752 
753    new_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
754    if (new_sel_ptr == NULL) FailAllocMessage();
755    new_sel_ptr->obj = ObjPtr;
756 
757    for ( ; sel_ptr != NULL && obj_ptr != ObjPtr; obj_ptr=obj_ptr->next) {
758       if (obj_ptr == sel_ptr->obj) {
759          sel_ptr = sel_ptr->next;
760       }
761    }
762    if (sel_ptr == NULL) {
763       /* the object is below the last selected object */
764       if (botSel == NULL) {
765          topSel = new_sel_ptr;
766       } else {
767          botSel->next = new_sel_ptr;
768       }
769       new_sel_ptr->prev = botSel;
770       new_sel_ptr->next = NULL;
771       botSel = new_sel_ptr;
772    } else {
773       /* the object is between sel_ptr and sel_ptr->prev */
774       if (sel_ptr->prev == NULL) {
775          topSel = new_sel_ptr;
776       } else {
777          sel_ptr->prev->next = new_sel_ptr;
778       }
779       new_sel_ptr->next = sel_ptr;
780       new_sel_ptr->prev = sel_ptr->prev;
781       sel_ptr->prev = new_sel_ptr;
782    }
783    numObjSelected++;
784 }
785 
ExpandCurSelBBoxes(obj_ptr)786 void ExpandCurSelBBoxes(obj_ptr)
787    struct ObjRec *obj_ptr;
788 {
789    if (obj_ptr->bbox.ltx < selLtX) selLtX = obj_ptr->bbox.ltx;
790    if (obj_ptr->bbox.lty < selLtY) selLtY = obj_ptr->bbox.lty;
791    if (obj_ptr->bbox.rbx < selRbX) selRbX = obj_ptr->bbox.rbx;
792    if (obj_ptr->bbox.rby < selRbY) selRbY = obj_ptr->bbox.rby;
793    if (obj_ptr->obbox.ltx < selObjLtX) {
794       selObjLtX = obj_ptr->obbox.ltx;
795    }
796    if (obj_ptr->obbox.lty < selObjLtY) {
797       selObjLtY = obj_ptr->obbox.lty;
798    }
799    if (obj_ptr->obbox.rbx < selObjRbX) {
800       selObjRbX = obj_ptr->obbox.rbx;
801    }
802    if (obj_ptr->obbox.rby < selObjRbY) {
803       selObjRbY = obj_ptr->obbox.rby;
804    }
805 }
806 
807 static
SetNoLockBBox(ObjPtr)808 void SetNoLockBBox(ObjPtr)
809    struct ObjRec *ObjPtr;
810 {
811    selNoLockLtX = ObjPtr->bbox.ltx;
812    selNoLockLtY = ObjPtr->bbox.lty;
813    selNoLockRbX = ObjPtr->bbox.rbx;
814    selNoLockRbY = ObjPtr->bbox.rby;
815    selNoLockObjLtX = ObjPtr->obbox.ltx;
816    selNoLockObjLtY = ObjPtr->obbox.lty;
817    selNoLockObjRbX = ObjPtr->obbox.rbx;
818    selNoLockObjRbY = ObjPtr->obbox.rby;
819 }
820 
UpdSelBBox()821 void UpdSelBBox()
822    /* update selLtX, selLtY, selRbX, selRbY */
823 {
824    register struct ObjRec *obj_ptr;
825    register struct SelRec *sel_ptr;
826    int seen_no_locked=FALSE;
827 
828    numObjSelected = 0;
829    numObjLocked = 0;
830    if ((sel_ptr = topSel) == NULL) return;
831 
832    numObjSelected++;
833    obj_ptr = sel_ptr->obj;
834    if (obj_ptr->locked) numObjLocked++;
835    selLtX = obj_ptr->bbox.ltx;
836    selLtY = obj_ptr->bbox.lty;
837    selRbX = obj_ptr->bbox.rbx;
838    selRbY = obj_ptr->bbox.rby;
839    selObjLtX = obj_ptr->obbox.ltx;
840    selObjLtY = obj_ptr->obbox.lty;
841    selObjRbX = obj_ptr->obbox.rbx;
842    selObjRbY = obj_ptr->obbox.rby;
843    if (!obj_ptr->locked) {
844       SetNoLockBBox(obj_ptr);
845       seen_no_locked = TRUE;
846    }
847    for (sel_ptr=topSel->next; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
848       numObjSelected++;
849       obj_ptr = sel_ptr->obj;
850       if (obj_ptr->bbox.ltx < selLtX) selLtX = obj_ptr->bbox.ltx;
851       if (obj_ptr->bbox.lty < selLtY) selLtY = obj_ptr->bbox.lty;
852       if (obj_ptr->bbox.rbx > selRbX) selRbX = obj_ptr->bbox.rbx;
853       if (obj_ptr->bbox.rby > selRbY) selRbY = obj_ptr->bbox.rby;
854       if (obj_ptr->obbox.ltx < selObjLtX) selObjLtX = obj_ptr->obbox.ltx;
855       if (obj_ptr->obbox.lty < selObjLtY) selObjLtY = obj_ptr->obbox.lty;
856       if (obj_ptr->obbox.rbx > selObjRbX) selObjRbX = obj_ptr->obbox.rbx;
857       if (obj_ptr->obbox.rby > selObjRbY) selObjRbY = obj_ptr->obbox.rby;
858       if (obj_ptr->locked) {
859          numObjLocked++;
860       } else {
861          if (seen_no_locked) {
862             if (obj_ptr->bbox.ltx < selNoLockLtX) {
863                selNoLockLtX = obj_ptr->bbox.ltx;
864             }
865             if (obj_ptr->bbox.lty < selNoLockLtY) {
866                selNoLockLtY = obj_ptr->bbox.lty;
867             }
868             if (obj_ptr->bbox.rbx > selNoLockRbX) {
869                selNoLockRbX = obj_ptr->bbox.rbx;
870             }
871             if (obj_ptr->bbox.rby > selNoLockRbY) {
872                selNoLockRbY = obj_ptr->bbox.rby;
873             }
874             if (obj_ptr->obbox.ltx < selNoLockObjLtX) {
875                selNoLockObjLtX = obj_ptr->obbox.ltx;
876             }
877             if (obj_ptr->obbox.lty < selNoLockObjLtY) {
878                selNoLockObjLtY = obj_ptr->obbox.lty;
879             }
880             if (obj_ptr->obbox.rbx > selNoLockObjRbX) {
881                selNoLockObjRbX = obj_ptr->obbox.rbx;
882             }
883             if (obj_ptr->obbox.rby > selNoLockObjRbY) {
884                selNoLockObjRbY = obj_ptr->obbox.rby;
885             }
886          } else {
887             SetNoLockBBox(obj_ptr);
888             seen_no_locked = TRUE;
889          }
890       }
891    }
892 }
893 
894 static
SelectOneVertex(XOff,YOff)895 struct VSelRec *SelectOneVertex(XOff, YOff)
896    int XOff, YOff;
897    /* XOff and YOff are screen offsets */
898 {
899    register struct ObjRec *obj_ptr;
900    int v_index, x, y;
901 
902    JustRemoveAllVSel();
903    if ((obj_ptr=FindAVertex(XOff, YOff, &v_index, &x, &y)) == NULL) {
904       return NULL;
905    }
906    topVSel = (struct VSelRec *)malloc(sizeof(struct VSelRec));
907    if (topVSel == NULL) FailAllocMessage();
908    memset(topVSel, 0, sizeof(struct VSelRec));
909    topVSel->obj = obj_ptr;
910    topVSel->max_v = 10;
911    topVSel->v_index = (int*)malloc(10*sizeof(int));
912    if (topVSel->v_index == NULL) FailAllocMessage();
913    topVSel->x = (int*)malloc(10*sizeof(int));
914    topVSel->y = (int*)malloc(10*sizeof(int));
915    if (topVSel->x == NULL || topVSel->y == NULL) FailAllocMessage();
916    topVSel->v_index[0] = v_index;
917    topVSel->x[0] = x;
918    topVSel->y[0] = y;
919    if (obj_ptr->type==OBJ_POLYGON && v_index==0) {
920       topVSel->n = 2;
921       topVSel->v_index[1] = obj_ptr->detail.g->n-1;
922       topVSel->x[1] = x;
923       topVSel->y[1] = y;
924    } else {
925       topVSel->n = 1;
926    }
927    topVSel->next = NULL;
928    topVSel->prev = NULL;
929    botVSel = topVSel;
930    UpdSelBBox();
931 
932    return topVSel;
933 }
934 
935 static
SelectOneObj(XOff,YOff,ppInnerObj)936 struct SelRec *SelectOneObj(XOff, YOff, ppInnerObj)
937    int XOff, YOff;
938    struct ObjRec **ppInnerObj;
939    /* XOff and YOff are screen offsets */
940 {
941    register struct ObjRec *obj_ptr;
942    struct ObjRec *owner_obj;
943 
944    RemoveAllSel();
945    if ((obj_ptr=FindAnObj(XOff,YOff,&owner_obj,NULL,NULL)) == NULL) {
946       return NULL;
947    }
948    if (ppInnerObj != NULL) {
949       *ppInnerObj = (owner_obj==NULL ? NULL : obj_ptr);
950    }
951    if (owner_obj != NULL) obj_ptr = owner_obj;
952 
953    topSel = (struct SelRec *)malloc(sizeof(struct SelRec));
954    if (topSel == NULL) FailAllocMessage();
955    topSel->next = NULL;
956    topSel->obj = obj_ptr;
957    topSel->prev = NULL;
958    botSel = topSel;
959    UpdSelBBox();
960 
961    return topSel;
962 }
963 
964 static
FindVertices(X1,Y1,X2,Y2,TopVSel,BotVSel,pn_struct_spline_msg)965 int FindVertices(X1, Y1, X2, Y2, TopVSel, BotVSel, pn_struct_spline_msg)
966    int X1, Y1, X2, Y2, *pn_struct_spline_msg;
967    struct VSelRec **TopVSel, **BotVSel;
968    /* X1, Y1, X2, Y2 are absolute coordinates */
969 {
970    struct SelRec *sel_ptr=NULL;
971    struct BBRec bbox;
972 
973    *TopVSel = *BotVSel = NULL;
974 
975    bbox.ltx = X1; bbox.lty = Y1;
976    bbox.rbx = X2; bbox.rby = Y2;
977    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
978       int i=0, n=0, count=0, max_count=0, j=0, curved=(-1);
979       IntPoint *v=NULL;
980       struct ObjRec *obj_ptr=sel_ptr->obj;
981 
982       if (obj_ptr->type != OBJ_POLY && obj_ptr->type != OBJ_POLYGON) continue;
983       if (!BBoxIntersect(bbox, obj_ptr->bbox)) continue;
984 
985       switch (obj_ptr->type) {
986       case OBJ_POLY:
987          curved = obj_ptr->detail.p->curved;
988          if (curved == LT_STRUCT_SPLINE) {
989             n = obj_ptr->detail.p->ssn;
990             v = obj_ptr->detail.p->ssvlist;
991          } else {
992             n = obj_ptr->detail.p->n;
993             v = obj_ptr->detail.p->vlist;
994          }
995          break;
996       case OBJ_POLYGON:
997          curved = obj_ptr->detail.g->curved;
998          if (curved == LT_STRUCT_SPLINE) {
999             n = obj_ptr->detail.g->ssn;
1000             v = obj_ptr->detail.g->ssvlist;
1001          } else {
1002             n = obj_ptr->detail.g->n;
1003             v = obj_ptr->detail.g->vlist;
1004          }
1005          break;
1006       }
1007       if (obj_ptr->ctm == NULL) {
1008          for (i = 0, count = 0; i < n; i++) {
1009             if (v[i].x >= X1 && v[i].x <= X2 && v[i].y >= Y1 && v[i].y <= Y2) {
1010                count++;
1011             }
1012          }
1013       } else {
1014          for (i = 0, count = 0; i < n; i++) {
1015             int x, y;
1016 
1017             TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y,
1018                   obj_ptr->ctm, &x, &y);
1019             if (x+obj_ptr->x >= X1 && x+obj_ptr->x <= X2 &&
1020                   y+obj_ptr->y >= Y1 && y+obj_ptr->y <= Y2) {
1021                count++;
1022             }
1023          }
1024       }
1025       if (count != 0) {
1026          struct VSelRec *vsel_ptr=NULL;
1027 
1028          if (curved == LT_STRUCT_SPLINE && count > 1) {
1029             if (!(*pn_struct_spline_msg)) {
1030                *pn_struct_spline_msg = TRUE;
1031                Msg(TgLoadString(STID_ONE_V_STRUCT_SPLINE_IN_V_MODE));
1032             }
1033             count = 1;
1034          }
1035          vsel_ptr = (struct VSelRec *)malloc(sizeof(struct VSelRec));
1036          if (vsel_ptr == NULL) FailAllocMessage();
1037          memset(vsel_ptr, 0, sizeof(struct VSelRec));
1038          vsel_ptr->obj = obj_ptr;
1039          vsel_ptr->next = *TopVSel;
1040          vsel_ptr->prev = NULL;
1041          if (*TopVSel == NULL) {
1042             *BotVSel = vsel_ptr;
1043          } else {
1044             (*TopVSel)->prev = vsel_ptr;
1045          }
1046          *TopVSel = vsel_ptr;
1047          vsel_ptr->n = count;
1048          max_count = ((count%10) == 0) ? 10*((int)(count/10)) :
1049                10*((int)(count/10)+1);
1050          vsel_ptr->max_v = max_count;
1051          vsel_ptr->v_index = (int*)malloc(max_count*sizeof(int));
1052          if (vsel_ptr->v_index == NULL) FailAllocMessage();
1053          vsel_ptr->x = (int*)malloc(max_count*sizeof(int));
1054          vsel_ptr->y = (int*)malloc(max_count*sizeof(int));
1055          if (vsel_ptr->x == NULL || vsel_ptr->y == NULL) FailAllocMessage();
1056 
1057          if (obj_ptr->ctm == NULL) {
1058             for (i = 0, j = 0; i < n; i++) {
1059                if (v[i].x >= X1 && v[i].x <= X2 &&
1060                      v[i].y >= Y1 && v[i].y <= Y2) {
1061                   vsel_ptr->v_index[j] = i;
1062                   vsel_ptr->x[j] = v[i].x;
1063                   vsel_ptr->y[j] = v[i].y;
1064                   j++;
1065                }
1066             }
1067          } else {
1068             for (i = 0, j = 0; i < n; i++) {
1069                int x, y;
1070 
1071                TransformPointThroughCTM(v[i].x-obj_ptr->x, v[i].y-obj_ptr->y,
1072                      obj_ptr->ctm, &x, &y);
1073                if (x+obj_ptr->x >= X1 && x+obj_ptr->x <= X2 &&
1074                      y+obj_ptr->y >= Y1 && y+obj_ptr->y <= Y2) {
1075                   vsel_ptr->v_index[j] = i;
1076                   vsel_ptr->x[j] = x+obj_ptr->x;
1077                   vsel_ptr->y[j] = y+obj_ptr->y;
1078                   j++;
1079                }
1080             }
1081          }
1082       }
1083    }
1084    return (*TopVSel != NULL);
1085 }
1086 
1087 static
FindObjects(X1,Y1,X2,Y2,TopSel,BotSel)1088 struct SelRec *FindObjects(X1, Y1, X2, Y2, TopSel, BotSel)
1089    int X1, Y1, X2, Y2;
1090    struct SelRec **TopSel, **BotSel;
1091    /* X1, Y1, X2, Y2 are absolute coordinates */
1092 {
1093    struct ObjRec *obj_ptr=NULL;
1094 
1095    *TopSel = *BotSel = NULL;
1096 
1097    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
1098       obj_ptr->tmp_parent = NULL;
1099       if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
1100          continue;
1101       }
1102       if (X1 <= obj_ptr->bbox.ltx && X2 >= obj_ptr->bbox.rbx &&
1103             Y1 <= obj_ptr->bbox.lty && Y2 >= obj_ptr->bbox.rby) {
1104          AddObjIntoSel(obj_ptr, NULL, *TopSel, TopSel, BotSel);
1105       }
1106    }
1107 
1108    return (*TopSel);
1109 }
1110 
SelBox(window,gc,x1,y1,x2,y2)1111 void SelBox(window, gc, x1, y1, x2, y2)
1112    Window window;
1113    GC gc;
1114    int x1, y1, x2, y2;
1115 {
1116    XPoint sv[5];
1117 
1118    if (x1 == x2 || y1 == y2) {
1119       XDrawLine(mainDisplay, window, gc, x1, y1, x2, y2);
1120    } else {
1121       sv[0].x = (short)x1; sv[0].y = (short)y1;
1122       sv[1].x = (short)x1; sv[1].y = (short)y2;
1123       sv[2].x = (short)x2; sv[2].y = (short)y2;
1124       sv[3].x = (short)x2; sv[3].y = (short)y1;
1125       sv[4].x = (short)x1; sv[4].y = (short)y1;
1126       XDrawLines(mainDisplay, window, gc, sv, 5, CoordModeOrigin);
1127    }
1128 }
1129 
1130 static
PtInObjList(XOff,YOff,FirstObjPtr)1131 struct ObjRec *PtInObjList(XOff, YOff, FirstObjPtr)
1132    int XOff, YOff;
1133    struct ObjRec *FirstObjPtr;
1134    /* XOff and YOff are screen offsets */
1135 {
1136    register struct ObjRec *obj_ptr, *obj_ptr1;
1137    register struct AttrRec *attr_ptr;
1138 
1139    for (obj_ptr=FirstObjPtr; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
1140       for (attr_ptr=obj_ptr->fattr; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
1141          if (attr_ptr->shown &&
1142                XOff >= OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1143                YOff >= OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1144                XOff <= OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1145                YOff <= OFFSET_Y(attr_ptr->obj->bbox.rby)+3) {
1146             return attr_ptr->obj;
1147          }
1148       }
1149       if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1150             YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1151             XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1152             YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1153          switch (obj_ptr->type) {
1154          case OBJ_TEXT:
1155             if (FindGoodText(XOff,YOff,obj_ptr)) return obj_ptr; break;
1156          case OBJ_XBM:
1157             if (FindGoodXBm(XOff,YOff,obj_ptr)) return obj_ptr; break;
1158          case OBJ_XPM:
1159             if (FindGoodXPm(XOff,YOff,obj_ptr)) return obj_ptr; break;
1160          case OBJ_BOX:
1161             if (FindGoodBox(XOff,YOff,obj_ptr)) return obj_ptr; break;
1162          case OBJ_OVAL:
1163             if (FindGoodOval(XOff,YOff,obj_ptr)) return obj_ptr; break;
1164          case OBJ_POLY:
1165             if (FindGoodPoly(XOff,YOff,obj_ptr)) return obj_ptr; break;
1166          case OBJ_POLYGON:
1167             if (FindGoodPolygon(XOff,YOff,obj_ptr)) return obj_ptr; break;
1168          case OBJ_ARC:
1169             if (FindGoodArc(XOff,YOff,obj_ptr)) return obj_ptr; break;
1170          case OBJ_RCBOX:
1171             if (FindGoodRCBox(XOff,YOff,obj_ptr)) return obj_ptr; break;
1172 
1173          case OBJ_GROUP:
1174          case OBJ_SYM:
1175          case OBJ_ICON:
1176             obj_ptr1 = PtInObjList(XOff, YOff, obj_ptr->detail.r->first);
1177             if (obj_ptr1 != NULL) return obj_ptr1;
1178             break;
1179          case OBJ_PIN:
1180             obj_ptr1 = PtInObjList(XOff, YOff,
1181                   GetPinObj(obj_ptr)->detail.r->first);
1182             if (obj_ptr1 != NULL) return obj_ptr1;
1183             break;
1184          }
1185       }
1186    }
1187    return NULL;
1188 }
1189 
1190 static
PtInSelected(XOff,YOff)1191 struct ObjRec *PtInSelected(XOff, YOff)
1192    int XOff, YOff;
1193    /* XOff and YOff are screen offsets */
1194 {
1195    register struct SelRec *sel_ptr;
1196    register struct ObjRec *obj_ptr, *obj_ptr1;
1197    register struct AttrRec *attr_ptr;
1198 
1199    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1200       obj_ptr = sel_ptr->obj;
1201 
1202       for (attr_ptr=obj_ptr->fattr; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
1203          if (attr_ptr->shown &&
1204                XOff >= OFFSET_X(attr_ptr->obj->bbox.ltx)-3 &&
1205                YOff >= OFFSET_Y(attr_ptr->obj->bbox.lty)-3 &&
1206                XOff <= OFFSET_X(attr_ptr->obj->bbox.rbx)+3 &&
1207                YOff <= OFFSET_Y(attr_ptr->obj->bbox.rby)+3) {
1208             return attr_ptr->obj;
1209          }
1210       }
1211       if (XOff >= OFFSET_X(obj_ptr->bbox.ltx)-3 &&
1212             YOff >= OFFSET_Y(obj_ptr->bbox.lty)-3 &&
1213             XOff <= OFFSET_X(obj_ptr->bbox.rbx)+3 &&
1214             YOff <= OFFSET_Y(obj_ptr->bbox.rby)+3) {
1215          switch (obj_ptr->type) {
1216          case OBJ_TEXT:
1217             if (FindGoodText(XOff,YOff,obj_ptr)) return obj_ptr; break;
1218          case OBJ_XBM:
1219             if (FindGoodXBm(XOff,YOff,obj_ptr)) return obj_ptr; break;
1220          case OBJ_XPM:
1221             if (FindGoodXPm(XOff,YOff,obj_ptr)) return obj_ptr; break;
1222          case OBJ_BOX:
1223             if (FindGoodBox(XOff,YOff,obj_ptr)) return obj_ptr; break;
1224          case OBJ_OVAL:
1225             if (FindGoodOval(XOff,YOff,obj_ptr)) return obj_ptr; break;
1226          case OBJ_POLY:
1227             if (FindGoodPoly(XOff,YOff,obj_ptr)) return obj_ptr; break;
1228          case OBJ_POLYGON:
1229             if (FindGoodPolygon(XOff,YOff,obj_ptr)) return obj_ptr; break;
1230          case OBJ_ARC:
1231             if (FindGoodArc(XOff,YOff,obj_ptr)) return obj_ptr; break;
1232          case OBJ_RCBOX:
1233             if (FindGoodRCBox(XOff,YOff,obj_ptr)) return obj_ptr; break;
1234 
1235          case OBJ_GROUP:
1236          case OBJ_ICON:
1237          case OBJ_SYM:
1238             obj_ptr1 = PtInObjList(XOff, YOff, obj_ptr->detail.r->first);
1239             if (obj_ptr1 != NULL) return obj_ptr1;
1240             break;
1241          case OBJ_PIN:
1242             obj_ptr1 = PtInObjList(XOff, YOff,
1243                   GetPinObj(obj_ptr)->detail.r->first);
1244             if (obj_ptr1 != NULL) return obj_ptr1;
1245             break;
1246          }
1247       }
1248    }
1249    return NULL;
1250 }
1251 
1252 static
ToggleVertexSelection(ObjPtr,VIndex,AbsX,AbsY,pn_struct_spline_msg)1253 void ToggleVertexSelection(ObjPtr, VIndex, AbsX, AbsY, pn_struct_spline_msg)
1254    struct ObjRec *ObjPtr;
1255    int VIndex, AbsX, AbsY, *pn_struct_spline_msg;
1256 {
1257    int i, j, n=0, curved=(-1), last_polygon_vertex=FALSE;
1258    struct VSelRec *vsel_ptr=NULL;
1259    char *smooth=NULL;
1260 
1261    switch (ObjPtr->type) {
1262    case OBJ_POLY:
1263       curved = ObjPtr->detail.p->curved;
1264       if (curved == LT_STRUCT_SPLINE) {
1265          smooth = ObjPtr->detail.p->ssmooth;
1266       } else {
1267          smooth = ObjPtr->detail.p->smooth;
1268       }
1269       break;
1270    case OBJ_POLYGON:
1271       curved = ObjPtr->detail.g->curved;
1272       if (curved == LT_STRUCT_SPLINE) {
1273          smooth = ObjPtr->detail.g->ssmooth;
1274          if (VIndex == ObjPtr->detail.g->ssn-1) {
1275             last_polygon_vertex = TRUE;
1276          }
1277       } else {
1278          smooth = ObjPtr->detail.g->smooth;
1279          if (VIndex == ObjPtr->detail.g->n-1) {
1280             last_polygon_vertex = TRUE;
1281          }
1282       }
1283       break;
1284    }
1285    if (VertexAlreadySelected(ObjPtr, VIndex, &vsel_ptr)) {
1286       /* de-select a vertex */
1287       if (vsel_ptr->n == 1) {
1288          if (vsel_ptr->prev == NULL) {
1289             topVSel = vsel_ptr->next;
1290          } else {
1291             vsel_ptr->prev->next = vsel_ptr->next;
1292          }
1293          if (vsel_ptr->next == NULL) {
1294             botVSel = vsel_ptr->prev;
1295          } else {
1296             vsel_ptr->next->prev = vsel_ptr->prev;
1297          }
1298          free(vsel_ptr->v_index);
1299          free(vsel_ptr->x);
1300          free(vsel_ptr->y);
1301          free(vsel_ptr);
1302       } else {
1303          for (j = 0; j < vsel_ptr->n; j++) {
1304             if (vsel_ptr->v_index[j] == VIndex) {
1305                break;
1306             }
1307          }
1308          if (j > vsel_ptr->n) {
1309             sprintf(gszMsgBox, TgLoadString(STID_INCONSIS_VERTEX_SEL_IN_FUNC),
1310                   "ToggleVertexSelection()");
1311             TgAssert(FALSE, gszMsgBox, NULL);
1312          }
1313          for (i=j; i < vsel_ptr->n-1; i++) {
1314             vsel_ptr->v_index[i] = vsel_ptr->v_index[i+1];
1315             vsel_ptr->x[i] = vsel_ptr->x[i+1];
1316             vsel_ptr->y[i] = vsel_ptr->y[i+1];
1317          }
1318          vsel_ptr->n--;
1319       }
1320    } else {
1321       if (vsel_ptr == NULL) {
1322          /* a new object */
1323          vsel_ptr = (struct VSelRec *)malloc(sizeof(struct VSelRec));
1324          if (vsel_ptr == NULL) FailAllocMessage();
1325          memset(vsel_ptr, 0, sizeof(struct VSelRec));
1326          vsel_ptr->obj = ObjPtr;
1327          n = vsel_ptr->n = 1;
1328          vsel_ptr->max_v = 10;
1329          vsel_ptr->v_index = (int*)malloc(10*sizeof(int));
1330          if (vsel_ptr->v_index == NULL) FailAllocMessage();
1331          vsel_ptr->x = (int*)malloc(10*sizeof(int));
1332          vsel_ptr->y = (int*)malloc(10*sizeof(int));
1333          if (vsel_ptr->x == NULL || vsel_ptr->y == NULL) FailAllocMessage();
1334 
1335          vsel_ptr->prev = NULL;
1336          vsel_ptr->next = topVSel;
1337          if (topVSel == NULL) {
1338             botVSel = vsel_ptr;
1339          } else {
1340             topVSel->prev = vsel_ptr;
1341          }
1342          topVSel = vsel_ptr;
1343       } else {
1344          if (!last_polygon_vertex && curved == LT_STRUCT_SPLINE) {
1345             if (!(*pn_struct_spline_msg)) {
1346                *pn_struct_spline_msg = TRUE;
1347                Msg(TgLoadString(STID_ONE_V_STRUCT_SPLINE_IN_V_MODE));
1348             }
1349             return;
1350          } else {
1351             n = ++(vsel_ptr->n);
1352             if (n > vsel_ptr->max_v) {
1353                int max_v;
1354 
1355                vsel_ptr->max_v += 10;
1356                max_v = vsel_ptr->max_v;
1357                vsel_ptr->v_index = (int*)realloc(vsel_ptr->v_index,
1358                      sizeof(int)*max_v);
1359                vsel_ptr->x = (int*)realloc(vsel_ptr->x, sizeof(int)*max_v);
1360                vsel_ptr->y = (int*)realloc(vsel_ptr->y, sizeof(int)*max_v);
1361             }
1362          }
1363       }
1364       vsel_ptr->v_index[n-1] = VIndex;
1365       vsel_ptr->x[n-1] = AbsX;
1366       vsel_ptr->y[n-1] = AbsY;
1367    }
1368    if (!last_polygon_vertex) {
1369       if (curved != LT_INTSPLINE && curved != (-1) && smooth != NULL) {
1370          if (smooth[VIndex]) {
1371             if (curved == LT_STRUCT_SPLINE) {
1372                MARKHO(drawWindow, revDefaultGC, OFFSET_X(AbsX), OFFSET_Y(AbsY));
1373             } else {
1374                MARKO(drawWindow, revDefaultGC, OFFSET_X(AbsX), OFFSET_Y(AbsY));
1375             }
1376          } else {
1377             if (curved == LT_STRUCT_SPLINE) {
1378                MARKHR(drawWindow, revDefaultGC, OFFSET_X(AbsX), OFFSET_Y(AbsY));
1379             } else {
1380                MARK(drawWindow, revDefaultGC, OFFSET_X(AbsX), OFFSET_Y(AbsY));
1381             }
1382          }
1383       } else {
1384          MARK(drawWindow, revDefaultGC, OFFSET_X(AbsX), OFFSET_Y(AbsY));
1385       }
1386       MARKV(drawWindow, revDefaultGC, OFFSET_X(AbsX), OFFSET_Y(AbsY));
1387    }
1388 }
1389 
1390 static
ToggleSelectedObjIfSelectedAlready(ObjPtr)1391 void ToggleSelectedObjIfSelectedAlready(ObjPtr)
1392    register struct ObjRec *ObjPtr;
1393 {
1394    register struct SelRec *sel_ptr;
1395 
1396    if ((sel_ptr=AlreadySelected(ObjPtr)) != NULL) {
1397       /* de-select an object */
1398       HighLightAnObj(ObjPtr);
1399 
1400       if (sel_ptr->prev == NULL) {
1401          topSel = sel_ptr->next;
1402       } else {
1403          sel_ptr->prev->next = sel_ptr->next;
1404       }
1405       if (sel_ptr->next == NULL) {
1406          botSel = sel_ptr->prev;
1407       } else {
1408          sel_ptr->next->prev = sel_ptr->prev;
1409       }
1410       free(sel_ptr);
1411       numObjSelected--;
1412    } else {
1413       /* add a newly selected object */
1414       AddNewSelObj(ObjPtr);
1415       HighLightAnObj(ObjPtr);
1416    }
1417 }
1418 
1419 static
ContinueSel(XOff,YOff,ShiftKeyDown)1420 void ContinueSel(XOff, YOff, ShiftKeyDown)
1421    int XOff, YOff, ShiftKeyDown;
1422    /* XOff and YOff are screen offsets, and they are not on grid */
1423 {
1424    int i, end_x, end_y, v_index, new_end_x, new_end_y;
1425    int done=FALSE, ltx, lty, rbx, rby, dx, dy, x, y;
1426    int struct_spline_msg=FALSE;
1427    char buf[80], w_buf[80], h_buf[80], x_buf[80], y_buf[80];
1428    XEvent input, ev;
1429    XMotionEvent *motion_ev=NULL;
1430    struct SelRec *sel_ptr=NULL, *top_sel_ptr=NULL, *bot_sel_ptr=NULL;
1431    struct VSelRec *vsel_ptr=NULL, *top_vsel_ptr=NULL, *bot_vsel_ptr=NULL;
1432    struct ObjRec *obj_ptr=NULL, *owner_obj=NULL;
1433 
1434    end_x = XOff;
1435    end_y = YOff;
1436 
1437    SelBox(drawWindow, revDefaultGC, XOff, YOff, end_x, end_y);
1438    PixelToMeasurementUnit(w_buf, 0);
1439    PixelToMeasurementUnit(h_buf, 0);
1440    PixelToMeasurementUnit(x_buf, ABS_X(end_x));
1441    PixelToMeasurementUnit(y_buf, ABS_Y(end_y));
1442    sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
1443    StartShowMeasureCursor(end_x, end_y, buf, TRUE);
1444    if (!debugNoPointerGrab) {
1445       XGrabPointer(mainDisplay, drawWindow, False,
1446             PointerMotionMask | ButtonReleaseMask,
1447             GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1448    }
1449    while (!done) {
1450       XNextEvent(mainDisplay, &input);
1451 
1452       if (input.type == Expose || input.type == VisibilityNotify) {
1453          ExposeEventHandler(&input, TRUE);
1454       } else if (input.type == ButtonRelease) {
1455          XUngrabPointer(mainDisplay, CurrentTime);
1456          PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(end_x-XOff)));
1457          PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(end_y-YOff)));
1458          PixelToMeasurementUnit(x_buf, ABS_X(end_x));
1459          PixelToMeasurementUnit(y_buf, ABS_Y(end_y));
1460          sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
1461          EndShowMeasureCursor(end_x, end_y, buf, TRUE);
1462          SelBox(drawWindow, revDefaultGC, XOff, YOff, end_x, end_y);
1463          done = TRUE;
1464       } else if (input.type == MotionNotify) {
1465          motion_ev = &(input.xmotion);
1466          new_end_x = motion_ev->x;
1467          new_end_y = motion_ev->y;
1468 
1469          PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(end_x-XOff)));
1470          PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(end_y-YOff)));
1471          PixelToMeasurementUnit(x_buf, ABS_X(end_x));
1472          PixelToMeasurementUnit(y_buf, ABS_Y(end_y));
1473          sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
1474          ShowMeasureCursor(end_x, end_y, buf, TRUE);
1475          SelBox(drawWindow, revDefaultGC, XOff, YOff, end_x, end_y);
1476          end_x = new_end_x; end_y = new_end_y;
1477          SelBox(drawWindow, revDefaultGC, XOff, YOff, end_x, end_y);
1478          PixelToMeasurementUnit(w_buf, ABS_SIZE(abs(end_x-XOff)));
1479          PixelToMeasurementUnit(h_buf, ABS_SIZE(abs(end_y-YOff)));
1480          PixelToMeasurementUnit(x_buf, ABS_X(end_x));
1481          PixelToMeasurementUnit(y_buf, ABS_Y(end_y));
1482          sprintf(buf, "w=%s\nh=%s\nx=%s\ny=%s", w_buf, h_buf, x_buf, y_buf);
1483          ShowMeasureCursor(end_x, end_y, buf, TRUE);
1484 
1485          MarkRulers(end_x, end_y);
1486          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1487       }
1488    }
1489 
1490    dx = abs(XOff - end_x);
1491    dy = abs(YOff - end_y);
1492    if (curChoice == VERTEXMODE) {
1493       if (dx <= 2 && dy <= 2) {
1494          if (topSel == NULL) {
1495             if (SelectOneObj(XOff, YOff, NULL) != NULL) {
1496                if ((topSel->obj->type == OBJ_POLY ||
1497                      topSel->obj->type == OBJ_POLYGON) &&
1498                      !topSel->obj->locked) {
1499                   HighLightForward();
1500                } else {
1501                   RemoveAllSel();
1502                }
1503             }
1504          } else if (ShiftKeyDown) {
1505             obj_ptr = FindAVertex(XOff, YOff, &v_index, &x, &y);
1506             if (obj_ptr != NULL) {
1507                ToggleVertexSelection(obj_ptr, v_index, x, y,
1508                      &struct_spline_msg);
1509                if (obj_ptr->type==OBJ_POLYGON && v_index==0) {
1510                   if (obj_ptr->detail.g->curved == LT_STRUCT_SPLINE) {
1511                      ToggleVertexSelection(obj_ptr,obj_ptr->detail.g->ssn-1,
1512                            x, y, &struct_spline_msg);
1513                   } else {
1514                      ToggleVertexSelection(obj_ptr,obj_ptr->detail.g->n-1,
1515                            x, y, &struct_spline_msg);
1516                   }
1517                }
1518                UpdSelBBox();
1519             }
1520          } else {
1521             HighLightReverse();
1522             SelectOneVertex(XOff, YOff);
1523             HighLightForward();
1524          }
1525       } else {
1526          CalcBBox(XOff, YOff, end_x, end_y, &ltx, &lty, &rbx, &rby);
1527          if (topSel == NULL) {
1528             if (FindObjects(ABS_X(ltx), ABS_Y(lty), ABS_X(rbx), ABS_Y(rby),
1529                   &top_sel_ptr, &bot_sel_ptr) != NULL) {
1530                topSel = top_sel_ptr;
1531                botSel = bot_sel_ptr;
1532                UnSelNonVertexObjs(FALSE, TRUE); /* do not highlight */
1533                UpdSelBBox();
1534                HighLightForward();
1535             }
1536          } else if (ShiftKeyDown) {
1537             if (FindVertices(ABS_X(ltx), ABS_Y(lty), ABS_X(rbx), ABS_Y(rby),
1538                   &top_vsel_ptr, &bot_vsel_ptr, &struct_spline_msg)) {
1539                struct VSelRec *next_vsel;
1540 
1541                for (vsel_ptr=top_vsel_ptr; vsel_ptr!=NULL; vsel_ptr=next_vsel) {
1542                   obj_ptr = vsel_ptr->obj;
1543                   for (i = 0; i < vsel_ptr->n; i++) {
1544                      ToggleVertexSelection(obj_ptr, vsel_ptr->v_index[i],
1545                            vsel_ptr->x[i], vsel_ptr->y[i], &struct_spline_msg);
1546                   }
1547                   next_vsel = vsel_ptr->next;
1548                   free(vsel_ptr->v_index);
1549                   free(vsel_ptr->x);
1550                   free(vsel_ptr->y);
1551                   free(vsel_ptr);
1552                }
1553                UpdSelBBox();
1554             }
1555          } else {
1556             HighLightReverse();
1557             JustRemoveAllVSel();
1558             if (FindVertices(ABS_X(ltx), ABS_Y(lty), ABS_X(rbx), ABS_Y(rby),
1559                   &top_vsel_ptr, &bot_vsel_ptr, &struct_spline_msg)) {
1560                topVSel = top_vsel_ptr;
1561                botVSel = bot_vsel_ptr;
1562                UpdSelBBox();
1563             }
1564             HighLightForward();
1565          }
1566       }
1567    } else {
1568       if (dx <= 2 && dy <= 2) {
1569          if (ShiftKeyDown) {
1570             obj_ptr = FindAnObj(XOff, YOff, &owner_obj, NULL, NULL);
1571             if (obj_ptr != NULL) {
1572                if (owner_obj != NULL) obj_ptr = owner_obj;
1573 
1574                ToggleSelectedObjIfSelectedAlready(obj_ptr);
1575                UpdSelBBox();
1576             }
1577          } else {
1578             if (topSel != NULL) HighLightReverse();
1579 
1580             if (SelectOneObj(XOff, YOff, NULL) != NULL) {
1581                HighLightForward();
1582             }
1583          }
1584       } else {
1585          CalcBBox(XOff, YOff, end_x, end_y, &ltx, &lty, &rbx, &rby);
1586          if (ShiftKeyDown) {
1587             if (FindObjects(ABS_X(ltx), ABS_Y(lty), ABS_X(rbx), ABS_Y(rby),
1588                   &top_sel_ptr, &bot_sel_ptr) != NULL) {
1589                struct SelRec *next_sel;
1590 
1591                for (sel_ptr=top_sel_ptr; sel_ptr!=NULL; sel_ptr=next_sel) {
1592                   next_sel = sel_ptr->next;
1593                   obj_ptr = sel_ptr->obj;
1594                   ToggleSelectedObjIfSelectedAlready(obj_ptr);
1595                   free(sel_ptr);
1596                }
1597                UpdSelBBox();
1598             }
1599          } else {
1600             if (topSel != NULL) HighLightReverse();
1601             RemoveAllSel();
1602             if (FindObjects(ABS_X(ltx), ABS_Y(lty), ABS_X(rbx), ABS_Y(rby),
1603                   &top_sel_ptr, &bot_sel_ptr) != NULL) {
1604                topSel = top_sel_ptr;
1605                botSel = bot_sel_ptr;
1606                UpdSelBBox();
1607                HighLightForward();
1608             }
1609          }
1610       }
1611    }
1612 }
1613 
1614 static XComposeStatus	c_stat;
1615 
1616 static
KeyPressInSelect(key_ev)1617 void KeyPressInSelect(key_ev)
1618    XKeyEvent *key_ev;
1619 {
1620    XButtonEvent button_ev;
1621    char s[80];
1622    KeySym key_sym;
1623    int delta, dx=0, dy=0, has_ch=FALSE;
1624 
1625    has_ch = XLookupString(key_ev, s, sizeof(s), &key_sym, &c_stat);
1626    TranslateKeys(s, &key_sym);
1627    if (inSlideShow) {
1628       if (CharIsESC(key_ev, s, key_sym, &has_ch)) {
1629          LeaveSlideShow();
1630          return;
1631       }
1632       switch (key_sym) {
1633       case XK_Left: PrevSlide(); return;
1634       case XK_KP_Left: PrevSlide(); return;
1635       case XK_Up: PrevSlide(); return;
1636       case XK_KP_Up: PrevSlide(); return;
1637       case XK_Right: NextSlide(); return;
1638       case XK_KP_Right: NextSlide(); return;
1639       case XK_Down: NextSlide(); return;
1640       case XK_KP_Down: NextSlide(); return;
1641       default: break;
1642       }
1643    }
1644    button_ev.state = ShiftMask;
1645    if (key_sym == XK_Page_Up || key_sym == XK_KP_Page_Up) {
1646       ScrollUp(&button_ev);
1647    } else if (key_sym == XK_Page_Down || key_sym == XK_KP_Page_Down) {
1648       ScrollDown(&button_ev);
1649    }
1650    if (topSel==NULL && topVSel==NULL) {
1651       if (key_ev->state & ControlMask) {
1652          switch (key_sym) {
1653          case XK_Left: ScrollLeft(&button_ev); break;
1654          case XK_KP_Left: ScrollLeft(&button_ev); break;
1655          case XK_Up: ScrollUp(&button_ev); break;
1656          case XK_KP_Up: ScrollUp(&button_ev); break;
1657          case XK_Right: ScrollRight(&button_ev); break;
1658          case XK_KP_Right: ScrollRight(&button_ev); break;
1659          case XK_Down: ScrollDown(&button_ev); break;
1660          case XK_KP_Down: ScrollDown(&button_ev); break;
1661          }
1662       } else {
1663          switch (key_sym) {
1664          case XK_Left: ScrollLeft(NULL); break;
1665          case XK_KP_Left: ScrollLeft(NULL); break;
1666          case XK_Up: ScrollUp(NULL); break;
1667          case XK_KP_Up: ScrollUp(NULL); break;
1668          case XK_Right: ScrollRight(NULL); break;
1669          case XK_KP_Right: ScrollRight(NULL); break;
1670          case XK_Down: ScrollDown(NULL); break;
1671          case XK_KP_Down: ScrollDown(NULL); break;
1672          }
1673       }
1674       return;
1675    }
1676    if (CharIsDEL(key_ev, s, key_sym, &has_ch)) {
1677       DelAllSelObj();
1678    }
1679    if (key_sym!=XK_Left && key_sym!=XK_Up && key_sym!=XK_Right &&
1680          key_sym!=XK_Down && key_sym!=XK_KP_Left && key_sym!=XK_KP_Up &&
1681          key_sym!=XK_KP_Right && key_sym!=XK_KP_Down) {
1682       return;
1683    }
1684 
1685    if (snapOn) {
1686       delta = (gridSystem==ENGLISH_GRID) ? GRID_ABS_SIZE(xyEnglishGrid) :
1687             GRID_ABS_SIZE(xyMetricGrid);
1688    } else {
1689       delta = GRID_ABS_SIZE(1);
1690    }
1691    HighLightReverse();
1692    switch (key_sym) {
1693    case XK_Left:     dx = -delta; dy = 0; break;
1694    case XK_KP_Left:  dx = -delta; dy = 0; break;
1695    case XK_Up:       dx = 0;      dy = -delta; break;
1696    case XK_KP_Up:    dx = 0;      dy = -delta; break;
1697    case XK_Right:    dx = delta;  dy = 0; break;
1698    case XK_KP_Right: dx = delta;  dy = 0; break;
1699    case XK_Down:     dx = 0;      dy = delta; break;
1700    case XK_KP_Down:  dx = 0;      dy = delta; break;
1701    }
1702    if (curChoice == VERTEXMODE) {
1703       MoveAllSelVs(dx, dy);
1704    } else if (numObjSelected == numObjLocked) {
1705       HighLightForward();
1706       return;
1707    } else {
1708       MoveAllSel(dx, dy);
1709    }
1710    HighLightForward();
1711    UpdSelBBox();
1712    if (justDupped) {
1713       dupDx += dx;
1714       dupDy += dy;
1715    }
1716    SetFileModified(TRUE);
1717 }
1718 
1719 static
PtInObjAboveSelected(XOff,YOff)1720 int PtInObjAboveSelected(XOff, YOff)
1721    int XOff, YOff;
1722    /*
1723     * returns TRUE if there is an object under the mouse that's above all the
1724     *       selected objects -- in this case, that object should be selected
1725     */
1726 {
1727    struct ObjRec *obj_ptr=NULL, *owner_obj=NULL, *found_obj=NULL;
1728 
1729    found_obj = FindAnObj(XOff, YOff, &owner_obj, NULL, NULL);
1730    if (found_obj == NULL) {
1731       /* no object under the cursor */
1732       return FALSE;
1733    }
1734    if (owner_obj != NULL) found_obj = owner_obj;
1735    if (topSel == NULL) {
1736       return TRUE;
1737    }
1738    for (obj_ptr=topObj; obj_ptr != NULL && obj_ptr != topSel->obj;
1739          obj_ptr=obj_ptr->next) {
1740       if (obj_ptr == found_obj) {
1741          return TRUE;
1742       }
1743    }
1744    return FALSE;
1745 }
1746 
Select(input)1747 void Select(input)
1748    XEvent *input;
1749 {
1750    register int i;
1751    XButtonEvent *button_ev;
1752    struct SelRec *sel_ptr;
1753    struct VSelRec *vsel_ptr;
1754    struct ObjRec *obj_ptr;
1755    Time click_time;
1756 
1757    if (input->type == KeyPress) {
1758       KeyPressInSelect(&(input->xkey));
1759       return;
1760    } else if (input->type != ButtonPress) {
1761       return;
1762    }
1763 
1764    button_ev = &(input->xbutton);
1765    if (button_ev->button == Button1) {
1766       static Time sSelectLastClickTime=(Time)0;
1767       static int snSelectJustClicked=FALSE;
1768 
1769       int mouse_x, mouse_y, grid_x, grid_y, corner;
1770 
1771       mouse_x = button_ev->x;
1772       mouse_y = button_ev->y;
1773       GridXY(mouse_x, mouse_y, &grid_x, &grid_y);
1774 
1775       click_time = button_ev->time;
1776       if (curChoice==VERTEXMODE && topSel!=NULL && snSelectJustClicked &&
1777             (click_time-sSelectLastClickTime) < doubleClickInterval) {
1778          snSelectJustClicked = FALSE;
1779          HighLightReverse();
1780          RemoveAllSel();
1781          return;
1782       } else if (curChoice==NOTHING && topSel!=NULL && snSelectJustClicked &&
1783             (click_time-sSelectLastClickTime) < doubleClickInterval) {
1784          snSelectJustClicked = FALSE;
1785          Teleport(button_ev);
1786          return;
1787       }
1788       snSelectJustClicked = TRUE;
1789       sSelectLastClickTime = click_time;
1790 
1791       if (button_ev->state & (ShiftMask | ControlMask)) {
1792          ContinueSel(mouse_x, mouse_y, TRUE);
1793          justDupped = FALSE;
1794          return;
1795       } else if (curChoice == VERTEXMODE && topVSel != NULL) {
1796          int found=FALSE;
1797 
1798          for (vsel_ptr=topVSel; vsel_ptr!=NULL && !found;
1799                vsel_ptr=vsel_ptr->next) {
1800             for (i = 0; i < vsel_ptr->n; i++) {
1801                if (PtInMark(mouse_x, mouse_y, OFFSET_X(vsel_ptr->x[i]),
1802                      OFFSET_Y(vsel_ptr->y[i]))) {
1803                   found = TRUE;
1804                   break;
1805                }
1806             }
1807          }
1808          if (found) {
1809             MoveSelVs(grid_x, grid_y);
1810             return;
1811          }
1812       } else if (curChoice == NOTHING) {
1813          struct ObjRec *inner_obj=NULL;
1814 
1815          if (topSel != NULL) {
1816             if (oneMotionSelectMove &&
1817                   PtInSelMark(mouse_x, mouse_y, &corner) == NULL &&
1818                   PtInSelected(mouse_x, mouse_y) == NULL) {
1819                /* may be pointing in not already selected object */
1820                HighLightReverse();
1821                RemoveAllSel();
1822                if (SelectOneObj(mouse_x, mouse_y, &inner_obj) != NULL) {
1823                   HighLightForward();
1824                   MoveSel(grid_x, grid_y,
1825                         (inner_obj==NULL ? topSel->obj : inner_obj), button_ev);
1826                   return;
1827                }
1828             } else if ((sel_ptr=PtInSelMark(mouse_x,mouse_y,&corner)) != NULL) {
1829                StretchSel(grid_x, grid_y, sel_ptr->obj, corner);
1830                return;
1831             } else if (!PtInObjAboveSelected(mouse_x, mouse_y) &&
1832                   (obj_ptr=PtInSelected(mouse_x, mouse_y)) != NULL) {
1833                MoveSel(grid_x, grid_y, obj_ptr, button_ev);
1834                return;
1835             }
1836          } else if (oneMotionSelectMove &&
1837                SelectOneObj(mouse_x, mouse_y, &inner_obj) != NULL) {
1838             HighLightForward();
1839             MoveSel(grid_x, grid_y,
1840                   (inner_obj==NULL ? topSel->obj : inner_obj), button_ev);
1841             return;
1842          }
1843       } else if (curChoice == ROTATEMODE && topSel != NULL) {
1844          if ((sel_ptr=PtInSelMark(mouse_x, mouse_y, &corner)) != NULL) {
1845             RotateShearSel(grid_x, grid_y, sel_ptr->obj, corner);
1846             return;
1847          }
1848          if (!autoRotatePivot && PtInRotatePivot(mouse_x, mouse_y)) {
1849             ContinueMoveRotatePivot(grid_x, grid_y);
1850             return;
1851          }
1852       }
1853       ContinueSel(mouse_x, mouse_y, FALSE);
1854       justDupped = FALSE;
1855    }
1856 }
1857 
FindFileAttrWithName(AttrName)1858 struct AttrRec *FindFileAttrWithName(AttrName)
1859    char *AttrName;
1860 {
1861    struct AttrRec *attr_ptr, *found_attr=NULL;
1862    int count=1, compare_name=(strchr(AttrName,'=') != NULL);
1863 
1864    if (tgifObj == NULL) return NULL;
1865 
1866    for (attr_ptr=tgifObj->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
1867       if (compare_name) {
1868          if (strcmp(attr_ptr->attr_name.s, AttrName) == 0) {
1869             found_attr = attr_ptr;
1870             break;
1871          }
1872       } else {
1873          if (strcmp(attr_ptr->attr_value.s, AttrName) == 0) {
1874             found_attr = attr_ptr;
1875             break;
1876          }
1877       }
1878    }
1879    if (attr_ptr == NULL) return NULL;
1880 
1881    if (GetTextObjFirstStrSeg(found_attr->obj)->color == colorIndex) {
1882       return found_attr;
1883    }
1884    for (attr_ptr=found_attr->next; attr_ptr!=NULL; attr_ptr=attr_ptr->next) {
1885       if (compare_name) {
1886          if (strcmp(attr_ptr->attr_name.s, AttrName) == 0) {
1887             if (GetTextObjFirstStrSeg(attr_ptr->obj)->color == colorIndex) {
1888                break;
1889             } else {
1890                count++;
1891             }
1892          }
1893       } else {
1894          if (strcmp(attr_ptr->attr_value.s, AttrName) == 0) {
1895             if (GetTextObjFirstStrSeg(attr_ptr->obj)->color == colorIndex) {
1896                break;
1897             } else {
1898                count++;
1899             }
1900          }
1901       }
1902    }
1903    if (attr_ptr != NULL) {
1904       found_attr = attr_ptr;
1905    } else if (count != 1) {
1906       sprintf(gszMsgBox,
1907             TgLoadCachedString(CSTID_CANT_FIND_FILEATTR_WITH_COLOR),
1908             AttrName, colorMenuItems[colorIndex]);
1909       Msg(gszMsgBox);
1910       return NULL;
1911    }
1912    return found_attr;
1913 }
1914 
FindAttrWithName(ObjPtr,AttrName,pp_top_owner)1915 struct AttrRec *FindAttrWithName(ObjPtr, AttrName, pp_top_owner)
1916    struct ObjRec *ObjPtr, **pp_top_owner;
1917    char *AttrName;
1918 {
1919    struct ObjRec *obj_ptr=NULL;
1920    char *dot_ptr=NULL;
1921 
1922    if (AttrName[0] == '!' && AttrName[1] == '*') {
1923       if (topSel == NULL) {
1924          return NULL;
1925       }
1926       if (pp_top_owner != NULL) *pp_top_owner = topSel->obj;
1927       return FindObjAttrWithName(topSel->obj, &AttrName[2]);
1928    }
1929    if ((dot_ptr=strchr(AttrName, '.')) == NULL) {
1930       if (pp_top_owner != NULL) *pp_top_owner = ObjPtr;
1931       return FindObjAttrWithName(ObjPtr, AttrName);
1932    }
1933    *dot_ptr = '\0';
1934    if (strcmp(AttrName, "!") == 0) {
1935       *dot_ptr++ = '.';
1936       if (pp_top_owner != NULL) *pp_top_owner = tgifObj;
1937       return FindFileAttrWithName(dot_ptr);
1938    }
1939    if (AttrName[0] == '#' && AttrName[1] == '#') {
1940       int obj_page_num=0;
1941       char *bang_ptr=strchr(&AttrName[2], '!');
1942 
1943       if (bang_ptr == NULL) {
1944          *dot_ptr = '.';
1945          return NULL;
1946       }
1947       *bang_ptr = '\0';
1948       if (sscanf(&AttrName[2], "%d", &obj_page_num) != 1) {
1949          *bang_ptr = '!';
1950          *dot_ptr = '.';
1951          return NULL;
1952       }
1953       if (obj_page_num < 1 || obj_page_num > lastPageNum) {
1954          sprintf(gszMsgBox, TgLoadString(STID_INVALID_PAGE_NUM),
1955                &AttrName[2]),
1956          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1957          *bang_ptr = '!';
1958          *dot_ptr = '.';
1959          return NULL;
1960       }
1961       *bang_ptr = '!';
1962       if (curPageNum == obj_page_num) {
1963          if ((obj_ptr=FindObjWithName(botObj, ObjPtr, bang_ptr, FALSE,
1964                FALSE, NULL, pp_top_owner)) == NULL) {
1965             *dot_ptr = '.';
1966             return NULL;
1967          }
1968       } else {
1969          struct PageRec *page_ptr=NULL;
1970          int page_num=0;
1971 
1972          for (page_ptr=firstPage, page_num=1; page_ptr != NULL;
1973                page_ptr=page_ptr->next, page_num++) {
1974             if (page_num == obj_page_num) {
1975                struct PageRec *saved_cur_page_ptr=curPage;
1976                int saved_cur_page_num=curPageNum;
1977 
1978                curPageNum = page_num;
1979                curPage = page_ptr;
1980                topObj = curPage->top;
1981                botObj = curPage->bot;
1982                obj_ptr = FindObjWithName(botObj, NULL, bang_ptr,
1983                      FALSE, FALSE, NULL, NULL);
1984                curPageNum = saved_cur_page_num;
1985                curPage = saved_cur_page_ptr;
1986                topObj = curPage->top;
1987                botObj = curPage->bot;
1988 
1989                if (obj_ptr == NULL) {
1990                   *dot_ptr = '.';
1991                   return NULL;
1992                }
1993                break;
1994             }
1995          }
1996          if (page_ptr == NULL) {
1997             *dot_ptr++ = '.';
1998             return NULL;
1999          }
2000       }
2001    } else {
2002       if ((obj_ptr=FindObjWithName(botObj, ObjPtr, AttrName, FALSE,
2003             FALSE, NULL, pp_top_owner)) == NULL) {
2004          *dot_ptr++ = '.';
2005          return NULL;
2006       }
2007    }
2008    *dot_ptr++ = '.';
2009    return FindObjAttrWithName(obj_ptr, dot_ptr);
2010 }
2011 
ValidAttrArg(c_ptr,obj_ptr,new_c_ptr)2012 struct AttrRec *ValidAttrArg(c_ptr, obj_ptr, new_c_ptr)
2013    char *c_ptr, **new_c_ptr;
2014    struct ObjRec *obj_ptr;
2015 {
2016    char name[MAXSTRING+1], *name_ptr;
2017    struct AttrRec *attr_ptr;
2018 
2019    name_ptr = name;
2020    if (c_ptr[0] == '$' && c_ptr[1] == '(') {
2021       for (c_ptr = &c_ptr[2]; *c_ptr != '\0'; c_ptr++) {
2022          switch (*c_ptr) {
2023          case '\\':
2024             c_ptr++;
2025             *name_ptr++ = *c_ptr;
2026             break;
2027          case ')':
2028             *name_ptr++ = '=';
2029             *name_ptr = '\0';
2030             *new_c_ptr = c_ptr;
2031             attr_ptr = FindAttrWithName(obj_ptr, name, NULL);
2032             if (attr_ptr == NULL) {
2033                char msg[MAXSTRING+1];
2034 
2035                sprintf(msg, TgLoadCachedString(CSTID_CANT_FIND_NAMED_ATTR),
2036                      name);
2037                Msg(msg);
2038             }
2039             return attr_ptr;
2040          default: *name_ptr++ = *c_ptr; break;
2041          }
2042       }
2043    }
2044    return NULL;
2045 }
2046 
DoTeleport(teleport_attr)2047 int DoTeleport(teleport_attr)
2048    struct AttrRec *teleport_attr;
2049 {
2050    char file_name[MAXPATHLENGTH+1], msg[MAXSTRING+1], *page_spec=NULL;
2051    char *dest_ptr=NULL;
2052    int do_not_save=FALSE, rc=TRUE, just_goto_page=FALSE, referer_set=FALSE;
2053 
2054    while (!DirIsRemote(curDir) && fileModified && !IsFiletUnSavable()) {
2055       XBell(mainDisplay, 0);
2056       switch (MsgBox(TgLoadString(STID_FILE_MOD_SAVE_BEFORE_OPEN), TOOL_NAME,
2057             YNC_MB)) {
2058       case MB_ID_YES: SaveFile(); break;
2059       case MB_ID_NO: do_not_save = TRUE; SetFileModified(FALSE); break;
2060       case MB_ID_CANCEL: return FALSE;
2061       }
2062    }
2063    if (!DirIsRemote(curDir) && fileModified && IsFiletUnSavable()) {
2064       do_not_save = TRUE;
2065       SetFileModified(FALSE);
2066    }
2067    if (!FormNewFileName(curDir, teleport_attr->attr_value.s,
2068          (strcmp(teleport_attr->attr_name.s,TELEPORT_ATTR)==0 ? OBJ_FILE_EXT :
2069          NULL), file_name, &page_spec)) {
2070       sprintf(msg, TgLoadString(STID_INVALID_NAMED_TELEPORT_DEST),
2071             teleport_attr->attr_value.s);
2072       MsgBox(msg, TOOL_NAME, INFO_MB);
2073       if (do_not_save) SetFileModified(TRUE);
2074       rc = FALSE;
2075    }
2076    if (*teleport_attr->attr_value.s == '#') just_goto_page = TRUE;
2077 
2078    if (rc && page_spec != NULL && just_goto_page) {
2079       int new_page_num=(-1);
2080 
2081       if (!GetPageNumFromPageSpec(page_spec, &new_page_num)) {
2082          sprintf(msg, TgLoadString(STID_INVALID_NAMED_TELEPORT_DEST),
2083                teleport_attr->attr_value.s);
2084          MsgBox(msg, TOOL_NAME, INFO_MB);
2085          if (do_not_save) SetFileModified(TRUE);
2086          rc = FALSE;
2087       } else if (new_page_num != curPageNum) {
2088          BeforeNavigate();
2089          GotoPageNum(new_page_num);
2090          ShowPage();
2091          ClearAndRedrawDrawWindow();
2092          RedrawTitleWindow();
2093          RedrawRulers();
2094          RedrawScrollBars();
2095          CleanUpCmds();
2096          CommitNavigate();
2097          justDupped = FALSE;
2098       }
2099       if (page_spec != NULL) free(page_spec);
2100       return rc;
2101    }
2102    if (!rc) {
2103       if (page_spec != NULL) free(page_spec);
2104       return rc;
2105    }
2106    MakeQuiescent();
2107 
2108    if (curFileDefined) {
2109       referer_set = TRUE;
2110       if (*curSymDir == '\0') {
2111          sprintf(gszMsgBox, "%s%c%s", curDir, DIR_SEP, curFileName);
2112       } else {
2113          sprintf(gszMsgBox, "%s%c%s", curSymDir, DIR_SEP, curFileName);
2114       }
2115       HttpSetReferer(gszMsgBox);
2116    }
2117    dest_ptr = UtilStrDup(teleport_attr->attr_value.s);
2118    if (dest_ptr == NULL) FailAllocMessage();
2119    if (FileIsRemote(file_name)) {
2120       char *buf=NULL, *content_type=NULL, final_url[MAXPATHLENGTH+1];
2121       int buf_sz=0, is_html=FALSE;
2122 
2123       *final_url = '\0';
2124       SetWatchCursor(drawWindow);
2125       SetWatchCursor(mainWindow);
2126       SaveStatusStrings();
2127       rc = LoadRemoteFileInMem(file_name, &buf, &content_type, &buf_sz,
2128             &is_html, FALSE, final_url, sizeof(final_url));
2129       RestoreStatusStrings();
2130       SetDefaultCursor(mainWindow);
2131       ShowCursor();
2132       if (rc && buf != NULL) {
2133          if (*final_url != '\0') {
2134             UtilStrCpyN(file_name, sizeof(file_name), final_url);
2135          }
2136          LoadRemoteFileFromMem(file_name, buf, content_type, buf_sz, is_html);
2137       } else {
2138          if (do_not_save) SetFileModified(TRUE);
2139          rc = FALSE;
2140       }
2141       if (content_type != NULL) FreeRemoteBuf(content_type);
2142       if (buf != NULL) FreeRemoteBuf(buf);
2143    } else {
2144       int obj_file=FALSE, gzipped=FALSE;
2145       FILE *fp=fopen(file_name, "r");
2146 
2147       if (fp == NULL) {
2148          sprintf(gszMsgBox, TgLoadString(STID_Q_FILE_NOT_EXIST_CREATE),
2149                file_name);
2150          switch (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB)) {
2151          case MB_ID_YES:
2152             MakeQuiescent();
2153             SaveNewFile(TRUE, file_name);
2154             break;
2155          case MB_ID_NO: break;
2156          case MB_ID_CANCEL:
2157             if (do_not_save) SetFileModified(TRUE);
2158             rc = FALSE;
2159             break;
2160          }
2161       } else {
2162          fclose(fp);
2163       }
2164       obj_file = FileNameHasExtension(file_name, OBJ_FILE_TYPE, &gzipped,
2165             NULL);
2166       if (rc && !LoadFile(file_name, obj_file, obj_file && gzipped)) {
2167          if (do_not_save) SetFileModified(TRUE);
2168          rc = FALSE;
2169       }
2170    }
2171    /* At this point teleport_attr is no longer valid */
2172    if (rc && page_spec != NULL && !just_goto_page) {
2173       int new_page_num=(-1);
2174 
2175       if (!GetPageNumFromPageSpec(page_spec, &new_page_num)) {
2176          sprintf(msg, TgLoadString(STID_INVALID_NAMED_TELEPORT_DEST), dest_ptr);
2177          MsgBox(msg, TOOL_NAME, INFO_MB);
2178          rc = FALSE;
2179       } else if (new_page_num != curPageNum) {
2180          /*
2181           * No need to call BeforeNavigate() here because either
2182           * LoadRemoteFileFromMem() is called (which calls LoadFile())
2183           * or LoadFile() is called directly.
2184           */
2185          GotoPageNum(new_page_num);
2186          ShowPage();
2187          ClearAndRedrawDrawWindow();
2188          RedrawTitleWindow();
2189          RedrawRulers();
2190          RedrawScrollBars();
2191          justDupped = FALSE;
2192       }
2193    }
2194    if (dest_ptr != NULL) free(dest_ptr);
2195    if (page_spec != NULL) free(page_spec);
2196 
2197    if (referer_set) {
2198       HttpClearReferer();
2199    }
2200    return rc;
2201 }
2202 
2203 #define DO_PAGE_BY_NUM 0
2204 #define DO_PAGE_BY_NAME 1
2205 
DoPageTeleport(teleport_attr,do_by_page_name)2206 int DoPageTeleport(teleport_attr, do_by_page_name)
2207    struct AttrRec *teleport_attr;
2208    int do_by_page_name;
2209 {
2210    int i, rc=TRUE;
2211    char msg[MAXSTRING+1];
2212 
2213    if (do_by_page_name) {
2214       struct PageRec *page_ptr;
2215 
2216       for (i=1, page_ptr=firstPage; page_ptr!=NULL;
2217             page_ptr=page_ptr->next, i++) {
2218          if (page_ptr->name != NULL && strcmp(page_ptr->name,
2219                teleport_attr->attr_value.s) == 0) {
2220             if (curPageNum != i) SetCurPage(i);
2221             return TRUE;
2222          }
2223       }
2224       sprintf(msg, TgLoadString(STID_CANT_FIND_PAGE_NAMED_TO_TEL),
2225             teleport_attr->attr_value.s);
2226       MsgBox(msg, TOOL_NAME, INFO_MB);
2227       rc = FALSE;
2228    } else {
2229       i = atoi(teleport_attr->attr_value.s);
2230       if (i >= 1 && i <= lastPageNum) {
2231          if (curPageNum != i) SetCurPage(i);
2232       } else {
2233          sprintf(msg, TgLoadString(STID_CANT_FIND_PAGE_NUM_TO_TEL), i);
2234          MsgBox(msg, TOOL_NAME, INFO_MB);
2235          rc = FALSE;
2236       }
2237    }
2238    return rc;
2239 }
2240 
2241 static
ResetDeckIndices()2242 void ResetDeckIndices()
2243 {
2244    register struct ObjRec *obj_ptr;
2245 
2246    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
2247       switch (obj_ptr->type) {
2248       case OBJ_GROUP:
2249       case OBJ_ICON:
2250       case OBJ_SYM:
2251       case OBJ_PIN:
2252          obj_ptr->detail.r->deck_index = (-1);
2253          break;
2254       default: break;
2255       }
2256    }
2257 }
2258 
DoExecLoop(obj_ptr,exec_attr)2259 void DoExecLoop(obj_ptr, exec_attr)
2260    struct ObjRec *obj_ptr;
2261    struct AttrRec *exec_attr;
2262 {
2263    ResetExec(TRUE);
2264 
2265    while (exec_attr != NULL) {
2266       int saved_intr_check_interval=intrCheckInterval;
2267       int one_line_status=FALSE, exec_rc=TRUE, teleport_aborted=FALSE;
2268       int saved_history_depth=historyDepth;
2269       char status_buf[MAX_STATUS_BTNS+1][MAXSTRING+1];
2270 
2271       MakeQuiescent();
2272       intrCheckInterval = 1;
2273       ShowInterrupt(1);
2274 
2275       ResetDeckIndices();
2276       SaveStatusStringsIntoBuf(status_buf, &one_line_status);
2277       if (cmdToExecAfterHyperJump != NULL) {
2278          free(cmdToExecAfterHyperJump);
2279          cmdToExecAfterHyperJump = NULL;
2280       }
2281       warpToAttr = NULL;
2282       execNavigateBack = FALSE;
2283       exec_rc = DoExec(exec_attr, obj_ptr);
2284       exec_attr = NULL;
2285       RemoveAllSel();
2286       EndExecAnimate();
2287       if (saved_history_depth != historyDepth) RestoreDefaultHistoryDepth();
2288       if (exec_rc == TRUE && warpToAttr != NULL) {
2289          teleport_aborted = !DoTeleport(warpToAttr);
2290       }
2291       RestoreStatusStringsFromBuf(status_buf, one_line_status);
2292 
2293       while (HideInterrupt() > 0) ;
2294       intrCheckInterval = saved_intr_check_interval;
2295 
2296       if (exec_rc==TRUE && warpToAttr!=NULL && !teleport_aborted) {
2297          if (cmdToExecAfterHyperJump == NULL) {
2298             if ((exec_attr=FindFileAttrWithName("auto_exec=")) == NULL) {
2299                ResetExec(FALSE);
2300                return;
2301             }
2302             obj_ptr = NULL;
2303             continue;
2304          } else {
2305             exec_attr = FindAttrWithName(NULL, cmdToExecAfterHyperJump,
2306                   &obj_ptr);
2307             if (exec_attr == NULL) {
2308                sprintf(gszMsgBox, TgLoadString(STID_CANT_FIND_NAMED_ATTR_EXEC),
2309                      cmdToExecAfterHyperJump, "hyperjump_then_exec");
2310                MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2311                ResetExec(FALSE);
2312                return;
2313             }
2314             continue;
2315          }
2316       }
2317       if (exec_rc==TRUE && execNavigateBack) {
2318          NavigateBack();
2319       }
2320       ResetExec(FALSE);
2321       return;
2322    }
2323    TwoLineMsg(TgLoadCachedString(CSTID_CANT_FIND_INTERPRETABLE_ATTR),
2324          TgLoadCachedString(CSTID_NO_ACTION_TAKEN));
2325    ResetExec(FALSE);
2326 }
2327 
Teleport(button_ev)2328 void Teleport(button_ev)
2329    XButtonEvent *button_ev;
2330 {
2331    struct AttrRec *teleport_attr, *launch_attr, *exec_attr;
2332    struct ObjRec *obj_ptr, *owner_obj;
2333    char buf[MAXSTRING+1];
2334    int len;
2335 
2336    if ((obj_ptr=FindAnObj(button_ev->x,button_ev->y,&owner_obj,NULL,NULL)) ==
2337          NULL) {
2338       if (inSlideShow) {
2339          NextSlide();
2340       }
2341       return;
2342    }
2343    if (owner_obj != NULL) obj_ptr = owner_obj;
2344 
2345    teleport_attr = FindAttrWithName(obj_ptr, TELEPORT_ATTR, NULL);
2346    if (teleport_attr != NULL) {
2347       if (DoTeleport(teleport_attr)) {
2348          if ((exec_attr=FindFileAttrWithName("auto_exec=")) != NULL) {
2349             DoExecLoop(NULL, exec_attr);
2350          }
2351       }
2352       return;
2353    }
2354    teleport_attr = FindAttrWithName(obj_ptr, "href=", NULL);
2355    if (teleport_attr != NULL && *teleport_attr->attr_value.s != '\0') {
2356       if (DoTeleport(teleport_attr)) {
2357          if ((exec_attr=FindFileAttrWithName("auto_exec=")) != NULL) {
2358             DoExecLoop(NULL, exec_attr);
2359          }
2360       }
2361       return;
2362    }
2363    strcpy(buf, TELEPORT_ATTR);
2364    len = strlen(buf);
2365    if (buf[len-1] == '=') {
2366       sprintf(&buf[len-1], "_page#=");
2367       teleport_attr = FindAttrWithName(obj_ptr, buf, NULL);
2368       if (teleport_attr != NULL && *teleport_attr->attr_value.s != '\0') {
2369          DoPageTeleport(teleport_attr, DO_PAGE_BY_NUM);
2370          return;
2371       }
2372       sprintf(&buf[len-1], "_page=");
2373       teleport_attr = FindAttrWithName(obj_ptr, buf, NULL);
2374       if (teleport_attr != NULL && *teleport_attr->attr_value.s != '\0') {
2375          DoPageTeleport(teleport_attr, DO_PAGE_BY_NAME);
2376          return;
2377       }
2378    }
2379    launch_attr = FindAttrWithName(obj_ptr, LAUNCH_ATTR, NULL);
2380    if (launch_attr != NULL) {
2381       DoLaunch(launch_attr, obj_ptr);
2382       return;
2383    }
2384    exec_attr = FindAttrWithName(obj_ptr, EXEC_ATTR, NULL);
2385    if (exec_attr == NULL && inSlideShow) {
2386       NextSlide();
2387       return;
2388    }
2389    DoExecLoop(obj_ptr, exec_attr);
2390 }
2391 
SelAllObj(high_light,ignore_slideshow)2392 void SelAllObj(high_light, ignore_slideshow)
2393    int high_light, ignore_slideshow;
2394 {
2395    struct ObjRec *obj_ptr=NULL;
2396 
2397    TieLooseEnds();
2398    SetCurChoice(NOTHING);
2399    if (topSel != NULL) {
2400       HighLightReverse();
2401       RemoveAllSel();
2402    }
2403    if (inSlideShow && !ignore_slideshow) {
2404       SetCurChoice(curChoiceBeforeMakeQuiescent);
2405       return;
2406    }
2407    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
2408       obj_ptr->tmp_parent = NULL;
2409       if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
2410          continue;
2411       }
2412       AddObjIntoSel(obj_ptr, NULL, topSel, &topSel, &botSel);
2413    }
2414    UpdSelBBox();
2415    if (high_light) HighLightForward();
2416    justDupped = FALSE;
2417 }
2418 
2419 static struct ObjRec	*tmpTopObj=NULL, *tmpBotObj=NULL;
2420 
2421 static
PushTmpObj(ObjPtr)2422 void PushTmpObj(ObjPtr)
2423    struct ObjRec *ObjPtr;
2424 {
2425    ObjPtr->next = tmpTopObj;
2426    ObjPtr->prev = NULL;
2427 
2428    if (tmpBotObj == NULL) {
2429       tmpBotObj = ObjPtr;
2430    } else {
2431       tmpTopObj->prev = ObjPtr;
2432    }
2433    tmpTopObj = ObjPtr;
2434 }
2435 
2436 static
BreakSel()2437 void BreakSel()
2438    /* break off selected objects from the main stream objects           */
2439    /* when returns, tmpTopObj points to the top of the selected objects */
2440    /*    and tmpBotObj points to the bottom of the selected objects     */
2441 {
2442    struct SelRec *sel_ptr=NULL;
2443 
2444    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2445       UnlinkObj(sel_ptr->obj);
2446       PushTmpObj(sel_ptr->obj);
2447    }
2448 }
2449 
JustMoveSelToTop()2450 void JustMoveSelToTop()
2451 {
2452    if (topSel == NULL) return;
2453 
2454    tmpTopObj = tmpBotObj = NULL;
2455 
2456    BreakSel();
2457    tmpBotObj->next = topObj;
2458    if (topObj == NULL) {
2459       curPage->bot = botObj = tmpBotObj;
2460    } else {
2461       topObj->prev = tmpBotObj;
2462    }
2463    curPage->top = topObj = tmpTopObj;
2464 }
2465 
MoveSelToTop()2466 void MoveSelToTop()
2467 {
2468    if (topSel == NULL) {
2469       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2470       return;
2471    }
2472    PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
2473    JustMoveSelToTop();
2474    RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
2475 }
2476 
MoveSelToBot()2477 void MoveSelToBot()
2478 {
2479    if (topSel == NULL) {
2480       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2481       return;
2482    }
2483    PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
2484    tmpTopObj = tmpBotObj = NULL;
2485 
2486    BreakSel();
2487    tmpTopObj->prev = botObj;
2488    if (topObj == NULL) {
2489       curPage->top = topObj = tmpTopObj;
2490    } else {
2491       botObj->next = tmpTopObj;
2492    }
2493    curPage->bot = botObj = tmpBotObj;
2494    RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
2495 }
2496 
2497 static
DeleteObjectInsteadOfVertex(obj_ptr)2498 void DeleteObjectInsteadOfVertex(obj_ptr)
2499    struct ObjRec *obj_ptr;
2500 {
2501    struct SelRec *sel_ptr=NULL, *saved_top_sel=NULL, *saved_bot_sel=NULL;
2502 
2503    for (sel_ptr=botSel; sel_ptr!=NULL; sel_ptr=sel_ptr->prev) {
2504       if (sel_ptr->obj == obj_ptr) {
2505          break;
2506       }
2507    }
2508    if (sel_ptr->prev == NULL) {
2509       topSel = sel_ptr->next;
2510    } else {
2511       sel_ptr->prev->next = sel_ptr->next;
2512    }
2513    if (sel_ptr->next == NULL) {
2514       botSel = sel_ptr->prev;
2515    } else {
2516       sel_ptr->next->prev = sel_ptr->prev;
2517    }
2518    saved_top_sel = topSel;
2519    saved_bot_sel = botSel;
2520    topSel = botSel = sel_ptr;
2521    sel_ptr->next = sel_ptr->prev = NULL;
2522    DelObj(obj_ptr);
2523    topSel = saved_top_sel;
2524    botSel = saved_bot_sel;
2525 
2526    free(sel_ptr);
2527    ChangeReplaceOneCmdToDeleteCmd();
2528 }
2529 
DelAllSelObj()2530 void DelAllSelObj()
2531 {
2532    struct ObjRec *obj_ptr=NULL;
2533    struct SelRec *sel_ptr=NULL;
2534    int j, i;
2535    struct VSelRec *vsel_ptr=NULL;
2536    IntPoint *vlist=NULL;
2537    struct PolyRec *poly_ptr=NULL;
2538    struct PolygonRec *polygon_ptr=NULL;
2539    int n=0;
2540    short *mark=NULL;
2541 
2542    if (topSel==NULL && topVSel==NULL) {
2543       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2544       return;
2545    }
2546    HighLightReverse();
2547    if (curChoice == VERTEXMODE) {
2548       StartCompositeCmd();
2549       for (vsel_ptr=botVSel; vsel_ptr!=NULL; vsel_ptr=vsel_ptr->prev) {
2550          int delete_it=FALSE, extra_vertex=FALSE, curved=(-1), ssn=0;
2551          char *smooth=NULL, *ssmooth=NULL;
2552          IntPoint *ssvlist=NULL;
2553 
2554          obj_ptr = vsel_ptr->obj;
2555 
2556          switch (obj_ptr->type) {
2557          case OBJ_POLY:
2558             poly_ptr = obj_ptr->detail.p;
2559             curved = poly_ptr->curved;
2560             if (curved == LT_STRUCT_SPLINE) {
2561                ssvlist = poly_ptr->ssvlist;
2562                ssn = poly_ptr->ssn;
2563                ssmooth = poly_ptr->ssmooth;
2564             } else {
2565                vlist = poly_ptr->vlist;
2566                n = poly_ptr->n;
2567                smooth = poly_ptr->smooth;
2568             }
2569             if (vsel_ptr->n >= n-1) delete_it = TRUE;
2570             break;
2571          case OBJ_POLYGON:
2572             polygon_ptr = obj_ptr->detail.g;
2573             curved = polygon_ptr->curved;
2574             if (curved == LT_STRUCT_SPLINE) {
2575                ssvlist = polygon_ptr->ssvlist;
2576                ssn = polygon_ptr->ssn;
2577                ssmooth = polygon_ptr->ssmooth;
2578             } else {
2579                vlist = polygon_ptr->vlist;
2580                n = polygon_ptr->n;
2581                smooth = polygon_ptr->smooth;
2582             }
2583             for (j=0; j < vsel_ptr->n; j++) {
2584                if (vsel_ptr->v_index[j] == 0) {
2585                   extra_vertex = TRUE;
2586                   break;
2587                }
2588             }
2589             if ((!extra_vertex && n-vsel_ptr->n <= 3) ||
2590                   (extra_vertex && n-vsel_ptr->n <= 2)) {
2591                delete_it = TRUE;
2592             }
2593             break;
2594          }
2595          if (curved == LT_STRUCT_SPLINE) {
2596             PrepareToReplaceAnObj(obj_ptr);
2597             if (DeleteStructuredSplinePoint(vsel_ptr->v_index[0], poly_ptr,
2598                   polygon_ptr)) {
2599                AdjObjSplineVs(obj_ptr);
2600                if (poly_ptr != NULL) {
2601                   UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
2602                } else if (polygon_ptr != NULL) {
2603                   UpdPolyBBox(obj_ptr, polygon_ptr->n,
2604                         polygon_ptr->vlist);
2605                }
2606                AdjObjBBox(obj_ptr);
2607                RecordReplaceAnObj(obj_ptr);
2608             } else {
2609                /* delete the object */
2610                DeleteObjectInsteadOfVertex(obj_ptr);
2611             }
2612          } else {
2613             PrepareToReplaceAnObj(obj_ptr);
2614             if (delete_it) {
2615                /* delete the object */
2616                DeleteObjectInsteadOfVertex(obj_ptr);
2617             } else {
2618                mark = (short *)malloc(n*sizeof(short));
2619                if (mark == NULL) FailAllocMessage();
2620                for (j=0; j < n; j++) mark[j] = FALSE;
2621                for (j=0; j < vsel_ptr->n; j++) {
2622                   mark[vsel_ptr->v_index[j]] = TRUE;
2623                }
2624                switch (obj_ptr->type) {
2625                case OBJ_POLY:
2626                   for (i=n-1; i >= 0; i--) {
2627                      if (mark[i]) {
2628                         for (j=i+1; j < n; j++) {
2629                            vlist[j-1] = vlist[j];
2630                            if (smooth != NULL) smooth[j-1] = smooth[j];
2631                         }
2632                         if (smooth != NULL) {
2633                            if (i == 0) {
2634                               smooth[0] = FALSE;
2635                            } else if (i == n-1) {
2636                               smooth[n-2] = FALSE;
2637                            }
2638                         }
2639                         n--;
2640                      }
2641                   }
2642                   poly_ptr->n -= vsel_ptr->n;
2643                   AdjObjSplineVs(obj_ptr);
2644                   if (poly_ptr->curved != LT_INTSPLINE) {
2645                      UpdPolyBBox(obj_ptr, poly_ptr->n, poly_ptr->vlist);
2646                   } else {
2647                      UpdPolyBBox(obj_ptr, poly_ptr->intn, poly_ptr->intvlist);
2648                   }
2649                   break;
2650                case OBJ_POLYGON:
2651                   for (i=n-2; i >= 0; i--) {
2652                      if (mark[i]) {
2653                         for (j=i+1; j < n; j++) {
2654                            vlist[j-1] = vlist[j];
2655                            if (smooth != NULL) smooth[j-1] = smooth[j];
2656                         }
2657                         n--;
2658                         if (smooth != NULL && i == 0) {
2659                            smooth[n-1] = smooth[0];
2660                         }
2661                      }
2662                   }
2663                   polygon_ptr->n -= vsel_ptr->n;
2664                   if (extra_vertex) vlist[polygon_ptr->n++] = vlist[0];
2665                   AdjObjSplineVs(obj_ptr);
2666                   if (polygon_ptr->curved != LT_INTSPLINE) {
2667                      UpdPolyBBox(obj_ptr, polygon_ptr->n, polygon_ptr->vlist);
2668                   } else {
2669                      UpdPolyBBox(obj_ptr, polygon_ptr->intn,
2670                            polygon_ptr->intvlist);
2671                   }
2672                   break;
2673                }
2674                free(mark);
2675                AdjObjBBox(obj_ptr);
2676                RecordReplaceAnObj(obj_ptr);
2677             }
2678          }
2679       }
2680       EndCompositeCmd();
2681       JustRemoveAllVSel();
2682    } else {
2683       struct SelRec *first_extra_poly_sel=NULL, *last_extra_poly_sel=NULL;
2684       struct BBRec extra_bbox;
2685       int extra_poly_count=0, delete_extra_poly=FALSE;
2686 
2687       delete_extra_poly = FindExtraPoly(topSel, botSel,
2688             &first_extra_poly_sel, &last_extra_poly_sel, &extra_poly_count,
2689             &extra_bbox);
2690       StartCompositeCmd();
2691       PrepareToRecord(CMD_DELETE, topSel, botSel, numObjSelected);
2692       for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2693          UnlinkObj(sel_ptr->obj);
2694          FreeObj(sel_ptr->obj);
2695       }
2696       RemoveAllSel();
2697       RecordCmd(CMD_DELETE, NULL, NULL, NULL, 0);
2698       if (delete_extra_poly) {
2699          /*
2700           * Please note that FindExtraPoly() returns the poly in the
2701           *	correct stacking order!
2702           */
2703          PrepareToRecord(CMD_DELETE, first_extra_poly_sel, last_extra_poly_sel,
2704                extra_poly_count);
2705          for (sel_ptr=last_extra_poly_sel; sel_ptr != NULL;
2706                sel_ptr=sel_ptr->prev) {
2707             UnlinkObj(sel_ptr->obj);
2708             FreeObj(sel_ptr->obj);
2709          }
2710          JustFreeSel(first_extra_poly_sel, last_extra_poly_sel);
2711          RecordCmd(CMD_DELETE, NULL, NULL, NULL, 0);
2712 
2713          ExpandExtents(&extra_bbox, &selLtX, &selLtY, &selRbX, &selRbY);
2714       }
2715       EndCompositeCmd();
2716    }
2717    RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2718          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2719    HighLightForward();
2720    SetFileModified(TRUE);
2721    justDupped = FALSE;
2722 }
2723 
GroupSingleObj(ForcePromoteAttrs)2724 void GroupSingleObj(ForcePromoteAttrs)
2725    int ForcePromoteAttrs;
2726 {
2727    tmpTopObj = tmpBotObj = NULL;
2728 
2729    BreakSel();
2730    CreateGroupObj(tmpTopObj, tmpBotObj);
2731    RemoveAllSel();
2732    if (tmpTopObj == tmpBotObj && tmpTopObj->fattr != NULL &&
2733          (ForcePromoteAttrs ||
2734          !(tmpTopObj->type == OBJ_GROUP || tmpTopObj->type == OBJ_SYM ||
2735          tmpTopObj->type == OBJ_ICON || tmpTopObj->type == OBJ_PIN))) {
2736       struct AttrRec *attr_ptr;
2737 
2738       topObj->fattr = tmpTopObj->fattr;
2739       topObj->lattr = tmpTopObj->lattr;
2740       tmpTopObj->fattr = tmpTopObj->lattr = NULL;
2741       for (attr_ptr=topObj->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
2742          attr_ptr->owner = topObj;
2743       }
2744    }
2745    topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
2746    if (topSel == NULL) FailAllocMessage();
2747    topSel->obj = topObj;
2748    topSel->next = topSel->prev = NULL;
2749    numObjSelected = 1;
2750 }
2751 
GroupSelObj(highlight,record_cmd,redraw)2752 void GroupSelObj(highlight, record_cmd, redraw)
2753    int highlight, record_cmd, redraw;
2754 {
2755    if (topSel == NULL) {
2756       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2757       return;
2758    }
2759    if (curChoice==VERTEXMODE && topSel!=NULL) {
2760       MsgBox(TgLoadString(STID_CANT_GROUP_IN_VERTEX_MODE), TOOL_NAME, INFO_MB);
2761       return;
2762    }
2763    if (topSel == botSel && topSel->obj->type != OBJ_POLY &&
2764          topSel->obj->type != OBJ_POLYGON) {
2765       MsgBox(TgLoadString(STID_CANT_GROUP_SINGLE_OBJECT), TOOL_NAME, INFO_MB);
2766       return;
2767    }
2768 
2769    tmpTopObj = tmpBotObj = NULL;
2770 
2771    if (highlight) HighLightReverse();
2772    if (record_cmd) PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
2773    BreakSel();
2774 
2775    CreateGroupObj(tmpTopObj, tmpBotObj);
2776 
2777    RemoveAllSel();
2778    topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
2779    if (topSel == NULL) FailAllocMessage();
2780    topSel->obj = topObj;
2781    topSel->next = topSel->prev = NULL;
2782    UpdSelBBox();
2783 
2784    if (record_cmd) RecordCmd(CMD_MANY_TO_ONE, NULL, topSel, botSel, 1);
2785    if (redraw) {
2786       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2787             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2788    }
2789    if (highlight) HighLightForward();
2790    SetFileModified(TRUE);
2791    justDupped = FALSE;
2792 }
2793 
SelectTopObj()2794 void SelectTopObj()
2795 {
2796    if (topObj == NULL) return;
2797 
2798    topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
2799    if (topSel == NULL) FailAllocMessage();
2800    topSel->obj = topObj;
2801    topSel->next = topSel->prev = NULL;
2802    UpdSelBBox();
2803 
2804    HighLightForward();
2805    justDupped = FALSE;
2806 }
2807