1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1991 by Paul King
4  * Parts Copyright (c) 1989-2007 by Brian V. Smith
5  *
6  * Any party obtaining a copy of these files is granted, free of charge, a
7  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
8  * nonexclusive right and license to deal in this software and documentation
9  * files (the "Software"), including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
11  * the Software, and to permit persons who receive copies from any such
12  * party to do so, with the only requirement being that the above copyright
13  * and this permission notice remain intact.
14  *
15  */
16 
17 #include "e_align.h"
18 
19 #include <stdlib.h>
20 #include <limits.h>		/* INT_MAX, INT_MIN */
21 #include <X11/Intrinsic.h>	/* includes X11/Xlib.h */
22 
23 #include "resources.h"
24 #include "object.h"
25 #include "paintop.h"
26 #include "mode.h"
27 #include "u_bound.h"
28 #include "u_create.h"
29 #include "u_draw.h"
30 #include "u_markers.h"
31 #include "u_search.h"
32 #include "u_translate.h"
33 #include "u_undo.h"
34 #include "w_canvas.h"
35 #include "w_cursor.h"
36 #include "w_layers.h"
37 #include "w_mousefun.h"
38 #include "w_msgpanel.h"
39 #include "w_setup.h"
40 #include "xfig_math.h"
41 
42 
43 static int	llx, lly, urx, ury;
44 static int	xcmin, ycmin, xcmax, ycmax;
45 static int	dx, dy;
46 
47 static Boolean	pos_arc(F_arc *a, int *min, int *size, int dir);
48 static Boolean	pos_ellipse(F_ellipse *e, int *min, int *size, int dir);
49 static Boolean	pos_line(F_line *l, int *min, int *size, int dir);
50 static Boolean	pos_spline(F_spline *s, int *min, int *size, int dir);
51 static Boolean	pos_text(F_text *t, int *min, int *size, int dir);
52 static Boolean	pos_compound(F_compound *c, int *min, int *size, int dir);
53 
54 static void	init_align(F_line *p, int type, int x, int y, int px, int py);
55 static void	init_align_canvas(int x, int y, unsigned int shift);
56 static void	align_arc(void);
57 static void	align_ellipse(void);
58 static void	align_line(void);
59 static void	align_spline(void);
60 static void	align_text(void);
61 static void	align_compound(void);
62 static void	get_dx_dy(void);
63 static void	distribute_horizontally(void);
64 static void	distribute_vertically(void);
65 
66 
67 
68 void
align_selected(void)69 align_selected(void)
70 {
71     set_mousefun("align compound", "align canvas", "", LOC_OBJ, "", LOC_OBJ);
72     canvas_kbd_proc = null_proc;
73     canvas_locmove_proc = null_proc;
74     canvas_ref_proc = null_proc;
75     init_searchproc_left(init_align);
76     canvas_leftbut_proc = object_search_left;
77     canvas_middlebut_proc = init_align_canvas;
78     canvas_rightbut_proc = null_proc;
79     set_cursor(pick15_cursor);
80     reset_action_on();
81 }
82 
83 /* align objects to the whole canvas */
84 
85 static void
init_align_canvas(int x,int y,unsigned int shift)86 init_align_canvas(int x, int y, unsigned int shift)
87 /* Shift Key Status from XEvent */
88 {
89 	(void)x;
90 	(void)y;
91 	(void)shift;
92     int		    ux;
93 
94     cur_c = &objects;
95     toggle_all_compoundmarkers();
96     draw_compoundelements(cur_c, ERASE);
97     old_c = copy_compound(&objects);
98     xcmin=ycmin=0;
99 
100     /* get the current page size */
101     xcmax = paper_sizes[appres.papersize].width;
102     ycmax = paper_sizes[appres.papersize].height;
103     if (!appres.INCHES) {
104 	xcmax = (int)(xcmax*2.54*PIX_PER_CM/PIX_PER_INCH);
105 	ycmax = (int)(ycmax*2.54*PIX_PER_CM/PIX_PER_INCH);
106     }
107     /* swap height and width if landscape */
108     if (appres.landscape) {
109 	ux = xcmax;
110 	xcmax = ycmax;
111 	ycmax = ux;
112     }
113     align_ellipse();
114     align_arc();
115     align_line();
116     align_spline();
117     align_compound();
118     align_text();
119 
120     /*
121      * Display messages indicating that distribution or alignment can't be
122      * performed with respect to the canvas.
123      */
124     if ((cur_halign == ALIGN_DISTRIB_C) || (cur_halign == ALIGN_DISTRIB_E))
125       put_msg("Can't DISTRIBUTE horizontally with respect to the canvas");
126     else if (cur_halign == ALIGN_ABUT)
127       put_msg("Can't ABUT horizontally with respect to the canvas");
128     if ((cur_valign == ALIGN_DISTRIB_C) || (cur_valign == ALIGN_DISTRIB_E))
129       put_msg("Can't DISTRIBUTE vertically with respect to the canvas");
130     else if (cur_valign == ALIGN_ABUT)
131       put_msg("Can't ABUT vertically with respect to the canvas");
132 
133     draw_compoundelements(cur_c, PAINT);
134     toggle_all_compoundmarkers();
135     clean_up();
136     set_latestobjects(old_c);
137     set_action_object(F_EDIT, O_ALL_OBJECT);
138     set_modifiedflag();
139 }
140 
141 static void
init_align(F_line * p,int type,int x,int y,int px,int py)142 init_align(F_line *p, int type, int x, int y, int px, int py)
143 {
144 	(void)x;
145 	(void)y;
146 	(void)px;
147 	(void)py;
148 
149     if (type != O_COMPOUND)
150 	return;
151     cur_c = (F_compound *) p;
152     toggle_compoundmarker(cur_c);
153     draw_compoundelements(cur_c, ERASE);
154     old_c = copy_compound(cur_c);
155     compound_bound(cur_c, &xcmin, &ycmin, &xcmax, &ycmax);
156     align_ellipse();
157     align_arc();
158     align_line();
159     align_spline();
160     align_compound();
161     align_text();
162 
163     /*
164      * Perform the distribution of the objects in the compound
165      */
166     if ( (cur_halign == ALIGN_DISTRIB_C) || (cur_halign == ALIGN_DISTRIB_E)
167 	|| (cur_halign == ALIGN_ABUT) )
168       distribute_horizontally();
169     if ( (cur_valign == ALIGN_DISTRIB_C) || (cur_valign == ALIGN_DISTRIB_E)
170 	|| (cur_valign == ALIGN_ABUT) )
171       distribute_vertically();
172 
173     /*
174      * recompute the compound's bounding box
175      */
176     compound_bound(cur_c, &cur_c->nwcorner.x, &cur_c->nwcorner.y,
177 		   &cur_c->secorner.x, &cur_c->secorner.y);
178     draw_compoundelements(cur_c, PAINT);
179     toggle_compoundmarker(cur_c);
180     clean_up();
181     old_c->next = cur_c;
182     set_latestcompound(old_c);
183     set_action_object(F_EDIT, O_COMPOUND);
184     set_modifiedflag();
185 }
186 
187 static void
align_ellipse(void)188 align_ellipse(void)
189 {
190     F_ellipse	   *e;
191 
192     for (e = cur_c->ellipses; e != NULL; e = e->next) {
193 	if (!active_layer(e->depth))
194 	    continue;
195 	ellipse_bound(e, &llx, &lly, &urx, &ury);
196 	get_dx_dy();
197 	translate_ellipse(e, dx, dy);
198     }
199 }
200 
201 static void
align_arc(void)202 align_arc(void)
203 {
204     F_arc	   *a;
205 
206     for (a = cur_c->arcs; a != NULL; a = a->next) {
207 	if (!active_layer(a->depth))
208 	    continue;
209 	arc_bound(a, &llx, &lly, &urx, &ury);
210 	get_dx_dy();
211 	translate_arc(a, dx, dy);
212     }
213 }
214 
215 static void
align_line(void)216 align_line(void)
217 {
218     F_line	   *l;
219 
220     for (l = cur_c->lines; l != NULL; l = l->next) {
221 	if (!active_layer(l->depth))
222 	    continue;
223 	line_bound(l, &llx, &lly, &urx, &ury);
224 	get_dx_dy();
225 	translate_line(l, dx, dy);
226     }
227 }
228 
229 static void
align_spline(void)230 align_spline(void)
231 {
232     F_spline	   *s;
233 
234     for (s = cur_c->splines; s != NULL; s = s->next) {
235 	if (!active_layer(s->depth))
236 	    continue;
237 	spline_bound(s, &llx, &lly, &urx, &ury);
238 	get_dx_dy();
239 	translate_spline(s, dx, dy);
240     }
241 }
242 
243 static void
align_compound(void)244 align_compound(void)
245 {
246     F_compound	   *c;
247 
248     for (c = cur_c->compounds; c != NULL; c = c->next) {
249 	if (!any_active_in_compound(c))
250 	    continue;
251 	compound_bound(c, &llx, &lly, &urx, &ury);
252 	get_dx_dy();
253 	translate_compound(c, dx, dy);
254     }
255 }
256 
257 static void
align_text(void)258 align_text(void)
259 {
260     F_text	   *t;
261     int		    dum;
262 
263     for (t = cur_c->texts; t != NULL; t = t->next) {
264 	if (!active_layer(t->depth))
265 	    continue;
266 	text_bound(t, &llx, &lly, &urx, &ury,
267 		   &dum,&dum,&dum,&dum,&dum,&dum,&dum,&dum);
268 	get_dx_dy();
269 	translate_text(t, dx, dy);
270     }
271 }
272 
273 static void
get_dx_dy(void)274 get_dx_dy(void)
275 {
276     switch (cur_valign) {
277 	case ALIGN_NONE:
278 	dy = 0;
279 	break;
280     case ALIGN_TOP:
281 	dy = ycmin - lly;
282 	break;
283     case ALIGN_BOTTOM:
284 	dy = ycmax - ury;
285 	break;
286     case ALIGN_CENTER:
287 	dy = (ycmin - lly) + (abs(ycmin - lly) + abs(ycmax - ury)) / 2;
288 	break;
289     case ALIGN_DISTRIB_C:
290     case ALIGN_DISTRIB_E:
291     case ALIGN_ABUT:
292 	break;
293     }
294     switch (cur_halign) {
295     case ALIGN_NONE:
296 	dx = 0;
297 	break;
298     case ALIGN_LEFT:
299 	dx = xcmin - llx;
300 	break;
301     case ALIGN_RIGHT:
302 	dx = xcmax - urx;
303 	break;
304     case ALIGN_CENTER:
305 	dx = (xcmin - llx) + (abs(xcmin - llx) + abs(xcmax - urx)) / 2;
306 	break;
307     case ALIGN_DISTRIB_C:
308     case ALIGN_DISTRIB_E:
309     case ALIGN_ABUT:
310 	break;
311     }
312 }
313 
314 
315 
316 
317 /* ====================== Object distribution routines =================== */
318 
319 
320 
321 /*
322  * pos_arc: If the position of the given arc is less than
323  * passed in and the arc hasn't already been distributed, adjust the value
324  * of the passed in parameter.  Also set the width/height if smaller.
325  * If dir == 0, handle horizontal, otherwise vertical.
326  */
327 static Boolean
pos_arc(F_arc * a,int * min,int * size,int dir)328 pos_arc (F_arc *a, int *min, int *size, int dir)
329 {
330   int center;
331 
332   arc_bound (a, &llx, &lly, &urx, &ury);
333   if (dir == 0) {
334     if (cur_halign == ALIGN_DISTRIB_C)
335       center = (urx + llx)/2;
336     else
337       center = min2(urx, llx);
338   } else {
339     if (cur_valign == ALIGN_DISTRIB_C)
340       center = (ury + lly)/2;
341     else
342       center = min2(ury, lly);
343   }
344 
345   if ( (center < *min) && (a->distrib == 0) ) {
346     *min = center;
347     if (dir == 0)
348       *size = abs(urx - llx);
349     else
350       *size = abs(ury - lly);
351     return True;
352   } else
353     return False;
354 } /* pos_arc */
355 
356 
357 
358 /*
359  * pos_ellipse: If the position of the given ellipse is less
360  * than passed in and the ellipse hasn't already been distributed, adjust the
361  * value of the passed in parameter.  Also set the width/height if smaller.
362  * If dir == 0, handle horizontal, otherwise vertical.
363  */
364 static Boolean
pos_ellipse(F_ellipse * e,int * min,int * size,int dir)365 pos_ellipse (F_ellipse *e, int *min, int *size, int dir)
366 {
367   int center;
368 
369   ellipse_bound (e, &llx, &lly, &urx, &ury);
370   if (dir == 0) {
371     if (cur_halign == ALIGN_DISTRIB_C)
372       center = (urx + llx)/2;
373     else
374       center = min2(urx, llx);
375   } else {
376     if (cur_valign == ALIGN_DISTRIB_C)
377       center = (ury + lly)/2;
378     else
379       center = min2(ury, lly);
380   }
381 
382   if ( (center < *min) && (e->distrib == 0) ) {
383     *min = center;
384     if (dir == 0)
385       *size = abs(urx - llx);
386     else
387       *size = abs(ury - lly);
388     return True;
389   } else
390     return False;
391 } /* pos_ellipse */
392 
393 
394 
395 /*
396  * pos_line: If the position of the given line is less than
397  * passed in and the line hasn't already been distributed, adjust the value
398  * of the passed in parameter.  Also set the width/height if smaller.
399  * If dir == 0, handle horizontal, otherwise vertical.
400  */
401 static Boolean
pos_line(F_line * l,int * min,int * size,int dir)402 pos_line (F_line *l, int *min, int *size, int dir)
403 {
404   int center;
405 
406   line_bound (l, &llx, &lly, &urx, &ury);
407   if (dir == 0) {
408     if (cur_halign == ALIGN_DISTRIB_C)
409       center = (urx + llx)/2;
410     else
411       center = min2(urx, llx);
412   } else {
413     if (cur_valign == ALIGN_DISTRIB_C)
414       center = (ury + lly)/2;
415     else
416       center = min2(ury, lly);
417   }
418 
419   if ( (center < *min) && (l->distrib == 0) ) {
420     *min = center;
421     if (dir == 0)
422       *size = abs(urx - llx);
423     else
424       *size = abs(ury - lly);
425     return True;
426   } else
427     return False;
428 } /* pos_line */
429 
430 
431 
432 /*
433  * pos_spline: If the position of the given spline is less than
434  * passed in and the spline hasn't already been distributed, adjust the value
435  * of the passed in parameter.  Also set the width/height if smaller.
436  * If dir == 0, handle horizontal, otherwise vertical.
437  */
438 static Boolean
pos_spline(F_spline * s,int * min,int * size,int dir)439 pos_spline (F_spline *s, int *min, int *size, int dir)
440 {
441   int center;
442 
443   spline_bound (s, &llx, &lly, &urx, &ury);
444   if (dir == 0) {
445     if (cur_halign == ALIGN_DISTRIB_C)
446       center = (urx + llx)/2;
447     else
448       center = min2(urx, llx);
449   } else {
450     if (cur_valign == ALIGN_DISTRIB_C)
451       center = (ury + lly)/2;
452     else
453       center = min2(ury, lly);
454   }
455 
456   if ( (center < *min) && (s->distrib == 0) ) {
457     *min = center;
458     if (dir == 0)
459       *size = abs(urx - llx);
460     else
461       *size = abs(ury - lly);
462     return True;
463   } else
464     return False;
465 } /* pos_spline */
466 
467 
468 
469 /*
470  * pos_text: If the position of the given text is less than
471  * passed in and the text hasn't already been distributed, adjust the value
472  * of the passed in parameter.  Also set the width/height if smaller.
473  * If dir == 0, handle horizontal, otherwise vertical.
474  */
475 static Boolean
pos_text(F_text * t,int * min,int * size,int dir)476 pos_text (F_text *t, int *min, int *size, int dir)
477 {
478   int center, dum;
479 
480   text_bound (t, &llx, &lly, &urx, &ury,
481 	      &dum,&dum,&dum,&dum,&dum,&dum,&dum,&dum);
482   if (dir == 0) {
483     if (cur_halign == ALIGN_DISTRIB_C)
484       center = (urx + llx)/2;
485     else
486       center = min2(urx, llx);
487   } else {
488     if (cur_valign == ALIGN_DISTRIB_C)
489       center = (ury + lly)/2;
490     else
491       center = min2(ury, lly);
492   }
493 
494   if ( (center < *min) && (t->distrib == 0) ) {
495     *min = center;
496     if (dir == 0)
497       *size = abs(urx - llx);
498     else
499       *size = abs(ury - lly);
500     return True;
501   } else
502     return False;
503 } /* pos_text */
504 
505 
506 /*
507  * pos_compound: If the position of the given compound is less
508  * than passed in and the compound hasn't already been distributed, adjust the
509  * value of the passed in parameter.  Also set the width/height if smaller.
510  * If dir == 0, handle horizontal, otherwise vertical.
511  */
512 static Boolean
pos_compound(F_compound * c,int * min,int * size,int dir)513 pos_compound (F_compound *c, int *min, int *size, int dir)
514 {
515   int center;
516 
517   compound_bound (c, &llx, &lly, &urx, &ury);
518   if (dir == 0) {
519     if (cur_halign == ALIGN_DISTRIB_C)
520       center = (urx + llx)/2;
521     else
522       center = min2(urx, llx);
523   } else {
524     if (cur_valign == ALIGN_DISTRIB_C)
525       center = (ury + lly)/2;
526     else
527       center = min2(ury, lly);
528   }
529 
530   if ( (center < *min) && (c->distrib == 0) ) {
531     *min = center;
532     if (dir == 0)
533       *size = abs(urx - llx);
534     else
535       *size = abs(ury - lly);
536     return True;
537   } else
538     return False;
539 } /* pos_compound */
540 
541 
542 
543 #define MIN_MAX_CENTRE(lower,upper,min,max) \
544 { \
545   int centre = (lower + upper)/2; \
546   if (centre < min) \
547     min = centre; \
548   if (centre > max) \
549     max = centre; \
550 }
551 
552 
553 
554 
555 /*
556  * Determine:
557  *   - the number of objects,
558  *   - the left/top most centre and the right/bottom most centre,
559  *   - mark all objects as not distributed.
560  *
561  * dir = 0 for horizontal, 1 for vertical.
562  */
563 static int
init_distrib_centres(int * min,int * max,int dir)564 init_distrib_centres (int *min, int *max, int dir)
565 {
566   F_ellipse	*e;
567   F_arc		*a;
568   F_line	*l;
569   F_spline	*s;
570   F_compound	*c;
571   F_text	*t;
572   int		 num_objects = 0;
573 
574   *min = INT_MAX;
575   *max = INT_MIN;
576 
577   for (e = cur_c->ellipses; e != NULL; e = e->next) {
578     num_objects++;
579     e->distrib = 0;
580     ellipse_bound (e, &llx, &lly, &urx, &ury);
581     if (dir == 0)
582       MIN_MAX_CENTRE(llx, urx, *min, *max)
583     else
584       MIN_MAX_CENTRE(lly, ury, *min, *max)
585   }
586 
587   for (a = cur_c->arcs; a != NULL; a = a->next) {
588     num_objects++;
589     a->distrib = 0;
590     arc_bound (a, &llx, &lly, &urx, &ury);
591     if (dir == 0)
592       MIN_MAX_CENTRE(llx, urx, *min, *max)
593     else
594       MIN_MAX_CENTRE(lly, ury, *min, *max)
595   }
596 
597   for (l = cur_c->lines; l != NULL; l = l->next) {
598     num_objects++;
599     l->distrib = 0;
600     line_bound (l, &llx, &lly, &urx, &ury);
601     if (dir == 0)
602       MIN_MAX_CENTRE(llx, urx, *min, *max)
603     else
604       MIN_MAX_CENTRE(lly, ury, *min, *max)
605   }
606 
607   for (s = cur_c->splines; s != NULL; s = s->next) {
608     num_objects++;
609     s->distrib = 0;
610     spline_bound (s, &llx, &lly, &urx, &ury);
611     if (dir == 0)
612       MIN_MAX_CENTRE(llx, urx, *min, *max)
613     else
614       MIN_MAX_CENTRE(lly, ury, *min, *max)
615   }
616 
617   for (c = cur_c->compounds; c != NULL; c = c->next) {
618     num_objects++;
619     c->distrib = 0;
620     compound_bound (c, &llx, &lly, &urx, &ury);
621     if (dir == 0)
622       MIN_MAX_CENTRE(llx, urx, *min, *max)
623     else
624       MIN_MAX_CENTRE(lly, ury, *min, *max)
625   }
626 
627   for (t = cur_c->texts; t != NULL; t = t->next) {
628     int   dum;
629     num_objects++;
630     t->distrib = 0;
631     text_bound (t, &llx, &lly, &urx, &ury,
632 		&dum,&dum,&dum,&dum,&dum,&dum,&dum,&dum);
633     if (dir == 0)
634       MIN_MAX_CENTRE(llx, urx, *min, *max)
635     else
636       MIN_MAX_CENTRE(lly, ury, *min, *max)
637   }
638 
639   return (num_objects);
640 } /* init_distrib_centres */
641 
642 
643 
644 /*
645  * Determine:
646  *   - the number of objects,
647  *   - the sum of the widths/heights of all objects,
648  *   - the left/top most left/top object edge,
649  *   - the right/bottom most right/bottom object edge,
650  *   - mark all objects as not distributed.
651  *
652  * dir = 0 for horizontal, 1 for vertical.
653  */
654 static int
init_distrib_edges(int * min,int * max,int * sum,int dir)655 init_distrib_edges (int *min, int *max, int *sum, int dir)
656 {
657   F_ellipse	*e;
658   F_arc		*a;
659   F_line	*l;
660   F_spline	*s;
661   F_compound	*c;
662   F_text	*t;
663   int		 num_objects = 0;
664 
665   *min = INT_MAX;
666   *max = INT_MIN;
667   *sum = 0;
668 
669   for (e = cur_c->ellipses; e != NULL; e = e->next) {
670     num_objects++;
671     e->distrib = 0;
672     ellipse_bound (e, &llx, &lly, &urx, &ury);
673     if (dir == 0) {
674       *sum += abs(urx - llx);
675       if (llx < *min) *min = llx;
676       if (urx > *max) *max = urx;
677     } else {
678       *sum += abs(ury - lly);
679       if (lly < *min) *min = lly;
680       if (ury > *max) *max = ury;
681     }
682   }
683 
684   for (a = cur_c->arcs; a != NULL; a = a->next) {
685     num_objects++;
686     a->distrib = 0;
687     arc_bound (a, &llx, &lly, &urx, &ury);
688     if (dir == 0) {
689       *sum += abs(urx - llx);
690       if (llx < *min) *min = llx;
691       if (urx > *max) *max = urx;
692     } else {
693       *sum += abs(ury - lly);
694       if (lly < *min) *min = lly;
695       if (ury > *max) *max = ury;
696     }
697   }
698 
699   for (l = cur_c->lines; l != NULL; l = l->next) {
700     num_objects++;
701     l->distrib = 0;
702     line_bound (l, &llx, &lly, &urx, &ury);
703     if (dir == 0) {
704       *sum += abs(urx - llx);
705       if (llx < *min) *min = llx;
706       if (urx > *max) *max = urx;
707     } else {
708       *sum += abs(ury - lly);
709       if (lly < *min) *min = lly;
710       if (ury > *max) *max = ury;
711     }
712   }
713 
714   for (s = cur_c->splines; s != NULL; s = s->next) {
715     num_objects++;
716     s->distrib = 0;
717     spline_bound (s, &llx, &lly, &urx, &ury);
718     if (dir == 0) {
719       *sum += abs(urx - llx);
720       if (llx < *min) *min = llx;
721       if (urx > *max) *max = urx;
722     } else {
723       *sum += abs(ury - lly);
724       if (lly < *min) *min = lly;
725       if (ury > *max) *max = ury;
726     }
727   }
728 
729   for (c = cur_c->compounds; c != NULL; c = c->next) {
730     num_objects++;
731     c->distrib = 0;
732     compound_bound (c, &llx, &lly, &urx, &ury);
733     if (dir == 0) {
734       *sum += abs(urx - llx);
735       if (llx < *min) *min = llx;
736       if (urx > *max) *max = urx;
737     } else {
738       *sum += abs(ury - lly);
739       if (lly < *min) *min = lly;
740       if (ury > *max) *max = ury;
741     }
742   }
743 
744   for (t = cur_c->texts; t != NULL; t = t->next) {
745     int   dum;
746     num_objects++;
747     t->distrib = 0;
748     text_bound (t, &llx, &lly, &urx, &ury,
749 		&dum,&dum,&dum,&dum,&dum,&dum,&dum,&dum);
750     if (dir == 0) {
751       *sum += abs(urx - llx);
752       if (llx < *min) *min = llx;
753       if (urx > *max) *max = urx;
754     } else {
755       *sum += abs(ury - lly);
756       if (lly < *min) *min = lly;
757       if (ury > *max) *max = ury;
758     }
759   }
760 
761   return (num_objects);
762 } /* init_distrib_edges */
763 
764 
765 static void
adjust_object_pos(F_line * obj_ptr,int obj_type,int delta_x,int delta_y)766 adjust_object_pos (F_line *obj_ptr, int obj_type, int delta_x, int delta_y)
767 {
768   F_ellipse	   *e;
769   F_arc		   *a;
770   F_line	   *l;
771   F_spline	   *s;
772   F_compound	   *c;
773   F_text	   *t;
774 
775 
776   switch (obj_type) {
777   case O_ELLIPSE:
778     e = (F_ellipse *) obj_ptr;
779     translate_ellipse(e, delta_x, delta_y);
780     e->distrib = 1;
781     break;
782   case O_POLYLINE:
783     l = (F_line *) obj_ptr;
784     translate_line(l, delta_x, delta_y);
785     l->distrib = 1;
786     break;
787   case O_SPLINE:
788     s = (F_spline *) obj_ptr;
789     translate_spline(s, delta_x, delta_y);
790     s->distrib = 1;
791     break;
792   case O_TXT:
793     t = (F_text *) obj_ptr;
794     translate_text(t, delta_x, delta_y);
795     t->distrib = 1;
796     break;
797   case O_ARC:
798     a = (F_arc *) obj_ptr;
799     translate_arc(a, delta_x, delta_y);
800     a->distrib = 1;
801     break;
802   case O_COMPOUND:
803     c = (F_compound *) obj_ptr;
804     translate_compound(c, delta_x, delta_y);
805     c->distrib = 1;
806     break;
807   default:
808     break;
809   }
810 
811 } /* adjust_object_pos */
812 
813 static void
distribute_horizontally(void)814 distribute_horizontally(void)
815 {
816   int		 num_objects = 0;
817   F_ellipse	*e;
818   F_arc		*a;
819   F_line	*l;
820   F_spline	*s;
821   F_compound	*c;
822   F_text	*t;
823   float		 inter_obj_space;
824   int		 min_x, max_x;
825   int		 obj1, obj2;
826   int		 obj_type;
827   F_line	*obj_ptr;
828   int		 min_left, min_width;
829   int		 req_pos;
830   int		 sum_obj_width;
831 
832 
833   if (cur_halign == ALIGN_DISTRIB_C)
834     num_objects = init_distrib_centres (&min_x, &max_x, 0);
835   else {
836     num_objects = init_distrib_edges (&min_x, &max_x, &sum_obj_width, 0);
837     req_pos = min_x;
838   }
839   if (num_objects <= 1)
840     return;
841 
842   /* Determine the amount of space between objects (centres or edges) */
843   if (cur_halign == ALIGN_DISTRIB_C)
844     inter_obj_space = (float) (max_x - min_x) / (float)(num_objects - 1);
845   else if (cur_halign == ALIGN_DISTRIB_E)
846     inter_obj_space = (float) (max_x - min_x - sum_obj_width) / (float)(num_objects - 1);
847   else
848     inter_obj_space = 0.0;
849 
850   /*
851    * Go through all of the objects, finding the left most, then the second
852    * left-most, ...
853    */
854   for (obj1=0; obj1<num_objects; obj1++) {
855     min_left = INT_MAX;
856     for (obj2=0; obj2<num_objects; obj2++) {
857       for (e = cur_c->ellipses; e != NULL; e = e->next)
858 	if (pos_ellipse(e, &min_left, &min_width, 0))
859 	  { obj_ptr = (F_line *) e; obj_type = O_ELLIPSE; }
860       for (a = cur_c->arcs; a != NULL; a = a->next)
861 	if (pos_arc(a, &min_left, &min_width, 0))
862 	  { obj_ptr = (F_line *) a; obj_type = O_ARC; }
863       for (l = cur_c->lines; l != NULL; l = l->next)
864 	if (pos_line(l, &min_left, &min_width, 0))
865 	  { obj_ptr = l; obj_type = O_POLYLINE; }
866       for (s = cur_c->splines; s != NULL; s = s->next)
867 	if (pos_spline(s, &min_left, &min_width, 0))
868 	  { obj_ptr = (F_line *) s; obj_type = O_SPLINE; }
869       for (c = cur_c->compounds; c != NULL; c = c->next)
870 	if (pos_compound(c, &min_left, &min_width, 0))
871 	  { obj_ptr = (F_line *) c; obj_type = O_COMPOUND; }
872       for (t = cur_c->texts; t != NULL; t = t->next)
873 	if (pos_text(t, &min_left, &min_width, 0))
874 	  { obj_ptr = (F_line *) t; obj_type = O_TXT; }
875     }
876 
877     /* Determine the new horizontal position of the object */
878     if (cur_halign == ALIGN_DISTRIB_C)
879       req_pos = min_x + (int)((float)obj1 * inter_obj_space);
880 
881     /* Adjust position of left-most undistributed object */
882     adjust_object_pos (obj_ptr, obj_type, req_pos - min_left, 0);
883 
884     /* Determine the horizontal position of the next object */
885     if ( (cur_halign == ALIGN_DISTRIB_E) || (cur_halign == ALIGN_ABUT) )
886       req_pos += min_width + (int)inter_obj_space;
887   } /* next object */
888 } /* distribute_horizontally */
889 
890 static void
distribute_vertically(void)891 distribute_vertically(void)
892 {
893   int		 num_objects = 0;
894   F_ellipse	*e;
895   F_arc		*a;
896   F_line	*l;
897   F_spline	*s;
898   F_compound	*c;
899   F_text	*t;
900   float		 inter_obj_space;
901   int		 min_y, max_y;
902   int		 obj1, obj2;
903   int		 obj_type;
904   F_line	*obj_ptr;
905   int		 min_top, min_height;
906   int		 req_pos;
907   int		 sum_obj_height;
908 
909 
910   if (cur_valign == ALIGN_DISTRIB_C)
911     num_objects = init_distrib_centres (&min_y, &max_y, 1);
912   else {
913     num_objects = init_distrib_edges (&min_y, &max_y, &sum_obj_height, 1);
914     req_pos = min_y;
915   }
916   if (num_objects <= 1)
917     return;
918 
919   /* Determine the amount of space between objects (centres or edges) */
920   if (cur_valign == ALIGN_DISTRIB_C)
921     inter_obj_space = (float) (max_y - min_y) / (float)(num_objects - 1);
922   else if (cur_valign == ALIGN_DISTRIB_E)
923     inter_obj_space = (float) (max_y - min_y - sum_obj_height) / (float)(num_objects - 1);
924   else
925     inter_obj_space = 0.0;
926 
927   /*
928    * Go through all of the objects, finding the top-most, then the second
929    * top-most, ...
930    */
931   for (obj1=0; obj1<num_objects; obj1++) {
932     min_top = INT_MAX;
933     for (obj2=0; obj2<num_objects; obj2++) {
934       for (e = cur_c->ellipses; e != NULL; e = e->next)
935 	if (pos_ellipse(e, &min_top, &min_height, 1))
936 	  { obj_ptr = (F_line *) e; obj_type = O_ELLIPSE; }
937       for (a = cur_c->arcs; a != NULL; a = a->next)
938 	if (pos_arc(a, &min_top, &min_height, 1))
939 	  { obj_ptr = (F_line *) a; obj_type = O_ARC; }
940       for (l = cur_c->lines; l != NULL; l = l->next)
941 	if (pos_line(l, &min_top, &min_height, 1))
942 	  { obj_ptr = (F_line *) l; obj_type = O_POLYLINE; }
943       for (s = cur_c->splines; s != NULL; s = s->next)
944 	if (pos_spline(s, &min_top, &min_height, 1))
945 	  { obj_ptr = (F_line *) s; obj_type = O_SPLINE; }
946       for (c = cur_c->compounds; c != NULL; c = c->next)
947 	if (pos_compound(c, &min_top, &min_height, 1))
948 	  { obj_ptr = (F_line *) c; obj_type = O_COMPOUND; }
949       for (t = cur_c->texts; t != NULL; t = t->next)
950 	if (pos_text(t, &min_top, &min_height, 1))
951 	  { obj_ptr = (F_line *) t; obj_type = O_TXT; }
952     }
953 
954     /* Determine the new vertical position of the object */
955     if (cur_valign == ALIGN_DISTRIB_C)
956       req_pos = min_y + (int)((float)obj1 * inter_obj_space);
957 
958     /* Adjust position of left-most undistributed object */
959     adjust_object_pos (obj_ptr, obj_type, 0, req_pos - min_top);
960 
961     /* Determine the virtical position of the next object */
962     if ((cur_valign == ALIGN_DISTRIB_E) || (cur_valign == ALIGN_ABUT) )
963       req_pos += min_height + (int)inter_obj_space;
964   }
965 
966 } /* distribute_vertically */
967 
968