chiark / gitweb /
Create readable text `.bas' for each tokenized BASIC `,ffb' file.
[ssr] / StraySrc / Glass / !Glass / c / tearEdit
1 /*
2  * tearEdit.c
3  *
4  * Editing icons in tearoff menus
5  *
6  * © 1994-1998 Straylight
7  */
8
9 /*----- Licensing note ----------------------------------------------------*
10  *
11  * This file is part of Straylight's Glass.
12  *
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)
16  * any later version.
17  *
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.
22  *
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.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 /*
31  * ANSI standard headers
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 /*
39  * Steel and RISC_OSLib headers
40  */
41
42 #define _STDAPP
43 #include "steel/Steel.h"
44
45 #include "steel/buttons.h"
46 #include "steel/akbd.h"
47 #include "steel/buffer.h"
48 #include "steel/colourtran.h"
49 #include "steel/tearoff.h"
50
51 /*
52  * Glass headers
53  */
54
55 #include "gStruct.h"
56
57 #include "glass.h"
58 #include "window.h"
59 #include "tfile.h"
60 #include "indir.h"
61 #include "tearEdit.h"
62
63 /*----- Static variables --------------------------------------------------*/
64
65 static glass_windPointer *tearEdit__window;   /* The window with the icon  */
66 static int tearEdit__icon=-1;           /* The icon we're editing          */
67
68 static tearoff tearEdit__main;          /* The main tearoff edit menu      */
69 static tearoff tearEdit__data;
70 static tearoff tearEdit__appear;
71 static tearoff tearEdit__actions;
72 static tearoff tearEdit__btype;
73 static tearoff tearEdit__colours;
74
75 /*----- Menu structure ----------------------------------------------------*
76  *
77  * Icon data => Data => [dbox]
78  *              Indirected => [dbox]
79  *              Text
80  *              Sprite
81  * Appearance => Anti-aliased => Font => [font menu]
82  *                               Size => [dbox]
83  *               Horizontally centred
84  *               Vertically centred
85  *               Right aligned
86  *               Border
87  *               Filled background
88  *               Half-size sprite
89  *               Needs help
90  * Actions => Button type => [type menu]
91  *            ESG => [dbox]
92  *            Adjust toggles
93  *            Selected
94  *            Shaded
95  * Colours => Foreground => [dbox]
96  *            Background => [dbox]
97  * Position => [dbox]
98  * Size => [dbox]
99  */
100
101 /*----- Icon numbers for dialogues ----------------------------------------*/
102
103 #define tearEdit__DATAOK 0
104 #define tearEdit__DATAWRITE 1
105
106 #define tearEdit__ESGOK 0
107 #define tearEdit__ESGUP 1
108 #define tearEdit__ESGDOWN 2
109 #define tearEdit__ESGWRITE 3
110
111 #define tearEdit__INDOK 0
112 #define tearEdit__INDINDIR 2
113 #define tearEdit__INDSWRITE 4
114 #define tearEdit__INDSUP 5
115 #define tearEdit__INDSDOWN 6
116 #define tearEdit__INDMINIMISE 7
117 #define tearEdit__INDPART 8
118 #define tearEdit__INDVALID 9
119 #define tearEdit__INDVALSTRING 10
120
121 #define tearEdit__COLOUROK 0
122 #define tearEdit__COLOURCOLS 2
123
124 #define tearEdit__POSOK 0
125 #define tearEdit__POSUP 2
126 #define tearEdit__POSDOWN 3
127 #define tearEdit__POSLEFT 4
128 #define tearEdit__POSRIGHT 5
129 #define tearEdit__POSWRITE 6
130
131 /*----- Item numbers for menus --------------------------------------------*/
132
133 enum
134 {
135   tearEdit__MAINDATA=1,
136   tearEdit__MAINAPPEAR,
137   tearEdit__MAINACTIONS,
138   tearEdit__MAINCOLOURS,
139   tearEdit__MAINPOS,
140   tearEdit__MAINSIZE
141 };
142
143 enum
144 {
145   tearEdit__DATADATA=1,
146   tearEdit__DATAINDIR,
147   tearEdit__DATATEXT,
148   tearEdit__DATASPRITE
149 };
150
151 enum
152 {
153   tearEdit__APPEARHCENTRE=1,
154   tearEdit__APPEARVCENTRE,
155   tearEdit__APPEARRALIGN,
156   tearEdit__APPEARBORDER,
157   tearEdit__APPEARFILLED,
158   tearEdit__APPEARHALF,
159   tearEdit__APPEARHELP
160 };
161
162 enum
163 {
164   tearEdit__ACTIONSBTYPE=1,
165   tearEdit__ACTIONSESG,
166   tearEdit__ACTIONSADJUST,
167   tearEdit__ACTIONSSELECT,
168   tearEdit__ACTIONSSHADE
169 };
170
171 enum
172 {
173   tearEdit__COLOURSFORE=1,
174   tearEdit__COLOURSBACK
175 };
176
177 /*----- Messing about with indirected data --------------------------------*/
178
179 /*
180  * void tearEdit__setData(wimp_icon *icn,
181  *                        char *data,
182  *                        char *valid,
183  *                        int newsize)
184  *
185  * Use
186  *  Sets an icon's data as required, possibly extending the data buffer and
187  *  indirecting if required.  Old buffers are freed and new ones allocated
188  *  etc.
189  *
190  * Parameters
191  *  wimp_icon *icn == the icon to edit in this way
192  *  char *data == pointer to the new data string, or 0 to leave it alone
193  *  char *valid == pointer to the new validation string, or 0 to leave it
194  *    alone, or tearEdit__NOVALID to delete it
195  *  int newsize == the size of the new indirection buffer, or
196  *    tearEdit__NOINDIR to not indirect the string
197  */
198
199 #define tearEdit__NOVALID ((char *)(-1))
200 #define tearEdit__NOINDIR (-1)
201 #define tearEdit__NOCHANGE (-2)
202
203 static void tearEdit__setData(wimp_icon *icn,
204                               char *data,
205                               char *valid,
206                               int newsize)
207 {
208   char nonind[13];
209   int maxlen=newsize;
210   wimp_iconflags nf=icn->flags;
211   char *p=0,*q;
212
213   /* --- Fill in default arguments --- */
214
215   if (!data)
216   {
217     if (tst(icn->flags,8))
218     {
219       data=icn->data.indirecttext.buffer;
220       utils_ctermToNterm(data);
221     }
222     else
223     {
224       memcpy(nonind,icn->data.text,12);
225       nonind[12]=0;
226       utils_ctermToNterm(nonind);
227       data=nonind;
228     }
229   }
230
231   if (!valid)
232   {
233     if (tst(icn->flags,0) && tst(icn->flags,8))
234     {
235       valid=icn->data.indirecttext.validstring;
236       if (valid!=tearEdit__NOVALID)
237         utils_ctermToNterm(valid);
238     }
239     else
240       valid=tearEdit__NOVALID;
241   }
242
243   if (maxlen==tearEdit__NOCHANGE)
244   {
245     if (tst(icn->flags,8))
246       maxlen=icn->data.indirecttext.bufflen;
247     else
248       maxlen=tearEdit__NOINDIR;
249   }
250
251   /* --- Set up new icon flags --- */
252
253   if (maxlen==tearEdit__NOINDIR)
254   {
255     maxlen=12;
256     reset(nf,8);
257   }
258   else
259     set(nf,8);
260
261   if (strlen(data)>=maxlen)
262   {
263     set(nf,8);
264     maxlen=strlen(data)+1;
265   }
266
267   /* --- Set up new buffers for data --- */
268
269   if (tst(nf,8))
270   {
271     if (p=indir_alloc(maxlen),!p)
272     {
273       werr(FALSE,msgs_lookup("teNEMUI"));
274       return;
275     }
276     if (tst(nf,0) && valid!=tearEdit__NOVALID)
277     {
278       if (q=indir_alloc(strlen(valid)+1),!q)
279       {
280         indir_free(p);
281         werr(FALSE,msgs_lookup("teNEMUI"));
282         return;
283       }
284       window_redrawIcon(tearEdit__window,tearEdit__icon);
285       strcpy(q,valid);
286       valid=q;
287       tearEdit__window->size+=strlen(valid)+1;
288     }
289     strcpy(p,data);
290     tearEdit__window->size+=maxlen;
291   }
292
293   /* --- Clear out the old buffers now --- */
294
295   if (tst(icn->flags,8))
296   {
297     tearEdit__window->size-=icn->data.indirecttext.bufflen;
298     if (tst(icn->flags,0) &&
299         icn->data.indirecttext.validstring!=tearEdit__NOVALID)
300     {
301       utils_ctermToNterm(icn->data.indirecttext.validstring);
302       tearEdit__window->size-=strlen(icn->data.indirecttext.validstring)+1;
303     }
304   }
305
306   /* --- Now copy the new data across --- */
307
308   if (tst(nf,8))
309   {
310     icn->data.indirecttext.bufflen=maxlen;
311     icn->data.indirecttext.buffer=p;
312     if ((nf & 3)==2)
313       icn->data.indirectsprite.spritearea=tearEdit__window->t->s;
314     else
315       icn->data.indirecttext.validstring=valid;
316   }
317   else
318     memcpy(icn->data.text,data,12);
319
320   icn->flags=nf;
321
322   /* --- That's it (phew!) --- */
323
324   window_redrawIcon(tearEdit__window,tearEdit__icon);
325   tfile_markAsAltered(tearEdit__window->t);
326 }
327
328 /*----- Icon data dialogue boxes ------------------------------------------*/
329
330 /* --- Alter data --- */
331
332 /*
333  * void tearEdit__dataBox(void)
334  *
335  * Use
336  *  Displays a dialogue box allowing the user to change an icon's data.
337  */
338
339 static void tearEdit__dataBox(void)
340 {
341   dbox d;
342   wimp_icon *icn;
343   char nonind[256];
344   char *data;
345   BOOL done=FALSE;
346
347   if (!tearEdit__window || tearEdit__icon==-1)
348     return;
349   icn=&tearEdit__window->def->i[tearEdit__icon].i;
350   if (!(icn->flags & 3))
351     return;
352
353   if (tst(icn->flags,8))
354     data=icn->data.indirecttext.buffer;
355   else
356   {
357     memcpy(nonind,icn->data.text,12);
358     nonind[13]=0;
359     data=nonind;
360   }
361   utils_ctermToNterm(data);
362
363   d=dbox_create("teditData");
364   if (!d)
365     return;
366
367   dbox_setfield(d,tearEdit__DATAWRITE,"%s",data);
368   dbox_display(d,dbox_MENU_OVERPTR);
369
370   while (!done)
371   {
372     switch (dbox_fillin(d))
373     {
374       case dbox_CLOSE:
375         done=TRUE;
376         break;
377       case tearEdit__DATAOK:
378         dbox_clickicon(d,tearEdit__DATAOK);
379         dbox_getfield(d,tearEdit__DATAWRITE,nonind,256);
380         tearEdit__setData(icn,nonind,0,tearEdit__NOCHANGE);
381         if (dbox_wasAdjustClick())
382           dbox_unclick();
383         else
384         {
385           dbox_hide(d);
386           dbox_unclick();
387           done=TRUE;
388         }
389         break;
390     }
391   }
392
393   dbox_delete(d);
394 }
395
396 /* --- Alter indirection --- */
397
398 /*
399  * void tearEdit__setupIndBox(dbox d,wimp_icon *icn,BOOL *ind,BOOL *val)
400  *
401  * Use
402  *  Sets up the icons in an indirection dialogue box.
403  *
404  * Parameters
405  *  dbox d == the dialogue box's handle
406  *  wimp_icon *icn == the icon to read the definition from
407  *  BOOL *ind == (output) whether the icon is indirected
408  *  BOOL *val == (output) whether the icon has a validation string
409  */
410
411 static void tearEdit__setupIndBox(dbox d,wimp_icon *icn,BOOL *ind,BOOL *val)
412 {
413   if (tst(icn->flags,8))
414   {
415     *ind=TRUE;
416     dbox_selecticon(d,tearEdit__INDINDIR,TRUE);
417     dbox_shadeicon(d,tearEdit__INDSUP,FALSE);
418     dbox_shadeicon(d,tearEdit__INDSDOWN,FALSE);
419     dbox_shadeicon(d,tearEdit__INDSWRITE,FALSE);
420     dbox_shadeicon(d,tearEdit__INDMINIMISE,FALSE);
421     dbox_shadeicon(d,tearEdit__INDPART,FALSE);
422     dbox_setfield(d,tearEdit__INDSWRITE,"%i",icn->data.indirecttext.bufflen);
423     if (tst(icn->flags,0))
424     {
425       if (icn->data.indirecttext.validstring!=tearEdit__NOVALID)
426       {
427         *val=TRUE;
428         dbox_selecticon(d,tearEdit__INDVALID,TRUE);
429         dbox_shadeicon(d,tearEdit__INDVALSTRING,FALSE);
430         utils_ctermToNterm(icn->data.indirecttext.validstring);
431         dbox_setfield(d,
432                       tearEdit__INDVALSTRING,
433                       "%s",
434                       icn->data.indirecttext.validstring);
435       }
436       else
437       {
438         *val=FALSE;
439         dbox_selecticon(d,tearEdit__INDVALID,FALSE);
440         dbox_shadeicon(d,tearEdit__INDVALID,FALSE);
441         dbox_shadeicon(d,tearEdit__INDVALSTRING,TRUE);
442         dbox_setfield(d,tearEdit__INDVALSTRING,"");
443       }
444     }
445     else
446     {
447       *val=FALSE;
448       dbox_selecticon(d,tearEdit__INDVALID,FALSE);
449       dbox_shadeicon(d,tearEdit__INDVALID,TRUE);
450       dbox_shadeicon(d,tearEdit__INDVALSTRING,TRUE);
451       dbox_setfield(d,tearEdit__INDVALSTRING,"");
452     }
453   }
454   else
455   {
456     *ind=FALSE;
457     dbox_selecticon(d,tearEdit__INDINDIR,FALSE);
458     dbox_shadeicon(d,tearEdit__INDSUP,TRUE);
459     dbox_shadeicon(d,tearEdit__INDSDOWN,TRUE);
460     dbox_shadeicon(d,tearEdit__INDSWRITE,TRUE);
461     dbox_shadeicon(d,tearEdit__INDMINIMISE,TRUE);
462     dbox_shadeicon(d,tearEdit__INDPART,TRUE);
463     dbox_setfield(d,tearEdit__INDSWRITE,"12");
464     *val=FALSE;
465     dbox_selecticon(d,tearEdit__INDVALID,FALSE);
466     dbox_shadeicon(d,tearEdit__INDVALID,TRUE);
467     dbox_shadeicon(d,tearEdit__INDVALSTRING,TRUE);
468     dbox_setfield(d,tearEdit__INDVALSTRING,"");
469   }
470 }
471
472 /*
473  * void tearEdit__indirBox(void)
474  *
475  * Use
476  *  Displays and handles an indirection dialogue box.
477  */
478
479 static void tearEdit__indirBox(void)
480 {
481   dbox d;
482   char buff[256];
483   wimp_icon *icn;
484   int size;
485   BOOL done=FALSE;
486   BOOL ind;
487   BOOL val;
488   buttons_simpleArrow sa={0,9999,FALSE};
489   dbox_field f;
490
491   if (!tearEdit__window || tearEdit__icon==-1)
492     return;
493
494   icn=&tearEdit__window->def->i[tearEdit__icon].i;
495   if (!(icn->flags & 3))
496     return;
497
498   d=dbox_create("teditIndir");
499   if (!d)
500     return;
501
502   tearEdit__setupIndBox(d,icn,&ind,&val);
503
504   dbox_display(d,dbox_MENU_OVERPTR);
505   while (!done)
506   {
507     switch (f=dbox_fillin(d),f)
508     {
509       case dbox_CLOSE:
510         done=TRUE;
511         break;
512       case tearEdit__INDINDIR:
513         ind=!ind;
514         dbox_shadeicon(d,tearEdit__INDSUP,!ind);
515         dbox_shadeicon(d,tearEdit__INDSDOWN,!ind);
516         dbox_shadeicon(d,tearEdit__INDSWRITE,!ind);
517         dbox_shadeicon(d,tearEdit__INDMINIMISE,!ind);
518         dbox_shadeicon(d,tearEdit__INDPART,!ind);
519         if (tst(icn->flags,0))
520         {
521           dbox_shadeicon(d,tearEdit__INDVALID,!ind);
522           dbox_shadeicon(d,tearEdit__INDVALSTRING,!(ind && val));
523         }
524         break;
525       case tearEdit__INDSUP:
526         buttons_arrow(d,f,d,tearEdit__INDSWRITE,0,+1,&sa);
527         break;
528       case tearEdit__INDSDOWN:
529         buttons_arrow(d,f,d,tearEdit__INDSWRITE,0,-1,&sa);
530         break;
531       case tearEdit__INDMINIMISE:
532         dbox_clickicon(d,f);
533         if (icn->flags & wimp_INDIRECT)
534         {
535           dbox_setfield(d,tearEdit__INDSWRITE,"%i",
536                         strlen(icn->data.indirecttext.buffer)+1);
537         }
538         else
539         {
540           char buff[15];
541           memcpy(buff,icn->data.text,12);
542           buff[12]=0;
543           utils_ctermToNterm(buff);
544           dbox_setfield(d,tearEdit__INDSWRITE,"%i",strlen(buff)+1);
545         }
546         dbox_unclick();
547         break;
548       case tearEdit__INDVALID:
549         val=!val;
550         dbox_shadeicon(d,tearEdit__INDVALSTRING,!val);
551         break;
552       case tearEdit__INDOK:
553         dbox_clickicon(d,tearEdit__INDOK);
554         if (ind)
555         {
556           dbox_scanfield(d,tearEdit__INDSWRITE,"%d",&size);
557           if (val)
558           {
559             dbox_getfield(d,tearEdit__INDVALSTRING,buff,256);
560             tearEdit__setData(icn,0,buff,size);
561           }
562           else
563             tearEdit__setData(icn,0,tearEdit__NOVALID,size);
564         }
565         else
566           tearEdit__setData(icn,0,tearEdit__NOVALID,tearEdit__NOINDIR);
567         if (dbox_wasAdjustClick())
568         {
569           tearEdit__setupIndBox(d,icn,&ind,&val);
570           dbox_unclick();
571         }
572         else
573         {
574           dbox_hide(d);
575           dbox_unclick();
576           done=TRUE;
577         }
578         break;
579     }
580   }
581
582   dbox_delete(d);
583 }
584
585 /*----- ESG dialogue box --------------------------------------------------*/
586
587 /*
588  * BOOL tearEdit__esgRaw(dbox d,wimp_eventstr *e,void *handle)
589  *
590  * Use
591  *  Handles raw events for the ESG dialogue box (basically, it forces the
592  *  ESG number to be in the correct range when you type it in.
593  *
594  * Parameters
595  *  dbox d == the dialogue box handle for the ESG dbox
596  *  wimp_eventstr *e == the event wot happened
597  *  void *handle == a handle wot we ignore
598  */
599
600 static BOOL tearEdit__esgRaw(dbox d,wimp_eventstr *e,void *handle)
601 {
602   BOOL handled=FALSE;
603   BOOL cursor=FALSE;
604   unused(handle);
605
606   switch (e->e)
607   {
608     case wimp_EKEY:
609       switch (e->data.key.c.i)
610       {
611         case tearEdit__ESGWRITE:
612           switch (e->data.key.chcode)
613           {
614             case akbd_DownK:
615             case akbd_UpK:
616             case akbd_TabK:
617             case akbd_TabK+akbd_Sh:
618             case akbd_UpK+akbd_Ctl:
619             case akbd_DownK+akbd_Ctl:
620               cursor=TRUE;
621               break;
622           }
623           handled=buttons_insertChar(d,e->data.key.chcode,'0','9');
624           if (handled || cursor)
625             buttons_arrowClick(d,tearEdit__ESGWRITE,0,31,0,FALSE);
626           break;
627       }
628       break;
629   }
630   return (handled);
631 }
632
633 /*
634  * void tearEdit__esgBox(void)
635  *
636  * Use
637  *  Allows the user to choose an exclusive selection group for an icon.
638  */
639
640 static void tearEdit__esgBox(void)
641 {
642   dbox d;
643   BOOL done=FALSE;
644   wimp_icon *icn;
645   int esg;
646   buttons_simpleArrow sa={0,31,FALSE};
647   dbox_field f;
648
649   if (!tearEdit__window || tearEdit__icon==-1)
650     return;
651
652   d=dbox_create("teditESG");
653   if (!d)
654     return;
655
656   icn=&tearEdit__window->def->i[tearEdit__icon].i;
657
658   dbox_setfield(d,tearEdit__ESGWRITE,"%i",(icn->flags & 0x001F0000)>>16);
659   dbox_rawEventHandler(d,tearEdit__esgRaw,0);
660
661   dbox_display(d,dbox_MENU_OVERPTR);
662   while (!done)
663   {
664     switch (f=dbox_fillin(d),f)
665     {
666       case dbox_CLOSE:
667         done=TRUE;
668         break;
669       case tearEdit__ESGUP:
670         buttons_arrow(d,f,d,tearEdit__ESGWRITE,0,+1,&sa);
671         break;
672       case tearEdit__ESGDOWN:
673         buttons_arrow(d,f,d,tearEdit__ESGWRITE,0,-1,&sa);
674         break;
675       case tearEdit__ESGOK:
676         dbox_clickicon(d,tearEdit__ESGOK);
677         dbox_scanfield(d,tearEdit__ESGWRITE,"%d",&esg);
678         icn->flags &= ~0x001F0000;
679         icn->flags |= esg<<16;
680         window_redrawIcon(tearEdit__window,tearEdit__icon);
681         tfile_markAsAltered(tearEdit__window->t);
682         if (dbox_wasAdjustClick())
683           dbox_unclick();
684         else
685         {
686           dbox_hide(d);
687           dbox_unclick();
688           done=TRUE;
689         }
690         break;
691     }
692   }
693
694   dbox_delete(d);
695 }
696
697 /*----- Colour dialogue boxes ---------------------------------------------*/
698
699 /*
700  * void tearEdit__addBorder(dbox d,int colour)
701  *
702  * Use
703  *  Adds a border around the specified colour.
704  *
705  * Parameters
706  *  dbox d == the colour dialogue box's handle
707  *  int colour == the number of the colour to select
708  */
709
710 static void tearEdit__addBorder(dbox d,int colour)
711 {
712   static wimp_paletteword blacknwhite[]={0,0,0,0, 0,255,255,255,};
713   static wimp_palettestr wimppal;
714   int col;
715
716   wimpt_noerr(wimp_readpalette(&wimppal));
717   wimpt_noerr(colourtran_return_Oppcolourformode(wimppal.c[colour],
718                                                  0,
719                                                  blacknwhite,
720                                                  &col));
721   wimpt_noerr(colourtran_return_colourformode(blacknwhite[col],
722                                               12,
723                                               wimppal.c,
724                                               &col));
725
726   /* --- We now have the correctly contrasting colour in col --- */
727
728   wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d),
729                                   colour+tearEdit__COLOURCOLS,
730                                   5 | (col<<24),
731                                   0x0F000005));
732 }
733
734 #define tearEdit__removeBorder(d,colour) \
735   wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d), \
736                                   colour+tearEdit__COLOURCOLS, \
737                                   0x00000000, \
738                                   0x0F000005)); \
739
740 /*
741  * void tearEdit__colourBox(BOOL fore)
742  *
743  * Use
744  *  Displays a dialogue box from which the user may choose an icon colour.
745  *
746  * Parameters
747  *  BOOL fore == whether this is the foreground or background we're editing
748  */
749
750 static void tearEdit__colourBox(BOOL fore)
751 {
752   dbox d;
753   wimp_icon *icn;
754   BOOL done=FALSE;
755   int colour;
756   dbox_field f;
757
758   if (!tearEdit__window || tearEdit__icon==-1)
759     return;
760
761   icn=&tearEdit__window->def->i[tearEdit__icon].i;
762
763   if (tst(icn->flags,6))
764     return;
765
766   d=dbox_create("teditColour");
767   if (!d)
768     return;
769
770   if (fore)
771     colour=(icn->flags & 0x0F000000)>>24;
772   else
773     colour=(icn->flags & 0xF0000000)>>28;
774
775   win_settitle(dbox_syshandle(d),msgs_lookup(fore ? "teFG" : "teBG"));
776
777   tearEdit__addBorder(d,colour);
778
779   dbox_display(d,dbox_MENU_OVERPTR);
780   while (!done)
781   {
782     switch (f=dbox_fillin(d),f)
783     {
784       case dbox_CLOSE:
785         done=TRUE;
786         break;
787       case tearEdit__COLOUROK:
788         dbox_clickicon(d,tearEdit__COLOUROK);
789         if (fore)
790         {
791           icn->flags &= ~0x0F000000;
792           icn->flags |= colour<<24;
793         }
794         else
795         {
796           icn->flags &= ~0xF0000000;
797           icn->flags |= colour<<28;
798         }
799         window_redrawIcon(tearEdit__window,tearEdit__icon);
800         tfile_markAsAltered(tearEdit__window->t);
801         if (dbox_wasAdjustClick())
802           dbox_unclick();
803         else
804         {
805           dbox_hide(d);
806           dbox_unclick();
807           done=TRUE;
808         }
809         break;
810       default:
811         if (f>=tearEdit__COLOURCOLS &&
812             f<tearEdit__COLOURCOLS+16 &&
813             f!=colour+tearEdit__COLOURCOLS)
814         {
815           tearEdit__removeBorder(d,colour);
816           colour=f-tearEdit__COLOURCOLS;
817           tearEdit__addBorder(d,colour);
818         }
819         break;
820     }
821   }
822
823   dbox_delete(d);
824 }
825
826 /*----- Size and position dialogue boxes ----------------------------------*/
827
828 /*
829  * void tearEdit__coordsArrows(dbox d,dbox_field f,int diff,void *handle)
830  *
831  * Use
832  *  Handles a click event on one of the position or size arrow buttons in
833  *  the dialogue box.  See the structure definition below for a description
834  *  of the data structure required.
835  */
836
837 typedef struct
838 {
839   BOOL xOrY;
840   BOOL sizing;
841 }
842 tearEdit__coordsArrowstr;
843
844 static void tearEdit__coordsArrows(dbox d,
845                                    dbox_field f,
846                                    int diff,
847                                    void *handle)
848 {
849   tearEdit__coordsArrowstr *s=handle;
850   int x,y;
851   int *v;
852
853   dbox_scanfield(d,f,"%d,%d",&x,&y);
854   v=s->xOrY ? &x : &y;
855   *v+=diff;
856   if (s->sizing && *v<0)
857     *v=0;
858   dbox_setfield(d,f,"%i,%i",x,y);
859 }
860
861 /*
862  * void tearEdit__coordsBox(BOOL size)
863  *
864  * Use
865  *  Displays a dialogue box and allows the user to alter either the size or
866  *  position of an icon.
867  *
868  * Parameters
869  *  BOOL size == whether to alter the size or position
870  */
871
872 static void tearEdit__coordsBox(BOOL size)
873 {
874   dbox d;
875   BOOL done=FALSE;
876   dbox_field f;
877   wimp_icon *icn;
878   int x,y;
879   tearEdit__coordsArrowstr ca;
880
881   if (!tearEdit__window || tearEdit__icon==-1)
882     return;
883
884   d=dbox_create(size ? "teditSize" : "teditPos");
885   if (!d)
886     return;
887
888   icn=&tearEdit__window->def->i[tearEdit__icon].i;
889   if (size)
890   {
891     x=icn->box.x1-icn->box.x0;
892     y=icn->box.y1-icn->box.y0;
893   }
894   else
895   {
896     x=icn->box.x0;
897     y=icn->box.y0;
898   }
899   ca.sizing=size;
900
901   dbox_setfield(d,tearEdit__POSWRITE,"%i,%i",x,y);
902   dbox_display(d,dbox_MENU_OVERPTR);
903
904   while (!done)
905   {
906     f=dbox_fillin(d);
907     switch (f)
908     {
909       case dbox_CLOSE:
910         done=TRUE;
911         break;
912       case tearEdit__POSUP:
913         ca.xOrY=FALSE;
914         buttons_arrow(d,f,d,tearEdit__POSWRITE,
915                       tearEdit__coordsArrows,+wimpt_dy(),&ca);
916         break;
917       case tearEdit__POSDOWN:
918         ca.xOrY=FALSE;
919         buttons_arrow(d,f,d,tearEdit__POSWRITE,
920                       tearEdit__coordsArrows,-wimpt_dy(),&ca);
921         break;
922       case tearEdit__POSLEFT:
923         ca.xOrY=TRUE;
924         buttons_arrow(d,f,d,tearEdit__POSWRITE,
925                       tearEdit__coordsArrows,-wimpt_dx(),&ca);
926         break;
927       case tearEdit__POSRIGHT:
928         ca.xOrY=TRUE;
929         buttons_arrow(d,f,d,tearEdit__POSWRITE,
930                       tearEdit__coordsArrows,+wimpt_dx(),&ca);
931         break;
932       case tearEdit__POSOK:
933         dbox_clickicon(d,f);
934         dbox_scanfield(d,tearEdit__POSWRITE,"%d,%d",&x,&y);
935         window_redrawIcon(tearEdit__window,tearEdit__icon);
936         if (size)
937         {
938           icn->box.x1=icn->box.x0+x;
939           icn->box.y1=icn->box.y0+y;
940         }
941         else
942         {
943           icn->box.x1+=x-icn->box.x0;
944           icn->box.y1+=y-icn->box.y0;
945           icn->box.x0=x;
946           icn->box.y0=y;
947         }
948         window_redrawIcon(tearEdit__window,tearEdit__icon);
949         tfile_markAsAltered(tearEdit__window->t);
950         if (dbox_wasAdjustClick())
951           dbox_unclick();
952         else
953         {
954           dbox_hide(d);
955           dbox_unclick();
956           done=TRUE;
957         }
958         break;
959     }
960   }
961   dbox_delete(d);
962 }
963
964 /*----- Menu handling -----------------------------------------------------*/
965
966 /*
967  * void tearEdit__mainHits(tearoff_message m,int hit,void *handle)
968  * etc.
969  *
970  * Use
971  *  Handles menu events for the main edit icon menu level
972  *
973  * Parameters
974  *  tearoff_message m == the type of event that happened
975  *  int hit == the item it happened to
976  *  void *handle == a waste of a good argument register
977  */
978
979 static void tearEdit__mainHits(tearoff_message m,int hit,void *handle)
980 {
981   unused(handle);
982   switch (m)
983   {
984     case tearoff_SELECTION:
985     case tearoff_SUBMENU:
986       switch (hit)
987       {
988         case tearEdit__MAINPOS:
989           tearEdit__coordsBox(FALSE);
990           break;
991         case tearEdit__MAINSIZE:
992           tearEdit__coordsBox(TRUE);
993           break;
994       }
995       break;
996   }
997 }
998
999 static void tearEdit__dataHits(tearoff_message m,int hit,void *handle)
1000 {
1001   unused(handle);
1002   switch (m)
1003   {
1004     case tearoff_SELECTION:
1005     case tearoff_SUBMENU:
1006       switch (hit)
1007       {
1008         case tearEdit__DATADATA:
1009           tearEdit__dataBox();
1010           break;
1011         case tearEdit__DATAINDIR:
1012           tearEdit__indirBox();
1013           break;
1014         case tearEdit__DATATEXT:
1015           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_ITEXT;
1016           tearEdit__setData(&tearEdit__window->def->i[tearEdit__icon].i,
1017                             0,
1018                             tearEdit__NOVALID,
1019                             tearEdit__NOCHANGE);
1020           break;
1021         case tearEdit__DATASPRITE:
1022           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_ISPRITE;
1023           tearEdit__setData(&tearEdit__window->def->i[tearEdit__icon].i,
1024                             0,
1025                             0,
1026                             tearEdit__NOCHANGE);
1027           break;
1028       }
1029       break;
1030   }
1031 }
1032
1033 static void tearEdit__appearHits(tearoff_message m,int hit,void *handle)
1034 {
1035   unused(handle);
1036   switch (m)
1037   {
1038     case tearoff_SELECTION:
1039     case tearoff_SUBMENU:
1040       switch (hit)
1041       {
1042         case tearEdit__APPEARHCENTRE:
1043           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IHCENTRE;
1044           window_redrawIcon(tearEdit__window,tearEdit__icon);
1045           tfile_markAsAltered(tearEdit__window->t);
1046           break;
1047         case tearEdit__APPEARVCENTRE:
1048           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IVCENTRE;
1049           window_redrawIcon(tearEdit__window,tearEdit__icon);
1050           tfile_markAsAltered(tearEdit__window->t);
1051           break;
1052         case tearEdit__APPEARRALIGN:
1053           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IRJUST;
1054           window_redrawIcon(tearEdit__window,tearEdit__icon);
1055           tfile_markAsAltered(tearEdit__window->t);
1056           break;
1057         case tearEdit__APPEARBORDER:
1058           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IBORDER;
1059           window_redrawIcon(tearEdit__window,tearEdit__icon);
1060           tfile_markAsAltered(tearEdit__window->t);
1061           break;
1062         case tearEdit__APPEARFILLED:
1063           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IFILLED;
1064           window_redrawIcon(tearEdit__window,tearEdit__icon);
1065           tfile_markAsAltered(tearEdit__window->t);
1066           break;
1067         case tearEdit__APPEARHALF:
1068           tearEdit__window->def->i[tearEdit__icon].i.flags ^=
1069                                                   wimp_IHALVESPRITE;
1070           window_redrawIcon(tearEdit__window,tearEdit__icon);
1071           tfile_markAsAltered(tearEdit__window->t);
1072           break;
1073         case tearEdit__APPEARHELP:
1074           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IREDRAW;
1075           window_redrawIcon(tearEdit__window,tearEdit__icon);
1076           tfile_markAsAltered(tearEdit__window->t);
1077           break;
1078       }
1079       break;
1080   }
1081 }
1082
1083 static void tearEdit__actionsHits(tearoff_message m,int hit,void *handle)
1084 {
1085   unused(handle);
1086   switch (m)
1087   {
1088     case tearoff_SELECTION:
1089     case tearoff_SUBMENU:
1090       switch (hit)
1091       {
1092         case tearEdit__ACTIONSESG:
1093           tearEdit__esgBox();
1094           break;
1095         case tearEdit__ACTIONSADJUST:
1096           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IESG_NOC;
1097           window_redrawIcon(tearEdit__window,tearEdit__icon);
1098           tfile_markAsAltered(tearEdit__window->t);
1099           break;
1100         case tearEdit__ACTIONSSELECT:
1101           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_ISELECTED;
1102           window_redrawIcon(tearEdit__window,tearEdit__icon);
1103           tfile_markAsAltered(tearEdit__window->t);
1104           break;
1105         case tearEdit__ACTIONSSHADE:
1106           tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_INOSELECT;
1107           window_redrawIcon(tearEdit__window,tearEdit__icon);
1108           tfile_markAsAltered(tearEdit__window->t);
1109           break;
1110       }
1111       break;
1112   }
1113 }
1114
1115 static void tearEdit__btypeHits(tearoff_message m,int hit,void *handle)
1116 {
1117   unused(handle);
1118   if (m==tearoff_SELECTION && hit>=1 && hit<=16)
1119   {
1120     tearEdit__window->def->i[tearEdit__icon].i.flags &= ~0x0000F000;
1121     tearEdit__window->def->i[tearEdit__icon].i.flags |= (hit-1)<<12;
1122     window_redrawIcon(tearEdit__window,tearEdit__icon);
1123     tfile_markAsAltered(tearEdit__window->t);
1124   }
1125 }
1126
1127 static void tearEdit__coloursHits(tearoff_message m,int hit,void *handle)
1128 {
1129   unused(handle);
1130   switch (m)
1131   {
1132     case tearoff_SELECTION:
1133     case tearoff_SUBMENU:
1134       switch (hit)
1135       {
1136         case tearEdit__COLOURSFORE:
1137           tearEdit__colourBox(TRUE);
1138           break;
1139         case tearEdit__COLOURSBACK:
1140           tearEdit__colourBox(FALSE);
1141           break;
1142       }
1143       break;
1144   }
1145 }
1146
1147 /*----- External functions ------------------------------------------------*/
1148
1149 /*
1150  * void tearEdit_open(void)
1151  *
1152  * Use
1153  *  Opens the edit icon menu, as a submenu if appropriate, otherwise as a
1154  *  full menu.
1155  */
1156
1157 void tearEdit_open(void)
1158 {
1159   tearoff_displayMenu(tearEdit__main,0);
1160 }
1161
1162 /*
1163  * void tearEdit_update(glass_windPointer *w,int icon)
1164  *
1165  * Use
1166  *  Updates the edit icon menu from the specified window and icon.  If the
1167  *  window handle is 0, or the icon is -1 then the menu is made unavailable
1168  *  (i.e. its items are shaded).  Otherwise, the menu is updated to reflect
1169  *  the state of the icon.
1170  *
1171  * Parameters
1172  *  glass_windPointer *w == the window containing the icon to edit
1173  *  int icon == the icon to be editing in the menu
1174  */
1175
1176 void tearEdit_update(glass_windPointer *w,int icon)
1177 {
1178   int i;
1179   wimp_iconflags f;
1180   int b;
1181
1182   /* --- Remember the new magic icon --- */
1183
1184   tearEdit__window=w;
1185   tearEdit__icon=icon;
1186
1187   /* --- If there isn't an icon any more, shade the menu --- */
1188
1189   if (!w || icon==-1)
1190   {
1191     for (i=tearEdit__MAINDATA;i<=tearEdit__MAINSIZE;i++)
1192     {
1193       tearoff_shadeItem(tearEdit__main,i,TRUE);
1194       tearoff_selectItem(tearEdit__main,i,FALSE);
1195     }
1196     for (i=tearEdit__DATADATA;i<=tearEdit__DATASPRITE;i++)
1197     {
1198       tearoff_shadeItem(tearEdit__data,i,TRUE);
1199       tearoff_selectItem(tearEdit__data,i,FALSE);
1200     }
1201     for (i=tearEdit__APPEARHCENTRE;i<=tearEdit__APPEARHELP;i++)
1202     {
1203       tearoff_shadeItem(tearEdit__appear,i,TRUE);
1204       tearoff_selectItem(tearEdit__appear,i,FALSE);
1205     }
1206     for (i=tearEdit__ACTIONSBTYPE;i<=tearEdit__ACTIONSSHADE;i++)
1207     {
1208       tearoff_shadeItem(tearEdit__actions,i,TRUE);
1209       tearoff_selectItem(tearEdit__actions,i,FALSE);
1210     }
1211     for (i=1;i<=16;i++)
1212     {
1213       tearoff_shadeItem(tearEdit__btype,i,TRUE);
1214       tearoff_selectItem(tearEdit__btype,i,FALSE);
1215     }
1216     for (i=tearEdit__COLOURSFORE;i<=tearEdit__COLOURSBACK;i++)
1217       tearoff_shadeItem(tearEdit__colours,i,TRUE);
1218   }
1219   else
1220   {
1221     /* --- Read information about the icon --- */
1222
1223     f=w->def->i[icon].i.flags;
1224
1225     /* --- Unshade the main menu --- */
1226
1227     tearoff_shadeItem(tearEdit__main,tearEdit__MAINDATA,FALSE);
1228     tearoff_shadeItem(tearEdit__main,tearEdit__MAINAPPEAR,FALSE);
1229     tearoff_shadeItem(tearEdit__main,tearEdit__MAINACTIONS,FALSE);
1230     tearoff_shadeItem(tearEdit__main,tearEdit__MAINCOLOURS,tst(f,6));
1231     tearoff_shadeItem(tearEdit__main,tearEdit__MAINPOS,FALSE);
1232     tearoff_shadeItem(tearEdit__main,tearEdit__MAINSIZE,FALSE);
1233
1234     /* --- Handle data things --- */
1235
1236     tearoff_shadeItem(tearEdit__data,tearEdit__DATADATA,!(f & 3));
1237     tearoff_shadeItem(tearEdit__data,tearEdit__DATAINDIR,!(f & 3));
1238     tearoff_selectItem(tearEdit__data,tearEdit__DATAINDIR,tst(f,8));
1239     tearoff_shadeItem(tearEdit__data,tearEdit__DATATEXT,FALSE);
1240     tearoff_selectItem(tearEdit__data,tearEdit__DATATEXT,tst(f,0));
1241     tearoff_shadeItem(tearEdit__data,tearEdit__DATASPRITE,FALSE);
1242     tearoff_selectItem(tearEdit__data,tearEdit__DATASPRITE,tst(f,1));
1243
1244     /* --- Handle appearance things --- */
1245
1246     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARHCENTRE,FALSE);
1247     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARHCENTRE,tst(f,3));
1248     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARVCENTRE,FALSE);
1249     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARVCENTRE,tst(f,4));
1250     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARRALIGN,FALSE);
1251     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARRALIGN,tst(f,9));
1252
1253     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARBORDER,FALSE);
1254     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARBORDER,tst(f,2));
1255     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARFILLED,FALSE);
1256     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARFILLED,tst(f,5));
1257     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARHALF,!tst(f,1));
1258     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARHALF,tst(f,11));
1259     tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARHELP,FALSE);
1260     tearoff_selectItem(tearEdit__appear,tearEdit__APPEARHELP,tst(f,7));
1261
1262     /* --- Handle actions things --- */
1263
1264     tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSBTYPE,FALSE);
1265     tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSESG,FALSE);
1266     tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSADJUST,FALSE);
1267     tearoff_selectItem(tearEdit__actions,tearEdit__ACTIONSADJUST,tst(f,10));
1268     tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSSELECT,FALSE);
1269     tearoff_selectItem(tearEdit__actions,tearEdit__ACTIONSSELECT,tst(f,21));
1270     tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSSHADE,FALSE);
1271     tearoff_selectItem(tearEdit__actions,tearEdit__ACTIONSSHADE,tst(f,22));
1272
1273     /* --- Handle button type --- */
1274
1275     b=(f & 0x0000F000)>>12;
1276     for (i=1;i<=16;i++)
1277     {
1278       tearoff_shadeItem(tearEdit__btype,i,FALSE);
1279       tearoff_selectItem(tearEdit__btype,i,(i-1==b) ?
1280                                              tearoff_RADIOED :
1281                                              FALSE);
1282     }
1283
1284     /* --- Handle colours --- */
1285
1286     tearoff_shadeItem(tearEdit__colours,tearEdit__COLOURSFORE,tst(f,6));
1287     tearoff_shadeItem(tearEdit__colours,tearEdit__COLOURSBACK,tst(f,6));
1288   }
1289 }
1290
1291 /*
1292  * void tearEdit_init(void)
1293  *
1294  * Use
1295  *  Initialises the tearoff menus for editing icons and starts up the tearoff
1296  *  menu manager.
1297  */
1298
1299 void tearEdit_init(void)
1300 {
1301   char *buf=buffer_find();
1302   int i;
1303
1304   /* --- If we're already up and running, then someone's stupid --- */
1305
1306   if (tearEdit__main)
1307     return;
1308
1309   tearoff_init();
1310
1311   tearEdit__main=tearoff_create(msgs_lookup("teEIMT"),
1312                                 msgs_lookup("teEIM"),
1313                                 TRUE,
1314                                 tearEdit__mainHits,
1315                                 0,
1316                                 0);
1317
1318   tearEdit__data=tearoff_create(msgs_lookup("teEIDT"),
1319                                 msgs_lookup("teEID"),
1320                                 TRUE,
1321                                 tearEdit__dataHits,
1322                                 0,
1323                                 0);
1324
1325   tearEdit__appear=tearoff_create(msgs_lookup("teAPMT"),
1326                                   msgs_lookup("teAPM"),
1327                                   TRUE,
1328                                   tearEdit__appearHits,
1329                                   0,
1330                                   0);
1331
1332   tearEdit__actions=tearoff_create(msgs_lookup("teACMT"),
1333                                    msgs_lookup("teACM"),
1334                                    TRUE,
1335                                    tearEdit__actionsHits,
1336                                    0,
1337                                    0);
1338
1339   tearEdit__colours=tearoff_create(msgs_lookup("teCMT"),
1340                                    msgs_lookup("teCM"),
1341                                    TRUE,
1342                                    tearEdit__coloursHits,
1343                                    0,
1344                                    0);
1345
1346   /* --- Change this code to use Edit Icon messages --- */
1347
1348   tearEdit__btype=tearoff_create(msgs_lookup("eiBTMT"),
1349                                  msgs_lookup("eiBTYPE0"),
1350                                  TRUE,
1351                                  tearEdit__btypeHits,
1352                                  0,
1353                                  0);
1354   for (i=1;i<=15;i++)
1355   {
1356     sprintf(buf,"eiBTYPE%i",i);
1357     tearEdit__btype=tearoff_extendMenu(tearEdit__btype,msgs_lookup(buf));
1358   }
1359   tearoff_shadeItem(tearEdit__btype,13,TRUE);
1360   tearoff_shadeItem(tearEdit__btype,14,TRUE);
1361
1362   if (!tearEdit__main ||
1363       !tearEdit__data ||
1364       !tearEdit__appear ||
1365       !tearEdit__actions ||
1366       !tearEdit__colours ||
1367       !tearEdit__btype)
1368     exit(1);
1369
1370   tearoff_attachSubMenu(tearEdit__main,
1371                         tearEdit__MAINDATA,
1372                         tearEdit__data);
1373   tearoff_attachSubMenu(tearEdit__main,
1374                         tearEdit__MAINAPPEAR,
1375                         tearEdit__appear);
1376   tearoff_attachSubMenu(tearEdit__main,
1377                         tearEdit__MAINACTIONS,
1378                         tearEdit__actions);
1379   tearoff_attachSubMenu(tearEdit__main,
1380                         tearEdit__MAINCOLOURS,
1381                         tearEdit__colours);
1382   tearoff_attachSubMenu(tearEdit__actions,
1383                         tearEdit__ACTIONSBTYPE,
1384                         tearEdit__btype);
1385
1386   tearEdit_update(0,-1);
1387 }