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/align.c,v 1.25 2011/05/16 16:21:56 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_ALIGN_C_
22 
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25 
26 #include "align.e"
27 #include "auxtext.e"
28 #include "button.e"
29 #include "choice.e"
30 #include "cmd.e"
31 #include "color.e"
32 #include "dialog.e"
33 #include "drawing.e"
34 #include "dup.e"
35 #include "grid.e"
36 #include "mark.e"
37 #include "mainmenu.e"
38 #include "menu.e"
39 #include "menuinfo.e"
40 #include "move.e"
41 #include "msg.e"
42 #include "obj.e"
43 #include "poly.e"
44 #include "raster.e"
45 #include "rect.e"
46 #include "select.e"
47 #include "setup.e"
48 #include "stretch.e"
49 #include "strtbl.e"
50 #include "util.e"
51 
52 typedef struct DistrVRec {
53    struct ObjRec *obj;
54    struct VSelRec *vsel;
55    int index, vindex, x, y;
56    struct DistrVRec *next, *prev;
57 } * DistrVRecPtr;
58 
59 int	horiAlign=ALIGN_L;
60 int	vertAlign=ALIGN_T;
61 
62 int	alignDirectType=INVALID;
63 
64 static
SetSSSIForDistr(obj_ptr,vsel_ptr,update_pmvi)65 void SetSSSIForDistr(obj_ptr, vsel_ptr, update_pmvi)
66    struct ObjRec *obj_ptr;
67    struct VSelRec *vsel_ptr;
68    int update_pmvi;
69 {
70    IntPoint *vlist=NULL;
71    int i=0, n=0;
72    StretchStructuredSplineInfo *psssi=NULL;
73 
74    switch (obj_ptr->type) {
75    case OBJ_POLY:
76       vlist = obj_ptr->detail.p->vlist;
77       n = obj_ptr->detail.p->n;
78       if (obj_ptr->userdata == NULL &&
79             obj_ptr->detail.p->curved == LT_STRUCT_SPLINE) {
80          psssi = (StretchStructuredSplineInfo*)malloc(
81                sizeof(StretchStructuredSplineInfo));
82          if (psssi == NULL) FailAllocMessage();
83          memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
84 
85          SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], n, vlist, psssi);
86 
87          psssi->orig_abs_x = psssi->new_abs_x = vlist[vsel_ptr->v_index[0]].x;
88          psssi->orig_abs_y = psssi->new_abs_y = vlist[vsel_ptr->v_index[0]].y;
89          obj_ptr->userdata = psssi;
90          if (obj_ptr->ctm != NULL) {
91             psssi->rotated_orig_abs_x = psssi->rotated_new_abs_x =
92                   vsel_ptr->x[0];
93             psssi->rotated_orig_abs_y = psssi->rotated_new_abs_y =
94                   vsel_ptr->y[0];
95          }
96       }
97       if (update_pmvi && vsel_ptr->pmvi == NULL &&
98             obj_ptr->detail.p->curved != LT_STRUCT_SPLINE) {
99          vsel_ptr->pmvi = (MoveVertexInfo*)malloc(
100                vsel_ptr->n*sizeof(MoveVertexInfo));
101          memset(vsel_ptr->pmvi, 0, vsel_ptr->n*sizeof(MoveVertexInfo));
102 
103          for (i=0; i < vsel_ptr->n; i++) {
104             vsel_ptr->pmvi[i].orig_abs_x = vsel_ptr->pmvi[i].new_abs_x =
105                   vlist[vsel_ptr->v_index[i]].x;
106             vsel_ptr->pmvi[i].orig_abs_y = vsel_ptr->pmvi[i].new_abs_y =
107                   vlist[vsel_ptr->v_index[i]].y;
108             if (obj_ptr->ctm != NULL) {
109                vsel_ptr->pmvi[i].rotated_orig_abs_x =
110                      vsel_ptr->pmvi[i].rotated_new_abs_x = vsel_ptr->x[i];
111                vsel_ptr->pmvi[i].rotated_orig_abs_y =
112                      vsel_ptr->pmvi[i].rotated_new_abs_y = vsel_ptr->y[i];
113             }
114          }
115       }
116       break;
117    case OBJ_POLYGON:
118       vlist = obj_ptr->detail.g->vlist;
119       n = obj_ptr->detail.g->n;
120       if (obj_ptr->userdata == NULL &&
121             obj_ptr->detail.g->curved == LT_STRUCT_SPLINE) {
122          psssi = (StretchStructuredSplineInfo*)malloc(
123                sizeof(StretchStructuredSplineInfo));
124          if (psssi == NULL) FailAllocMessage();
125          memset(psssi, 0, sizeof(StretchStructuredSplineInfo));
126 
127          SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], n, vlist, psssi);
128 
129          psssi->orig_abs_x = psssi->new_abs_x = vlist[vsel_ptr->v_index[0]].x;
130          psssi->orig_abs_y = psssi->new_abs_y = vlist[vsel_ptr->v_index[0]].y;
131          obj_ptr->userdata = psssi;
132          if (obj_ptr->ctm != NULL) {
133             psssi->rotated_orig_abs_x = psssi->rotated_new_abs_x =
134                   vsel_ptr->x[0];
135             psssi->rotated_orig_abs_y = psssi->rotated_new_abs_y =
136                   vsel_ptr->y[0];
137          }
138       }
139       if (update_pmvi && vsel_ptr->pmvi == NULL &&
140             obj_ptr->detail.g->curved != LT_STRUCT_SPLINE) {
141          vsel_ptr->pmvi = (MoveVertexInfo*)malloc(
142                vsel_ptr->n*sizeof(MoveVertexInfo));
143          memset(vsel_ptr->pmvi, 0, vsel_ptr->n*sizeof(MoveVertexInfo));
144 
145          for (i=0; i < vsel_ptr->n; i++) {
146             vsel_ptr->pmvi[i].orig_abs_x = vsel_ptr->pmvi[i].new_abs_x =
147                   vlist[vsel_ptr->v_index[i]].x;
148             vsel_ptr->pmvi[i].orig_abs_y = vsel_ptr->pmvi[i].new_abs_y =
149                   vlist[vsel_ptr->v_index[i]].y;
150             if (obj_ptr->ctm != NULL) {
151                vsel_ptr->pmvi[i].rotated_orig_abs_x =
152                      vsel_ptr->pmvi[i].rotated_new_abs_x = vsel_ptr->x[i];
153                vsel_ptr->pmvi[i].rotated_orig_abs_y =
154                      vsel_ptr->pmvi[i].rotated_new_abs_y = vsel_ptr->y[i];
155             }
156          }
157       }
158       break;
159    }
160 }
161 
DistrSelObjs()162 void DistrSelObjs()
163 {
164    int i=0, dx=0, dy=0, ltx, lty, rbx, rby, count, w, h;
165    struct SelRec *sel_ptr=NULL, *next_sel=NULL;
166    struct ObjRec *obj_ptr=NULL;
167    struct VSelRec *vsel_ptr=NULL;
168    double x=0.0, y=0.0, h_dist=0.0, v_dist=0.0;
169 
170    if ((topSel==NULL && topVSel==NULL) ||
171          (horiAlign==ALIGN_N && vertAlign==ALIGN_N)) {
172       return;
173    }
174    if (numObjLocked != 0) {
175       MsgBox(TgLoadString(STID_CANNOT_DISTRIBUTE_LOCKED_OBJS),
176             TOOL_NAME, INFO_MB);
177       return;
178    }
179    if (curChoice == VERTEXMODE) {
180       int start=0, vertices_count=0;
181       struct DistrVRec *dv_ptr=NULL, *left_dv=NULL, *right_dv=NULL;
182       struct DistrVRec *top_dv=NULL, *bottom_dv=NULL;
183       struct DistrVRec *ptr=NULL, *hori_dv=NULL, *vert_dv=NULL;
184       struct SelRec *tmp_top_sel=NULL, *tmp_bot_sel=NULL, *tmp_sel_ptr=NULL;
185       StretchStructuredSplineInfo *psssi=NULL;
186 
187       if ((vertices_count=CountSelectedVertices()) <= 2) return;
188 
189       HighLightReverse();
190 
191       dv_ptr = (struct DistrVRec *)malloc(
192             2*vertices_count*sizeof(struct DistrVRec));
193       if (dv_ptr == NULL) FailAllocMessage();
194 
195       start = 1;
196 
197       ptr = dv_ptr;
198       ptr->obj = topVSel->obj;
199       ptr->vsel = topVSel;
200       ptr->index = topVSel->v_index[0];
201       ptr->vindex = 0;
202       ptr->x = topVSel->x[0];
203       ptr->y = topVSel->y[0];
204       ptr->next = ptr->prev = NULL;
205       left_dv = right_dv = ptr;
206 
207       ptr++;
208       ptr->obj = topVSel->obj;
209       ptr->vsel = topVSel;
210       ptr->index = topVSel->v_index[0];
211       ptr->vindex = 0;
212       ptr->x = topVSel->x[0];
213       ptr->y = topVSel->y[0];
214       ptr->next = ptr->prev = NULL;
215       top_dv = bottom_dv = ptr;
216 
217       ptr++;
218       for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
219          sel_ptr->obj->marked = FALSE;
220          sel_ptr->obj->userdata = NULL;
221       }
222       for (vsel_ptr=topVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->next) {
223          int obj_type=vsel_ptr->obj->type, last_index=0, n=0;
224 
225          if (obj_type == OBJ_POLYGON) {
226             last_index = vsel_ptr->obj->detail.g->n-1;
227          }
228          obj_ptr = vsel_ptr->obj;
229          n = vsel_ptr->n;
230          for (i=start; i < n; i++) {
231             if (!(obj_type==OBJ_POLYGON && vsel_ptr->v_index[i]==last_index)) {
232                for (hori_dv=left_dv; hori_dv!=NULL; hori_dv=hori_dv->next) {
233                   if (hori_dv->x > vsel_ptr->x[i] ||
234                         (hori_dv->x == vsel_ptr->x[i] &&
235                         hori_dv->y > vsel_ptr->y[i])) {
236                      break;
237                   }
238                }
239                ptr->obj = obj_ptr;
240                ptr->vsel = vsel_ptr;
241                ptr->index = vsel_ptr->v_index[i];
242                ptr->vindex = i;
243                ptr->x = vsel_ptr->x[i];
244                ptr->y = vsel_ptr->y[i];
245 
246                ptr->next = hori_dv;
247                if (hori_dv == NULL) {
248                   ptr->prev = right_dv;
249                   right_dv->next = ptr;
250                   right_dv = ptr;
251                } else {
252                   ptr->prev = hori_dv->prev;
253                   if (hori_dv->prev == NULL) {
254                      left_dv = ptr;
255                   } else {
256                      hori_dv->prev->next = ptr;
257                   }
258                   hori_dv->prev = ptr;
259                }
260                ptr++;
261 
262                for (vert_dv=top_dv; vert_dv!=NULL; vert_dv=vert_dv->next) {
263                   if (vert_dv->y > vsel_ptr->y[i] ||
264                         (vert_dv->y == vsel_ptr->y[i] &&
265                         vert_dv->x > vsel_ptr->x[i])) {
266                      break;
267                   }
268                }
269                ptr->obj = obj_ptr;
270                ptr->vsel = vsel_ptr;
271                ptr->index = vsel_ptr->v_index[i];
272                ptr->vindex = i;
273                ptr->x = vsel_ptr->x[i];
274                ptr->y = vsel_ptr->y[i];
275 
276                ptr->next = vert_dv;
277                if (vert_dv == NULL) {
278                   ptr->prev = bottom_dv;
279                   bottom_dv->next = ptr;
280                   bottom_dv = ptr;
281                } else {
282                   ptr->prev = vert_dv->prev;
283                   if (vert_dv->prev == NULL) {
284                      top_dv = ptr;
285                   } else {
286                      vert_dv->prev->next = ptr;
287                   }
288                   vert_dv->prev = ptr;
289                }
290                ptr++;
291             }
292          }
293          start = 0;
294       }
295 
296       if (horiAlign != ALIGN_N) {
297          for (ptr=left_dv; ptr->next!=right_dv; ptr=ptr->next) {
298             obj_ptr = ptr->next->obj;
299             vsel_ptr = ptr->next->vsel;
300             if (!(obj_ptr->type==OBJ_POLYGON &&
301                   ptr->next->index==obj_ptr->detail.g->n-1)) {
302                obj_ptr->marked = TRUE;
303                SetSSSIForDistr(obj_ptr, vsel_ptr, TRUE);
304             }
305          }
306       }
307       if (vertAlign != ALIGN_N) {
308          for (ptr=top_dv; ptr->next!=bottom_dv; ptr=ptr->next) {
309             obj_ptr = ptr->next->obj;
310             vsel_ptr = ptr->next->vsel;
311             if (!(obj_ptr->type==OBJ_POLYGON &&
312                   ptr->next->index==obj_ptr->detail.g->n-1)) {
313                obj_ptr->marked = TRUE;
314                SetSSSIForDistr(obj_ptr, vsel_ptr, TRUE);
315             }
316          }
317       }
318 
319       tmp_top_sel = tmp_bot_sel = NULL;
320       count = 0;
321       for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
322          obj_ptr = sel_ptr->obj;
323          if (obj_ptr->marked) {
324             count++;
325             AddObjIntoSel(obj_ptr, tmp_bot_sel, NULL, &tmp_top_sel,
326                   &tmp_bot_sel);
327          }
328       }
329       if (count != 0) {
330          PrepareToRecord(CMD_REPLACE, tmp_top_sel, tmp_bot_sel, count);
331       }
332       if (horiAlign != ALIGN_N) {
333          x = (double)(left_dv->x);
334          h_dist = ((double)(right_dv->x-x))/((double)(vertices_count-1));
335          for (ptr=left_dv; ptr->next!=right_dv; ptr=ptr->next) {
336             int new_x=0;
337 
338             obj_ptr = ptr->next->obj;
339             vsel_ptr = ptr->next->vsel;
340 
341             if (obj_ptr->type==OBJ_POLYGON &&
342                   ptr->next->index==obj_ptr->detail.g->n-1) {
343                continue;
344             }
345             obj_ptr->marked = TRUE;
346             new_x = round(x+h_dist);
347 
348             if (obj_ptr->userdata != NULL) {
349                psssi = (StretchStructuredSplineInfo *)obj_ptr->userdata;
350 
351                if (obj_ptr->ctm == NULL) {
352                   psssi->new_abs_x = new_x;
353                   psssi->abs_dx = new_x - psssi->orig_abs_x;
354                } else {
355                   psssi->rotated_new_abs_x = new_x;
356                   psssi->rotated_abs_dx = new_x - psssi->rotated_orig_abs_x;
357                }
358             } else {
359                int vindex=ptr->next->vindex;
360                MoveVertexInfo *pmvi=vsel_ptr->pmvi;
361 
362                if (obj_ptr->ctm == NULL) {
363                   pmvi[vindex].new_abs_x = new_x;
364                   pmvi[vindex].abs_dx = new_x - pmvi[vindex].orig_abs_x;
365                } else {
366                   pmvi[vindex].rotated_new_abs_x = new_x;
367                   pmvi[vindex].rotated_abs_dx = new_x -
368                         pmvi[vindex].rotated_orig_abs_x;
369                }
370             }
371             vsel_ptr->x[ptr->next->vindex] = new_x;
372             x += h_dist;
373          }
374       }
375       if (vertAlign != ALIGN_N) {
376          y = (double)(top_dv->y);
377          v_dist = ((double)(bottom_dv->y-y))/((double)(vertices_count-1));
378          for (ptr=top_dv; ptr->next!=bottom_dv; ptr=ptr->next) {
379             int new_y=0;
380 
381             obj_ptr = ptr->next->obj;
382             vsel_ptr = ptr->next->vsel;
383 
384             if (obj_ptr->type==OBJ_POLYGON &&
385                   ptr->next->index==obj_ptr->detail.g->n-1) {
386                continue;
387             }
388             obj_ptr->marked = TRUE;
389             new_y = round(y+v_dist);
390 
391             if (obj_ptr->userdata != NULL) {
392                psssi = (StretchStructuredSplineInfo *)obj_ptr->userdata;
393 
394                if (obj_ptr->ctm == NULL) {
395                   psssi->new_abs_y = new_y;
396                   psssi->abs_dy = new_y - psssi->orig_abs_y;
397                } else {
398                   psssi->rotated_new_abs_y = new_y;
399                   psssi->rotated_abs_dy = new_y - psssi->rotated_orig_abs_y;
400                }
401             } else {
402                int vindex=ptr->next->vindex;
403                MoveVertexInfo *pmvi=vsel_ptr->pmvi;
404 
405                if (obj_ptr->ctm == NULL) {
406                   pmvi[vindex].new_abs_y = new_y;
407                   pmvi[vindex].abs_dy = new_y - pmvi[vindex].orig_abs_y;
408                } else {
409                   pmvi[vindex].rotated_new_abs_y = new_y;
410                   pmvi[vindex].rotated_abs_dy = new_y -
411                         pmvi[vindex].rotated_orig_abs_y;
412                }
413             }
414             vsel_ptr->y[ptr->next->vindex] = new_y;
415             y += v_dist;
416          }
417       }
418       for (vsel_ptr=topVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->next) {
419          obj_ptr = vsel_ptr->obj;
420          if (obj_ptr->marked) {
421             IntPoint *vlist=NULL;
422 
423             switch (obj_ptr->type) {
424             case OBJ_POLY: vlist = obj_ptr->detail.p->vlist; break;
425             case OBJ_POLYGON: vlist = obj_ptr->detail.g->vlist; break;
426             }
427             if (obj_ptr->type==OBJ_POLYGON) {
428                struct PolygonRec *polygon_ptr=obj_ptr->detail.g;
429 
430                polygon_ptr->vlist[polygon_ptr->n-1].x = polygon_ptr->vlist[0].x;
431                polygon_ptr->vlist[polygon_ptr->n-1].y = polygon_ptr->vlist[0].y;
432             }
433             if (obj_ptr->userdata != NULL) {
434                StretchStructuredSplineInfo *psssi=
435                      (StretchStructuredSplineInfo *)obj_ptr->userdata;
436 
437                if (obj_ptr->ctm == NULL) {
438                   FinishMoveVertexForStretchStructSpline(vsel_ptr,
439                         psssi->abs_dx, psssi->abs_dy, psssi);
440                } else {
441                   FinishMoveVertexForStretchStructSpline(vsel_ptr,
442                         psssi->rotated_abs_dx, psssi->rotated_abs_dy, psssi);
443                }
444                free(psssi);
445                obj_ptr->userdata = NULL;
446             } else {
447                MoveVertexInfo *pmvi=vsel_ptr->pmvi;
448 
449                if (obj_ptr->ctm == NULL) {
450                   for (i=0; i < vsel_ptr->n; i++) {
451                      if (pmvi[i].abs_dx != 0 || pmvi[i].abs_dy != 0) {
452                         vlist[vsel_ptr->v_index[i]].x += pmvi[i].abs_dx;
453                         vlist[vsel_ptr->v_index[i]].y += pmvi[i].abs_dy;
454                      }
455                   }
456                } else {
457                   for (i=0; i < vsel_ptr->n; i++) {
458                      if (pmvi[i].rotated_abs_dx != 0 ||
459                            pmvi[i].rotated_abs_dy != 0) {
460                         int tmp_x=0, tmp_y=0;
461 
462                         ReverseTransformPointThroughCTM(
463                               pmvi[i].rotated_new_abs_x-obj_ptr->x,
464                               pmvi[i].rotated_new_abs_y-obj_ptr->y,
465                               obj_ptr->ctm, &tmp_x, &tmp_y);
466                         vlist[vsel_ptr->v_index[i]].x = tmp_x + obj_ptr->x;
467                         vlist[vsel_ptr->v_index[i]].y = tmp_y + obj_ptr->y;
468                      }
469                   }
470                }
471                free(pmvi);
472                vsel_ptr->pmvi = NULL;
473             }
474             AdjObjSplineVs(obj_ptr);
475             UpdPolyOrPolygonBBox(obj_ptr);
476          }
477       }
478       if (count != 0) {
479          RecordCmd(CMD_REPLACE, NULL, tmp_top_sel, tmp_bot_sel, count);
480       }
481       for (tmp_sel_ptr=tmp_top_sel; tmp_sel_ptr!=NULL; tmp_sel_ptr=next_sel) {
482          next_sel = tmp_sel_ptr->next;
483          free(tmp_sel_ptr);
484       }
485       free(dv_ptr);
486 
487       if (horiAlign != ALIGN_N) {
488          sprintf(gszMsgBox, TgLoadString(STID_VERTICES_HORI_APART),
489                round(h_dist));
490          Msg(gszMsgBox);
491       }
492       if (vertAlign != ALIGN_N) {
493          sprintf(gszMsgBox, TgLoadString(STID_VERTICES_VERT_APART),
494                round(v_dist));
495          Msg(gszMsgBox);
496       }
497    } else {
498       struct SelRec *left_sel=NULL, *right_sel=NULL;
499       struct SelRec *top_sel=NULL, *bottom_sel=NULL;
500       struct SelRec *vert_sel=NULL, *hori_sel=NULL, *new_sel=NULL;
501       struct SubCmdRec *sub_cmd=NULL;
502       struct SelRec *tmp_sel_ptr=NULL;
503 
504       if (topSel==botSel || topSel->next==botSel) return;
505 
506       tmp_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
507       if (tmp_sel_ptr == NULL) FailAllocMessage();
508       tmp_sel_ptr->next = tmp_sel_ptr->prev = NULL;
509 
510       sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
511       if (sub_cmd == NULL) FailAllocMessage();
512       memset(sub_cmd, 0, sizeof(struct SubCmdRec));
513 
514       StartCompositeCmd();
515       HighLightReverse();
516 
517       left_sel = right_sel = (struct SelRec *)malloc(sizeof(struct SelRec));
518       top_sel = bottom_sel = (struct SelRec *)malloc(sizeof(struct SelRec));
519       if (left_sel == NULL || right_sel == NULL ||
520             top_sel == NULL || bottom_sel == NULL) {
521          FailAllocMessage();
522       }
523       left_sel->obj = right_sel->obj = botSel->obj;
524       top_sel->obj = bottom_sel->obj = botSel->obj;
525       left_sel->prev = right_sel->next = NULL;
526       top_sel->prev = bottom_sel->next = NULL;
527 
528       count = 1;
529       w = left_sel->obj->obbox.rbx - left_sel->obj->obbox.ltx;
530       h = left_sel->obj->obbox.rby - left_sel->obj->obbox.lty;
531       for (sel_ptr=botSel->prev; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
532          count++;
533          obj_ptr = sel_ptr->obj;
534          w += obj_ptr->obbox.rbx - obj_ptr->obbox.ltx;
535          h += obj_ptr->obbox.rby - obj_ptr->obbox.lty;
536          switch (horiAlign) {
537          case ALIGN_N:
538          case ALIGN_L:
539          case ALIGN_S:
540             for (hori_sel=left_sel; hori_sel!=NULL; hori_sel=hori_sel->next) {
541                if (hori_sel->obj->obbox.ltx > obj_ptr->obbox.ltx ||
542                      (hori_sel->obj->obbox.ltx == obj_ptr->obbox.ltx &&
543                      hori_sel->obj->obbox.lty > obj_ptr->obbox.lty)) {
544                   break;
545                }
546             }
547             break;
548          case ALIGN_C:
549             for (hori_sel=left_sel; hori_sel!=NULL; hori_sel=hori_sel->next) {
550                if (hori_sel->obj->obbox.ltx+hori_sel->obj->obbox.rbx >
551                      obj_ptr->obbox.ltx+obj_ptr->obbox.rbx ||
552                      (hori_sel->obj->obbox.ltx+hori_sel->obj->obbox.rbx ==
553                      obj_ptr->obbox.ltx+obj_ptr->obbox.rbx &&
554                      hori_sel->obj->obbox.lty+hori_sel->obj->obbox.rby >
555                      obj_ptr->obbox.lty+obj_ptr->obbox.rby)) {
556                   break;
557                }
558             }
559             break;
560          case ALIGN_R:
561             for (hori_sel=left_sel; hori_sel!=NULL; hori_sel=hori_sel->next) {
562                if (hori_sel->obj->obbox.rbx > obj_ptr->obbox.rbx ||
563                      (hori_sel->obj->obbox.rbx == obj_ptr->obbox.rbx &&
564                      hori_sel->obj->obbox.rby > obj_ptr->obbox.rby)) {
565                   break;
566                }
567             }
568             break;
569          }
570          new_sel = (struct SelRec *)malloc(sizeof(struct SelRec));
571          if (new_sel == NULL) FailAllocMessage();
572          new_sel->obj = obj_ptr;
573          new_sel->next = hori_sel;
574          if (hori_sel == NULL) {
575             new_sel->prev = right_sel;
576             right_sel->next = new_sel;
577             right_sel = new_sel;
578          } else {
579             new_sel->prev = hori_sel->prev;
580             if (hori_sel->prev == NULL) {
581                left_sel = new_sel;
582             } else {
583                hori_sel->prev->next = new_sel;
584             }
585             hori_sel->prev = new_sel;
586          }
587          switch (vertAlign) {
588          case ALIGN_N:
589          case ALIGN_T:
590          case ALIGN_S:
591             for (vert_sel=top_sel; vert_sel!=NULL; vert_sel=vert_sel->next) {
592                if (vert_sel->obj->obbox.lty > obj_ptr->obbox.lty ||
593                      (vert_sel->obj->obbox.lty == obj_ptr->obbox.lty &&
594                      vert_sel->obj->obbox.ltx > obj_ptr->obbox.ltx)) {
595                   break;
596                }
597             }
598             break;
599          case ALIGN_M:
600             for (vert_sel=top_sel; vert_sel!=NULL; vert_sel=vert_sel->next) {
601                if (vert_sel->obj->obbox.lty+vert_sel->obj->obbox.rby >
602                      obj_ptr->obbox.lty+obj_ptr->obbox.rby ||
603                      (vert_sel->obj->obbox.lty+vert_sel->obj->obbox.rby ==
604                      obj_ptr->obbox.lty+obj_ptr->obbox.rby &&
605                      vert_sel->obj->obbox.ltx+vert_sel->obj->obbox.rbx >
606                      obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)) {
607                   break;
608                }
609             }
610             break;
611          case ALIGN_B:
612             for (vert_sel=top_sel; vert_sel!=NULL; vert_sel=vert_sel->next) {
613                if (vert_sel->obj->obbox.rby > obj_ptr->obbox.rby ||
614                      (vert_sel->obj->obbox.rby == obj_ptr->obbox.rby &&
615                      vert_sel->obj->obbox.rbx > obj_ptr->obbox.rbx)) {
616                   break;
617                }
618             }
619             break;
620          }
621          new_sel = (struct SelRec *)malloc(sizeof(struct SelRec));
622          if (new_sel == NULL) FailAllocMessage();
623          new_sel->obj = obj_ptr;
624          new_sel->next = vert_sel;
625          if (vert_sel == NULL)
626          {
627             new_sel->prev = bottom_sel;
628             bottom_sel->next = new_sel;
629             bottom_sel = new_sel;
630          } else {
631             new_sel->prev = vert_sel->prev;
632             if (vert_sel->prev == NULL) {
633                top_sel = new_sel;
634             } else {
635                vert_sel->prev->next = new_sel;
636             }
637             vert_sel->prev = new_sel;
638          }
639       }
640       switch (horiAlign) {
641       case ALIGN_N:
642       case ALIGN_L:
643          x = (double)(left_sel->obj->obbox.ltx);
644          h_dist = ((double)(right_sel->obj->obbox.ltx-x))/((double)(count-1));
645          break;
646       case ALIGN_C:
647          x = (double)(left_sel->obj->obbox.rbx+left_sel->obj->obbox.ltx);
648          h_dist = ((double)(right_sel->obj->obbox.rbx +
649                right_sel->obj->obbox.ltx - x)) / ((double)(count-1));
650          break;
651       case ALIGN_R:
652          x = (double)(left_sel->obj->obbox.rbx);
653          h_dist = ((double)(right_sel->obj->obbox.rbx-x))/((double)(count-1));
654          break;
655       case ALIGN_S:
656          x = (double)(left_sel->obj->obbox.rbx);
657          h_dist = ((double)(right_sel->obj->obbox.rbx -
658                left_sel->obj->obbox.ltx - w)) / ((double)(count-1));
659          break;
660       }
661       switch (vertAlign) {
662       case ALIGN_N:
663       case ALIGN_T:
664          y = (double)(top_sel->obj->obbox.lty);
665          v_dist = ((double)(bottom_sel->obj->obbox.lty-y))/((double)(count-1));
666          break;
667       case ALIGN_M:
668          y = (double)(top_sel->obj->obbox.rby+top_sel->obj->obbox.lty);
669          v_dist = ((double)(bottom_sel->obj->obbox.rby +
670                bottom_sel->obj->obbox.lty - y)) / ((double)(count-1));
671          break;
672       case ALIGN_B:
673          y = (double)(top_sel->obj->obbox.rby);
674          v_dist = ((double)(bottom_sel->obj->obbox.rby-y))/((double)(count-1));
675          break;
676       case ALIGN_S:
677          y = (double)(top_sel->obj->obbox.rby);
678          v_dist = ((double)(bottom_sel->obj->obbox.rby -
679                top_sel->obj->obbox.lty - h)) / ((double)(count-1));
680          break;
681       }
682       for (sel_ptr=left_sel; sel_ptr->next!=right_sel; sel_ptr=next_sel) {
683          switch (horiAlign) {
684          case ALIGN_N: dx = 0; break;
685          case ALIGN_L:
686             dx = round(x+h_dist-sel_ptr->next->obj->obbox.ltx);
687             break;
688          case ALIGN_C:
689             dx = round((x + h_dist - sel_ptr->next->obj->obbox.rbx -
690                   sel_ptr->next->obj->obbox.ltx) / ((double)2.0));
691             break;
692          case ALIGN_R:
693             dx = round(x+h_dist-sel_ptr->next->obj->obbox.rbx);
694             break;
695          case ALIGN_S:
696             dx = round(x+h_dist-sel_ptr->next->obj->obbox.ltx);
697             break;
698          }
699          if (dx != 0) {
700             sub_cmd->detail.move.dx = dx;
701             sub_cmd->detail.move.dy = 0;
702             tmp_sel_ptr->obj = sel_ptr->next->obj;
703             PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
704             RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
705 
706             MoveObj(sel_ptr->next->obj, dx, 0);
707          }
708 
709          x += h_dist;
710          if (horiAlign == ALIGN_S) {
711             x += sel_ptr->next->obj->obbox.rbx - sel_ptr->next->obj->obbox.ltx;
712          }
713          next_sel = sel_ptr->next;
714          free(sel_ptr);
715       }
716       free(sel_ptr);
717       free(right_sel);
718 
719       for (sel_ptr=top_sel; sel_ptr->next!=bottom_sel; sel_ptr=next_sel) {
720          switch (vertAlign) {
721          case ALIGN_N: dy = 0; break;
722          case ALIGN_T:
723             dy = round(y+v_dist-sel_ptr->next->obj->obbox.lty);
724             break;
725          case ALIGN_M:
726             dy = round((y + v_dist - sel_ptr->next->obj->obbox.rby -
727                   sel_ptr->next->obj->obbox.lty) / ((double)2.0));
728             break;
729          case ALIGN_B:
730             dy = round(y+v_dist-sel_ptr->next->obj->obbox.rby);
731             break;
732          case ALIGN_S:
733             dy = round(y+v_dist-sel_ptr->next->obj->obbox.lty);
734             break;
735          }
736          if (dy != 0) {
737             sub_cmd->detail.move.dx = 0;
738             sub_cmd->detail.move.dy = dy;
739             tmp_sel_ptr->obj = sel_ptr->next->obj;
740             PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
741             RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
742 
743             MoveObj(sel_ptr->next->obj, 0, dy);
744          }
745 
746          y += v_dist;
747          if (vertAlign == ALIGN_S) {
748             y += sel_ptr->next->obj->obbox.rby - sel_ptr->next->obj->obbox.lty;
749          }
750          next_sel = sel_ptr->next;
751          free(sel_ptr);
752       }
753       free(sel_ptr);
754       free(bottom_sel);
755 
756       EndCompositeCmd();
757       free(sub_cmd);
758       free(tmp_sel_ptr);
759 
760       switch (horiAlign) {
761       case ALIGN_L:
762          sprintf(gszMsgBox, TgLoadString(STID_LEFT_SIDES_APART), round(h_dist));
763          Msg(gszMsgBox);
764          break;
765       case ALIGN_C:
766          sprintf(gszMsgBox, TgLoadString(STID_CENTERS_APART),
767                round(h_dist/((double)2.0)));
768          Msg(gszMsgBox);
769          break;
770       case ALIGN_R:
771          sprintf(gszMsgBox, TgLoadString(STID_RIGHT_SIDES_APART),
772                round(h_dist));
773          Msg(gszMsgBox);
774          break;
775       case ALIGN_S:
776          sprintf(gszMsgBox, TgLoadString(STID_SPACED_APART_HORI),
777                round(h_dist));
778          Msg(gszMsgBox);
779          break;
780       }
781       switch (vertAlign) {
782       case ALIGN_T:
783          sprintf(gszMsgBox, TgLoadString(STID_TOP_SIDES_APART),
784                round(v_dist));
785          Msg(gszMsgBox);
786          break;
787       case ALIGN_M:
788          sprintf(gszMsgBox, TgLoadString(STID_MIDDLES_APART),
789                round(v_dist/((double)2.0)));
790          Msg(gszMsgBox);
791          break;
792       case ALIGN_B:
793          sprintf(gszMsgBox, TgLoadString(STID_BOTTOM_SIDES_APART),
794                round(v_dist));
795          Msg(gszMsgBox);
796          break;
797       case ALIGN_S:
798          sprintf(gszMsgBox, TgLoadString(STID_SPACED_APART_VERT),
799                round(v_dist));
800          Msg(gszMsgBox);
801          break;
802       }
803    }
804    ltx = selLtX; lty = selLtY; rbx = selRbX, rby = selRbY;
805    UpdSelBBox();
806    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
807          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
808          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
809          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
810    HighLightForward();
811    SetFileModified(TRUE);
812    justDupped = FALSE;
813 }
814 
DistributeDirect(alignment)815 void DistributeDirect(alignment)
816    int alignment;
817 {
818    int saved_h_align=horiAlign, saved_v_align=vertAlign;
819    int v_mode=(alignment%MAXALIGNS);
820    int h_mode=((alignment-v_mode)/MAXALIGNS);
821 
822    horiAlign = h_mode;
823    vertAlign = v_mode;
824    DistrSelObjs();
825    horiAlign = saved_h_align;
826    vertAlign = saved_v_align;
827 }
828 
829 static
GetDistrDirectMenuStr(i)830 char *GetDistrDirectMenuStr(i)
831    int i;
832    /* returned string has been translated */
833 {
834    char *psz=NULL, *msg=NULL;
835 
836    if (curChoice == VERTEXMODE) {
837       int v_mode=(i%MAXALIGNS);
838       int h_mode=((i-v_mode)/MAXALIGNS);
839 
840       if (v_mode == ALIGN_N) {
841          if (h_mode == ALIGN_N) {
842             msg = TgLoadCachedString(CSTID_PARANED_NONE);
843          } else {
844             msg = TgLoadString(STID_DISTR_VERTEX_HORI);
845          }
846       } else {
847          if (h_mode == ALIGN_N) {
848             msg = TgLoadString(STID_DISTR_VERTEX_VERT);
849          } else {
850             msg = TgLoadString(STID_DISTR_VERTEX_VERT_AND_HORI);
851          }
852       }
853    } else {
854       msg = DistrDirectLoadString(i);
855    }
856    psz = UtilStrDup(msg);
857    if (psz == NULL) FailAllocMessage();
858    return psz;
859 }
860 
CreateDistributeDirectMenu(parent_menu,x,y,menu_info,status_str_xlated)861 TgMenu *CreateDistributeDirectMenu(parent_menu, x, y, menu_info,
862       status_str_xlated)
863    TgMenu *parent_menu;
864    int x, y;
865    TgMenuInfo *menu_info;
866    int status_str_xlated; /* ignored, always 0 */
867 {
868    int i=0, num_entries=(MAXALIGNS*MAXALIGNS);
869    TgMenu *menu=NULL;
870    TgMenuInfo stMenuInfo;
871    TgMenuItemInfo *item_info=NULL;
872 
873    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
874    stMenuInfo.items = (TgMenuItemInfo*)malloc(
875          (num_entries+1)*sizeof(TgMenuItemInfo));
876    if (stMenuInfo.items == NULL) FailAllocMessage();
877    memset(stMenuInfo.items, 0,
878          (num_entries+1)*sizeof(TgMenuItemInfo));
879    for (item_info=stMenuInfo.items, i=0; i < num_entries; item_info++, i++) {
880       item_info->menu_str = (char*)(Pixmap*)(&distrDirectPixmap[i]);
881       item_info->shortcut_str = NULL;
882       item_info->status_str = GetDistrDirectMenuStr(i);
883       item_info->submenu_info = NULL;
884       item_info->cmdid = CMDID_DISTRIBUTEDIRECT;
885    }
886    stMenuInfo.items[num_entries].cmdid = INVALID;
887 
888    /* the status_str has been translated in GetDistrDirectMenuStr() */
889    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
890    for (item_info=stMenuInfo.items, i=0; i < num_entries; item_info++, i++) {
891       UtilFree(item_info->status_str);
892    }
893    memset(stMenuInfo.items, 0, (num_entries+1)*sizeof(TgMenuItemInfo));
894    free(stMenuInfo.items);
895    stMenuInfo.items = NULL;
896    if (menu != NULL) {
897       menu->track_menubar = TRUE;
898       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, MAXALIGNS);
899    }
900    return menu;
901 }
902 
903 static
AutoJustifiable(obj_ptr)904 int AutoJustifiable(obj_ptr)
905    struct ObjRec *obj_ptr;
906 {
907    struct TextRec *text_ptr;
908    int auto_justifiable=TRUE, just;
909 
910    if (obj_ptr->type!=OBJ_TEXT || obj_ptr->detail.t->lines!=1) return FALSE;
911    if (obj_ptr->ctm != NULL) return FALSE;
912 
913    text_ptr = obj_ptr->detail.t;
914    just = text_ptr->minilines.just;
915 
916    if ((horiAlign==ALIGN_L && just==JUST_L) ||
917          (horiAlign==ALIGN_C && just==JUST_C) ||
918          (horiAlign==ALIGN_R && just==JUST_R)) {
919       auto_justifiable = FALSE;
920    }
921    return auto_justifiable;
922 }
923 
924 static
AutoJustify(obj_ptr)925 void AutoJustify(obj_ptr)
926    struct ObjRec *obj_ptr;
927 {
928    struct TextRec *text_ptr;
929    int new_ltx, new_lty, dx, dy, ltx, lty;
930 
931    text_ptr = obj_ptr->detail.t;
932 
933    ltx = obj_ptr->obbox.ltx; lty = obj_ptr->obbox.lty;
934    switch (horiAlign) {
935    case ALIGN_L: text_ptr->minilines.just = JUST_L; break;
936    case ALIGN_C: text_ptr->minilines.just = JUST_C; break;
937    case ALIGN_R: text_ptr->minilines.just = JUST_R; break;
938    }
939    UpdTextBBox(obj_ptr);
940    dx = dy = 0;
941    new_ltx = obj_ptr->obbox.ltx; new_lty = obj_ptr->obbox.lty;
942    dx = ltx-new_ltx;
943 
944    if (text_ptr->cached_bitmap != None) {
945       XFreePixmap(mainDisplay, text_ptr->cached_bitmap);
946    }
947    text_ptr->cached_zoom = 0;
948    text_ptr->cached_bitmap = None;
949 
950    MoveObj(obj_ptr, dx, dy);
951 }
952 
AlignSelObjs()953 void AlignSelObjs()
954 {
955    register int x=0, y=0, i;
956    struct SelRec *sel_ptr=NULL;
957    struct ObjRec *obj_ptr=NULL;
958    struct VSelRec *vsel_ptr=NULL;
959    int pivot_x=0, pivot_y=0, auto_justifiable=FALSE;
960    int dx=0, dy=0, ltx=0, lty=0, rbx=0, rby=0;
961 
962    if (topSel == NULL && topVSel == NULL) return;
963 
964    if (curChoice == VERTEXMODE) {
965       int changed=FALSE, n=0, first_time=TRUE, start;
966       IntPoint *vlist=NULL;
967 
968       if (topVSel!=NULL && (topVSel->next!=NULL || topVSel->n>=3  ||
969             (topVSel->n==2 &&
970             !(topVSel->obj->type==OBJ_POLYGON && topVSel->v_index[0]==0))) &&
971             horiAlign!=ALIGN_N && horiAlign!=ALIGN_S &&
972             vertAlign!=ALIGN_N && vertAlign!=ALIGN_S) {
973          if (MsgBox(TgLoadString(STID_MOVE_ALL_VERTICES_YNC),
974                TOOL_NAME, YNC_MB) != MB_ID_YES) {
975             return;
976          }
977       }
978       StartCompositeCmd();
979       HighLightReverse();
980       for (vsel_ptr = topVSel; vsel_ptr != NULL; vsel_ptr = vsel_ptr->next) {
981          if (first_time) {
982             first_time = FALSE;
983             ltx = vsel_ptr->x[0]; lty = vsel_ptr->y[0];
984             rbx = vsel_ptr->x[0]; rby = vsel_ptr->y[0];
985             start = 1;
986          } else {
987             start = 0;
988          }
989          for (i = start; i < vsel_ptr->n; i++) {
990             if (vsel_ptr->x[i] < ltx) ltx = vsel_ptr->x[i];
991             if (vsel_ptr->y[i] < lty) lty = vsel_ptr->y[i];
992             if (vsel_ptr->x[i] > rbx) rbx = vsel_ptr->x[i];
993             if (vsel_ptr->y[i] > rby) rby = vsel_ptr->y[i];
994          }
995       }
996       switch (horiAlign) {
997       case ALIGN_L: pivot_x = ltx; break;
998       case ALIGN_C: pivot_x = (ltx + rbx) / 2; break;
999       case ALIGN_R: pivot_x = rbx; break;
1000       }
1001       switch (vertAlign) {
1002       case ALIGN_T: pivot_y = lty; break;
1003       case ALIGN_M: pivot_y = (lty + rby) / 2; break;
1004       case ALIGN_B: pivot_y = rby; break;
1005       }
1006 
1007       for (vsel_ptr = topVSel; vsel_ptr != NULL; vsel_ptr = vsel_ptr->next) {
1008          StretchStructuredSplineInfo sssi;
1009          int curved=(-1), ssn=(-1);
1010          IntPoint *ssvlist=NULL;
1011          struct PolyRec *poly_ptr=NULL;
1012          struct PolygonRec *polygon_ptr=NULL;
1013 
1014          memset(&sssi, 0, sizeof(StretchStructuredSplineInfo));
1015          obj_ptr = vsel_ptr->obj;
1016          switch (obj_ptr->type) {
1017          case OBJ_POLY:
1018             poly_ptr = obj_ptr->detail.p;
1019             curved = poly_ptr->curved;
1020             n = poly_ptr->n;
1021             vlist = poly_ptr->vlist;
1022             if (curved == LT_STRUCT_SPLINE) {
1023                ssn = poly_ptr->ssn;
1024                ssvlist = poly_ptr->ssvlist;
1025                SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], n, vlist, &sssi);
1026             }
1027             break;
1028          case OBJ_POLYGON:
1029             polygon_ptr = obj_ptr->detail.g;
1030             curved = polygon_ptr->curved;
1031             n = polygon_ptr->n;
1032             vlist = polygon_ptr->vlist;
1033             if (curved == LT_STRUCT_SPLINE) {
1034                ssn = polygon_ptr->ssn;
1035                ssvlist = polygon_ptr->ssvlist;
1036                SetIPTInfoForStretchPolygon(vsel_ptr->v_index[0], n, vlist,
1037                      &sssi);
1038             }
1039             break;
1040          }
1041          PrepareToReplaceAnObj(obj_ptr);
1042          for (i=0; i < vsel_ptr->n; i++) {
1043             int abs_dx=0,  abs_dy=0;
1044 
1045             if (horiAlign!=ALIGN_N && horiAlign!=ALIGN_S &&
1046                   vsel_ptr->x[i]!=pivot_x) {
1047                changed = TRUE;
1048                abs_dx = pivot_x - vsel_ptr->x[i];
1049             }
1050             if (vertAlign!=ALIGN_N && vertAlign!=ALIGN_S &&
1051                   vsel_ptr->y[i]!=pivot_y) {
1052                changed = TRUE;
1053                abs_dy = pivot_y - vsel_ptr->y[i];
1054             }
1055             if (changed) {
1056                if (obj_ptr->ctm == NULL) {
1057                   vsel_ptr->x[i] = pivot_x;
1058                   vsel_ptr->y[i] = pivot_y;
1059                   if (curved == LT_STRUCT_SPLINE) {
1060                      /*
1061                       * don't do anything here, will be handled in
1062                       *       FinishMoveVertexForStretchStructSpline();
1063                       */
1064                   } else {
1065                      vlist[vsel_ptr->v_index[i]].x = pivot_x;
1066                      vlist[vsel_ptr->v_index[i]].y = pivot_y;
1067                   }
1068                } else {
1069                   int tmp_x=0, tmp_y=0, tmp_x2=0, tmp_y2=0;
1070 
1071                   ReverseTransformPointThroughCTM(
1072                         pivot_x-obj_ptr->x, pivot_y-obj_ptr->y, obj_ptr->ctm,
1073                         &tmp_x, &tmp_y);
1074                   if (curved == LT_STRUCT_SPLINE) {
1075                      /*
1076                       * don't do anything here, will be handled in
1077                       *       FinishMoveVertexForStretchStructSpline();
1078                       */
1079                   } else {
1080                      dx = tmp_x + obj_ptr->x - vlist[vsel_ptr->v_index[i]].x;
1081                      dy = tmp_y + obj_ptr->y - vlist[vsel_ptr->v_index[i]].y;
1082                      vlist[vsel_ptr->v_index[i]].x = tmp_x + obj_ptr->x;
1083                      vlist[vsel_ptr->v_index[i]].y = tmp_y + obj_ptr->y;
1084                   }
1085                   TransformPointThroughCTM(tmp_x, tmp_y, obj_ptr->ctm,
1086                          &tmp_x2, &tmp_y2);
1087                   vsel_ptr->x[i] = tmp_x2 + obj_ptr->x;
1088                   vsel_ptr->y[i] = tmp_y2 + obj_ptr->y;
1089                }
1090             }
1091             if (curved == LT_STRUCT_SPLINE) {
1092                FinishMoveVertexForStretchStructSpline(vsel_ptr, abs_dx, abs_dy,
1093                      &sssi);
1094             }
1095          }
1096          if (changed) {
1097             AdjObjSplineVs(obj_ptr);
1098             UpdNonIntSplinePolyBBox(obj_ptr, n, vlist);
1099             RecordReplaceAnObj(obj_ptr);
1100          } else {
1101             AbortPrepareCmd(CMD_REPLACE);
1102          }
1103       }
1104       EndCompositeCmd();
1105    } else {
1106       struct SubCmdRec *sub_cmd=NULL;
1107       struct SelRec *tmp_sel_ptr=NULL;
1108       struct ObjRec *locked_obj=NULL;
1109       char *psz=NULL;
1110 
1111       if (numObjLocked > 1) {
1112          MsgBox(TgLoadString(STID_CANNOT_ALIGN_OBJS_TOO_MANY), TOOL_NAME,
1113                INFO_MB);
1114          return;
1115       } else if (numObjLocked == 1) {
1116          for (sel_ptr=topSel; sel_ptr!=NULL; sel_ptr=sel_ptr->next) {
1117             if (sel_ptr->obj->locked) {
1118                locked_obj = sel_ptr->obj;
1119                break;
1120             }
1121          }
1122       }
1123       tmp_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
1124       if (tmp_sel_ptr == NULL) FailAllocMessage();
1125       tmp_sel_ptr->next = tmp_sel_ptr->prev = NULL;
1126 
1127       sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
1128       if (sub_cmd == NULL) FailAllocMessage();
1129       memset(sub_cmd, 0, sizeof(struct SubCmdRec));
1130 
1131       StartCompositeCmd();
1132       HighLightReverse();
1133       switch (horiAlign) {
1134       case ALIGN_L:
1135          pivot_x = (locked_obj==NULL) ? selObjLtX : locked_obj->obbox.ltx;
1136          break;
1137       case ALIGN_C:
1138          pivot_x = (locked_obj==NULL) ? ((selObjLtX+selObjRbX)>>1) :
1139                ((locked_obj->obbox.ltx+locked_obj->obbox.rbx)>>1);
1140          break;
1141       case ALIGN_R:
1142          pivot_x = (locked_obj==NULL) ? selObjRbX : locked_obj->obbox.rbx;
1143          break;
1144       }
1145       switch (vertAlign) {
1146       case ALIGN_T:
1147          pivot_y = (locked_obj==NULL) ? selObjLtY : locked_obj->obbox.lty;
1148          break;
1149       case ALIGN_M:
1150          pivot_y = (locked_obj==NULL) ? ((selObjLtY+selObjRbY)>>1) :
1151                ((locked_obj->obbox.lty+locked_obj->obbox.rby)>>1);
1152          break;
1153       case ALIGN_B:
1154          pivot_y = (locked_obj==NULL) ? selObjRbY : locked_obj->obbox.rby;
1155          break;
1156       }
1157 
1158       for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
1159          obj_ptr = sel_ptr->obj;
1160          if (obj_ptr->locked) continue;
1161 
1162          if ((auto_justifiable = AutoJustifiable(obj_ptr))) {
1163             PrepareToReplaceAnObj(obj_ptr);
1164             AutoJustify(obj_ptr);
1165          }
1166          switch (horiAlign) {
1167          case ALIGN_L: x = obj_ptr->obbox.ltx; break;
1168          case ALIGN_C: x = (obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)/2; break;
1169          case ALIGN_R: x = obj_ptr->obbox.rbx; break;
1170          }
1171          switch (vertAlign) {
1172          case ALIGN_T: y = obj_ptr->obbox.lty; break;
1173          case ALIGN_M: y = (obj_ptr->obbox.lty+obj_ptr->obbox.rby)/2; break;
1174          case ALIGN_B: y = obj_ptr->obbox.rby; break;
1175          }
1176          if (horiAlign==ALIGN_N || horiAlign==ALIGN_S) x = pivot_x;
1177          if (vertAlign==ALIGN_N || vertAlign==ALIGN_S) y = pivot_y;
1178 
1179          dx = pivot_x - x;
1180          dy = pivot_y - y;
1181          if (dx != 0 || dy != 0) {
1182             if (auto_justifiable) {
1183                MoveObj(obj_ptr, dx, dy);
1184                RecordReplaceAnObj(obj_ptr);
1185             } else {
1186                sub_cmd->detail.move.dx = dx;
1187                sub_cmd->detail.move.dy = dy;
1188                tmp_sel_ptr->obj = obj_ptr;
1189                PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
1190                RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
1191 
1192                MoveObj(obj_ptr, dx, dy);
1193             }
1194          } else if (auto_justifiable) {
1195             RecordReplaceAnObj(obj_ptr);
1196          }
1197       }
1198       EndCompositeCmd();
1199 
1200       free(sub_cmd);
1201       free(tmp_sel_ptr);
1202 
1203       psz = AlignedLoadString(horiAlign, vertAlign);
1204       if (psz != NULL) Msg(psz);
1205    }
1206    ltx = selLtX; lty = selLtY; rbx = selRbX, rby = selRbY;
1207    UpdSelBBox();
1208    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1209          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1210          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1211          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1212    HighLightForward();
1213    SetFileModified(TRUE);
1214    justDupped = FALSE;
1215 }
1216 
AlignSelToPage()1217 void AlignSelToPage()
1218 {
1219    int i=0;
1220    struct SelRec *sel_ptr=NULL;
1221    struct ObjRec *obj_ptr=NULL;
1222    struct VSelRec *vsel_ptr=NULL;
1223    int pivot_x=0, pivot_y=0, dx=0, dy=0, ltx=0, lty=0, rbx=0, rby=0;
1224 
1225    if (topSel == NULL && topVSel == NULL) return;
1226 
1227    if (curChoice == VERTEXMODE) {
1228       int changed=FALSE, n=0;
1229       IntPoint *vlist=NULL;
1230 
1231       if (topVSel!=NULL && (topVSel->next!=NULL || topVSel->n>=3  ||
1232             (topVSel->n==2 &&
1233             !(topVSel->obj->type==OBJ_POLYGON && topVSel->v_index[0]==0))) &&
1234             horiAlign!=ALIGN_N && horiAlign!=ALIGN_S &&
1235             vertAlign!=ALIGN_N && vertAlign!=ALIGN_S) {
1236          if (MsgBox(TgLoadString(STID_MOVE_ALL_VERTICES_YNC), TOOL_NAME,
1237                YNC_MB) != MB_ID_YES) {
1238             return;
1239          }
1240       }
1241       for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1242          sel_ptr->obj->userdata = NULL;
1243       }
1244       StartCompositeCmd();
1245       HighLightReverse();
1246 
1247       switch (horiAlign) {
1248       case ALIGN_L: pivot_x = 0; break;
1249       case ALIGN_C: pivot_x = paperWidth / 2; break;
1250       case ALIGN_R: pivot_x = paperWidth; break;
1251       }
1252       switch (vertAlign) {
1253       case ALIGN_T: pivot_y = 0; break;
1254       case ALIGN_M: pivot_y = paperHeight / 2; break;
1255       case ALIGN_B: pivot_y = paperHeight; break;
1256       }
1257       for (vsel_ptr=topVSel; vsel_ptr != NULL; vsel_ptr=vsel_ptr->next) {
1258          obj_ptr = vsel_ptr->obj;
1259          SetSSSIForDistr(obj_ptr, vsel_ptr, FALSE);
1260 
1261          switch (obj_ptr->type) {
1262          case OBJ_POLY:
1263             n = obj_ptr->detail.p->n;
1264             vlist = obj_ptr->detail.p->vlist;
1265             break;
1266          case OBJ_POLYGON:
1267             n = obj_ptr->detail.g->n;
1268             vlist = obj_ptr->detail.g->vlist;
1269             break;
1270          }
1271          PrepareToReplaceAnObj(obj_ptr);
1272          for (i = 0; i < vsel_ptr->n; i++) {
1273             if (horiAlign!=ALIGN_N && horiAlign!=ALIGN_S &&
1274                   vsel_ptr->x[i]!=pivot_x) {
1275                changed = TRUE;
1276                if (obj_ptr->userdata != NULL) {
1277                   StretchStructuredSplineInfo *psssi=
1278                         (StretchStructuredSplineInfo *)obj_ptr->userdata;
1279 
1280                   if (obj_ptr->ctm == NULL) {
1281                      psssi->new_abs_x = pivot_x;
1282                      psssi->abs_dx = pivot_x - psssi->orig_abs_x;
1283                   } else {
1284                      psssi->rotated_new_abs_x = pivot_x;
1285                      psssi->rotated_abs_dx = pivot_x -
1286                            psssi->rotated_orig_abs_x;
1287                   }
1288                } else {
1289                   vlist[vsel_ptr->v_index[i]].x = pivot_x;
1290                }
1291                vsel_ptr->x[i] = pivot_x;
1292             }
1293             if (vertAlign!=ALIGN_N && vertAlign!=ALIGN_S &&
1294                   vsel_ptr->y[i]!=pivot_y) {
1295                changed = TRUE;
1296                if (obj_ptr->userdata != NULL) {
1297                   StretchStructuredSplineInfo *psssi=
1298                         (StretchStructuredSplineInfo *)obj_ptr->userdata;
1299 
1300                   if (obj_ptr->ctm == NULL) {
1301                      psssi->new_abs_y = pivot_y;
1302                      psssi->abs_dy = pivot_y - psssi->orig_abs_y;
1303                   } else {
1304                      psssi->rotated_new_abs_y = pivot_y;
1305                      psssi->rotated_abs_dy = pivot_y -
1306                            psssi->rotated_orig_abs_y;
1307                   }
1308                } else {
1309                   vlist[vsel_ptr->v_index[i]].y = pivot_y;
1310                }
1311                vsel_ptr->y[i] = pivot_y;
1312             }
1313             if (obj_ptr->userdata != NULL) {
1314                StretchStructuredSplineInfo *psssi=
1315                      (StretchStructuredSplineInfo *)obj_ptr->userdata;
1316 
1317                if (changed) {
1318                   if (obj_ptr->ctm == NULL) {
1319                      FinishMoveVertexForStretchStructSpline(vsel_ptr,
1320                            psssi->abs_dx, psssi->abs_dy, psssi);
1321                   } else {
1322                      FinishMoveVertexForStretchStructSpline(vsel_ptr,
1323                            psssi->rotated_abs_dx, psssi->rotated_abs_dy, psssi);
1324                   }
1325                }
1326                free(psssi);
1327                obj_ptr->userdata = NULL;
1328             }
1329          }
1330          if (changed) {
1331             AdjObjSplineVs(obj_ptr);
1332             UpdNonIntSplinePolyBBox(obj_ptr, n, vlist);
1333             RecordReplaceAnObj(obj_ptr);
1334          } else {
1335             AbortPrepareCmd(CMD_REPLACE);
1336          }
1337       }
1338       EndCompositeCmd();
1339    } else {
1340       HighLightReverse();
1341       dx = dy = 0;
1342       switch (horiAlign) {
1343       case ALIGN_L: dx = 0 - selLtX; break;
1344       case ALIGN_C: dx = (paperWidth>>1) - ((selRbX+selLtX)>>1); break;
1345       case ALIGN_R: dx = paperWidth - selRbX; break;
1346       }
1347       switch (vertAlign) {
1348       case ALIGN_T: dy = 0 - selLtY; break;
1349       case ALIGN_M: dy = (paperHeight>>1) - ((selRbY+selLtY)>>1); break;
1350       case ALIGN_B: dy = paperHeight - selRbY; break;
1351       }
1352       if (dx != 0 || dy != 0) {
1353          struct SubCmdRec *sub_cmd=NULL;
1354 
1355          sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
1356          if (sub_cmd == NULL) FailAllocMessage();
1357          memset(sub_cmd, 0, sizeof(struct SubCmdRec));
1358 
1359          sub_cmd->detail.move.dx = dx;
1360          sub_cmd->detail.move.dy = dy;
1361 
1362          PrepareToRecord(CMD_MOVE, topSel, botSel, numObjSelected);
1363          RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
1364          for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
1365             if (!sel_ptr->obj->locked) {
1366                MoveObj(sel_ptr->obj, dx, dy);
1367             }
1368          }
1369          free(sub_cmd);
1370       }
1371    }
1372    ltx = selLtX; lty = selLtY; rbx = selRbX, rby = selRbY;
1373    UpdSelBBox();
1374    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1375          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1376          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1377          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1378    HighLightForward();
1379    SetFileModified(TRUE);
1380    justDupped = FALSE;
1381 }
1382 
AlignSelToGrid()1383 void AlignSelToGrid()
1384 {
1385    int x=0, y=0, i;
1386    struct ObjRec *obj_ptr=NULL;
1387    struct SelRec *sel_ptr=NULL;
1388    struct VSelRec *vsel_ptr=NULL;
1389    int grid_x, grid_y, dx, dy, ltx, lty, rbx, rby, auto_justifiable;
1390    int saved_draw_orig_x=0, saved_draw_orig_y=0;
1391 
1392    if (topSel == NULL && topVSel == NULL) return;
1393 
1394    StartCompositeCmd();
1395    HighLightReverse();
1396    if (curChoice == VERTEXMODE) {
1397       for (vsel_ptr = topVSel; vsel_ptr != NULL; vsel_ptr = vsel_ptr->next) {
1398          int changed=FALSE, n=0, ssn=(-1), curved=(-1);
1399          IntPoint *vlist=NULL, *ssvlist=NULL;
1400          struct PolyRec *poly_ptr=NULL;
1401          struct PolygonRec *polygon_ptr=NULL;
1402          StretchStructuredSplineInfo sssi;
1403 
1404          memset(&sssi, 0, sizeof(StretchStructuredSplineInfo));
1405 
1406          obj_ptr = vsel_ptr->obj;
1407          switch (obj_ptr->type) {
1408          case OBJ_POLY:
1409             poly_ptr = obj_ptr->detail.p;
1410             curved = poly_ptr->curved;
1411             n = poly_ptr->n;
1412             vlist = poly_ptr->vlist;
1413             if (curved == LT_STRUCT_SPLINE) {
1414                ssn = poly_ptr->ssn;
1415                ssvlist = poly_ptr->ssvlist;
1416                SetIPTInfoForStretchPoly(vsel_ptr->v_index[0], n, vlist, &sssi);
1417             }
1418             break;
1419          case OBJ_POLYGON:
1420             polygon_ptr = obj_ptr->detail.g;
1421             curved = polygon_ptr->curved;
1422             n = polygon_ptr->n;
1423             vlist = polygon_ptr->vlist;
1424             if (curved == LT_STRUCT_SPLINE) {
1425                ssn = polygon_ptr->ssn;
1426                ssvlist = polygon_ptr->ssvlist;
1427                SetIPTInfoForStretchPolygon(vsel_ptr->v_index[0], n, vlist,
1428                      &sssi);
1429             }
1430             break;
1431          }
1432          PrepareToReplaceAnObj(obj_ptr);
1433 
1434          saved_draw_orig_x = drawOrigX;
1435          saved_draw_orig_y = drawOrigY;
1436 
1437          drawOrigX = drawOrigY = 0;
1438 
1439          for (i = 0; i < vsel_ptr->n; i++) {
1440             if (horiAlign!=ALIGN_N && horiAlign!=ALIGN_S) x = vsel_ptr->x[i];
1441             if (vertAlign!=ALIGN_N && vertAlign!=ALIGN_S) y = vsel_ptr->y[i];
1442             if (zoomedIn) {
1443                GridXY(ZOOMED_SIZE(x), ZOOMED_SIZE(y), &grid_x, &grid_y);
1444                if (horiAlign==ALIGN_N || horiAlign==ALIGN_S) {
1445                   x = ABS_SIZE(grid_x);
1446                }
1447                if (vertAlign==ALIGN_N || vertAlign==ALIGN_S) {
1448                   y = ABS_SIZE(grid_y);
1449                }
1450                dx = ABS_SIZE(grid_x) - x;
1451                dy = ABS_SIZE(grid_y) - y;
1452             } else {
1453                GridXY(ZOOMED_SIZE(x), ZOOMED_SIZE(y), &grid_x, &grid_y);
1454                if (horiAlign==ALIGN_N || horiAlign==ALIGN_S) x = grid_x;
1455                if (vertAlign==ALIGN_N || vertAlign==ALIGN_S) y = grid_y;
1456 
1457                dx = ABS_SIZE(grid_x) - x;
1458                dy = ABS_SIZE(grid_y) - y;
1459             }
1460             if (dx != 0 || dy != 0) {
1461                changed = TRUE;
1462                if (ssvlist != NULL) {
1463                   /* LT_STRUCT_SPLINE */
1464                   if (obj_ptr->ctm == NULL) {
1465                      vsel_ptr->x[i] += dx;
1466                      vsel_ptr->y[i] += dy;
1467                   } else {
1468                      int tmp_x=0, tmp_y=0, tmp_x2=0, tmp_y2=0;
1469 
1470                      /*
1471                       * looks like of silly here, but it's to fix round-off
1472                       *         errors
1473                       */
1474                      ReverseTransformPointThroughCTM(
1475                            vsel_ptr->x[i]+dx-obj_ptr->x,
1476                            vsel_ptr->y[i]+dy-obj_ptr->y, obj_ptr->ctm,
1477                            &tmp_x, &tmp_y);
1478                      TransformPointThroughCTM(tmp_x, tmp_y, obj_ptr->ctm,
1479                             &tmp_x2, &tmp_y2);
1480                      vsel_ptr->x[i] = tmp_x2 + obj_ptr->x;
1481                      vsel_ptr->y[i] = tmp_y2 + obj_ptr->y;
1482                   }
1483                   FinishMoveVertexForStretchStructSpline(vsel_ptr, dx, dy,
1484                         &sssi);
1485                } else {
1486                   if (obj_ptr->ctm == NULL) {
1487                      vlist[vsel_ptr->v_index[i]].x += dx;
1488                      vlist[vsel_ptr->v_index[i]].y += dy;
1489                      vsel_ptr->x[i] += dx;
1490                      vsel_ptr->y[i] += dy;
1491                   } else {
1492                      int tmp_x=0, tmp_y=0, tmp_x2=0, tmp_y2=0;
1493 
1494                      ReverseTransformPointThroughCTM(
1495                            vsel_ptr->x[i]+dx-obj_ptr->x,
1496                            vsel_ptr->y[i]+dy-obj_ptr->y, obj_ptr->ctm,
1497                            &tmp_x, &tmp_y);
1498                      vlist[vsel_ptr->v_index[i]].x = tmp_x+obj_ptr->x;
1499                      vlist[vsel_ptr->v_index[i]].y = tmp_y+obj_ptr->y;
1500 
1501                      TransformPointThroughCTM(tmp_x, tmp_y, obj_ptr->ctm,
1502                             &tmp_x2, &tmp_y2);
1503                      vsel_ptr->x[i] = tmp_x2 + obj_ptr->x;
1504                      vsel_ptr->y[i] = tmp_y2 + obj_ptr->y;
1505                   }
1506                }
1507             }
1508          }
1509          drawOrigX = saved_draw_orig_x;
1510          drawOrigY = saved_draw_orig_y;
1511 
1512          if (changed) {
1513             AdjObjSplineVs(obj_ptr);
1514             UpdNonIntSplinePolyBBox(obj_ptr, n, vlist);
1515             RecordReplaceAnObj(obj_ptr);
1516          } else {
1517             AbortPrepareCmd(CMD_REPLACE);
1518          }
1519       }
1520    } else {
1521       struct SubCmdRec *sub_cmd=NULL;
1522       struct SelRec *tmp_sel_ptr=NULL;
1523 
1524       tmp_sel_ptr = (struct SelRec *)malloc(sizeof(struct SelRec));
1525       if (tmp_sel_ptr == NULL) FailAllocMessage();
1526       tmp_sel_ptr->next = tmp_sel_ptr->prev = NULL;
1527 
1528       sub_cmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
1529       if (sub_cmd == NULL) FailAllocMessage();
1530       memset(sub_cmd, 0, sizeof(struct SubCmdRec));
1531 
1532       for (sel_ptr = topSel; sel_ptr != NULL; sel_ptr = sel_ptr->next) {
1533          obj_ptr = sel_ptr->obj;
1534          if (obj_ptr->locked) continue;
1535 
1536          if ((auto_justifiable=AutoJustifiable(obj_ptr))) {
1537             PrepareToReplaceAnObj(obj_ptr);
1538             AutoJustify(obj_ptr);
1539          }
1540          switch (horiAlign) {
1541          case ALIGN_L: x = obj_ptr->obbox.ltx; break;
1542          case ALIGN_C: x = (obj_ptr->obbox.ltx+obj_ptr->obbox.rbx)/2; break;
1543          case ALIGN_R: x = obj_ptr->obbox.rbx; break;
1544          }
1545          switch (vertAlign) {
1546          case ALIGN_T: y = obj_ptr->obbox.lty; break;
1547          case ALIGN_M: y = (obj_ptr->obbox.lty+obj_ptr->obbox.rby)/2; break;
1548          case ALIGN_B: y = obj_ptr->obbox.rby; break;
1549          }
1550          saved_draw_orig_x = drawOrigX;
1551          saved_draw_orig_y = drawOrigY;
1552 
1553          drawOrigX = drawOrigY = 0;
1554 
1555          if (zoomedIn) {
1556             GridXY(ZOOMED_SIZE(x), ZOOMED_SIZE(y), &grid_x, &grid_y);
1557             if (horiAlign==ALIGN_N || horiAlign==ALIGN_S) x = ABS_SIZE(grid_x);
1558             if (vertAlign==ALIGN_N || vertAlign==ALIGN_S) y = ABS_SIZE(grid_y);
1559 
1560             dx = ABS_SIZE(grid_x) - x;
1561             dy = ABS_SIZE(grid_y) - y;
1562          } else {
1563             GridXY(ZOOMED_SIZE(x), ZOOMED_SIZE(y), &grid_x, &grid_y);
1564             if (horiAlign==ALIGN_N || horiAlign==ALIGN_S) x = grid_x;
1565             if (vertAlign==ALIGN_N || vertAlign==ALIGN_S) y = grid_y;
1566 
1567             dx = ABS_SIZE(grid_x) - x;
1568             dy = ABS_SIZE(grid_y) - y;
1569          }
1570          drawOrigX = saved_draw_orig_x;
1571          drawOrigY = saved_draw_orig_y;
1572 
1573          if (dx != 0 || dy != 0) {
1574             if (auto_justifiable) {
1575                MoveObj(obj_ptr, dx, dy);
1576                RecordReplaceAnObj(obj_ptr);
1577             } else {
1578                sub_cmd->detail.move.dx = dx;
1579                sub_cmd->detail.move.dy = dy;
1580                tmp_sel_ptr->obj = obj_ptr;
1581                PrepareToRecord(CMD_MOVE, tmp_sel_ptr, tmp_sel_ptr, 1);
1582                RecordCmd(CMD_MOVE, sub_cmd, NULL, NULL, 0);
1583 
1584                MoveObj(obj_ptr, dx, dy);
1585             }
1586          } else if (auto_justifiable) {
1587             RecordReplaceAnObj(obj_ptr);
1588          }
1589       }
1590       free(sub_cmd);
1591       free(tmp_sel_ptr);
1592    }
1593    EndCompositeCmd();
1594 
1595    ltx = selLtX; lty = selLtY; rbx = selRbX, rby = selRbY;
1596    UpdSelBBox();
1597    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1598          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1599          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1600          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1601    HighLightForward();
1602    SetFileModified(TRUE);
1603    justDupped = FALSE;
1604 }
1605 
HoriAlignSubMenu(index)1606 void HoriAlignSubMenu(index)
1607    int index;
1608 {
1609    char *psz=NULL;
1610 
1611    horiAlign = index;
1612    psz = HoriAlignLoadString(horiAlign);
1613    if (psz != NULL) Msg(psz);
1614    ShowHoriAlign();
1615    UpdatePinnedMenu(MENU_HORIALIGN);
1616 }
1617 
RefreshHoriAlignMenu(menu)1618 void RefreshHoriAlignMenu(menu)
1619    TgMenu *menu;
1620 {
1621    int i, num_items=menu->num_items;
1622    TgMenuItem *menuitems=menu->menuitems;
1623 
1624    for (i=0; i < num_items; i++) {
1625       TgMenuItem *menu_item=(&menuitems[i]);
1626       TgMenuItem stMenuItem;
1627 
1628       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1629       stMenuItem.state = TGBS_NORMAL;
1630       stMenuItem.checked = (i == horiAlign);
1631       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
1632             &stMenuItem);
1633    }
1634 }
1635 
CreateHoriAlignMenu(parent_menu,x,y,menu_info,status_str_xlated)1636 TgMenu *CreateHoriAlignMenu(parent_menu, x, y, menu_info, status_str_xlated)
1637    TgMenu *parent_menu;
1638    int x, y;
1639    TgMenuInfo *menu_info;
1640    int status_str_xlated; /* ignored, always 0 */
1641 {
1642    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
1643 
1644    if (menu != NULL) {
1645       TgMenuItem *menu_item=NULL;
1646       TgMenuItem stMenuItem;
1647 
1648       menu->track_menubar = TRUE;
1649       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, MAXALIGNS);
1650       menu_item = (&menu->menuitems[horiAlign]);
1651 
1652       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1653       stMenuItem.checked = TRUE;
1654       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
1655          return TgDestroyMenu(menu, TRUE);
1656       }
1657       menu->refresh_proc = ((RefreshMenuFunc*)RefreshHoriAlignMenu);
1658    }
1659    return menu;
1660 }
1661 
HoriAlignMenu(X,Y,TrackMenubar)1662 int HoriAlignMenu(X, Y, TrackMenubar)
1663    int X, Y, TrackMenubar;
1664 {
1665    int rc=INVALID;
1666    TgMenu *menu=(horiAlignMenuInfo.create_proc)(NULL, X, Y, &horiAlignMenuInfo,
1667          INVALID);
1668 
1669    activeMenu = MENU_HORIALIGN;
1670    if (menu != NULL) {
1671       menu->track_menubar = TrackMenubar;
1672 
1673       rc = TgMenuLoop(menu);
1674       TgDestroyMenu(menu, TRUE);
1675    }
1676    return rc;
1677 }
1678 
VertAlignSubMenu(index)1679 void VertAlignSubMenu(index)
1680    int index;
1681 {
1682    char *psz=NULL;
1683 
1684    vertAlign = index;
1685    psz = VertAlignLoadString(vertAlign);
1686    if (psz != NULL) Msg(psz);
1687    ShowVertAlign();
1688    UpdatePinnedMenu(MENU_VERTALIGN);
1689 }
1690 
RefreshVertAlignMenu(menu)1691 void RefreshVertAlignMenu(menu)
1692    TgMenu *menu;
1693 {
1694    int i, num_items=menu->num_items;
1695    TgMenuItem *menuitems=menu->menuitems;
1696 
1697    for (i=0; i < num_items; i++) {
1698       TgMenuItem *menu_item=(&menuitems[i]);
1699       TgMenuItem stMenuItem;
1700 
1701       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1702       stMenuItem.state = TGBS_NORMAL;
1703       stMenuItem.checked = (i == vertAlign);
1704       TgSetMenuItemInfo(menu_item, TGMU_MASK_STATE|TGMU_MASK_CHECK,
1705             &stMenuItem);
1706    }
1707 }
1708 
CreateVertAlignMenu(parent_menu,x,y,menu_info,status_str_xlated)1709 TgMenu *CreateVertAlignMenu(parent_menu, x, y, menu_info, status_str_xlated)
1710    TgMenu *parent_menu;
1711    int x, y;
1712    TgMenuInfo *menu_info;
1713    int status_str_xlated; /* ignored, always 0 */
1714 {
1715    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
1716 
1717    if (menu != NULL) {
1718       TgMenuItem *menu_item=NULL;
1719       TgMenuItem stMenuItem;
1720 
1721       menu->track_menubar = TRUE;
1722       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, MAXALIGNS);
1723       menu_item = (&menu->menuitems[vertAlign]);
1724 
1725       memset(&stMenuItem, 0, sizeof(TgMenuItem));
1726       stMenuItem.checked = TRUE;
1727       if (!TgSetMenuItemInfo(menu_item, TGMU_MASK_CHECK, &stMenuItem)) {
1728          return TgDestroyMenu(menu, TRUE);
1729       }
1730       menu->refresh_proc = ((RefreshMenuFunc*)RefreshVertAlignMenu);
1731    }
1732    return menu;
1733 }
1734 
VertAlignMenu(X,Y,TrackMenubar)1735 int VertAlignMenu(X, Y, TrackMenubar)
1736    int X, Y, TrackMenubar;
1737 {
1738    int rc=INVALID;
1739    TgMenu *menu=(vertAlignMenuInfo.create_proc)(NULL, X, Y, &vertAlignMenuInfo,
1740          INVALID);
1741 
1742    activeMenu = MENU_VERTALIGN;
1743    if (menu != NULL) {
1744       menu->track_menubar = TrackMenubar;
1745 
1746       rc = TgMenuLoop(menu);
1747       TgDestroyMenu(menu, TRUE);
1748    }
1749    return rc;
1750 }
1751 
AlignDirect(alignment)1752 void AlignDirect(alignment)
1753    int alignment;
1754 {
1755    int saved_h_align=horiAlign, saved_v_align=vertAlign;
1756    int v_align=(alignment%(MAXALIGNS-1));
1757    int h_align=((alignment-v_align)/(MAXALIGNS-1));
1758 
1759    horiAlign = h_align;
1760    vertAlign = v_align;
1761    switch (alignDirectType) {
1762    case ALIGN_OBJS_DIRECT: AlignSelObjs(); break;
1763    case ALIGN_TO_GRID_DIRECT: AlignSelToGrid(); break;
1764    case ALIGN_TO_PAGE_DIRECT: AlignSelToPage(); break;
1765    }
1766    horiAlign = saved_h_align;
1767    vertAlign = saved_v_align;
1768 }
1769 
1770 static
GetAlignDirectMenuStr(i)1771 char *GetAlignDirectMenuStr(i)
1772    int i;
1773    /* returned string has been translated */
1774 {
1775    char *psz=NULL, *msg=NULL;
1776 
1777    if (curChoice == VERTEXMODE) {
1778       if (alignDirectType == ALIGN_TO_PAGE_DIRECT) {
1779          if (i == 0) {
1780             msg = TgLoadCachedString(CSTID_PARANED_NONE);
1781          } else {
1782             msg = AlignVerticesDirectToPageLoadString(i);
1783          }
1784       } else {
1785          int v_align=(i%(MAXALIGNS-1));
1786          int h_align=((i-v_align)/(MAXALIGNS-1));
1787 
1788          if (v_align == ALIGN_N) {
1789             if (h_align == ALIGN_N) {
1790                msg = TgLoadCachedString(CSTID_PARANED_NONE);
1791             } else {
1792                msg = (alignDirectType==ALIGN_TO_GRID_DIRECT ?
1793                      TgLoadString(STID_ALIGN_VERTICES_HORI_TO_GRID) :
1794                      TgLoadString(STID_ALIGN_VERTICES_VERT));
1795             }
1796          } else {
1797             if (h_align == ALIGN_N) {
1798                msg = (alignDirectType==ALIGN_TO_GRID_DIRECT ?
1799                      TgLoadString(STID_ALIGN_VERTICES_VERT_TO_GRID) :
1800                      TgLoadString(STID_ALIGN_VERTICES_HORI));
1801             } else {
1802                msg = (alignDirectType==ALIGN_TO_GRID_DIRECT ?
1803                      TgLoadString(STID_ALIGN_VERTICES_TO_GRID) :
1804                      TgLoadString(STID_ALIGN_VERTICES));
1805             }
1806          }
1807       }
1808    } else {
1809       if (alignDirectType == ALIGN_TO_PAGE_DIRECT) {
1810          if (i == 0) {
1811             msg = TgLoadCachedString(CSTID_PARANED_NONE);
1812          } else {
1813             msg = AlignDirectToPageLoadString(i);
1814          }
1815       } else {
1816          if (i == 0) {
1817             msg = TgLoadCachedString(CSTID_PARANED_NONE);
1818          } else if (alignDirectType == ALIGN_TO_GRID_DIRECT) {
1819             msg = AlignDirectToGridLoadString(i);
1820          } else {
1821             msg = AlignDirectLoadString(i);
1822          }
1823       }
1824    }
1825    psz = UtilStrDup(msg);
1826    if (psz == NULL) FailAllocMessage();
1827    return psz;
1828 }
1829 
1830 static
CreateAlignDirectMenu(parent_menu,x,y,menu_info)1831 TgMenu *CreateAlignDirectMenu(parent_menu, x, y, menu_info)
1832    TgMenu *parent_menu;
1833    int x, y;
1834    TgMenuInfo *menu_info;
1835 {
1836    int i=0, num_entries=((MAXALIGNS-1)*(MAXALIGNS-1));
1837    TgMenu *menu=NULL;
1838    TgMenuInfo stMenuInfo;
1839    TgMenuItemInfo *item_info=NULL;
1840 
1841    memcpy(&stMenuInfo, menu_info, sizeof(TgMenuInfo));
1842    stMenuInfo.items = (TgMenuItemInfo*)malloc(
1843          (num_entries+1)*sizeof(TgMenuItemInfo));
1844    if (stMenuInfo.items == NULL) FailAllocMessage();
1845    memset(stMenuInfo.items, 0, (num_entries+1)*sizeof(TgMenuItemInfo));
1846    for (item_info=stMenuInfo.items, i=0; i < num_entries; item_info++, i++) {
1847       item_info->menu_str = (char*)(Pixmap*)(&alignDirectPixmap[i]);
1848       item_info->shortcut_str = NULL;
1849       item_info->status_str = GetAlignDirectMenuStr(i);
1850       item_info->submenu_info = NULL;
1851       item_info->cmdid = CMDID_ALIGNDIRECT;
1852    }
1853    stMenuInfo.items[num_entries].cmdid = INVALID;
1854 
1855    /* the status_str has been translated in GetAlignDirectMenuStr() */
1856    menu = TgCreateMenuFromMenuInfo(parent_menu, x, y, &stMenuInfo, TRUE);
1857    for (item_info=stMenuInfo.items, i=0; i < num_entries; item_info++, i++) {
1858       UtilFree(item_info->status_str);
1859    }
1860    memset(stMenuInfo.items, 0, (num_entries+1)*sizeof(TgMenuItemInfo));
1861    free(stMenuInfo.items);
1862    stMenuInfo.items = NULL;
1863    if (menu != NULL) {
1864       menu->track_menubar = TRUE;
1865       TgAdjustMenuGeometry(menu, choiceImageW, choiceImageH, (MAXALIGNS-1));
1866    }
1867    return menu;
1868 }
1869 
CreateAlignObjsDirectMenu(parent_menu,x,y,menu_info,status_str_xlated)1870 TgMenu *CreateAlignObjsDirectMenu(parent_menu, x, y, menu_info,
1871       status_str_xlated)
1872    TgMenu *parent_menu;
1873    int x, y;
1874    TgMenuInfo *menu_info;
1875    int status_str_xlated; /* ignored, always 0 */
1876 {
1877    alignDirectType = ALIGN_OBJS_DIRECT;
1878    return CreateAlignDirectMenu(parent_menu, x, y, menu_info);
1879 }
1880 
CreateAlignToGridDirectMenu(parent_menu,x,y,menu_info,status_str_xlated)1881 TgMenu *CreateAlignToGridDirectMenu(parent_menu, x, y, menu_info,
1882       status_str_xlated)
1883    TgMenu *parent_menu;
1884    int x, y;
1885    TgMenuInfo *menu_info;
1886    int status_str_xlated; /* ignored, always 0 */
1887 {
1888    alignDirectType = ALIGN_TO_GRID_DIRECT;
1889    return CreateAlignDirectMenu(parent_menu, x, y, menu_info);
1890 }
1891 
CreateAlignToPageDirectMenu(parent_menu,x,y,menu_info,status_str_xlated)1892 TgMenu *CreateAlignToPageDirectMenu(parent_menu, x, y, menu_info,
1893       status_str_xlated)
1894    TgMenu *parent_menu;
1895    int x, y;
1896    TgMenuInfo *menu_info;
1897    int status_str_xlated; /* ignored, always 0 */
1898 {
1899    alignDirectType = ALIGN_TO_PAGE_DIRECT;
1900    return CreateAlignDirectMenu(parent_menu, x, y, menu_info);
1901 }
1902 
CenterAnEndPoint()1903 void CenterAnEndPoint()
1904 {
1905    struct ObjRec *other_obj=NULL, *poly_obj=NULL;
1906    IntPoint *v;
1907    int cx, cy, x1, y1, xn, yn, d1, dn, n=0, index, x, y, tmp_x, tmp_y;
1908 
1909    if (curChoice != NOTHING) return;
1910    if (topSel == NULL) {
1911       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
1912       return;
1913    }
1914    if (numObjSelected != 2 ||
1915          (!((topSel->obj->type == OBJ_POLY && botSel->obj->type != OBJ_POLY) ||
1916          (topSel->obj->type != OBJ_POLY && botSel->obj->type == OBJ_POLY)))) {
1917       MsgBox(TgLoadString(STID_SELECT_ONE_POLY_ONE_NON_POLY), TOOL_NAME,
1918             INFO_MB);
1919       return;
1920    }
1921    if (topSel->obj->type == OBJ_POLY) {
1922       poly_obj = topSel->obj;
1923       other_obj = botSel->obj;
1924    } else {
1925       poly_obj = botSel->obj;
1926       other_obj = topSel->obj;
1927    }
1928    if (poly_obj->locked) {
1929       MsgBox(TgLoadString(STID_CANNOT_MOVE_A_VERTEX_LOCKED), TOOL_NAME,
1930             INFO_MB);
1931       return;
1932    }
1933    cx = (other_obj->obbox.ltx+other_obj->obbox.rbx)>>1;
1934    cy = (other_obj->obbox.lty+other_obj->obbox.rby)>>1;
1935    n = poly_obj->detail.p->n;
1936    v = poly_obj->detail.p->vlist;
1937    if (poly_obj->ctm == NULL) {
1938       x1 = v[0].x;
1939       y1 = v[0].y;
1940       xn = v[n-1].x;
1941       yn = v[n-1].y;
1942    } else {
1943       TransformPointThroughCTM(v[0].x-poly_obj->x, v[0].y-poly_obj->y,
1944             poly_obj->ctm, &tmp_x, &tmp_y);
1945       x1 = tmp_x+poly_obj->x;
1946       y1 = tmp_y+poly_obj->y;
1947       TransformPointThroughCTM(v[n-1].x-poly_obj->x,
1948             v[n-1].y-poly_obj->y, poly_obj->ctm, &tmp_x, &tmp_y);
1949       xn = tmp_x+poly_obj->x;
1950       yn = tmp_y+poly_obj->y;
1951    }
1952    d1 = (x1-cx)*(x1-cx)+(y1-cy)*(y1-cy);
1953    dn = (xn-cx)*(xn-cx)+(yn-cy)*(yn-cy);
1954    if (d1 <= dn) {
1955       index = 0;
1956       x = x1;
1957       y = y1;
1958    } else {
1959       index = n-1;
1960       x = xn;
1961       y = yn;
1962    }
1963    if (cx != x || cy != y) {
1964       int ltx=0, lty=0, rbx=0, rby=0;
1965 
1966       HighLightReverse();
1967       PrepareToReplaceAnObj(poly_obj);
1968       if (poly_obj->ctm == NULL) {
1969          v[index].x = cx;
1970          v[index].y = cy;
1971       } else {
1972          ReverseTransformPointThroughCTM(cx-poly_obj->x, cy-poly_obj->y,
1973                poly_obj->ctm, &tmp_x, &tmp_y);
1974          v[index].x = tmp_x+poly_obj->x;
1975          v[index].y = tmp_y+poly_obj->y;
1976       }
1977       AdjObjSplineVs(poly_obj);
1978       switch (poly_obj->detail.p->curved) {
1979       case LT_STRAIGHT:
1980       case LT_SPLINE:
1981       case LT_STRUCT_SPLINE:
1982          UpdPolyBBox(poly_obj, n, v);
1983          break;
1984       case LT_INTSPLINE:
1985          UpdPolyBBox(poly_obj, poly_obj->detail.p->intn,
1986                poly_obj->detail.p->intvlist);
1987          break;
1988       }
1989       RecordReplaceAnObj(poly_obj);
1990       ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
1991       UpdSelBBox();
1992       RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1993             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
1994             selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1995             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1996       HighLightForward();
1997       SetFileModified(TRUE);
1998       justDupped = FALSE;
1999    }
2000 }
2001