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/pattern.c,v 1.26 2011/05/16 16:21:58 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_PATTERN_C_
22 
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25 
26 #include "arc.e"
27 #include "choice.e"
28 #include "color.e"
29 #include "cmd.e"
30 #include "cutpaste.e"
31 #include "dialog.e"
32 #include "drawing.e"
33 #include "file.e"
34 #include "font.e"
35 #include "mainmenu.e"
36 #include "mark.e"
37 #include "menu.e"
38 #include "menuinfo.e"
39 #include "miniline.e"
40 #include "msg.e"
41 #include "navigate.e"
42 #include "obj.e"
43 #include "pattern.e"
44 #include "poly.e"
45 #include "raster.e"
46 #include "select.e"
47 #include "setup.e"
48 #include "spline.e"
49 #include "strtbl.e"
50 #include "text.e"
51 #include "util.e"
52 
53 int     objFill=NONEPAT;
54 int     transPat=FALSE;
55 int     lineStyle=LS_RIGHT;
56 int     lineWidth=0;
57 int     penPat=SOLIDPAT;
58 int     curSpline=LT_STRAIGHT;
59 int     curDash=0;
60 int     rcbRadius=DEF_RCB_RADIUS;
61 int     useGray=FALSE;
62 char    patternStr[]="8 1 0 72 300 32 div div tgifsetpattern";
63 
64 int	stickyMenuSelection=FALSE;
65 
66 static int	tileAsGrayDetected=FALSE;
67 static int	canFakeGray=FALSE;
68 static char	*grayStr[9] =
69 {
70    "0.995", "0.94", "0.868", "0.779", "0.763", "0.55", "0.41", "0.253", "0.079"
71 };
72 
ResetGrayDetection()73 void ResetGrayDetection()
74 {
75    tileAsGrayDetected = FALSE;
76    canFakeGray = FALSE;
77 }
78 
GrayStr(index)79 char *GrayStr(index)
80    int index;
81    /* this routine should only be called when useGray == TRUE */
82 {
83    if (index <= 2) {
84       fprintf(stderr, "%s\n",
85             TgLoadCachedString(CSTID_GRAYSTR_CALLED_WITH_IDX_2));
86       return("");
87    } else if (index >= 12) {
88       if (!tileAsGrayDetected) {
89          char buf[MAXSTRING];
90 
91          tileAsGrayDetected = TRUE;
92          strcpy(buf, TgLoadCachedString(CSTID_GRAY_SCALE_USED_FOR_PAT));
93          if (PRTGIF) {
94             fprintf(stderr, "%s.\n", buf);
95          } else {
96             MsgBox(buf, TOOL_NAME, INFO_MB);
97          }
98       }
99       switch (index) {
100       case 12: index = 5; break;
101       case 13: index = 4; break;
102       case 14: index = 7; break;
103       case 15: index = 6; break;
104       case 16: index = 7; break;
105       case 17: index = 6; break;
106       case 18: index = 6; break;
107       case 19: index = 6; break;
108       case 20: index = 5; break;
109       case 21: index = 6; break;
110       case 22: index = 8; break;
111       case 23: index = 7; break;
112       case 24: index = 9; break;
113       case 25: index = 8; break;
114       case 26: index = 5; break;
115       case 27: index = 6; break;
116       case 28: index = 8; break;
117       case 29: index = 7; break;
118       case 30: index = 9; break;
119       case 31: index = 8; break;
120       }
121    }
122    return (grayStr[index-3]);
123 }
124 
GrayCheck(index)125 void GrayCheck(index)
126    int index;
127    /* this routine should only be called when useGray == FALSE */
128 {
129    if (index > BACKPAT) {
130       if (index >= 12) {
131          tileAsGrayDetected = TRUE;
132       } else {
133          canFakeGray = TRUE;
134       }
135    }
136 }
137 
EndGrayDetection()138 void EndGrayDetection()
139    /* this routine should only be called when useGray == FALSE */
140 {
141    int num_msgs = 1;
142    char msg1[MAXSTRING], msg2[MAXSTRING];
143 
144    if (colorDump) return;
145 
146    if (useGray) {
147       if (!tileAsGrayDetected && !canFakeGray) return;
148 
149       strcpy(msg1, TgLoadString(STID_GRAY_SCALE_USED_IN_PRINT_PAT));
150    } else if (tileAsGrayDetected) {
151       strcpy(msg1, TgLoadString(STID_NOTE_SLOW_PRINT_DUE_USE_PAT));
152    } else if (canFakeGray) {
153       num_msgs = 2;
154       strcpy(msg1, TgLoadString(STID_NOTE_SLOW_PRINT_DUE_USE_PAT));
155       sprintf(msg2, "      %s",
156             TgLoadString(STID_SUGGEST_USEGRAYSCALE_TO_SPEED));
157    } else {
158       return;
159    }
160    if (PRTGIF) {
161       fprintf(stderr, "%s.\n", msg1);
162       if (num_msgs==2) fprintf(stderr, "%s.\n", msg2);
163    } else {
164       if (num_msgs==1) {
165          Msg(msg1);
166       } else {
167          TwoLineMsg(msg1, msg2);
168       }
169    }
170 }
171 
RefreshModeMenu(menu)172 int RefreshModeMenu(menu)
173    TgMenu *menu;
174 {
175    int i, num_items=menu->num_items, rc=TRUE;
176    TgMenuItem *menuitems=menu->menuitems;
177 
178    for (i=0; i < num_items; i++) {
179       TgMenuItem *menu_item=(&menuitems[i]);
180       TgMenuItem stMenuItem;
181 
182       memset(&stMenuItem, 0, sizeof(TgMenuItem));
183       stMenuItem.state = TGBS_NORMAL;
184       stMenuItem.checked = (i == curChoice);
185       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
186             &stMenuItem)) {
187          rc = FALSE;
188       }
189    }
190    if (inSlideShow && !goHyperSpaceInSlideShow) {
191       TgEnableMenuItemByIndex(menu, NOTHING, FALSE);
192       TgEnableMenuItemByIndex(menu, VERTEXMODE, FALSE);
193       TgEnableMenuItemByIndex(menu, ROTATEMODE, FALSE);
194    }
195    return rc;
196 }
197 
CreateModeMenu(parent_menu,x,y,menu_info,status_str_xlated)198 TgMenu *CreateModeMenu(parent_menu, x, y, menu_info, status_str_xlated)
199    TgMenu *parent_menu;
200    int x, y;
201    TgMenuInfo *menu_info;
202    int status_str_xlated; /* ignored, always 0 */
203 {
204    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
205 
206    if (menu != NULL) {
207       TgMenuItem *menu_item=NULL;
208       TgMenuItem stMenuItem;
209 
210       menu->track_menubar = FALSE;
211       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, MAXCHOICES);
212       menu_item = (&menu->menuitems[curChoice]);
213 
214       memset(&stMenuItem, 0, sizeof(TgMenuItem));
215       stMenuItem.checked = TRUE;
216       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
217          return TgDestroyMenu(menu, TRUE);
218       }
219       if (!RefreshModeMenu(menu)) {
220          return TgDestroyMenu(menu, TRUE);
221       }
222       menu->refresh_proc = ((RefreshMenuFunc*)RefreshModeMenu);
223    }
224    return menu;
225 }
226 
ModeMenu(X,Y,TrackMenubar)227 int ModeMenu(X, Y, TrackMenubar)
228    int X, Y, TrackMenubar;
229 {
230    int rc=INVALID;
231    TgMenu *menu=(modeMenuInfo.create_proc)(NULL, X, Y, &modeMenuInfo, INVALID);
232 
233    activeMenu = MENU_MODE;
234    if (menu != NULL) {
235       menu->track_menubar = TrackMenubar;
236 
237       rc = TgMenuLoop(menu);
238       TgDestroyMenu(menu, TRUE);
239    }
240    return rc;
241 }
242 
243 /* ------------------ TransPat Functions ------------------ */
244 
ChangeObjTransPat(ObjPtr,TransPat)245 int ChangeObjTransPat(ObjPtr, TransPat)
246    struct ObjRec *ObjPtr;
247    int TransPat;
248 {
249    if (ObjPtr->trans_pat != TransPat) {
250       ObjPtr->trans_pat = TransPat;
251       return TRUE;
252    }
253    return FALSE;
254 }
255 
ChangeAllSelTransPat(TransPat,HighLight)256 void ChangeAllSelTransPat(TransPat, HighLight)
257    int TransPat, HighLight;
258 {
259    struct SelRec *sel_ptr=NULL;
260    int changed=FALSE, ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
261 
262    if (topSel == NULL || stickyMenuSelection) {
263       if (!(curChoice == DRAWTEXT && textCursorShown)) {
264          TieLooseEnds();
265       }
266       transPat = TransPat;
267       if (curChoice == DRAWTEXT && textCursorShown) {
268          if (ChangeObjTransPat(curTextObj, TransPat)) {
269             curTextModified = TRUE;
270             UpdCurTextBBox();
271             RedrawCurText();
272             SetFileModified(TRUE);
273             if (cycleThroughChoice) {
274                SetPushedFontValue(PUSH_TRANSPAT, transPat);
275             }
276          }
277       } else {
278          textCursorShown = FALSE;
279       }
280       if (topSel == NULL) {
281          switch (transPat) {
282          case NO_TRANSPAT_MODE:
283             Msg(TgLoadString(STID_FILL_PEN_PAT_OPAQUE));
284             break;
285          case TRANSPAT_MODE:
286             Msg(TgLoadString(STID_FILL_PEN_PAT_TRANSPARENT));
287             break;
288          }
289       }
290       ShowTransPatMode();
291       UpdatePinnedMenu(MENU_TRANSPAT);
292       if (topSel == NULL) return;
293    }
294 
295    if (HighLight) HighLightReverse();
296    StartCompositeCmd();
297    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
298       PrepareToReplaceAnObj(sel_ptr->obj);
299       if (ChangeObjTransPat(sel_ptr->obj, TransPat)) {
300          changed = TRUE;
301          RecordReplaceAnObj(sel_ptr->obj);
302       } else {
303          AbortPrepareCmd(CMD_REPLACE);
304       }
305    }
306    EndCompositeCmd();
307 
308    if (changed) {
309       SetFileModified(TRUE);
310       UpdSelBBox();
311       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
312             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1),
313             selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
314             selRbY+GRID_ABS_SIZE(1));
315    }
316    if (HighLight) HighLightForward();
317 }
318 
319 /* ------------------ Fill Functions ------------------ */
320 
ChangeObjFill(ObjPtr,FillIndex)321 int ChangeObjFill(ObjPtr, FillIndex)
322    struct ObjRec *ObjPtr;
323    int FillIndex;
324 {
325    register struct ObjRec *obj_ptr;
326    int changed=FALSE;
327 
328    switch (ObjPtr->type) {
329    case OBJ_TEXT:
330       if (ObjPtr->detail.t->fill != FillIndex) {
331          ObjPtr->detail.t->fill = FillIndex;
332          changed = TRUE;
333       }
334       break;
335    case OBJ_BOX:
336       if (ObjPtr->detail.b->fill != FillIndex) {
337          ObjPtr->detail.b->fill = FillIndex;
338          changed = TRUE;
339       }
340       break;
341    case OBJ_OVAL:
342       if (ObjPtr->detail.o->fill != FillIndex) {
343          ObjPtr->detail.o->fill = FillIndex;
344          changed = TRUE;
345       }
346       break;
347    case OBJ_POLY:
348       if (ObjPtr->detail.p->fill != FillIndex) {
349          ObjPtr->detail.p->fill = FillIndex;
350          changed = TRUE;
351       }
352       break;
353    case OBJ_POLYGON:
354       if (ObjPtr->detail.g->fill != FillIndex) {
355          ObjPtr->detail.g->fill = FillIndex;
356          changed = TRUE;
357       }
358       break;
359    case OBJ_ARC:
360       if (ObjPtr->detail.a->fill != FillIndex) {
361          if (ObjPtr->detail.a->fill == NONEPAT || FillIndex == NONEPAT) {
362             ObjPtr->detail.a->fill = FillIndex;
363             AdjObjBBox(ObjPtr);
364          } else {
365             ObjPtr->detail.a->fill = FillIndex;
366          }
367          changed = TRUE;
368       }
369       break;
370    case OBJ_RCBOX:
371       if (ObjPtr->detail.rcb->fill != FillIndex) {
372          ObjPtr->detail.rcb->fill = FillIndex;
373          changed = TRUE;
374       }
375       break;
376    case OBJ_XBM:
377       if (ObjPtr->detail.xbm->fill != FillIndex) {
378          ObjPtr->detail.xbm->fill = FillIndex;
379          changed = TRUE;
380       }
381       break;
382    case OBJ_XPM:
383       if (ObjPtr->detail.xpm->fill != FillIndex) {
384          ObjPtr->detail.xpm->fill = FillIndex;
385          changed = TRUE;
386       }
387       break;
388 
389    case OBJ_SYM:
390    case OBJ_GROUP:
391       for (obj_ptr = ObjPtr->detail.r->last; obj_ptr != NULL;
392             obj_ptr = obj_ptr->prev) {
393          if (ChangeObjFill(obj_ptr, FillIndex)) {
394             changed = TRUE;
395          }
396       }
397       break;
398    }
399    if (changePropertiesOfAttrs && ObjPtr->type != OBJ_TEXT) {
400       struct AttrRec *attr_ptr=ObjPtr->fattr;
401 
402       for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
403          changed |= ChangeObjFill(attr_ptr->obj, FillIndex);
404       }
405    }
406    return changed;
407 }
408 
ChangeAllSelFill(FillIndex,HighLight)409 void ChangeAllSelFill(FillIndex, HighLight)
410    int FillIndex, HighLight;
411 {
412    register struct SelRec *sel_ptr;
413    int changed=FALSE, ltx, lty, rbx, rby;
414 
415    if (topSel == NULL || stickyMenuSelection) {
416       if (!(curChoice == DRAWTEXT && textCursorShown)) {
417          TieLooseEnds();
418       }
419       objFill = FillIndex;
420       if (curChoice == DRAWTEXT && textCursorShown) {
421          if (ChangeObjFill(curTextObj, FillIndex)) {
422             curTextModified = TRUE;
423             UpdCurTextBBox();
424             RedrawCurText();
425             SetFileModified(TRUE);
426             if (cycleThroughChoice) {
427                SetPushedFontValue(PUSH_FILL, objFill);
428             }
429          }
430       } else {
431          textCursorShown = FALSE;
432       }
433       ShowFill();
434       UpdatePinnedMenu(MENU_FILL);
435       if (topSel == NULL) return;
436    }
437 
438    if (HighLight) HighLightReverse();
439    StartCompositeCmd();
440    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
441       PrepareToReplaceAnObj(sel_ptr->obj);
442       if (ChangeObjFill(sel_ptr->obj, FillIndex)) {
443          changed = TRUE;
444          RecordReplaceAnObj(sel_ptr->obj);
445       } else {
446          AbortPrepareCmd(CMD_REPLACE);
447       }
448    }
449    EndCompositeCmd();
450 
451    if (changed) {
452       SetFileModified(TRUE);
453       ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
454       UpdSelBBox();
455       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
456             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1),
457             selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
458             selRbY+GRID_ABS_SIZE(1));
459    }
460    if (HighLight) HighLightForward();
461 }
462 
RefreshFillMenu(menu)463 void RefreshFillMenu(menu)
464    TgMenu *menu;
465 {
466    int i, num_items=menu->num_items;
467    TgMenuItem *menuitems=menu->menuitems;
468 
469    for (i=0; i < num_items; i++) {
470       TgMenuItem *menu_item=(&menuitems[i]);
471       TgMenuItem stMenuItem;
472 
473       memset(&stMenuItem, 0, sizeof(TgMenuItem));
474       stMenuItem.state = TGBS_NORMAL;
475       stMenuItem.checked = (i == objFill);
476       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
477             &stMenuItem);
478    }
479 }
480 
CreateFillMenu(parent_menu,x,y,menu_info,status_str_xlated)481 TgMenu *CreateFillMenu(parent_menu, x, y, menu_info, status_str_xlated)
482    TgMenu *parent_menu;
483    int x, y;
484    TgMenuInfo *menu_info;
485    int status_str_xlated; /* ignored, always 0 */
486 {
487    int i=0;
488    TgMenu *menu=NULL;
489    TgMenuInfo stMenuInfo;
490    TgMenuItemInfo *item_info=NULL;
491 
492    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
493    stMenuInfo.items = (TgMenuItemInfo*)malloc(
494          (MAXPATTERNS+1)*sizeof(TgMenuItemInfo));
495    if (stMenuInfo.items == NULL) FailAllocMessage();
496    memset(stMenuInfo.items, 0, (MAXPATTERNS+1)*sizeof(TgMenuItemInfo));
497    for (item_info=stMenuInfo.items, i=0; i < MAXPATTERNS; item_info++, i++) {
498       item_info->menu_str = (char*)(Pixmap*)(&patPixmap[i]);
499       item_info->shortcut_str = NULL;
500       switch (i) {
501       case NONEPAT:
502          strcpy(gszMsgBox, TgLoadCachedString(CSTID_SET_FILL_TO_NONE));
503          break;
504       case SOLIDPAT:
505          strcpy(gszMsgBox, TgLoadCachedString(CSTID_SET_FILL_TO_SOLID));
506          break;
507       case BACKPAT:
508          strcpy(gszMsgBox, TgLoadCachedString(CSTID_SET_FILL_TO_BACKGROUND));
509          break;
510       default:
511          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_FILL_TO_PAT_NUMBER),
512                i);
513          break;
514       }
515       item_info->status_str = UtilStrDup(gszMsgBox);
516       if (item_info->status_str == NULL) FailAllocMessage();
517       item_info->submenu_info = NULL;
518       item_info->cmdid = CMDID_CHANGEALLSELFILL;
519    }
520    stMenuInfo.items[MAXPATTERNS].cmdid = INVALID;
521 
522    /* the status_str has been translated in TgLoadCachedString() */
523    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
524    for (item_info=stMenuInfo.items, i=0; i < MAXPATTERNS; item_info++, i++) {
525       UtilFree(item_info->status_str);
526    }
527    memset(stMenuInfo.items, 0, (MAXPATTERNS+1)*sizeof(TgMenuItemInfo));
528    free(stMenuInfo.items);
529    stMenuInfo.items = NULL;
530    if (menu != NULL) {
531       TgMenuItem *menu_item=NULL;
532       TgMenuItem stMenuItem;
533 
534       menu->track_menubar = TRUE;
535       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, 8);
536       menu_item = (&menu->menuitems[objFill]);
537 
538       memset(&stMenuItem, 0, sizeof(TgMenuItem));
539       stMenuItem.checked = TRUE;
540       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
541          return TgDestroyMenu(menu, TRUE);
542       }
543    }
544    return menu;
545 }
546 
FillMenu(X,Y,TrackMenubar)547 int FillMenu(X, Y, TrackMenubar)
548    int X, Y, TrackMenubar;
549 {
550    int rc=INVALID;
551    TgMenu *menu=(fillMenuInfo.create_proc)(NULL, X, Y, &fillMenuInfo, INVALID);
552 
553    activeMenu = MENU_FILL;
554    if (menu != NULL) {
555       menu->track_menubar = TrackMenubar;
556 
557       rc = TgMenuLoop(menu);
558       TgDestroyMenu(menu, TRUE);
559    }
560    return rc;
561 }
562 
563 /* ------------------ LineStyle Functions ------------------ */
564 
565 static
ChangeObjLineStyle(ObjPtr,StyleIndex)566 int ChangeObjLineStyle(ObjPtr, StyleIndex)
567    struct ObjRec *ObjPtr;
568    int StyleIndex;
569 {
570    register struct ObjRec *obj_ptr;
571    register int changed=FALSE;
572 
573    switch (ObjPtr->type) {
574    case OBJ_POLY:
575       if (ObjPtr->detail.p->style != StyleIndex) {
576          ObjPtr->detail.p->style = StyleIndex;
577          changed = TRUE;
578          AdjObjSplineVs(ObjPtr);
579          if (ObjPtr->detail.p->curved != LT_INTSPLINE) {
580             UpdPolyBBox(ObjPtr, ObjPtr->detail.p->n,
581                   ObjPtr->detail.p->vlist);
582          } else {
583             UpdPolyBBox(ObjPtr, ObjPtr->detail.p->intn,
584                   ObjPtr->detail.p->intvlist);
585          }
586       }
587       break;
588    case OBJ_ARC:
589       if (ObjPtr->detail.a->style != StyleIndex) {
590          ObjPtr->detail.a->style = StyleIndex;
591          changed = TRUE;
592          AdjObjSplineVs(ObjPtr);
593       }
594       break;
595    case OBJ_GROUP:
596    case OBJ_SYM:
597       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
598             obj_ptr=obj_ptr->prev) {
599          if (ChangeObjLineStyle(obj_ptr, StyleIndex)) {
600             changed = TRUE;
601          }
602       }
603       break;
604    }
605    if (changed) AdjObjBBox(ObjPtr);
606    return changed;
607 }
608 
ChangeAllSelLineStyle(StyleIndex,HighLight)609 void ChangeAllSelLineStyle(StyleIndex, HighLight)
610    int StyleIndex, HighLight;
611 {
612    register struct SelRec *sel_ptr;
613    int ltx, lty, rbx, rby, changed=FALSE;
614 
615    if (topSel == NULL || stickyMenuSelection) {
616       lineStyle = StyleIndex;
617       ShowLineStyle();
618       UpdatePinnedMenu(MENU_LINESTYLE);
619       if (topSel == NULL) return;
620    }
621 
622    if (HighLight) HighLightReverse();
623    StartCompositeCmd();
624    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
625       PrepareToReplaceAnObj(sel_ptr->obj);
626       if (ChangeObjLineStyle(sel_ptr->obj, StyleIndex)) {
627          changed = TRUE;
628          RecordReplaceAnObj(sel_ptr->obj);
629       } else {
630          AbortPrepareCmd(CMD_REPLACE);
631       }
632    }
633    EndCompositeCmd();
634 
635    if (changed) {
636       SetFileModified(TRUE);
637       ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
638       UpdSelBBox();
639       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
640             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1),
641             selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
642             selRbY+GRID_ABS_SIZE(1));
643    }
644    if (HighLight) HighLightForward();
645 }
646 
RefreshLineStyleMenu(menu)647 void RefreshLineStyleMenu(menu)
648    TgMenu *menu;
649 {
650    int i, num_items=menu->num_items;
651    TgMenuItem *menuitems=menu->menuitems;
652 
653    for (i=0; i < num_items; i++) {
654       TgMenuItem *menu_item=(&menuitems[i]);
655       TgMenuItem stMenuItem;
656 
657       memset(&stMenuItem, 0, sizeof(TgMenuItem));
658       stMenuItem.state = TGBS_NORMAL;
659       stMenuItem.checked = (i == lineStyle);
660       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
661             &stMenuItem);
662    }
663 }
664 
CreateLineStyleMenu(parent_menu,x,y,menu_info,status_str_xlated)665 TgMenu *CreateLineStyleMenu(parent_menu, x, y, menu_info, status_str_xlated)
666    TgMenu *parent_menu;
667    int x, y;
668    TgMenuInfo *menu_info;
669    int status_str_xlated; /* ignored, always 0 */
670 {
671    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
672 
673    if (menu != NULL) {
674       TgMenuItem *menu_item=NULL;
675       TgMenuItem stMenuItem;
676 
677       menu->track_menubar = TRUE;
678       TgAdjustMenuGeometry(menu, menuImageW, menuImageH, MAXLINESTYLES);
679       menu_item = (&menu->menuitems[lineStyle]);
680 
681       memset(&stMenuItem, 0, sizeof(TgMenuItem));
682       stMenuItem.checked = TRUE;
683       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
684          return TgDestroyMenu(menu, TRUE);
685       }
686    }
687    return menu;
688 }
689 
LineStyleMenu(X,Y,TrackMenubar)690 int LineStyleMenu(X, Y, TrackMenubar)
691    int X, Y, TrackMenubar;
692 {
693    int rc=INVALID;
694    TgMenu *menu=(lineStyleMenuInfo.create_proc)(NULL, X, Y, &lineStyleMenuInfo,
695          INVALID);
696 
697    activeMenu = MENU_LINESTYLE;
698    if (menu != NULL) {
699       menu->track_menubar = TrackMenubar;
700 
701       rc = TgMenuLoop(menu);
702       TgDestroyMenu(menu, TRUE);
703    }
704    return rc;
705 }
706 
707 /* ------------------ LineType Functions ------------------ */
708 
GetPolyOrPolygonControlPoints(obj_ptr,pp_poly,pp_polygon,pn_curved,pn_num_pts,pp_ip,ppsz_smooth)709 int GetPolyOrPolygonControlPoints(obj_ptr, pp_poly, pp_polygon, pn_curved,
710       pn_num_pts, pp_ip, ppsz_smooth)
711    struct ObjRec *obj_ptr;
712    struct PolyRec **pp_poly;
713    struct PolygonRec **pp_polygon;
714    int *pn_curved, *pn_num_pts;
715    IntPoint **pp_ip;
716    char **ppsz_smooth;
717 {
718    struct PolyRec *poly_ptr=NULL;
719    struct PolygonRec *polygon_ptr=NULL;
720 
721    switch (obj_ptr->type) {
722    case OBJ_POLY:
723       poly_ptr = obj_ptr->detail.p;
724       *pn_curved = poly_ptr->curved;
725       if ((*pn_curved) == LT_STRUCT_SPLINE) {
726          *pn_num_pts = poly_ptr->ssn;
727          *pp_ip = poly_ptr->ssvlist;
728          *ppsz_smooth = poly_ptr->ssmooth;
729       } else {
730          *pn_num_pts = poly_ptr->n;
731          *pp_ip = poly_ptr->vlist;
732          *ppsz_smooth = poly_ptr->smooth;
733       }
734       break;
735    case OBJ_POLYGON:
736       polygon_ptr = obj_ptr->detail.g;
737       *pn_curved = polygon_ptr->curved;
738       if ((*pn_curved) == LT_STRUCT_SPLINE) {
739          *pn_num_pts = polygon_ptr->ssn;
740          *pp_ip = polygon_ptr->ssvlist;
741          *ppsz_smooth = polygon_ptr->ssmooth;
742       } else {
743          *pn_num_pts = polygon_ptr->n;
744          *pp_ip = polygon_ptr->vlist;
745          *ppsz_smooth = polygon_ptr->smooth;
746       }
747       break;
748    default: return FALSE;
749    }
750    if (pp_poly != NULL) *pp_poly = poly_ptr;
751    if (pp_polygon != NULL) *pp_polygon = polygon_ptr;
752 
753    return TRUE;
754 }
755 
756 static
CanConvertSplineToStructuredSpline(ObjPtr,pn_hinge_count,vlist_updated)757 int CanConvertSplineToStructuredSpline(ObjPtr, pn_hinge_count, vlist_updated)
758    struct ObjRec *ObjPtr;
759    int *pn_hinge_count;
760    IntPoint *vlist_updated;
761    /*
762     * returns TRUE means that conversion will be made (and something
763     *       will change)
764     */
765 {
766    int i=0, last_hinge_index=0, hinge_count=1, num_ss_pts=0;
767    struct PolyRec *poly_ptr=NULL;
768    int curved=(-1), n=0, earlier_smooth=FALSE;
769    IntPoint *vs=NULL;
770    char *smooth=NULL;
771 
772    if (!GetPolyOrPolygonControlPoints(ObjPtr, &poly_ptr, NULL, &curved, &n, &vs,
773          &smooth)) {
774       return FALSE;
775    }
776    if (vlist_updated != NULL) {
777       num_ss_pts = ((*pn_hinge_count)*3)-2;
778       vlist_updated[0].x = vs[0].x;
779       vlist_updated[0].y = vs[0].y;
780       vlist_updated[num_ss_pts-1].x = vs[n-1].x;
781       vlist_updated[num_ss_pts-1].y = vs[n-1].y;
782    }
783    for (i=1; i < n; i++) {
784       if (smooth == NULL || !smooth[i]) {
785          int idx=0;
786 
787          hinge_count++;
788 
789          switch (i-last_hinge_index) {
790          case 3:
791             if (last_hinge_index == 0) {
792                /* the first point can be anything, so still okay */
793                if (vlist_updated != NULL) {
794                   vlist_updated[1].x = vs[1].x;
795                   vlist_updated[1].y = vs[1].y;
796                }
797             } else if (earlier_smooth) {
798                if ((vs[last_hinge_index].x<<1) ==
799                      (vs[last_hinge_index-1].x+vs[last_hinge_index+1].x) &&
800                      (vs[last_hinge_index].y<<1) ==
801                      (vs[last_hinge_index-1].y+vs[last_hinge_index+1].y)) {
802                   /* still okay */
803                   if (vlist_updated != NULL) {
804                      idx = (hinge_count-2)*3;
805 #ifdef _TGIF_DBG /* debug, do not translate */
806                      TgAssert(
807                            vlist_updated[idx-1].x==vs[last_hinge_index-1].x &&
808                            vlist_updated[idx-1].y==vs[last_hinge_index-1].y &&
809                            vlist_updated[idx].x==vs[last_hinge_index].x &&
810                            vlist_updated[idx].y==vs[last_hinge_index].y,
811                            "check #1 failed in CanConvertSplineToStructuredSpline()",
812                            NULL);
813 #endif /* _TGIF_DBG */
814                      vlist_updated[idx+1].x = vs[last_hinge_index+1].x;
815                      vlist_updated[idx+1].y = vs[last_hinge_index+1].y;
816                   }
817                } else {
818                   return FALSE;
819                }
820             } else {
821                return FALSE;
822             }
823             earlier_smooth = TRUE;
824             if (vlist_updated != NULL) {
825                idx = (hinge_count-1)*3;
826                vlist_updated[idx-1].x = vs[i-1].x;
827                vlist_updated[idx-1].y = vs[i-1].y;
828                vlist_updated[idx].x = vs[i].x;
829                vlist_updated[idx].y = vs[i].y;
830             }
831             break;
832          case 2:
833             if (last_hinge_index == 0) {
834                /* it can go either way */
835                if (i == n-1) {
836                   /* still can go either way */
837                   earlier_smooth = TRUE;
838                   if (vlist_updated != NULL) {
839                      vlist_updated[1].x = vs[0].x;
840                      vlist_updated[1].y = vs[0].y;
841                   }
842                } else if (smooth != NULL && smooth[i+1]) {
843                   if ((vs[i].x<<1) == (vs[i-1].x+vs[i+1].x) &&
844                         (vs[i].y<<1) == (vs[i-1].y+vs[i+1].y)) {
845                      /* still okay */
846                      earlier_smooth = TRUE;
847                      if (vlist_updated != NULL) {
848                         vlist_updated[1].x = vs[0].x;
849                         vlist_updated[1].y = vs[0].y;
850                      }
851                   } else {
852                      /* still okay */
853                      earlier_smooth = FALSE;
854                   }
855                } else {
856                   /* still okay */
857                   earlier_smooth = FALSE;
858                }
859                if (vlist_updated != NULL) {
860                   idx = (hinge_count-2)*3;
861                   if (!earlier_smooth) {
862                      vlist_updated[idx+1].x = vs[i-1].x;
863                      vlist_updated[idx+1].y = vs[i-1].y;
864                   }
865                }
866             } else if (earlier_smooth) {
867                if ((vs[last_hinge_index].x<<1) ==
868                      (vs[last_hinge_index-1].x+vs[last_hinge_index+1].x) &&
869                      (vs[last_hinge_index].y<<1) ==
870                      (vs[last_hinge_index-1].y+vs[last_hinge_index+1].y)) {
871                   /* still okay */
872                   earlier_smooth = FALSE;
873                   if (vlist_updated != NULL) {
874                      idx = (hinge_count-2)*3;
875 #ifdef _TGIF_DBG /* debug, do not translate */
876                      TgAssert(
877                            vlist_updated[idx-1].x==vs[last_hinge_index-1].x &&
878                            vlist_updated[idx-1].y==vs[last_hinge_index-1].y &&
879                            vlist_updated[idx].x==vs[last_hinge_index].x &&
880                            vlist_updated[idx].y==vs[last_hinge_index].y,
881                            "check #2 failed in CanConvertSplineToStructuredSpline()",
882                            NULL);
883 #endif /* _TGIF_DBG */
884                      vlist_updated[idx+1].x = vs[last_hinge_index+1].x;
885                      vlist_updated[idx+1].y = vs[last_hinge_index+1].y;
886                   }
887                } else {
888                   return FALSE;
889                }
890             } else {
891                /* still okay */
892                if (vlist_updated != NULL) {
893                   idx = (hinge_count-2)*3;
894                   vlist_updated[idx+1].x = vlist_updated[idx].x;
895                   vlist_updated[idx+1].y = vlist_updated[idx].y;
896                }
897                earlier_smooth = TRUE;
898             }
899             if (vlist_updated != NULL) {
900                idx = (hinge_count-1)*3;
901                if (earlier_smooth) {
902                   vlist_updated[idx-1].x = vs[i-1].x;
903                   vlist_updated[idx-1].y = vs[i-1].y;
904                } else {
905                   vlist_updated[idx-1].x = vs[i].x;
906                   vlist_updated[idx-1].y = vs[i].y;
907                }
908                vlist_updated[idx].x = vs[i].x;
909                vlist_updated[idx].y = vs[i].y;
910             }
911             break;
912          case 1:
913             if (earlier_smooth) {
914                return FALSE;
915             }
916             if (vlist_updated != NULL) {
917                idx = (hinge_count-2)*3;
918                vlist_updated[idx+1].x = vs[last_hinge_index].x;
919                vlist_updated[idx+1].y = vs[last_hinge_index].y;
920 
921                idx = (hinge_count-1)*3;
922                vlist_updated[idx-1].x = vs[i].x;
923                vlist_updated[idx-1].y = vs[i].y;
924                vlist_updated[idx].x = vs[i].x;
925                vlist_updated[idx].y = vs[i].y;
926             }
927             break;
928          default: /* too many consecutive smooth points */ return FALSE;
929          }
930          last_hinge_index = i;
931       }
932    }
933    if (pn_hinge_count != NULL && vlist_updated == NULL) {
934       *pn_hinge_count = hinge_count;
935    }
936    return TRUE;
937 }
938 
939 static
CanConvertClosedSplineToStructuredSpline(ObjPtr,pn_hinge_count,vlist_updated)940 int CanConvertClosedSplineToStructuredSpline(ObjPtr, pn_hinge_count,
941       vlist_updated)
942    struct ObjRec *ObjPtr;
943    int *pn_hinge_count;
944    IntPoint *vlist_updated;
945    /*
946     * returns TRUE means that conversion will be made (and something
947     *       will change)
948     */
949 {
950    int i=0, last_hinge_index=0, hinge_count=1, num_ss_pts=0;
951    struct PolygonRec *polygon_ptr=NULL;
952    int curved=(-1), n=0, earlier_smooth=FALSE;
953    IntPoint *vs=NULL;
954    char *smooth=NULL;
955 
956    if (!GetPolyOrPolygonControlPoints(ObjPtr, NULL, &polygon_ptr, &curved, &n,
957          &vs, &smooth)) {
958       return FALSE;
959    }
960    if (vlist_updated != NULL) {
961       num_ss_pts = ((*pn_hinge_count)*3)-2;
962       vlist_updated[0].x = vs[0].x;
963       vlist_updated[0].y = vs[0].y;
964       vlist_updated[num_ss_pts-1].x = vs[n-1].x;
965       vlist_updated[num_ss_pts-1].y = vs[n-1].y;
966    }
967    for (i=1; i < n; i++) {
968       if (smooth == NULL || !smooth[i]) {
969          int idx=0;
970 
971          hinge_count++;
972 
973          switch (i-last_hinge_index) {
974          case 3:
975             if (last_hinge_index == 0) {
976                if (smooth != NULL && smooth[n-2]) {
977                   if ((vs[0].x<<1) == (vs[n-2].x+vs[1].x) &&
978                         (vs[0].y<<1) == (vs[n-2].y+vs[1].y)) {
979                      /* still okay */
980                      if (vlist_updated != NULL) {
981                         idx = (*pn_hinge_count)*3-3;
982                         vlist_updated[1].x = vs[1].x;
983                         vlist_updated[1].y = vs[1].y;
984                         vlist_updated[idx-1].x = vs[n-2].x;
985                         vlist_updated[idx-1].y = vs[n-2].y;
986                      }
987                   } else {
988                      return FALSE;
989                   }
990                } else {
991                   return FALSE;
992                }
993             } else if (earlier_smooth) {
994                if ((vs[last_hinge_index].x<<1) ==
995                      (vs[last_hinge_index-1].x+vs[last_hinge_index+1].x) &&
996                      (vs[last_hinge_index].y<<1) ==
997                      (vs[last_hinge_index-1].y+vs[last_hinge_index+1].y)) {
998                   /* still okay */
999                   if (vlist_updated != NULL) {
1000                      idx = (hinge_count-2)*3;
1001 #ifdef _TGIF_DBG /* debug, do not translate */
1002                      TgAssert(
1003                            vlist_updated[idx-1].x==vs[last_hinge_index-1].x &&
1004                            vlist_updated[idx-1].y==vs[last_hinge_index-1].y &&
1005                            vlist_updated[idx].x==vs[last_hinge_index].x &&
1006                            vlist_updated[idx].y==vs[last_hinge_index].y,
1007                            "check #1 failed in CanConvertClosedSplineToStructuredSpline()",
1008                            NULL);
1009 #endif /* _TGIF_DBG */
1010                      vlist_updated[idx+1].x = vs[last_hinge_index+1].x;
1011                      vlist_updated[idx+1].y = vs[last_hinge_index+1].y;
1012                   }
1013                } else {
1014                   return FALSE;
1015                }
1016             } else {
1017                return FALSE;
1018             }
1019             earlier_smooth = TRUE;
1020             if (vlist_updated != NULL) {
1021                idx = (hinge_count-1)*3;
1022                vlist_updated[idx-1].x = vs[i-1].x;
1023                vlist_updated[idx-1].y = vs[i-1].y;
1024                vlist_updated[idx].x = vs[i].x;
1025                vlist_updated[idx].y = vs[i].y;
1026             }
1027             if (i == n-1) {
1028                if (smooth != NULL && smooth[1]) {
1029                   if ((vs[0].x<<1) == (vs[n-2].x+vs[1].x) &&
1030                         (vs[0].y<<1) == (vs[n-2].y+vs[1].y)) {
1031                      /* still okay */
1032                   } else {
1033                      return FALSE;
1034                   }
1035                } else {
1036                   return FALSE;
1037                }
1038             }
1039             break;
1040          case 2:
1041             if (last_hinge_index == 0) {
1042                /* it can go either way */
1043                if (smooth != NULL && smooth[i+1]) {
1044                   if ((vs[i].x<<1) == (vs[i-1].x+vs[i+1].x) &&
1045                         (vs[i].y<<1) == (vs[i-1].y+vs[i+1].y)) {
1046                      /* still okay */
1047                      earlier_smooth = TRUE;
1048                      if (vlist_updated != NULL) {
1049                         vlist_updated[1].x = vs[0].x;
1050                         vlist_updated[1].y = vs[0].y;
1051 
1052                         idx = (hinge_count-1)*3;
1053                         vlist_updated[idx-1].x = vs[i-1].x;
1054                         vlist_updated[idx-1].y = vs[i-1].y;
1055                         vlist_updated[idx].x = vs[i].x;
1056                         vlist_updated[idx].y = vs[i].y;
1057                      }
1058                   } else {
1059                      /* still okay */
1060                      if (smooth != NULL && smooth[n-2]) {
1061                         if ((vs[0].x<<1) == (vs[n-2].x+vs[1].x) &&
1062                               (vs[0].y<<1) == (vs[n-2].y+vs[1].y)) {
1063                            /* still okay */
1064                         } else {
1065                            return FALSE;
1066                         }
1067                      } else {
1068                         return FALSE;
1069                      }
1070                      earlier_smooth = FALSE;
1071                   }
1072                } else {
1073                   /* still okay */
1074                   earlier_smooth = FALSE;
1075                }
1076             } else if (earlier_smooth) {
1077                if ((vs[last_hinge_index].x<<1) ==
1078                      (vs[last_hinge_index-1].x+vs[last_hinge_index+1].x) &&
1079                      (vs[last_hinge_index].y<<1) ==
1080                      (vs[last_hinge_index-1].y+vs[last_hinge_index+1].y)) {
1081                   /* still okay */
1082                   earlier_smooth = FALSE;
1083                } else {
1084                   return FALSE;
1085                }
1086             } else {
1087                /* still okay */
1088                earlier_smooth = TRUE;
1089                if (i == n-1) {
1090                   if (smooth != NULL && smooth[1]) {
1091                      if ((vs[0].x<<1) == (vs[n-2].x+vs[1].x) &&
1092                            (vs[0].y<<1) == (vs[n-2].y+vs[1].y)) {
1093                         /* still okay */
1094                      } else {
1095                         return FALSE;
1096                      }
1097                   } else {
1098                      return FALSE;
1099                   }
1100                }
1101             }
1102             if (vlist_updated != NULL) {
1103                idx = (hinge_count-1)*3;
1104                if (earlier_smooth) {
1105                   vlist_updated[idx-1].x = vs[i-1].x;
1106                   vlist_updated[idx-1].y = vs[i-1].y;
1107                } else {
1108                   vlist_updated[idx-1].x = vs[i].x;
1109                   vlist_updated[idx-1].y = vs[i].y;
1110                }
1111                vlist_updated[idx].x = vs[i].x;
1112                vlist_updated[idx].y = vs[i].y;
1113             }
1114             break;
1115          case 1:
1116             if (earlier_smooth) {
1117                return FALSE;
1118             }
1119             if (vlist_updated != NULL) {
1120                idx = (hinge_count-2)*3;
1121                vlist_updated[idx+1].x = vs[last_hinge_index].x;
1122                vlist_updated[idx+1].y = vs[last_hinge_index].y;
1123 
1124                idx = (hinge_count-1)*3;
1125                vlist_updated[idx-1].x = vs[i].x;
1126                vlist_updated[idx-1].y = vs[i].y;
1127                vlist_updated[idx].x = vs[i].x;
1128                vlist_updated[idx].y = vs[i].y;
1129             }
1130             break;
1131          default: /* too many consecutive smooth points */ return FALSE;
1132          }
1133          last_hinge_index = i;
1134       }
1135    }
1136    if (last_hinge_index == 0) {
1137       return FALSE;
1138    }
1139    if (pn_hinge_count != NULL && vlist_updated == NULL) {
1140       *pn_hinge_count = hinge_count;
1141    }
1142    return TRUE;
1143 }
1144 
1145 static
CanConvertObjLineType(ObjPtr,TypeIndex,pn_failed_count,pn_hinge_count)1146 int CanConvertObjLineType(ObjPtr, TypeIndex, pn_failed_count, pn_hinge_count)
1147    struct ObjRec *ObjPtr;
1148    int TypeIndex, *pn_failed_count, *pn_hinge_count;
1149    /*
1150     * returns FALSE if ObjPtr has the same line type as TypeIndex or
1151     *       if there is no way to make the conversion (for example,
1152     *       from spline to structured spline where the smooth vertices
1153     *       are not all at the right places); this object will not change
1154     *       in this case
1155     * returns TRUE means that conversion will be made (and something
1156     *       will change)
1157     */
1158 {
1159    int i=0;
1160    int curved=(-1), n=0;
1161    IntPoint *vs=NULL;
1162    char *smooth=NULL;
1163 
1164    if (!GetPolyOrPolygonControlPoints(ObjPtr, NULL, NULL, &curved, &n, &vs,
1165          &smooth)) {
1166       return FALSE;
1167    }
1168    switch (TypeIndex) {
1169    case LT_STRAIGHT:
1170       if (curved == LT_INTSPLINE) return TRUE;
1171       if (curved == LT_STRUCT_SPLINE) return TRUE;
1172       if (curved == LT_STRAIGHT && smooth == NULL) return FALSE;
1173       if (curved == LT_SPLINE && smooth == NULL) return TRUE;
1174       switch (ObjPtr->type) {
1175       case OBJ_POLY:
1176          for (i=1; i < n-1; i++) if (smooth[i]) return TRUE;
1177          break;
1178       case OBJ_POLYGON:
1179          for (i=0; i < n; i++) if (smooth[i]) return TRUE;
1180          break;
1181       }
1182       return FALSE;
1183    case LT_SPLINE:
1184       if (curved == LT_INTSPLINE) return TRUE;
1185       if (curved == LT_STRUCT_SPLINE) return TRUE;
1186       if (curved == LT_STRAIGHT && smooth == NULL) return TRUE;
1187       if (curved == LT_SPLINE && smooth == NULL) return FALSE;
1188       switch (ObjPtr->type) {
1189       case OBJ_POLY:
1190          for (i=1; i < n-1; i++) if (!smooth[i]) return TRUE;
1191          break;
1192       case OBJ_POLYGON:
1193          for (i=0; i < n; i++) if (!smooth[i]) return TRUE;
1194          break;
1195       }
1196       return FALSE;
1197    case LT_INTSPLINE:
1198       if (curved == LT_INTSPLINE) return FALSE;
1199       if (curved == LT_STRUCT_SPLINE) {
1200          int min_num_vertices=0, max_vs_to_check=n, count=1;
1201 
1202          if (ObjPtr->type == OBJ_POLY) {
1203             min_num_vertices = 2;
1204          } else { /* ObjPtr->type is OBJ_POLYGON */
1205             min_num_vertices = 4;
1206          }
1207          if (smooth == NULL) {
1208             if (n < min_num_vertices) {
1209                (*pn_failed_count)++;
1210                return FALSE;
1211             }
1212          } else {
1213             for (i=1; i < max_vs_to_check; i++) {
1214                if (!smooth[i]) count++;
1215             }
1216             if (count < min_num_vertices) {
1217                (*pn_failed_count)++;
1218                return FALSE;
1219             }
1220          }
1221       }
1222       return TRUE;
1223    case LT_STRUCT_SPLINE:
1224       if (curved == LT_INTSPLINE) {
1225          if (pn_hinge_count != NULL) *pn_hinge_count = n;
1226          return TRUE;
1227       }
1228       if (curved == LT_STRUCT_SPLINE) return FALSE;
1229       if (curved == LT_STRAIGHT && smooth == NULL) {
1230          if (pn_hinge_count != NULL) *pn_hinge_count = n;
1231          return TRUE;
1232       }
1233       if (curved == LT_SPLINE && smooth == NULL) return FALSE;
1234       switch (ObjPtr->type) {
1235       case OBJ_POLY:
1236          if (!CanConvertSplineToStructuredSpline(ObjPtr, pn_hinge_count,
1237                NULL)) {
1238             (*pn_failed_count)++;
1239             return FALSE;
1240          }
1241          break;
1242       case OBJ_POLYGON:
1243          if (!CanConvertClosedSplineToStructuredSpline(ObjPtr, pn_hinge_count,
1244                NULL)) {
1245             (*pn_failed_count)++;
1246             return FALSE;
1247          }
1248          break;
1249       }
1250       break;
1251    }
1252    return TRUE;
1253 }
1254 
1255 static
GetNumUsableStraightVs(pn_num_usable_vs,num_pts,vs)1256 IntPoint *GetNumUsableStraightVs(pn_num_usable_vs, num_pts, vs)
1257    int *pn_num_usable_vs, num_pts;
1258    IntPoint *vs;
1259 {
1260    int i=0, index=1, x=0, y=0;
1261    IntPoint *pv=(IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
1262 
1263    if (pv == NULL) FailAllocMessage();
1264    memset(pv, 0, num_pts*sizeof(IntPoint));
1265    x = pv[0].x = vs[0].x;
1266    y = pv[0].y = vs[0].y;
1267    for (i=1; i < num_pts; i++) {
1268       if (vs[i].x != x || vs[i].y != y) {
1269          x = pv[index].x = vs[i].x;
1270          y = pv[index].y = vs[i].y;
1271          index++;
1272       }
1273    }
1274    if (index == 1) {
1275       *pn_num_usable_vs = 0;
1276       free(pv);
1277       return NULL;
1278    }
1279    *pn_num_usable_vs = index;
1280 
1281    return pv;
1282 }
1283 
1284 static
GetNumUsableSplineVs(pn_num_usable_vs,ppsz_smooth,num_pts,vs,smooth)1285 IntPoint *GetNumUsableSplineVs(pn_num_usable_vs, ppsz_smooth, num_pts, vs,
1286       smooth)
1287    int *pn_num_usable_vs, num_pts;
1288    char **ppsz_smooth, *smooth;
1289    IntPoint *vs;
1290 {
1291    int i=0, index=1, x=0, y=0;
1292    IntPoint *pv=(IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
1293    char *psz_smooth=(char*)malloc((num_pts+1)*sizeof(char));
1294 
1295    if (pv == NULL || psz_smooth == NULL) FailAllocMessage();
1296    memset(pv, 0, num_pts*sizeof(IntPoint));
1297    memset(psz_smooth, 0, num_pts*sizeof(char));
1298    x = pv[0].x = vs[0].x;
1299    y = pv[0].y = vs[0].y;
1300    psz_smooth[0] = FALSE;
1301    for (i=1; i < num_pts; i++) {
1302       if (vs[i].x != x || vs[i].y != y) {
1303          psz_smooth[index] = smooth[i];
1304          x = pv[index].x = vs[i].x;
1305          y = pv[index].y = vs[i].y;
1306          index++;
1307       }
1308    }
1309    psz_smooth[index] = FALSE;
1310 
1311    if (index == 1) {
1312       *pn_num_usable_vs = 0;
1313       *ppsz_smooth = NULL;
1314       free(pv);
1315       free(psz_smooth);
1316       return NULL;
1317    }
1318    *pn_num_usable_vs = index;
1319    *ppsz_smooth = psz_smooth;
1320 
1321    return pv;
1322 }
1323 
1324 static
GetNumUsableIntSplineVsFromStructuredSpline(pn_num_usable_vs,num_pts,vs)1325 IntPoint *GetNumUsableIntSplineVsFromStructuredSpline(pn_num_usable_vs, num_pts,
1326       vs)
1327    int *pn_num_usable_vs, num_pts;
1328    IntPoint *vs;
1329 {
1330    int j=0, index=1, x=0, y=0;
1331    IntPoint *pv=(IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
1332 
1333    if (pv == NULL) FailAllocMessage();
1334    memset(pv, 0, num_pts*sizeof(IntPoint));
1335    x = pv[0].x = vs[0].x;
1336    y = pv[0].y = vs[0].y;
1337    for (j=3; j < num_pts; j+=3) {
1338       if (abs(vs[j].x-x) > 1 || abs(vs[j].y-y) > 1) {
1339          x = pv[index].x = vs[j].x;
1340          y = pv[index].y = vs[j].y;
1341          index++;
1342       }
1343    }
1344    if (index == 1) {
1345       *pn_num_usable_vs = 0;
1346       free(pv);
1347       return NULL;
1348    }
1349    *pn_num_usable_vs = index;
1350 
1351    return pv;
1352 }
1353 
1354 static
GetNumUsableIntSplineVs(pn_num_usable_vs,num_pts,vs,smooth)1355 IntPoint *GetNumUsableIntSplineVs(pn_num_usable_vs, num_pts, vs, smooth)
1356    int *pn_num_usable_vs, num_pts;
1357    IntPoint *vs;
1358    char *smooth;
1359 {
1360    int i=0, index=1, x=0, y=0;
1361    IntPoint *pv=(IntPoint*)malloc((num_pts+1)*sizeof(IntPoint));
1362 
1363    if (pv == NULL) FailAllocMessage();
1364    memset(pv, 0, num_pts*sizeof(IntPoint));
1365    x = pv[0].x = vs[0].x;
1366    y = pv[0].y = vs[0].y;
1367    for (i=1; i < num_pts; i++) {
1368       if (abs(vs[i].x-x) > 1 || abs(vs[i].y-y) > 1) {
1369          x = pv[index].x = vs[i].x;
1370          y = pv[index].y = vs[i].y;
1371          index++;
1372       }
1373    }
1374    if (index == 1) {
1375       *pn_num_usable_vs = 0;
1376       free(pv);
1377       return NULL;
1378    }
1379    *pn_num_usable_vs = index;
1380 
1381    return pv;
1382 }
1383 
1384 static
GetNumUsableStructuredSplineVs(pn_num_usable_vs,ppsz_smooth,obj_type,n,vs,intn,intvs)1385 IntPoint *GetNumUsableStructuredSplineVs(pn_num_usable_vs, ppsz_smooth,
1386       obj_type, n, vs, intn, intvs)
1387    int *pn_num_usable_vs, obj_type, n, intn;
1388    char **ppsz_smooth;
1389    IntPoint *vs, *intvs;
1390 {
1391    int i=0, j=0, k=0, index=1, x=0, y=0, num_ss_pts=(n*3)-2;
1392    IntPoint *pv=(IntPoint*)malloc((num_ss_pts+2)*sizeof(IntPoint));
1393    char *psz_smooth=(char*)malloc((num_ss_pts+2)*sizeof(char));
1394 
1395    if (pv == NULL || psz_smooth == NULL) FailAllocMessage();
1396    memset(pv, 0, (num_ss_pts+1)*sizeof(IntPoint));
1397    memset(psz_smooth, 0, (num_ss_pts+1)*sizeof(char));
1398    x = pv[0].x = vs[0].x;
1399    y = pv[0].y = vs[0].y;
1400    psz_smooth[0] = psz_smooth[num_ss_pts-1] = FALSE;
1401    if (obj_type == OBJ_POLY) {
1402       pv[1].x = vs[0].x;
1403       pv[1].y = vs[0].y;
1404       psz_smooth[1] = psz_smooth[num_ss_pts-2] = FALSE;
1405    } else { /* obj_type == OBJ_POLYGON */
1406       pv[1].x = intvs[0].x;
1407       pv[1].y = intvs[0].y;
1408       psz_smooth[1] = psz_smooth[num_ss_pts-2] = TRUE;
1409    }
1410    for (i=1; i < n; i++) {
1411       if (abs(vs[i].x-x) > 3 || abs(vs[i].y-y) > 3) {
1412          j = (index*3);
1413          k = (i<<1)-1;
1414          pv[j-1].x = intvs[k].x;
1415          pv[j-1].y = intvs[k].y;
1416          x = pv[j].x = vs[i].x;
1417          y = pv[j].y = vs[i].y;
1418          pv[j+1].x = (x<<1) - pv[j-1].x;
1419          pv[j+1].y = (y<<1) - pv[j-1].y;
1420          if (pv[j-1].x == pv[j+1].x && pv[j-1].y == pv[j+1].y) {
1421             psz_smooth[j-1] = psz_smooth[j+1] = FALSE;
1422          } else {
1423             psz_smooth[j-1] = psz_smooth[j+1] = TRUE;
1424          }
1425          psz_smooth[j] = FALSE;
1426          index++;
1427       }
1428    }
1429    if (index == 1) {
1430       *pn_num_usable_vs = 0;
1431       *ppsz_smooth = NULL;
1432       free(pv);
1433       free(psz_smooth);
1434       return NULL;
1435    }
1436    j = (index-1)*3;
1437    pv[j].x = x;
1438    pv[j].y = y;
1439    psz_smooth[j] = FALSE;
1440    if (obj_type == OBJ_POLY) {
1441       pv[j-1].x = x;
1442       pv[j-1].y = y;
1443       psz_smooth[j-1] = FALSE;
1444    } else { /* obj_type == OBJ_POLYGON */
1445       if (x != pv[0].x || y != pv[0].y) {
1446          /*
1447           * need to add more vertices?
1448           * let's assume this cannot happen for now
1449           */
1450          if (index == n) {
1451             x = pv[j].x = pv[0].x;
1452             y = pv[j].y = pv[0].y;
1453          } else {
1454             psz_smooth[j-1] = psz_smooth[j] = psz_smooth[j+1] = FALSE;
1455             pv[j-1].x = pv[j+1].x = pv[j].x;
1456             pv[j-1].y = pv[j+1].y = pv[j].y;
1457             j += 3;
1458             x = pv[j-1].x = pv[j].x = pv[0].x;
1459             y = pv[j-1].y = pv[j].y = pv[0].y;
1460             psz_smooth[j-1] = psz_smooth[j] = FALSE;
1461          }
1462       } else {
1463          pv[j-1].x = (x<<1) - pv[1].x;
1464          pv[j-1].y = (y<<1) - pv[1].y;
1465          psz_smooth[j-1] = TRUE;
1466       }
1467    }
1468    *pn_num_usable_vs = j+1;
1469    *ppsz_smooth = psz_smooth;
1470 
1471    return pv;
1472 }
1473 
1474 static
SetObjSmooth(ObjPtr,TypeIndex,hinge_count)1475 void SetObjSmooth(ObjPtr, TypeIndex, hinge_count)
1476    struct ObjRec *ObjPtr;
1477    int TypeIndex, hinge_count;
1478 {
1479    int i=0, n=0, num_ss_pts=0;
1480    char *smooth=NULL, *usable_smooth=NULL;
1481    struct PolyRec *poly_ptr=NULL;
1482    struct PolygonRec *polygon_ptr=NULL;
1483    IntPoint *vlist=NULL, *usable_vlist=NULL;
1484 
1485    switch (ObjPtr->type) {
1486    case OBJ_POLY:
1487       poly_ptr = ObjPtr->detail.p;
1488       smooth = poly_ptr->smooth;
1489       n = poly_ptr->n;
1490       switch (TypeIndex) {
1491       case LT_STRAIGHT:
1492          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
1493             usable_vlist = GetNumUsableStraightVs(&n, poly_ptr->ssn,
1494                   poly_ptr->ssvlist);
1495          }
1496          if (usable_vlist != NULL) {
1497             if (poly_ptr->vlist != NULL) free(poly_ptr->vlist);
1498             poly_ptr->n = n;
1499             poly_ptr->vlist = usable_vlist;
1500          }
1501          if (smooth == NULL) smooth = (char*)malloc((n+1)*sizeof(char));
1502          if (smooth == NULL) FailAllocMessage();
1503          for (i=0; i < n; i++) smooth[i] = FALSE;
1504          poly_ptr->smooth = smooth;
1505          return;
1506       case LT_SPLINE:
1507          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
1508             usable_vlist = GetNumUsableSplineVs(&n, &usable_smooth,
1509                   poly_ptr->ssn, poly_ptr->ssvlist, poly_ptr->ssmooth);
1510          }
1511          if (usable_vlist != NULL) {
1512             if (poly_ptr->vlist != NULL) free(poly_ptr->vlist);
1513             if (poly_ptr->smooth != NULL) free(poly_ptr->smooth);
1514             poly_ptr->n = n;
1515             poly_ptr->vlist = usable_vlist;
1516             poly_ptr->smooth = usable_smooth;
1517          } else {
1518             if (smooth == NULL) smooth = (char*)malloc((n+1)*sizeof(char));
1519             if (smooth == NULL) FailAllocMessage();
1520             smooth[0] = smooth[n-1] = FALSE;
1521             for (i=1; i < n-1; i++) smooth[i] = TRUE;
1522             poly_ptr->smooth = smooth;
1523          }
1524          return;
1525       case LT_INTSPLINE:
1526          if (poly_ptr->curved == LT_STRUCT_SPLINE) {
1527             usable_vlist = GetNumUsableIntSplineVsFromStructuredSpline(&n,
1528                   poly_ptr->n, poly_ptr->vlist);
1529          } else {
1530             usable_vlist = GetNumUsableIntSplineVs(&n, poly_ptr->n,
1531                   poly_ptr->vlist, poly_ptr->smooth);
1532          }
1533          if (usable_vlist != NULL) {
1534             if (poly_ptr->vlist != NULL) free(poly_ptr->vlist);
1535             poly_ptr->n = n;
1536             poly_ptr->vlist = usable_vlist;
1537          }
1538          if (smooth != NULL) {
1539             free(smooth);
1540             poly_ptr->smooth = NULL;
1541          }
1542          return;
1543       case LT_STRUCT_SPLINE:
1544          if (poly_ptr->curved == LT_INTSPLINE) {
1545             usable_vlist = GetNumUsableStructuredSplineVs(&n, &usable_smooth,
1546                   OBJ_POLY, poly_ptr->n, poly_ptr->vlist, poly_ptr->intn,
1547                   poly_ptr->intvlist);
1548          }
1549          if (usable_vlist != NULL) {
1550             if (poly_ptr->vlist != NULL) free(poly_ptr->vlist);
1551             poly_ptr->n = n;
1552             poly_ptr->vlist = usable_vlist;
1553             if (poly_ptr->smooth != NULL) free(poly_ptr->smooth);
1554             poly_ptr->smooth = usable_smooth;
1555          } else {
1556             num_ss_pts = (hinge_count*3)-2;
1557             vlist = (IntPoint*)malloc((num_ss_pts+1)*sizeof(IntPoint));
1558             if (vlist == NULL) FailAllocMessage();
1559             memset(vlist, 0, (num_ss_pts+1)*sizeof(IntPoint));
1560             if (!CanConvertSplineToStructuredSpline(ObjPtr, &hinge_count,
1561                   vlist)) {
1562 #ifdef _TGIF_DBG /* debug, do not translate */
1563                TgAssert(FALSE, "conversion failed in SetObjSmooth()", NULL);
1564 #endif /* _TGIF_DBG */
1565                return;
1566             }
1567             if (smooth != NULL) free(smooth);
1568             free(poly_ptr->vlist);
1569             poly_ptr->vlist = vlist;
1570             poly_ptr->n = num_ss_pts;
1571             poly_ptr->smooth = NULL;
1572          }
1573          return;
1574       }
1575       break;
1576    case OBJ_POLYGON:
1577       polygon_ptr = ObjPtr->detail.g;
1578       smooth = polygon_ptr->smooth;
1579       n = polygon_ptr->n;
1580       switch (TypeIndex) {
1581       case LT_STRAIGHT:
1582          if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
1583             usable_vlist = GetNumUsableStraightVs(&n, polygon_ptr->ssn,
1584                   polygon_ptr->ssvlist);
1585          }
1586          if (usable_vlist != NULL) {
1587             if (polygon_ptr->vlist != NULL) free(polygon_ptr->vlist);
1588             polygon_ptr->n = n;
1589             polygon_ptr->vlist = usable_vlist;
1590          }
1591          if (smooth == NULL) smooth = (char*)malloc((n+1)*sizeof(char));
1592          if (smooth == NULL) FailAllocMessage();
1593          for (i=0; i < n; i++) smooth[i] = FALSE;
1594          polygon_ptr->smooth = smooth;
1595          return;
1596       case LT_SPLINE:
1597          if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
1598             usable_vlist = GetNumUsableSplineVs(&n, &usable_smooth,
1599                   polygon_ptr->ssn, polygon_ptr->ssvlist, polygon_ptr->ssmooth);
1600          }
1601          if (usable_vlist != NULL) {
1602             if (polygon_ptr->vlist != NULL) free(polygon_ptr->vlist);
1603             if (polygon_ptr->smooth != NULL) free(polygon_ptr->smooth);
1604             polygon_ptr->n = n;
1605             polygon_ptr->vlist = usable_vlist;
1606             polygon_ptr->smooth = usable_smooth;
1607          } else {
1608             if (smooth == NULL) smooth = (char*)malloc((n+1)*sizeof(char));
1609             if (smooth == NULL) FailAllocMessage();
1610             for (i=0; i < n; i++) smooth[i] = TRUE;
1611             polygon_ptr->smooth = smooth;
1612          }
1613          return;
1614       case LT_INTSPLINE:
1615          if (polygon_ptr->curved == LT_STRUCT_SPLINE) {
1616             usable_vlist = GetNumUsableIntSplineVsFromStructuredSpline(&n,
1617                   polygon_ptr->n, polygon_ptr->vlist);
1618          } else {
1619             usable_vlist = GetNumUsableIntSplineVs(&n, polygon_ptr->n,
1620                   polygon_ptr->vlist, polygon_ptr->smooth);
1621          }
1622          if (usable_vlist != NULL) {
1623             if (polygon_ptr->vlist != NULL) free(polygon_ptr->vlist);
1624             polygon_ptr->n = n;
1625             polygon_ptr->vlist = usable_vlist;
1626          }
1627          if (smooth != NULL) {
1628             free(smooth);
1629             polygon_ptr->smooth = NULL;
1630          }
1631          return;
1632       case LT_STRUCT_SPLINE:
1633          if (polygon_ptr->curved == LT_INTSPLINE) {
1634             usable_vlist = GetNumUsableStructuredSplineVs(&n, &usable_smooth,
1635                   OBJ_POLYGON, polygon_ptr->n, polygon_ptr->vlist,
1636                   polygon_ptr->intn, polygon_ptr->intvlist);
1637          }
1638          if (usable_vlist != NULL) {
1639             if (polygon_ptr->vlist != NULL) free(polygon_ptr->vlist);
1640             polygon_ptr->n = n;
1641             polygon_ptr->vlist = usable_vlist;
1642             if (polygon_ptr->smooth != NULL) free(polygon_ptr->smooth);
1643             polygon_ptr->smooth = usable_smooth;
1644          } else {
1645             num_ss_pts = (hinge_count*3)-2;
1646             vlist = (IntPoint*)malloc((num_ss_pts+2)*sizeof(IntPoint));
1647             if (vlist == NULL) FailAllocMessage();
1648             memset(vlist, 0, (num_ss_pts+2)*sizeof(IntPoint));
1649             if (!CanConvertSplineToStructuredSpline(ObjPtr, &hinge_count,
1650                   vlist)) {
1651 #ifdef _TGIF_DBG /* debug, do not translate */
1652                TgAssert(FALSE, "conversion failed in SetObjSmooth()", NULL);
1653 #endif /* _TGIF_DBG */
1654                return;
1655             }
1656             if (smooth != NULL) free(smooth);
1657             free(polygon_ptr->vlist);
1658             polygon_ptr->vlist = vlist;
1659             polygon_ptr->n = num_ss_pts;
1660             polygon_ptr->smooth = NULL;
1661          }
1662          return;
1663       }
1664       break;
1665    }
1666 }
1667 
1668 static
ChangeObjLineType(ObjPtr,TypeIndex,pn_failed_count)1669 int ChangeObjLineType(ObjPtr, TypeIndex, pn_failed_count)
1670    struct ObjRec *ObjPtr;
1671    int TypeIndex, *pn_failed_count;
1672 {
1673    struct ObjRec *obj_ptr=NULL;
1674    int changed=FALSE, hinge_count=0;
1675 
1676    switch (ObjPtr->type) {
1677    case OBJ_POLY:
1678       if (CanConvertObjLineType(ObjPtr, TypeIndex, pn_failed_count,
1679             &hinge_count)) {
1680          /* hinge_count is only valid if TypeIndex is LT_STRUCT_SPLINE */
1681          SetObjSmooth(ObjPtr, TypeIndex, hinge_count);
1682          ObjPtr->detail.p->curved = TypeIndex;
1683          changed = TRUE;
1684          AdjObjSplineVs(ObjPtr);
1685          if (ObjPtr->detail.p->curved != LT_INTSPLINE) {
1686             UpdPolyBBox(ObjPtr, ObjPtr->detail.p->n,
1687                   ObjPtr->detail.p->vlist);
1688          } else {
1689             UpdPolyBBox(ObjPtr, ObjPtr->detail.p->intn,
1690                   ObjPtr->detail.p->intvlist);
1691          }
1692       }
1693       break;
1694    case OBJ_POLYGON:
1695          /* hinge_count is only valid if TypeIndex is LT_STRUCT_SPLINE */
1696       if (CanConvertObjLineType(ObjPtr, TypeIndex, pn_failed_count,
1697             &hinge_count)) {
1698          SetObjSmooth(ObjPtr, TypeIndex, hinge_count);
1699          ObjPtr->detail.g->curved = TypeIndex;
1700          changed = TRUE;
1701          AdjObjSplineVs(ObjPtr);
1702          if (ObjPtr->detail.g->curved != LT_INTSPLINE) {
1703             UpdPolyBBox(ObjPtr, ObjPtr->detail.g->n,
1704                   ObjPtr->detail.g->vlist);
1705          } else {
1706             UpdPolyBBox(ObjPtr, ObjPtr->detail.g->intn,
1707                   ObjPtr->detail.g->intvlist);
1708          }
1709       }
1710       break;
1711 
1712    case OBJ_GROUP:
1713    case OBJ_SYM:
1714       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
1715             obj_ptr=obj_ptr->prev) {
1716          if (ChangeObjLineType(obj_ptr, TypeIndex, pn_failed_count)) {
1717             changed = TRUE;
1718          }
1719       }
1720       break;
1721    }
1722    if (changed) AdjObjBBox(ObjPtr);
1723    return changed;
1724 }
1725 
ChangeAllSelLineType(TypeIndex,HighLight)1726 void ChangeAllSelLineType(TypeIndex, HighLight)
1727    int TypeIndex, HighLight;
1728 {
1729    struct SelRec *sel_ptr=NULL;
1730    int ltx, lty, rbx, rby, changed=FALSE, dont_do_obj=FALSE, failed_count=0;
1731 
1732    if (topSel == NULL || stickyMenuSelection) {
1733       curSpline = TypeIndex;
1734       ShowLineType();
1735       UpdatePinnedMenu(MENU_LINETYPE);
1736       if (topSel == NULL) dont_do_obj = TRUE;
1737    }
1738    *gszMsgBox = '\0';
1739    switch (curSpline) {
1740    case LT_STRAIGHT:
1741       sprintf(gszMsgBox, TgLoadString(STID_LINE_TYPE_IS_STRAIGHT));
1742       break;
1743    case LT_SPLINE:
1744       sprintf(gszMsgBox, TgLoadString(STID_LINE_TYPE_IS_SPLINE));
1745       break;
1746    case LT_INTSPLINE:
1747       sprintf(gszMsgBox, TgLoadString(STID_LINE_TYPE_IS_INTSPLINE));
1748       break;
1749    case LT_STRUCT_SPLINE:
1750       sprintf(gszMsgBox, TgLoadString(STID_LINE_TYPE_IS_STRUCT_SPLINE));
1751       break;
1752    }
1753    Msg(gszMsgBox);
1754    if (dont_do_obj) return;
1755 
1756    if (HighLight) HighLightReverse();
1757    StartCompositeCmd();
1758    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1759       PrepareToReplaceAnObj(sel_ptr->obj);
1760       if (ChangeObjLineType(sel_ptr->obj, TypeIndex, &failed_count)) {
1761          changed = TRUE;
1762          RecordReplaceAnObj(sel_ptr->obj);
1763       } else {
1764          AbortPrepareCmd(CMD_REPLACE);
1765       }
1766    }
1767    EndCompositeCmd();
1768 
1769    if (changed) {
1770       SetFileModified(TRUE);
1771       ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
1772       UpdSelBBox();
1773       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1774             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1),
1775             selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
1776             selRbY+GRID_ABS_SIZE(1));
1777    }
1778    if (HighLight) HighLightForward();
1779    if (failed_count > 0) {
1780       if (HighLight && failed_count == numObjSelected) {
1781          MsgBox(TgLoadString(STID_CANNOT_CONVERT_SEL_LINETYPE), TOOL_NAME,
1782                INFO_MB);
1783       } else {
1784          Msg(TgLoadString(STID_SOME_LT_FAILED_TO_CONVERT));
1785       }
1786    }
1787 }
1788 
RefreshLineTypeMenu(menu)1789 void RefreshLineTypeMenu(menu)
1790    TgMenu *menu;
1791 {
1792    int i, num_items=menu->num_items;
1793    TgMenuItem *menuitems=menu->menuitems;
1794 
1795    for (i=0; i < num_items; i++) {
1796       TgMenuItem *menu_item=(&menuitems[i]);
1797       TgMenuItem stMenuItem;
1798 
1799       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1800       stMenuItem.state = TGBS_NORMAL;
1801       stMenuItem.checked = (i == curSpline);
1802       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
1803             &stMenuItem);
1804    }
1805 }
1806 
CreateLineTypeMenu(parent_menu,x,y,menu_info,status_str_xlated)1807 TgMenu *CreateLineTypeMenu(parent_menu, x, y, menu_info, status_str_xlated)
1808    TgMenu *parent_menu;
1809    int x, y;
1810    TgMenuInfo *menu_info;
1811    int status_str_xlated; /* ignored, always 0 */
1812 {
1813    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
1814 
1815    if (menu != NULL) {
1816       TgMenuItem *menu_item=NULL;
1817       TgMenuItem stMenuItem;
1818 
1819       menu->track_menubar = TRUE;
1820       TgAdjustMenuGeometry(menu, menuImageW, menuImageH, MAXLINETYPES);
1821       menu_item = (&menu->menuitems[curSpline]);
1822 
1823       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1824       stMenuItem.checked = TRUE;
1825       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
1826          return TgDestroyMenu(menu, TRUE);
1827       }
1828    }
1829    return menu;
1830 }
1831 
LineTypeMenu(X,Y,TrackMenubar)1832 int LineTypeMenu(X, Y, TrackMenubar)
1833    int X, Y, TrackMenubar;
1834 {
1835    int rc=INVALID;
1836    TgMenu *menu=(lineTypeMenuInfo.create_proc)(NULL, X, Y, &lineTypeMenuInfo,
1837          INVALID);
1838 
1839    activeMenu = MENU_LINETYPE;
1840    if (menu != NULL) {
1841       menu->track_menubar = TrackMenubar;
1842 
1843       rc = TgMenuLoop(menu);
1844       TgDestroyMenu(menu, TRUE);
1845    }
1846    return rc;
1847 }
1848 
1849 /* ------------------ LineWidth Functions ------------------ */
1850 
1851 static
ChangeObjLineWidth(ObjPtr,nMask,W,AW,AH,width_spec,aw_spec,ah_spec)1852 int ChangeObjLineWidth(ObjPtr, nMask, W, AW, AH, width_spec, aw_spec, ah_spec)
1853    struct ObjRec *ObjPtr;
1854    int nMask, W, AW, AH;
1855    char *width_spec, *aw_spec, *ah_spec;
1856 {
1857    register struct ObjRec *obj_ptr;
1858    register int changed=FALSE;
1859 
1860    switch (ObjPtr->type) {
1861    case OBJ_POLY:
1862       if ((((nMask & CHANGE_WIDTH) == CHANGE_WIDTH) &&
1863             (ObjPtr->detail.p->width != W ||
1864             strcmp(ObjPtr->detail.p->width_spec, width_spec) != 0)) ||
1865             (AW != (-1) && ((nMask & CHANGE_AW) == CHANGE_AW) &&
1866             (ObjPtr->detail.p->aw != AW ||
1867             strcmp(ObjPtr->detail.p->aw_spec, aw_spec) != 0)) ||
1868             (AH != (-1) && ((nMask & CHANGE_AH) == CHANGE_AH) &&
1869             (ObjPtr->detail.p->ah != AH ||
1870             strcmp(ObjPtr->detail.p->ah_spec, ah_spec) != 0))) {
1871          if (((nMask & CHANGE_WIDTH) == CHANGE_WIDTH)) {
1872             ObjPtr->detail.p->width = W;
1873             UtilStrCpyN(ObjPtr->detail.p->width_spec,
1874                   sizeof(ObjPtr->detail.p->width_spec), width_spec);
1875          }
1876          if (AW != (-1) && ((nMask & CHANGE_AW) == CHANGE_AW)) {
1877             ObjPtr->detail.p->aw = AW;
1878             UtilStrCpyN(ObjPtr->detail.p->aw_spec,
1879                   sizeof(ObjPtr->detail.p->aw_spec), aw_spec);
1880          }
1881          if (AH != (-1) && ((nMask & CHANGE_AH) == CHANGE_AH)) {
1882             ObjPtr->detail.p->ah = AH;
1883             UtilStrCpyN(ObjPtr->detail.p->ah_spec,
1884                   sizeof(ObjPtr->detail.p->ah_spec), ah_spec);
1885          }
1886          changed = TRUE;
1887          AdjObjSplineVs(ObjPtr);
1888          if (ObjPtr->detail.p->curved != LT_INTSPLINE) {
1889             UpdPolyBBox(ObjPtr, ObjPtr->detail.p->n,
1890                   ObjPtr->detail.p->vlist);
1891          } else {
1892             UpdPolyBBox(ObjPtr, ObjPtr->detail.p->intn,
1893                   ObjPtr->detail.p->intvlist);
1894          }
1895       }
1896       break;
1897    case OBJ_BOX:
1898       if ((nMask & CHANGE_WIDTH) == CHANGE_WIDTH) {
1899          if (ObjPtr->detail.b->width != W ||
1900                strcmp(ObjPtr->detail.b->width_spec, width_spec) != 0) {
1901             ObjPtr->detail.b->width = W;
1902             UtilStrCpyN(ObjPtr->detail.b->width_spec,
1903                   sizeof(ObjPtr->detail.b->width_spec), width_spec);
1904             changed = TRUE;
1905          }
1906       }
1907       break;
1908    case OBJ_OVAL:
1909       if ((nMask & CHANGE_WIDTH) == CHANGE_WIDTH) {
1910          if (ObjPtr->detail.o->width != W ||
1911                strcmp(ObjPtr->detail.o->width_spec, width_spec) != 0) {
1912             ObjPtr->detail.o->width = W;
1913             UtilStrCpyN(ObjPtr->detail.o->width_spec,
1914                   sizeof(ObjPtr->detail.o->width_spec), width_spec);
1915             changed = TRUE;
1916          }
1917       }
1918       break;
1919    case OBJ_POLYGON:
1920       if ((nMask & CHANGE_WIDTH) == CHANGE_WIDTH) {
1921          if (ObjPtr->detail.g->width != W ||
1922                strcmp(ObjPtr->detail.g->width_spec, width_spec) != 0) {
1923             ObjPtr->detail.g->width = W;
1924             UtilStrCpyN(ObjPtr->detail.g->width_spec,
1925                   sizeof(ObjPtr->detail.g->width_spec), width_spec);
1926             changed = TRUE;
1927          }
1928       }
1929       break;
1930    case OBJ_ARC:
1931       if ((((nMask & CHANGE_WIDTH) == CHANGE_WIDTH) &&
1932             (ObjPtr->detail.a->width != W ||
1933             strcmp(ObjPtr->detail.a->width_spec, width_spec) != 0)) ||
1934             (AW != (-1) && ((nMask & CHANGE_AW) == CHANGE_AW) &&
1935             (ObjPtr->detail.a->aw != AW ||
1936             strcmp(ObjPtr->detail.a->aw_spec, aw_spec) != 0)) ||
1937             (AH != (-1) && ((nMask & CHANGE_AH) == CHANGE_AH) &&
1938             (ObjPtr->detail.a->ah != AH ||
1939             strcmp(ObjPtr->detail.a->ah_spec, ah_spec) != 0))) {
1940          if (((nMask & CHANGE_WIDTH) == CHANGE_WIDTH)) {
1941             ObjPtr->detail.a->width = W;
1942             UtilStrCpyN(ObjPtr->detail.a->width_spec,
1943                   sizeof(ObjPtr->detail.a->width_spec), width_spec);
1944          }
1945          if (AW != (-1) && ((nMask & CHANGE_AW) == CHANGE_AW)) {
1946             ObjPtr->detail.a->aw = AW;
1947             UtilStrCpyN(ObjPtr->detail.a->aw_spec,
1948                   sizeof(ObjPtr->detail.a->aw_spec), aw_spec);
1949          }
1950          if (AH != (-1) && ((nMask & CHANGE_AH) == CHANGE_AH)) {
1951             ObjPtr->detail.a->ah = AH;
1952             UtilStrCpyN(ObjPtr->detail.a->ah_spec,
1953                   sizeof(ObjPtr->detail.a->ah_spec), ah_spec);
1954          }
1955          changed = TRUE;
1956          AdjObjSplineVs(ObjPtr);
1957       }
1958       break;
1959    case OBJ_RCBOX:
1960       if ((nMask & CHANGE_WIDTH) == CHANGE_WIDTH) {
1961          if (ObjPtr->detail.rcb->width != W ||
1962                strcmp(ObjPtr->detail.rcb->width_spec, width_spec) != 0) {
1963             ObjPtr->detail.rcb->width = W;
1964             UtilStrCpyN(ObjPtr->detail.rcb->width_spec,
1965                   sizeof(ObjPtr->detail.rcb->width_spec), width_spec);
1966             changed = TRUE;
1967          }
1968       }
1969       break;
1970 
1971    case OBJ_GROUP:
1972    case OBJ_SYM:
1973       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
1974             obj_ptr=obj_ptr->prev) {
1975          if (ChangeObjLineWidth(obj_ptr, nMask, W, AW, AH, width_spec, aw_spec,
1976                ah_spec)) {
1977             changed = TRUE;
1978          }
1979       }
1980       break;
1981    }
1982    if (changed) AdjObjBBox(ObjPtr);
1983    return changed;
1984 }
1985 
ChangeAllSelLineWidth(WidthIndex,HighLight)1986 void ChangeAllSelLineWidth(WidthIndex, HighLight)
1987    int WidthIndex, HighLight;
1988 {
1989    struct SelRec *sel_ptr;
1990    int ltx, lty, rbx, rby, changed=FALSE, w, aw, ah, dont_do_obj=FALSE;
1991    char *width_spec, *aw_spec, *ah_spec;
1992 
1993    if (topSel == NULL || stickyMenuSelection) {
1994       lineWidth = WidthIndex;
1995       ShowLineWidth();
1996       UpdatePinnedMenu(MENU_LINEWIDTH);
1997       if (topSel == NULL) dont_do_obj = TRUE;
1998    }
1999    sprintf(gszMsgBox, TgLoadString(STID_LINE_WIDTH_SET_TO_GIVEN_STR),
2000          curWidthOfLineSpec[WidthIndex]);
2001    Msg(gszMsgBox);
2002    if (dont_do_obj) return;
2003 
2004    w = curWidthOfLine[WidthIndex];
2005    aw = curArrowHeadW[WidthIndex];
2006    ah = curArrowHeadH[WidthIndex];
2007    width_spec = curWidthOfLineSpec[WidthIndex];
2008    aw_spec = curArrowHeadWSpec[WidthIndex];
2009    ah_spec = curArrowHeadHSpec[WidthIndex];
2010 
2011    if (HighLight) HighLightReverse();
2012    StartCompositeCmd();
2013    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2014       PrepareToReplaceAnObj(sel_ptr->obj);
2015       if (ChangeObjLineWidth(sel_ptr->obj, CHANGE_LINE_ALL, w, aw, ah,
2016             width_spec, aw_spec, ah_spec)) {
2017          changed = TRUE;
2018          RecordReplaceAnObj(sel_ptr->obj);
2019       } else {
2020          AbortPrepareCmd(CMD_REPLACE);
2021       }
2022    }
2023    EndCompositeCmd();
2024 
2025    if (changed) {
2026       SetFileModified(TRUE);
2027       ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
2028       UpdSelBBox();
2029       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2030             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1),
2031             selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
2032             selRbY+GRID_ABS_SIZE(1));
2033    }
2034    if (HighLight) HighLightForward();
2035 }
2036 
2037 static
GetLineWidthMatch(index,width,aw,ah)2038 int GetLineWidthMatch(index, width, aw, ah)
2039    int index, width, aw, ah;
2040 {
2041    int diff=0;
2042 
2043    if (width != INVALID && width != curWidthOfLine[index]) {
2044       diff += 10*abs(width-curWidthOfLine[index]);
2045    }
2046    if (aw != INVALID && aw != curArrowHeadW[index]) {
2047       diff += abs(aw-curArrowHeadW[index]);
2048    }
2049    if (ah != INVALID && ah != curArrowHeadH[index]) {
2050       diff += abs(ah-curArrowHeadH[index]);
2051    }
2052    return diff;
2053 }
2054 
GetBestLineWidthIndex(width,aw,ah)2055 int GetBestLineWidthIndex(width, aw, ah)
2056    int width, aw, ah;
2057 {
2058    int min_diff=0, min_index=0, index=0;
2059 
2060    min_diff = GetLineWidthMatch(0, width, aw, ah);
2061    for (index=1; index < maxLineWidths; index++) {
2062       int diff=GetLineWidthMatch(index, width, aw, ah);
2063 
2064       if (diff < min_diff) {
2065          min_diff = diff;
2066          min_index = index;
2067       }
2068    }
2069    return min_index;
2070 }
2071 
RefreshLineWidthMenu(menu)2072 void RefreshLineWidthMenu(menu)
2073    TgMenu *menu;
2074 {
2075    int i, num_items=menu->num_items;
2076    TgMenuItem *menuitems=menu->menuitems;
2077 
2078    for (i=0; i < num_items; i++) {
2079       TgMenuItem *menu_item=(&menuitems[i]);
2080       TgMenuItem stMenuItem;
2081 
2082       memset(&stMenuItem, 0, sizeof(TgMenuItem));
2083       stMenuItem.state = TGBS_NORMAL;
2084       stMenuItem.checked = (i == lineWidth);
2085       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
2086             &stMenuItem);
2087    }
2088 }
2089 
CreateLineWidthMenu(parent_menu,x,y,menu_info,status_str_xlated)2090 TgMenu *CreateLineWidthMenu(parent_menu, x, y, menu_info, status_str_xlated)
2091    TgMenu *parent_menu;
2092    int x, y;
2093    TgMenuInfo *menu_info;
2094    int status_str_xlated; /* ignored, always 0 */
2095 {
2096    int i=0;
2097    TgMenu *menu=NULL;
2098    TgMenuInfo stMenuInfo;
2099    TgMenuItemInfo *item_info=NULL;
2100 
2101    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
2102    stMenuInfo.items = (TgMenuItemInfo*)malloc(
2103          (maxLineWidths+1)*sizeof(TgMenuItemInfo));
2104    if (stMenuInfo.items == NULL) FailAllocMessage();
2105    memset(stMenuInfo.items, 0, (maxLineWidths+1)*sizeof(TgMenuItemInfo));
2106    for (item_info=stMenuInfo.items, i=0; i < maxLineWidths; item_info++, i++) {
2107       item_info->menu_str = (char*)(Pixmap*)(&lineWidthPixmap[i]);
2108       item_info->shortcut_str = NULL;
2109       sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_LINE_WIDTH_TO_GIVEN_S),
2110             curWidthOfLineSpec[i]);
2111       item_info->status_str = UtilStrDup(gszMsgBox);
2112       if (item_info->status_str == NULL) FailAllocMessage();
2113       item_info->submenu_info = NULL;
2114       item_info->cmdid = CMDID_CHANGEALLSELLINEWIDTH;
2115    }
2116    stMenuInfo.items[maxLineWidths].cmdid = INVALID;
2117 
2118    /* the status_str has been translated in TgLoadCachedString() */
2119    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
2120    for (item_info=stMenuInfo.items, i=0; i < maxLineWidths; item_info++, i++) {
2121       UtilFree(item_info->status_str);
2122    }
2123    memset(stMenuInfo.items, 0, (maxLineWidths+1)*sizeof(TgMenuItemInfo));
2124    free(stMenuInfo.items);
2125    stMenuInfo.items = NULL;
2126    if (menu != NULL) {
2127       TgMenuItem *menu_item=NULL;
2128       TgMenuItem stMenuItem;
2129 
2130       menu->track_menubar = TRUE;
2131       TgAdjustMenuGeometry(menu, menuImageW, menuImageH, maxLineWidths);
2132       menu_item = (&menu->menuitems[lineWidth]);
2133 
2134       memset(&stMenuItem, 0, sizeof(TgMenuItem));
2135       stMenuItem.checked = TRUE;
2136       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
2137          return TgDestroyMenu(menu, TRUE);
2138       }
2139    }
2140    return menu;
2141 }
2142 
LineWidthMenu(X,Y,TrackMenubar)2143 int LineWidthMenu(X, Y, TrackMenubar)
2144    int X, Y, TrackMenubar;
2145 {
2146    int rc=INVALID;
2147    TgMenu *menu=(lineWidthMenuInfo.create_proc)(NULL, X, Y, &lineWidthMenuInfo,
2148          INVALID);
2149 
2150    activeMenu = MENU_LINEWIDTH;
2151    if (menu != NULL) {
2152       menu->track_menubar = TrackMenubar;
2153 
2154       rc = TgMenuLoop(menu);
2155       TgDestroyMenu(menu, TRUE);
2156    }
2157    return rc;
2158 }
2159 
2160 /* ------------------ LineDash Functions ------------------ */
2161 
2162 static
ChangeObjLineDash(ObjPtr,DashIndex)2163 int ChangeObjLineDash(ObjPtr, DashIndex)
2164    struct ObjRec *ObjPtr;
2165    int DashIndex;
2166 {
2167    register struct ObjRec *obj_ptr;
2168    int changed=FALSE;
2169 
2170    switch (ObjPtr->type) {
2171    case OBJ_POLY:
2172       if (ObjPtr->detail.p->dash != DashIndex) {
2173          ObjPtr->detail.p->dash = DashIndex;
2174          changed = TRUE;
2175       }
2176       break;
2177    case OBJ_BOX:
2178       if (ObjPtr->detail.b->dash != DashIndex) {
2179          ObjPtr->detail.b->dash = DashIndex;
2180          changed = TRUE;
2181       }
2182       break;
2183    case OBJ_OVAL:
2184       if (ObjPtr->detail.o->dash != DashIndex) {
2185          ObjPtr->detail.o->dash = DashIndex;
2186          changed = TRUE;
2187       }
2188       break;
2189    case OBJ_POLYGON:
2190       if (ObjPtr->detail.g->dash != DashIndex) {
2191          ObjPtr->detail.g->dash = DashIndex;
2192          changed = TRUE;
2193       }
2194       break;
2195    case OBJ_ARC:
2196       if (ObjPtr->detail.a->dash != DashIndex) {
2197          ObjPtr->detail.a->dash = DashIndex;
2198          changed = TRUE;
2199       }
2200       break;
2201    case OBJ_RCBOX:
2202       if (ObjPtr->detail.rcb->dash != DashIndex) {
2203          ObjPtr->detail.rcb->dash = DashIndex;
2204          changed = TRUE;
2205       }
2206       break;
2207 
2208    case OBJ_GROUP:
2209    case OBJ_SYM:
2210       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
2211             obj_ptr=obj_ptr->prev) {
2212          if (ChangeObjLineDash(obj_ptr, DashIndex)) {
2213             changed = TRUE;
2214          }
2215       }
2216       break;
2217    }
2218    return changed;
2219 }
2220 
ChangeAllSelLineDash(DashIndex,HighLight)2221 void ChangeAllSelLineDash(DashIndex, HighLight)
2222    int DashIndex, HighLight;
2223 {
2224    register struct SelRec *sel_ptr;
2225    int changed=FALSE;
2226 
2227    if (topSel == NULL || stickyMenuSelection) {
2228       curDash = DashIndex;
2229       ShowDash();
2230       UpdatePinnedMenu(MENU_LINEDASH);
2231       if (topSel == NULL) return;
2232    }
2233 
2234    if (HighLight) HighLightReverse();
2235    StartCompositeCmd();
2236    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2237       PrepareToReplaceAnObj(sel_ptr->obj);
2238       if (ChangeObjLineDash(sel_ptr->obj, DashIndex)) {
2239          changed = TRUE;
2240          RecordReplaceAnObj(sel_ptr->obj);
2241       } else {
2242          AbortPrepareCmd(CMD_REPLACE);
2243       }
2244    }
2245    EndCompositeCmd();
2246 
2247    if (changed) {
2248       SetFileModified(TRUE);
2249       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2250             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2251    }
2252    if (HighLight) HighLightForward();
2253 }
2254 
RefreshLineDashMenu(menu)2255 void RefreshLineDashMenu(menu)
2256    TgMenu *menu;
2257 {
2258    int i, num_items=menu->num_items;
2259    TgMenuItem *menuitems=menu->menuitems;
2260 
2261    for (i=0; i < num_items; i++) {
2262       TgMenuItem *menu_item=(&menuitems[i]);
2263       TgMenuItem stMenuItem;
2264 
2265       memset(&stMenuItem, 0, sizeof(TgMenuItem));
2266       stMenuItem.state = TGBS_NORMAL;
2267       stMenuItem.checked = (i == curDash);
2268       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
2269             &stMenuItem);
2270    }
2271 }
2272 
CreateLineDashMenu(parent_menu,x,y,menu_info,status_str_xlated)2273 TgMenu *CreateLineDashMenu(parent_menu, x, y, menu_info, status_str_xlated)
2274    TgMenu *parent_menu;
2275    int x, y;
2276    TgMenuInfo *menu_info;
2277    int status_str_xlated; /* ignored, always 0 */
2278 {
2279    int i=0;
2280    TgMenu *menu=NULL;
2281    TgMenuInfo stMenuInfo;
2282    TgMenuItemInfo *item_info=NULL;
2283 
2284    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
2285    stMenuInfo.items = (TgMenuItemInfo*)malloc(
2286          (MAXDASHES+1)*sizeof(TgMenuItemInfo));
2287    if (stMenuInfo.items == NULL) FailAllocMessage();
2288    memset(stMenuInfo.items, 0, (MAXDASHES+1)*sizeof(TgMenuItemInfo));
2289    for (item_info=stMenuInfo.items, i=0; i < MAXDASHES; item_info++, i++) {
2290       item_info->menu_str = (char*)(Pixmap*)(&lineDashPixmap[i]);
2291       item_info->shortcut_str = NULL;
2292       if (i == 0) {
2293          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_PEN_DASH_PAT_NO_DASH));
2294       } else {
2295          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_PEN_DASH_PAT_PAT_NUM),
2296                i);
2297       }
2298       item_info->status_str = UtilStrDup(gszMsgBox);
2299       if (item_info->status_str == NULL) FailAllocMessage();
2300       item_info->submenu_info = NULL;
2301       item_info->cmdid = CMDID_CHANGEALLSELLINEDASH;
2302    }
2303    stMenuInfo.items[MAXDASHES].cmdid = INVALID;
2304 
2305    /* the status_str has been translated in TgLoadCachedString() */
2306    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
2307    for (item_info=stMenuInfo.items, i=0; i < MAXDASHES; item_info++, i++) {
2308       UtilFree(item_info->status_str);
2309    }
2310    memset(stMenuInfo.items, 0, (MAXDASHES+1)*sizeof(TgMenuItemInfo));
2311    free(stMenuInfo.items);
2312    stMenuInfo.items = NULL;
2313    if (menu != NULL) {
2314       TgMenuItem *menu_item=NULL;
2315       TgMenuItem stMenuItem;
2316 
2317       menu->track_menubar = TRUE;
2318       TgAdjustMenuGeometry(menu, menuImageW, menuImageH, MAXDASHES);
2319       menu_item = (&menu->menuitems[curDash]);
2320 
2321       memset(&stMenuItem, 0, sizeof(TgMenuItem));
2322       stMenuItem.checked = TRUE;
2323       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
2324          return TgDestroyMenu(menu, TRUE);
2325       }
2326    }
2327    return menu;
2328 }
2329 
LineDashMenu(X,Y,TrackMenubar)2330 int LineDashMenu(X, Y, TrackMenubar)
2331    int X, Y, TrackMenubar;
2332 {
2333    int rc=INVALID;
2334    TgMenu *menu=(lineDashMenuInfo.create_proc)(NULL, X, Y, &lineDashMenuInfo,
2335          INVALID);
2336 
2337    activeMenu = MENU_LINEDASH;
2338    if (menu != NULL) {
2339       menu->track_menubar = TrackMenubar;
2340 
2341       rc = TgMenuLoop(menu);
2342       TgDestroyMenu(menu, TRUE);
2343    }
2344    return rc;
2345 }
2346 
2347 /* ------------------ Pen Functions ------------------ */
2348 
ChangeObjPen(ObjPtr,PenIndex)2349 int ChangeObjPen(ObjPtr, PenIndex)
2350    struct ObjRec *ObjPtr;
2351    int PenIndex;
2352 {
2353    register struct ObjRec *obj_ptr;
2354    int changed=FALSE;
2355 
2356    switch (ObjPtr->type) {
2357    case OBJ_POLY:
2358       if (ObjPtr->detail.p->pen != PenIndex) {
2359          ObjPtr->detail.p->pen = PenIndex;
2360          changed = TRUE;
2361       }
2362       break;
2363    case OBJ_TEXT:
2364       if (ObjPtr->detail.t->pen != PenIndex) {
2365          ObjPtr->detail.t->pen = PenIndex;
2366          AdjObjCache(ObjPtr);
2367          changed = TRUE;
2368       }
2369       break;
2370    case OBJ_BOX:
2371       if (ObjPtr->detail.b->pen != PenIndex) {
2372          ObjPtr->detail.b->pen = PenIndex;
2373          changed = TRUE;
2374       }
2375       break;
2376    case OBJ_OVAL:
2377       if (ObjPtr->detail.o->pen != PenIndex) {
2378          ObjPtr->detail.o->pen = PenIndex;
2379          changed = TRUE;
2380       }
2381       break;
2382    case OBJ_POLYGON:
2383       if (ObjPtr->detail.g->pen != PenIndex) {
2384          ObjPtr->detail.g->pen = PenIndex;
2385          changed = TRUE;
2386       }
2387       break;
2388    case OBJ_ARC:
2389       if (ObjPtr->detail.a->pen != PenIndex) {
2390          ObjPtr->detail.a->pen = PenIndex;
2391          changed = TRUE;
2392       }
2393       break;
2394    case OBJ_RCBOX:
2395       if (ObjPtr->detail.rcb->pen != PenIndex) {
2396          ObjPtr->detail.rcb->pen = PenIndex;
2397          changed = TRUE;
2398       }
2399       break;
2400 
2401    case OBJ_GROUP:
2402    case OBJ_SYM:
2403       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
2404             obj_ptr=obj_ptr->prev) {
2405          if (ChangeObjPen(obj_ptr, PenIndex)) {
2406             changed = TRUE;
2407          }
2408       }
2409       break;
2410    }
2411    if (changePropertiesOfAttrs && ObjPtr->type != OBJ_TEXT) {
2412       struct AttrRec *attr_ptr=ObjPtr->fattr;
2413 
2414       for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
2415          changed |= ChangeObjPen(attr_ptr->obj, PenIndex);
2416       }
2417    }
2418    return changed;
2419 }
2420 
ChangeAllSelPen(PenIndex,HighLight)2421 void ChangeAllSelPen(PenIndex, HighLight)
2422    int PenIndex, HighLight;
2423 {
2424    register struct SelRec *sel_ptr;
2425    int changed=FALSE;
2426 
2427    if (topSel == NULL || stickyMenuSelection) {
2428       if (!(curChoice == DRAWTEXT && textCursorShown)) {
2429          TieLooseEnds();
2430       }
2431       penPat = PenIndex;
2432       if (curChoice == DRAWTEXT && textCursorShown) {
2433          if (ChangeObjPen(curTextObj, PenIndex)) {
2434             curTextModified = TRUE;
2435             UpdCurTextBBox();
2436             RedrawCurText();
2437             SetFileModified(TRUE);
2438             if (cycleThroughChoice) {
2439                SetPushedFontValue(PUSH_PEN, penPat);
2440             }
2441          }
2442       } else {
2443          textCursorShown = FALSE;
2444       }
2445       ShowPen();
2446       UpdatePinnedMenu(MENU_PEN);
2447       if (topSel == NULL) return;
2448    }
2449 
2450    if (HighLight) HighLightReverse();
2451    StartCompositeCmd();
2452    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2453       PrepareToReplaceAnObj(sel_ptr->obj);
2454       if (ChangeObjPen(sel_ptr->obj, PenIndex)) {
2455          changed = TRUE;
2456          RecordReplaceAnObj(sel_ptr->obj);
2457       } else {
2458          AbortPrepareCmd(CMD_REPLACE);
2459       }
2460    }
2461    EndCompositeCmd();
2462 
2463    if (changed) {
2464       SetFileModified(TRUE);
2465       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2466             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2467    }
2468    if (HighLight) HighLightForward();
2469 }
2470 
RefreshPenMenu(menu)2471 void RefreshPenMenu(menu)
2472    TgMenu *menu;
2473 {
2474    int i, num_items=menu->num_items;
2475    TgMenuItem *menuitems=menu->menuitems;
2476 
2477    for (i=0; i < num_items; i++) {
2478       TgMenuItem *menu_item=(&menuitems[i]);
2479       TgMenuItem stMenuItem;
2480 
2481       memset(&stMenuItem, 0, sizeof(TgMenuItem));
2482       stMenuItem.state = TGBS_NORMAL;
2483       stMenuItem.checked = (i == penPat);
2484       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
2485             &stMenuItem);
2486    }
2487 }
2488 
CreatePenMenu(parent_menu,x,y,menu_info,status_str_xlated)2489 TgMenu *CreatePenMenu(parent_menu, x, y, menu_info, status_str_xlated)
2490    TgMenu *parent_menu;
2491    int x, y;
2492    TgMenuInfo *menu_info;
2493    int status_str_xlated; /* ignored, always 0 */
2494 {
2495    int i=0;
2496    TgMenu *menu=NULL;
2497    TgMenuInfo stMenuInfo;
2498    TgMenuItemInfo *item_info=NULL;
2499 
2500    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
2501    stMenuInfo.items = (TgMenuItemInfo*)malloc(
2502          (MAXPATTERNS+1)*sizeof(TgMenuItemInfo));
2503    if (stMenuInfo.items == NULL) FailAllocMessage();
2504    memset(stMenuInfo.items, 0, (MAXPATTERNS+1)*sizeof(TgMenuItemInfo));
2505    for (item_info=stMenuInfo.items, i=0; i < MAXPATTERNS; item_info++, i++) {
2506       item_info->menu_str = (char*)(Pixmap*)(&patPixmap[i]);
2507       item_info->shortcut_str = NULL;
2508       switch (i) {
2509       case NONEPAT:
2510          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_PEN_TO_NONE));
2511          break;
2512       case SOLIDPAT:
2513          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_PEN_TO_SOLID));
2514          break;
2515       case BACKPAT:
2516          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_PEN_TO_BACKGROUND));
2517          break;
2518       default:
2519          sprintf(gszMsgBox, TgLoadCachedString(CSTID_SET_PEN_TO_PAT_NUM), i);
2520          break;
2521       }
2522       item_info->status_str = UtilStrDup(gszMsgBox);
2523       if (item_info->status_str == NULL) FailAllocMessage();
2524       item_info->submenu_info = NULL;
2525       item_info->cmdid = CMDID_CHANGEALLSELPEN;
2526    }
2527    stMenuInfo.items[MAXPATTERNS].cmdid = INVALID;
2528 
2529    /* the status_str has been translated in TgLoadCachedString() */
2530    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
2531    for (item_info=stMenuInfo.items, i=0; i < MAXPATTERNS; item_info++, i++) {
2532       UtilFree(item_info->status_str);
2533    }
2534    memset(stMenuInfo.items, 0, (MAXPATTERNS+1)*sizeof(TgMenuItemInfo));
2535    free(stMenuInfo.items);
2536    stMenuInfo.items = NULL;
2537    if (menu != NULL) {
2538       TgMenuItem *menu_item=NULL;
2539       TgMenuItem stMenuItem;
2540 
2541       menu->track_menubar = TRUE;
2542       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, 8);
2543       menu_item = (&menu->menuitems[penPat]);
2544 
2545       memset(&stMenuItem, 0, sizeof(TgMenuItem));
2546       stMenuItem.checked = TRUE;
2547       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
2548          return TgDestroyMenu(menu, TRUE);
2549       }
2550    }
2551    return menu;
2552 }
2553 
PenMenu(X,Y,TrackMenubar)2554 int PenMenu(X, Y, TrackMenubar)
2555    int X, Y, TrackMenubar;
2556 {
2557    int rc=INVALID;
2558    TgMenu *menu=(penMenuInfo.create_proc)(NULL, X, Y, &penMenuInfo, INVALID);
2559 
2560    activeMenu = MENU_PEN;
2561    if (menu != NULL) {
2562       menu->track_menubar = TrackMenubar;
2563 
2564       rc = TgMenuLoop(menu);
2565       TgDestroyMenu(menu, TRUE);
2566    }
2567    return rc;
2568 }
2569 
2570 /* ------------------ Toggling and Changing Functions ------------------ */
2571 
2572 static
ToggleObjLineType(ObjPtr)2573 int ToggleObjLineType(ObjPtr)
2574    struct ObjRec *ObjPtr;
2575 {
2576    register struct ObjRec *obj_ptr;
2577    register int changed=FALSE;
2578 
2579    switch (ObjPtr->type) {
2580    case OBJ_POLY:
2581       ObjPtr->detail.p->curved = (ObjPtr->detail.p->curved+1) % MAXLINETYPES;
2582       changed = TRUE;
2583       AdjObjSplineVs(ObjPtr);
2584       if (ObjPtr->detail.p->curved != LT_INTSPLINE) {
2585          UpdPolyBBox(ObjPtr, ObjPtr->detail.p->n,
2586                ObjPtr->detail.p->vlist);
2587       } else {
2588          UpdPolyBBox(ObjPtr, ObjPtr->detail.p->intn,
2589                ObjPtr->detail.p->intvlist);
2590       }
2591       break;
2592    case OBJ_POLYGON:
2593       ObjPtr->detail.g->curved = (ObjPtr->detail.g->curved+1) % MAXLINETYPES;
2594       changed = TRUE;
2595       AdjObjSplineVs(ObjPtr);
2596       if (ObjPtr->detail.g->curved != LT_INTSPLINE) {
2597          UpdPolyBBox(ObjPtr, ObjPtr->detail.g->n,
2598                ObjPtr->detail.g->vlist);
2599       } else {
2600          UpdPolyBBox(ObjPtr, ObjPtr->detail.g->intn,
2601                ObjPtr->detail.g->intvlist);
2602       }
2603       break;
2604 
2605    case OBJ_GROUP:
2606    case OBJ_SYM:
2607       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
2608             obj_ptr=obj_ptr->prev) {
2609          if (ToggleObjLineType(obj_ptr)) {
2610             changed = TRUE;
2611          }
2612       }
2613       break;
2614    }
2615    if (changed) AdjObjBBox(ObjPtr);
2616    return changed;
2617 }
2618 
ToggleAllSelLineType()2619 void ToggleAllSelLineType()
2620 {
2621    register struct SelRec *sel_ptr;
2622    register int changed=FALSE;
2623 
2624    if (topSel == NULL) {
2625       curSpline = (curSpline+1) % MAXLINETYPES;
2626       ShowLineType();
2627       UpdatePinnedMenu(MENU_LINETYPE);
2628       return;
2629    }
2630 
2631    HighLightReverse();
2632    StartCompositeCmd();
2633    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2634       PrepareToReplaceAnObj(sel_ptr->obj);
2635       if (ToggleObjLineType(sel_ptr->obj)) {
2636          changed = TRUE;
2637          RecordReplaceAnObj(sel_ptr->obj);
2638       } else {
2639          AbortPrepareCmd(CMD_REPLACE);
2640       }
2641    }
2642    EndCompositeCmd();
2643 
2644    if (changed) {
2645       SetFileModified(TRUE);
2646       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2647             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2648    }
2649    HighLightForward();
2650 }
2651 
2652 static
ChangeObjRCBRadius(ObjPtr,Radius)2653 int ChangeObjRCBRadius(ObjPtr, Radius)
2654    struct ObjRec *ObjPtr;
2655    int Radius;
2656 {
2657    register struct ObjRec *obj_ptr;
2658    int changed=FALSE;
2659 
2660    switch (ObjPtr->type) {
2661    case OBJ_RCBOX:
2662       if (ObjPtr->detail.rcb->radius != Radius) {
2663          ObjPtr->detail.rcb->radius = Radius;
2664          AdjObjCache(ObjPtr);
2665          changed = TRUE;
2666       }
2667       break;
2668 
2669    case OBJ_GROUP:
2670    case OBJ_SYM:
2671       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
2672             obj_ptr=obj_ptr->prev) {
2673          if (ChangeObjRCBRadius(obj_ptr, Radius)) {
2674             changed = TRUE;
2675          }
2676       }
2677       break;
2678    }
2679    return changed;
2680 }
2681 
ChangeAllSelRCBRadius(Radius)2682 void ChangeAllSelRCBRadius(Radius)
2683    int Radius;
2684 {
2685    register struct SelRec *sel_ptr;
2686    int changed=FALSE;
2687 
2688    if (topSel == NULL) {
2689       rcbRadius = Radius;
2690       ShowRCBRadius();
2691       return;
2692    }
2693 
2694    HighLightReverse();
2695    StartCompositeCmd();
2696    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2697       PrepareToReplaceAnObj(sel_ptr->obj);
2698       if (ChangeObjRCBRadius(sel_ptr->obj, Radius)) {
2699          changed = TRUE;
2700          RecordReplaceAnObj(sel_ptr->obj);
2701       } else {
2702          AbortPrepareCmd(CMD_REPLACE);
2703       }
2704    }
2705    EndCompositeCmd();
2706 
2707    if (changed) {
2708       SetFileModified(TRUE);
2709       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
2710             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
2711    }
2712    HighLightForward();
2713 }
2714 
UpdateSelObjs()2715 void UpdateSelObjs()
2716 {
2717    struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
2718 
2719    if (topSel == NULL) {
2720       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2721       return;
2722    }
2723    BackupCopiedProperties();
2724    HighLightReverse();
2725 
2726    topSel = botSel = NULL;
2727    CopyProperties(FALSE);
2728 
2729    topSel = saved_top_sel;
2730    botSel = saved_bot_sel;
2731    PasteProperties(FALSE);
2732 
2733    HighLightForward();
2734    RestoreCopiedProperties();
2735 }
2736 
ChangeAllSelRealLineWidth(nMask,Width,AW,AH,width_spec,aw_spec,ah_spec,HighLight)2737 void ChangeAllSelRealLineWidth(nMask, Width, AW, AH,
2738       width_spec, aw_spec, ah_spec, HighLight)
2739    int nMask, Width, AW, AH, HighLight;
2740    char *width_spec, *aw_spec, *ah_spec;
2741 {
2742    register struct SelRec *sel_ptr;
2743    int changed=FALSE;
2744 
2745    if (topSel == NULL) {
2746       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2747       return;
2748    }
2749    if (HighLight) HighLightReverse();
2750    StartCompositeCmd();
2751    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
2752       PrepareToReplaceAnObj(sel_ptr->obj);
2753       if (ChangeObjLineWidth(sel_ptr->obj, nMask, Width, AW, AH,
2754             width_spec, aw_spec, ah_spec)) {
2755          changed = TRUE;
2756          RecordReplaceAnObj(sel_ptr->obj);
2757       } else {
2758          AbortPrepareCmd(CMD_REPLACE);
2759       }
2760    }
2761    EndCompositeCmd();
2762 
2763    if (changed) {
2764       int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
2765 
2766       SetFileModified(TRUE);
2767       UpdSelBBox();
2768       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2769             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1), selLtX-GRID_ABS_SIZE(1),
2770             selLtY-GRID_ABS_SIZE(1), selRbX+GRID_ABS_SIZE(1),
2771             selRbY+GRID_ABS_SIZE(1));
2772    }
2773    if (HighLight) HighLightForward();
2774 }
2775 
SetSelLineWidth(pszBuf)2776 void SetSelLineWidth(pszBuf)
2777    char *pszBuf;
2778 {
2779    char spec[MAXSTRING+1], *w_str=NULL, *aw_str=NULL, *ah_str=NULL, *c_ptr=NULL;
2780    int w=(-1), aw=(-1), ah=(-1), mult_set=FALSE;
2781    char width_spec[40], aw_spec[40], ah_spec[40];
2782    float fw, faw, fah, mult=((float)1.0);
2783 
2784    if (topSel == NULL) {
2785       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2786       return;
2787    }
2788    *spec = '\0';
2789    if (pszBuf == NULL) {
2790       Dialog(TgLoadString(STID_ENTER_LINE_WIDTH_OPT_AW_AH),
2791             TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL), spec);
2792    } else {
2793       UtilStrCpyN(spec, sizeof(spec), pszBuf);
2794    }
2795    UtilTrimBlanks(spec);
2796    if (*spec == '\0') return;
2797    *width_spec = *aw_spec = *ah_spec = '\0';
2798    if ((w_str=strtok(spec, ", \t\n\r")) == NULL) return;
2799    UtilTrimBlanks(w_str);
2800    if ((c_ptr=strstr(w_str, "in")) != NULL ||
2801          (c_ptr=strstr(w_str, "In")) != NULL ||
2802          (c_ptr=strstr(w_str, "IN")) != NULL) {
2803       *c_ptr = '\0';
2804       mult = (float)PIX_PER_INCH;
2805       mult_set = TRUE;
2806    } else if ((c_ptr=strstr(w_str, "cm")) != NULL ||
2807          (c_ptr=strstr(w_str, "Cm")) != NULL ||
2808          (c_ptr=strstr(w_str, "CM")) != NULL) {
2809       *c_ptr = '\0';
2810       mult = (float)ONE_CM;
2811       mult_set = TRUE;
2812    }
2813    if (sscanf(w_str, "%f", &fw) != 1 || fw < (float)0.0) {
2814       sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_STR_WIDTH), w_str);
2815       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2816       return;
2817    }
2818    if (mult_set) {
2819       fw *= mult;
2820       sprintf(width_spec, "%.3f", fw);
2821    } else {
2822       UtilStrCpyN(width_spec, sizeof(width_spec), w_str);
2823    }
2824    w = round(fw);
2825 
2826    if ((aw_str=strtok(NULL, ", \t\n\r")) != NULL &&
2827          (ah_str=strtok(NULL, ", \t\n\r")) != NULL) {
2828       int aw_mult_set=FALSE, ah_mult_set=FALSE;
2829       float aw_mult=((float)1.0), ah_mult=((float)1.0);
2830 
2831       UtilTrimBlanks(aw_str);
2832       UtilTrimBlanks(ah_str);
2833 
2834       if ((c_ptr=strstr(aw_str, "in")) != NULL ||
2835             (c_ptr=strstr(aw_str, "In")) != NULL ||
2836             (c_ptr=strstr(aw_str, "IN")) != NULL) {
2837          *c_ptr = '\0';
2838          aw_mult = (float)PIX_PER_INCH;
2839          aw_mult_set = TRUE;
2840       } else if ((c_ptr=strstr(aw_str, "cm")) != NULL ||
2841             (c_ptr=strstr(aw_str, "Cm")) != NULL ||
2842             (c_ptr=strstr(aw_str, "CM")) != NULL) {
2843          *c_ptr = '\0';
2844          aw_mult = (float)ONE_CM;
2845          aw_mult_set = TRUE;
2846       }
2847       if ((c_ptr=strstr(ah_str, "in")) != NULL ||
2848             (c_ptr=strstr(ah_str, "In")) != NULL ||
2849             (c_ptr=strstr(ah_str, "IN")) != NULL) {
2850          *c_ptr = '\0';
2851          ah_mult = (float)PIX_PER_INCH;
2852          ah_mult_set = TRUE;
2853       } else if ((c_ptr=strstr(ah_str, "cm")) != NULL ||
2854             (c_ptr=strstr(ah_str, "Cm")) != NULL ||
2855             (c_ptr=strstr(ah_str, "CM")) != NULL) {
2856          *c_ptr = '\0';
2857          ah_mult = (float)ONE_CM;
2858          ah_mult_set = TRUE;
2859       }
2860       if (sscanf(aw_str, "%f", &faw) != 1 || faw < (float)0.0 ||
2861             sscanf(ah_str, "%f", &fah) != 1 || fah < (float)0.0) {
2862          sprintf(gszMsgBox, TgLoadString(STID_INVALID_GIVEN_STR_AW_AH),
2863                aw_str, ah_str);
2864          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2865          return;
2866       }
2867       if (aw_mult_set) {
2868          faw *= aw_mult;
2869          sprintf(aw_spec, "%.3f", faw);
2870       } else {
2871          UtilStrCpyN(aw_spec, sizeof(aw_spec), aw_str);
2872       }
2873       aw = round(faw);
2874 
2875       if (ah_mult_set) {
2876          fah *= ah_mult;
2877          sprintf(ah_spec, "%.3f", fah);
2878       } else {
2879          UtilStrCpyN(ah_spec, sizeof(ah_spec), ah_str);
2880       }
2881       ah = round(fah);
2882    }
2883    ChangeAllSelRealLineWidth(CHANGE_LINE_ALL, w, aw, ah,
2884          width_spec, aw_spec, ah_spec, TRUE);
2885 }
2886 
2887