4 * The alignment dialogue box
6 * © 1994-1998 Straylight
9 /*----- Licensing note ----------------------------------------------------*
11 * This file is part of Straylight's Glass.
13 * Glass is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * Glass is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with Glass. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /*----- Header files ------------------------------------------------------*/
31 * ANSI standard headers
42 #include "steel/Steel.h"
55 /*----- Type definitions --------------------------------------------------*/
72 /*----- Static global variables -------------------------------------------*/
74 static dbox align__dbox;
75 static align__order align__sortOrder;
77 /*----- Support routines --------------------------------------------------*/
80 * int align__horizCompare(const void *a,const void *b)
83 * Compares two icons for horizontal alignment. Used as a compare for
87 static int align__horizCompare(const void *a,const void *b)
89 const align__iconstr *x=a;
90 const align__iconstr *y=b;
92 switch (align__sortOrder)
95 result=x->box.x0-y->box.x0;
98 result=x->box.x1-y->box.x1;
101 result=x->box.x1+x->box.x0-y->box.x0-y->box.x1;
104 werr(TRUE,msgs_lookup("alBATH"));
111 * int align__vertCompare(const void *a,const void *b)
114 * Compares two icons for vertical alignment. Used as a compare for
118 static int align__vertCompare(const void *a,const void *b)
120 const align__iconstr *x=a;
121 const align__iconstr *y=b;
123 switch (align__sortOrder)
126 result=x->box.y0-y->box.y0;
129 result=x->box.y1-y->box.y1;
132 result=x->box.y1+x->box.y0-y->box.y0-y->box.y1;
135 werr(TRUE,msgs_lookup("alBATV"));
142 * void align__doAlign(void)
145 * Does an align on the currently selected icons, wherever they may be.
146 * The settings are read from the dialogue box, and processed.
149 static void align__doAlign(void)
151 align__iconstr *a; /* Array of icons to align */
152 glass_windPointer *w=window_selectionOwner(); /* Window containing icons */
153 wimp_box bound; /* Bounding box of the selection */
154 int width=0; /* Total width of all the icons */
155 int height=0; /* Total height of all the icons */
157 int xcont=-1; /* Index/icon of horizontal container */
158 int ycont=-1; /* Index/icon of vertical container */
160 int num; /* Number of selected icons */
162 /* --- Loop variables --- */
167 /* --- Ensure that we have something to do --- */
176 /* --- Put the icons into an array for sorting etc. --- *
178 * We also keep track of the bounding box of the selected icons, their
179 * total width and their total height, and which, if any, are containers.
185 /* --- Allocate memory for the array --- */
187 if (a=mem_alloc(num*sizeof(align__iconstr)),!a)
189 werr(FALSE,msgs_lookup("alNEM"));
194 for (i=0;i<w->def->desc.w.nicons;i++)
196 if (w->def->i[i].selected)
199 window_boundingBox(w,i,&a[j].box);
200 width+=a[j].box.x1-a[j].box.x0;
201 height+=a[j].box.y1-a[j].box.y0;
210 if (bound.x0>a[j].box.x0)
212 bound.x0=a[j].box.x0;
213 if (bound.x1<a[j].box.x1)
215 bound.x1=a[j].box.x1;
221 else if (bound.x1<a[j].box.x1)
223 bound.x1=a[j].box.x1;
227 if (bound.y0>a[j].box.y0)
229 bound.y0=a[j].box.y0;
230 if (bound.y1<a[j].box.y1)
232 bound.y1=a[j].box.y1;
238 else if (bound.y1<a[j].box.y1)
240 bound.y1=a[j].box.y1;
255 /* --- Now to do the job properly --- *
257 * Aligning is easy. Just find the align position and Bob's your uncle.
258 * Distributing the icons is more difficult. I'll come to that when
259 * it's a better time.
262 /* --- First do horizontal movement --- */
264 if (dbox_selecticon(align__dbox,glass_AHALIGN,dbox_READSTATE))
267 /* --- Right. Just aligning to do. This is really easy --- */
269 if (dbox_selecticon(align__dbox,glass_AHLEFT,dbox_READSTATE))
273 a[i].box.x1+=bound.x0-a[i].box.x0;
274 a[i].box.x0=bound.x0;
277 else if (dbox_selecticon(align__dbox,glass_AHRIGHT,dbox_READSTATE))
281 a[i].box.x0+=bound.x1-a[i].box.x1;
282 a[i].box.x1=bound.x1;
290 /* --- Centring is complicated by the two bounding boxes --- */
292 if (dbox_selecticon(align__dbox,glass_AHBOUND,dbox_READSTATE))
293 centre=(bound.x1+bound.x0)/2;
296 centre=w->def->desc.w.scx+
297 (w->def->desc.w.box.x1-w->def->desc.w.box.x0)/2;
302 icwidth=a[i].box.x1-a[i].box.x0;
303 a[i].box.x0=centre-icwidth/2;
304 a[i].box.x1=centre+icwidth/2;
308 else if (dbox_selecticon(align__dbox,glass_AHDISTRIB,dbox_READSTATE))
311 /* --- Hmm... right. Got to distribute these --- *
313 * First of all, we've got to put them in some sort of order.
316 if (dbox_selecticon(align__dbox,glass_AHLEFT,dbox_READSTATE))
317 align__sortOrder=align__MIN;
318 else if (dbox_selecticon(align__dbox,glass_AHCENTRE,dbox_READSTATE) ||
319 dbox_selecticon(align__dbox,glass_AHWIDTH,dbox_READSTATE))
320 align__sortOrder=align__CENTRE;
322 align__sortOrder=align__MAX;
324 qsort(a,w->selno,sizeof(align__iconstr),align__horizCompare);
326 if (dbox_selecticon(align__dbox,glass_AHLEFT,dbox_READSTATE))
328 int space=a[num-1].box.x0-a[0].box.x0;
329 int anchor=a[0].box.x0;
334 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
335 a[i].box.x1+=thisBit-a[i].box.x0;
339 else if (dbox_selecticon(align__dbox,glass_AHRIGHT,dbox_READSTATE))
341 int space=a[num-1].box.x1-a[0].box.x1;
342 int anchor=a[0].box.x1;
347 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
348 a[i].box.x0+=thisBit-a[i].box.x1;
352 else if (dbox_selecticon(align__dbox,glass_AHCENTRE,dbox_READSTATE))
354 int space=(a[num-1].box.x1+a[num-1].box.x0)/2-
355 (a[0].box.x1+a[0].box.x0)/2;
356 int anchor=(a[0].box.x1+a[0].box.x0)/2;
362 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
363 icwidth=a[i].box.x1-a[i].box.x0;
364 a[i].box.x0=thisBit-icwidth/2;
365 a[i].box.x1=thisBit+icwidth/2;
368 else if (dbox_selecticon(align__dbox,glass_AHBOUND,dbox_READSTATE))
370 int space=bound.x1-bound.x0-width;
373 int anchor=bound.x0; /* This anchor moves, unlike the last lot */
377 icwidth=a[i].box.x1-a[i].box.x0;
378 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
380 a[i].box.x1=thisBit+icwidth;
384 else if (dbox_selecticon(align__dbox,glass_AHVISAREA,dbox_READSTATE))
386 int space=w->def->desc.w.box.x1-w->def->desc.w.box.x0-width;
389 int anchor=w->def->desc.w.scx; /* This anchor also moves */
393 icwidth=a[i].box.x1-a[i].box.x0;
394 thisBit=anchor + ( ( space*(i+1) )/(num+1) & ~(wimpt_dx()-1) );
396 a[i].box.x1=thisBit+icwidth;
402 int space=2*(bound.x1-bound.x0)-width;
405 int anchor=bound.x0; /* This anchor also moves */
411 continue; /* Don't move the container icon at all */
412 icwidth=a[i].box.x1-a[i].box.x0;
413 thisBit=anchor + ( (space*done)/num & ~(wimpt_dx()-1) );
415 a[i].box.x1=thisBit+icwidth;
422 note(msgs_lookup("alNOHC"));
426 /* --- Now do the vertical bit (just a case'n'paste of above) --- */
428 if (dbox_selecticon(align__dbox,glass_AVALIGN,dbox_READSTATE))
431 /* --- Right. Just aligning to do. This is really easy --- */
433 if (dbox_selecticon(align__dbox,glass_AVBOTTOM,dbox_READSTATE))
437 a[i].box.y1+=bound.y0-a[i].box.y0;
438 a[i].box.y0=bound.y0;
441 else if (dbox_selecticon(align__dbox,glass_AVTOP,dbox_READSTATE))
445 a[i].box.y0+=bound.y1-a[i].box.y1;
446 a[i].box.y1=bound.y1;
454 /* --- Centring is complicated by the two bounding boxes --- */
456 if (dbox_selecticon(align__dbox,glass_AVBOUND,dbox_READSTATE))
457 centre=(bound.y1+bound.y0)/2;
460 centre=w->def->desc.w.scy-
461 (w->def->desc.w.box.y1-w->def->desc.w.box.y0)/2;
466 icheight=a[i].box.y1-a[i].box.y0;
467 a[i].box.y0=centre-icheight/2;
468 a[i].box.y1=centre+icheight/2;
472 else if (dbox_selecticon(align__dbox,glass_AVDISTRIB,dbox_READSTATE))
475 /* --- Hmm... right. Got to distribute these --- *
477 * First of all, we've got to put them in some sort of order.
480 if (dbox_selecticon(align__dbox,glass_AVBOTTOM,dbox_READSTATE))
481 align__sortOrder=align__MIN;
482 else if (dbox_selecticon(align__dbox,glass_AVCENTRE,dbox_READSTATE) ||
483 dbox_selecticon(align__dbox,glass_AVHEIGHT,dbox_READSTATE))
484 align__sortOrder=align__CENTRE;
486 align__sortOrder=align__MAX;
488 qsort(a,w->selno,sizeof(align__iconstr),align__vertCompare);
490 if (dbox_selecticon(align__dbox,glass_AVBOTTOM,dbox_READSTATE))
492 int space=a[num-1].box.y0-a[0].box.y0;
493 int anchor=a[0].box.y0;
498 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
499 a[i].box.y1+=thisBit-a[i].box.y0;
503 else if (dbox_selecticon(align__dbox,glass_AVTOP,dbox_READSTATE))
505 int space=a[num-1].box.y1-a[0].box.y1;
506 int anchor=a[0].box.y1;
511 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
512 a[i].box.y0+=thisBit-a[i].box.y1;
516 else if (dbox_selecticon(align__dbox,glass_AVCENTRE,dbox_READSTATE))
518 int space=(a[num-1].box.y1+a[num-1].box.y0)/2-
519 (a[0].box.y1+a[0].box.y0)/2;
520 int anchor=(a[0].box.y1+a[0].box.y0)/2;
526 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
527 icheight=a[i].box.y1-a[i].box.y0;
528 a[i].box.y0=thisBit-icheight/2;
529 a[i].box.y1=thisBit+icheight/2;
532 else if (dbox_selecticon(align__dbox,glass_AVBOUND,dbox_READSTATE))
534 int space=bound.y1-bound.y0-height;
537 int anchor=bound.y0; /* This anchor moves, unlike the last lot */
541 icheight=a[i].box.y1-a[i].box.y0;
542 thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
544 a[i].box.y1=thisBit+icheight;
548 else if (dbox_selecticon(align__dbox,glass_AVVISAREA,dbox_READSTATE))
550 int space=w->def->desc.w.box.y1-w->def->desc.w.box.y0;
553 int anchor=w->def->desc.w.scy-space; /* This anchor also moves */
558 icheight=a[i].box.y1-a[i].box.y0;
559 thisBit=anchor + ( ( space*(i+1) )/(num+1) & ~(wimpt_dy()-1) );
561 a[i].box.y1=thisBit+icheight;
567 int space=2*(bound.y1-bound.y0)-height;
570 int anchor=bound.y0; /* This anchor also moves */
576 continue; /* Don't move the container icon at all */
577 icheight=a[i].box.y1-a[i].box.y0;
578 thisBit=anchor + ( (space*done)/num & ~(wimpt_dy()-1) );
580 a[i].box.y1=thisBit+icheight;
587 note(msgs_lookup("alNOVC"));
591 tfile_markAsAltered(w->t);
593 for (i=0;i<w->selno;i++)
594 window_setBox(w,a[i].i,&a[i].box);
599 /*----- Event handlers ----------------------------------------------------*/
602 * void align__dboxHandler(dbox d,dbox_field f,void *handle)
605 * Handles events for the Alignment dialogue box.
608 * dbox d == the dbox handle (align__dbox)
609 * dbox_field f == what happened (usually a mouse click)
610 * void *handle == a pointer (ignored)
613 static void align__dboxHandler(dbox d,dbox_field f,void *handle)
626 if (!dbox_wasAdjustClick())
629 if (!dbox_wasAdjustClick())
644 dbox_shadeicon(d,glass_AHLEFT,TRUE);
645 dbox_shadeicon(d,glass_AHRIGHT,TRUE);
646 dbox_shadeicon(d,glass_AHCENTRE,TRUE);
647 dbox_shadeicon(d,glass_AHWIDTH,TRUE);
648 dbox_shadeicon(d,glass_AHBOUND,TRUE);
649 dbox_shadeicon(d,glass_AHVISAREA,TRUE);
650 dbox_shadeicon(d,glass_AHCONTAIN,TRUE);
655 dbox_shadeicon(d,glass_AHLEFT,FALSE);
656 dbox_shadeicon(d,glass_AHRIGHT,FALSE);
657 dbox_shadeicon(d,glass_AHCENTRE,FALSE);
658 dbox_shadeicon(d,glass_AHWIDTH,TRUE);
659 if (dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE))
661 dbox_selecticon(d,glass_AHWIDTH,FALSE);
662 dbox_selecticon(d,glass_AHCENTRE,TRUE);
664 shadeBox=!dbox_selecticon(d,glass_AHCENTRE,dbox_READSTATE);
665 dbox_shadeicon(d,glass_AHBOUND,shadeBox);
666 dbox_shadeicon(d,glass_AHVISAREA,shadeBox);
667 dbox_shadeicon(d,glass_AHCONTAIN,TRUE);
668 if (dbox_selecticon(d,glass_AHCONTAIN,dbox_READSTATE))
670 dbox_selecticon(d,glass_AHCONTAIN,FALSE);
671 dbox_selecticon(d,glass_AHBOUND,TRUE);
675 case glass_AHDISTRIB:
677 dbox_shadeicon(d,glass_AHLEFT,FALSE);
678 dbox_shadeicon(d,glass_AHRIGHT,FALSE);
679 dbox_shadeicon(d,glass_AHCENTRE,FALSE);
680 dbox_shadeicon(d,glass_AHWIDTH,FALSE);
681 shadeBox=!dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE);
682 dbox_shadeicon(d,glass_AHBOUND,shadeBox);
683 dbox_shadeicon(d,glass_AHVISAREA,shadeBox);
684 dbox_shadeicon(d,glass_AHCONTAIN,shadeBox);
689 dbox_shadeicon(d,glass_AVTOP,TRUE);
690 dbox_shadeicon(d,glass_AVBOTTOM,TRUE);
691 dbox_shadeicon(d,glass_AVCENTRE,TRUE);
692 dbox_shadeicon(d,glass_AVHEIGHT,TRUE);
693 dbox_shadeicon(d,glass_AVBOUND,TRUE);
694 dbox_shadeicon(d,glass_AVVISAREA,TRUE);
695 dbox_shadeicon(d,glass_AVCONTAIN,TRUE);
700 dbox_shadeicon(d,glass_AVTOP,FALSE);
701 dbox_shadeicon(d,glass_AVBOTTOM,FALSE);
702 dbox_shadeicon(d,glass_AVCENTRE,FALSE);
703 dbox_shadeicon(d,glass_AVHEIGHT,TRUE);
704 if (dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE))
706 dbox_selecticon(d,glass_AVHEIGHT,FALSE);
707 dbox_selecticon(d,glass_AVCENTRE,TRUE);
709 shadeBox=!dbox_selecticon(d,glass_AVCENTRE,dbox_READSTATE);
710 dbox_shadeicon(d,glass_AVBOUND,shadeBox);
711 dbox_shadeicon(d,glass_AVVISAREA,shadeBox);
712 dbox_shadeicon(d,glass_AVCONTAIN,TRUE);
713 if (dbox_selecticon(d,glass_AVCONTAIN,dbox_READSTATE))
715 dbox_selecticon(d,glass_AVCONTAIN,FALSE);
716 dbox_selecticon(d,glass_AVBOUND,TRUE);
720 case glass_AVDISTRIB:
722 dbox_shadeicon(d,glass_AVTOP,FALSE);
723 dbox_shadeicon(d,glass_AVBOTTOM,FALSE);
724 dbox_shadeicon(d,glass_AVCENTRE,FALSE);
725 dbox_shadeicon(d,glass_AVHEIGHT,FALSE);
726 shadeBox=!dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE);
727 dbox_shadeicon(d,glass_AVBOUND,shadeBox);
728 dbox_shadeicon(d,glass_AVVISAREA,shadeBox);
729 dbox_shadeicon(d,glass_AVCONTAIN,shadeBox);
737 case glass_AHVISAREA:
738 case glass_AHCONTAIN:
740 if (dbox_selecticon(d,glass_AHALIGN,dbox_READSTATE))
741 shadeBox=!dbox_selecticon(d,glass_AHCENTRE,dbox_READSTATE);
743 shadeBox=!dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE);
744 dbox_shadeicon(d,glass_AHBOUND,shadeBox);
745 dbox_shadeicon(d,glass_AHVISAREA,shadeBox);
748 !dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE));
756 case glass_AVVISAREA:
757 case glass_AVCONTAIN:
759 if (dbox_selecticon(d,glass_AVALIGN,dbox_READSTATE))
760 shadeBox=!dbox_selecticon(d,glass_AVCENTRE,dbox_READSTATE);
762 shadeBox=!dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE);
763 dbox_shadeicon(d,glass_AVBOUND,shadeBox);
764 dbox_shadeicon(d,glass_AVVISAREA,shadeBox);
767 !dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE));
773 /*----- External routines -------------------------------------------------*/
779 * Opens the align dialogue box. There can only be one selection, ergo
780 * there can only be one align box.
787 align__dbox=dbox_create("align");
791 dbox_shadeicon(align__dbox,glass_AHLEFT,TRUE);
792 dbox_shadeicon(align__dbox,glass_AHRIGHT,TRUE);
793 dbox_shadeicon(align__dbox,glass_AHCENTRE,TRUE);
794 dbox_shadeicon(align__dbox,glass_AHWIDTH,TRUE);
795 dbox_shadeicon(align__dbox,glass_AHBOUND,TRUE);
796 dbox_shadeicon(align__dbox,glass_AHVISAREA,TRUE);
797 dbox_shadeicon(align__dbox,glass_AHCONTAIN,TRUE);
799 dbox_shadeicon(align__dbox,glass_AVTOP,TRUE);
800 dbox_shadeicon(align__dbox,glass_AVBOTTOM,TRUE);
801 dbox_shadeicon(align__dbox,glass_AVCENTRE,TRUE);
802 dbox_shadeicon(align__dbox,glass_AVHEIGHT,TRUE);
803 dbox_shadeicon(align__dbox,glass_AVBOUND,TRUE);
804 dbox_shadeicon(align__dbox,glass_AVVISAREA,TRUE);
805 dbox_shadeicon(align__dbox,glass_AVCONTAIN,TRUE);
807 dbox_eventHandler(align__dbox,align__dboxHandler,0);
809 dbox_display(align__dbox,dbox_STATIC_LASTPOS);