chiark / gitweb /
Initial revision
[ssr] / StraySrc / Glass / !Glass / c / wMenus
1 /*
2  * wMenus.c
3  *
4  * Handling the Template Window Menu
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 headers
40  */
41
42 #define _STDAPP
43 #define _LOWLVL
44 #include "steel/Steel.h"
45
46 #include "steel/buttons.h"
47 #include "steel/choices.h"
48 #include "steel/bbc.h"
49 #include "steel/buffer.h"
50 #include "steel/tearoff.h"
51
52 /*
53  * Glass headers
54  */
55
56 #include "gStruct.h"
57 #include "gMenus.h"
58 #include "gIcons.h"
59
60 #include "glass.h"
61 #include "gPrefs.h"
62 #include "tfile.h"
63 #include "window.h"
64 #include "_window.h"
65 #include "editIcon.h"
66 #include "editWin.h"
67 #include "align.h"
68 #include "iconData.h"
69 #include "tearEdit.h"
70
71 /*----- Private data ------------------------------------------------------*/
72
73 static int window__menuX;        /* x-position of pointer on menu click    */
74 static int window__menuY;        /* y-position of pointer on menu click    */
75 static int window__newIcons;     /* Number of new icon types defined       */
76
77 static glass_windPointer* window__menuWin; /* Which window owns the menu   */
78
79 static tearoff window__mRoot;    /* Root of menu structure                 */
80 static tearoff window__mMisc;    /* Misc submenu                           */
81 static tearoff window__mSelect;  /* Select submenu                         */
82 static tearoff window__mButton;  /* Button type submenu                    */
83 static tearoff window__mIcon;    /* Icon submenu                           */
84 static tearoff window__mCreate;  /* Icon types submenu                     */
85 static tearoff window__mGuide;   /* Guides submenu                         */
86
87 /*----- Main code ---------------------------------------------------------*/
88
89 /*
90  * glass_windPointer *window__menuOwner(void)
91  *
92  * Use
93  *  Returns which window currently owns the menu.
94  *
95  * Returns
96  *  A pointer to the window's anchor block.
97  */
98
99 glass_windPointer *window__menuOwner(void)
100 {
101   return (window__menuWin);
102 }
103
104 /*
105  * void window__doTable(unsigned short *p,int s,unsigned int f,tearoff t)
106  *
107  * Use
108  *  Updates a tearoff menu using the given table.
109  *
110  * Parameters
111  *  unsigned short *p == pointer to shade flags table
112  *  int s == number of items in table
113  *  unsigned int f == which flags to use to mask with
114  *  tearoff t == which tearoff menu to play with
115  */
116
117 static void window__doTable(const unsigned short *p,
118                             int s,unsigned int f,tearoff t)
119 {
120   unsigned int *tbl=(unsigned int *)p;
121   int i;
122   unsigned int w;
123   for (i=0;i<s;i++)
124   {
125     w = (i&1 ? w>>16 : *tbl++);
126     tearoff_shadeItem(t,i+1,(w & f)!=0);
127   }
128 }
129
130 /*
131  * void window__updateMenu(glass_windPointer *w)
132  *
133  * Use
134  *  Updates the menu attached to the main window.
135  *
136  * Parameters
137  *  glass_windPointer *w == pointer to owning menu
138  */
139
140 void window__updateMenu(glass_windPointer *w)
141 {
142   int i;
143   unsigned int sflags;
144   int gflags;
145   glass_windPointer *wso=window_selectionOwner();
146
147   /* --- Redesign --- *
148    *
149    * Based on the Sapphire idea, we define a number of shade flags,
150    * and a big table which says which items need to be shaded when.
151    *
152    * The table is carefully organised so as not to give clues about how
153    * to implement test mode.  This isn't important.
154    */
155
156   #define s_all (1<<15)
157
158   #define s_guide (1<<0 | s_all)
159   #define s_gsel (1<<1 | s_all)
160   #define s_sel (1<<2 | s_all)
161   #define s_icon (1<<3 | s_all)
162   #define s_ren (1<<4 | s_all)
163   #define s_copy (1<<5 | s_all)
164   #define s_grid (1<<6 | s_all)
165
166 #ifndef glass_DEMO
167   #define s_test (1<<7 | s_all)
168 #else
169   #define s_test (s_all)
170 #endif
171
172   #define s_qs (s_test | s_ren)
173   #define s_s (s_sel | s_qs)
174
175   /* --- Shading table --- *
176    *
177    * Each entry packed into a single byte.  This is quite good, for C ;-)
178    */
179
180   const static unsigned short root[]=
181                   { s_all, s_all, s_test, s_qs, s_qs, s_qs, s_qs };
182
183   const static unsigned short misc[]=
184                   { s_all, s_qs, s_ren, s_qs, s_qs, s_all };
185
186   const static unsigned short select[]=
187                   { s_icon|s_qs,  s_s, s_qs|s_copy, s_s,
188                     s_sel|s_test, s_s, s_s, s_s, s_s,
189                     s_s|s_grid,   s_s,
190                     s_s,          s_s};
191
192   const static unsigned short icon[]=
193                   { s_qs, s_qs, s_qs };
194
195   const static unsigned short guide[]=
196                   { s_qs|s_guide, s_qs|s_gsel, s_qs|s_gsel, s_qs, s_qs };
197
198   /* --- Build the mask word --- */
199
200   if (!w)
201     sflags=s_all;
202   else
203   {
204     sflags=0;
205
206     /* --- Work out guide status --- */
207
208     gflags=0;
209     for (i=0;i<glass_GUIDELIMIT;i++)
210     {
211       if (w->guide[i].active)
212         gflags|=1;
213       if (w->guide[i].selected)
214         gflags|=2;
215     }
216
217     /* --- Now set flags appropriately --- */
218
219     if (!(gflags & 1))           sflags|=s_guide & ~s_all;
220     if (!(gflags & 2))           sflags|=s_gsel  & ~s_all;
221     if (!w->selno)               sflags|=s_sel   & ~s_all;
222     if (!w->def->desc.w.nicons)  sflags|=s_icon  & ~s_all;
223     if (w->renumber)             sflags|=s_ren   & ~s_all;
224     if (!wso || !wso->selno)     sflags|=s_copy  & ~s_all;
225     if (!w->gridLock)            sflags|=s_grid  & ~s_all;
226
227   #ifndef glass_DEMO
228     if (w->testMode)             sflags|=s_test  & ~s_all;
229   #endif
230   }
231
232   /* --- Now shade all the items --- */
233
234   window__doTable(root,sizeof(root)/2,sflags,window__mRoot);
235   window__doTable(misc,sizeof(misc)/2,sflags,window__mMisc);
236   window__doTable(select,sizeof(select)/2,sflags,window__mSelect);
237   window__doTable(icon,sizeof(icon)/2,sflags,window__mIcon);
238   window__doTable(guide,sizeof(guide)/2,sflags,window__mGuide);
239
240   for (i=0;i<16;i++)
241     tearoff_shadeItem(window__mButton,i+1,(s_s & sflags)!=0);
242
243   for (i=0;i<window__newIcons;i++)
244     tearoff_shadeItem(window__mCreate,i+1,(s_qs & sflags)!=0);
245
246   /* --- Tick the items that need it --- */
247
248 #ifndef glass_DEMO
249   tearoff_selectItem(window__mMisc,glass_TWMTEST,w && w->testMode);
250 #endif
251   tearoff_selectItem(window__mSelect,glass_TWSORDER,w && w->renumber);
252
253   /* --- That's it, then --- *
254    *
255    * We need to remember which window all of this applies to so that the
256    * user doesn't get all confused.
257    */
258
259   window__menuWin=w;
260 }
261
262 /*
263  * void window__gridBox(glass_windPointer *w)
264  *
265  * Use
266  *  Displays and processes a grid dialogue box
267  */
268
269 static void window__gridBox(glass_windPointer *w)
270 {
271   dbox d;
272   dbox_field f;
273   buttons_simpleArrow sa={0,999,FALSE};
274   wimp_redrawstr r;
275   BOOL shade;
276   BOOL done=FALSE;
277   wimp_wstate s;
278
279   if (d=dbox_create("grid"),!d)
280     return;
281   dbox_selecticon(d,glass_GDISP,w->gridShow);
282   dbox_selecticon(d,glass_GLOCK,w->gridLock);
283   dbox_setfield(d,glass_GWWRITE,"%i",w->gridx);
284   dbox_setfield(d,glass_GHWRITE,"%i",w->gridy);
285   shade=!(w->gridShow || w->gridLock);
286   dbox_shadeicon(d,glass_GWUP,shade);
287   dbox_shadeicon(d,glass_GWDOWN,shade);
288   dbox_shadeicon(d,glass_GWWRITE,shade);
289   dbox_shadeicon(d,glass_GHUP,shade);
290   dbox_shadeicon(d,glass_GHDOWN,shade);
291   dbox_shadeicon(d,glass_GHWRITE,shade);
292   dbox_display(d,dbox_MENU_OVERPTR);
293   done=FALSE;
294   while (!done)
295   {
296     switch (f=dbox_fillin(d),f)
297     {
298       case dbox_CLOSE:
299         done=TRUE;
300         break;
301       case glass_GOK:
302         dbox_clickicon(d,glass_GOK);
303         w->gridShow=dbox_selecticon(d,glass_GDISP,dbox_READSTATE);
304         w->gridLock=dbox_selecticon(d,glass_GLOCK,dbox_READSTATE);
305         dbox_scanfield(d,glass_GWWRITE,"%d",&w->gridx);
306         dbox_scanfield(d,glass_GHWRITE,"%d",&w->gridy);
307         wimpt_noerr(wimp_get_wind_state(w->h,&s));
308         r.w=w->h;
309         r.box.x0=s.o.x;
310         r.box.x1=r.box.x0+s.o.box.x1-s.o.box.x0;
311         r.box.y1=s.o.y;
312         r.box.y0=r.box.y1+s.o.box.y0-s.o.box.y1;
313         wimpt_noerr(wimp_force_redraw(&r));
314         window__updateMenu(w);
315         if (!dbox_wasAdjustClick())
316           dbox_hide(d);
317         dbox_unclick();
318         if (!dbox_wasAdjustClick())
319           done=TRUE;
320         break;
321       case glass_GDISP:
322       case glass_GLOCK:
323         shade=!(dbox_selecticon(d,glass_GDISP,dbox_READSTATE) ||
324                 dbox_selecticon(d,glass_GLOCK,dbox_READSTATE));
325         dbox_shadeicon(d,glass_GWUP,shade);
326         dbox_shadeicon(d,glass_GWDOWN,shade);
327         dbox_shadeicon(d,glass_GWWRITE,shade);
328         dbox_shadeicon(d,glass_GHUP,shade);
329         dbox_shadeicon(d,glass_GHDOWN,shade);
330         dbox_shadeicon(d,glass_GHWRITE,shade);
331         break;
332       case glass_GWUP:
333         buttons_arrow(d,f,d,glass_GWWRITE,0,+1,&sa);
334         break;
335       case glass_GWDOWN:
336         buttons_arrow(d,f,d,glass_GWWRITE,0,-1,&sa);
337         break;
338       case glass_GHUP:
339         buttons_arrow(d,f,d,glass_GHWRITE,0,+1,&sa);
340         break;
341       case glass_GHDOWN:
342         buttons_arrow(d,f,d,glass_GHWRITE,0,-1,&sa);
343         break;
344     }
345   }
346   dbox_delete(d);
347 }
348
349 /*
350  * void window__thHelp(char *prefix,int hit)
351  *
352  * Use
353  *  Does help for a tearoff menu.
354  *
355  * Parameters
356  *  char *prefix == pointer to prefix string
357  *  int hit == which item
358  */
359
360 static void window__thHelp(char *prefix,int hit)
361 {
362   char *p=buffer_find();
363   sprintf(p,"%s%i",prefix,hit);
364   help_startHelp();
365   help_addLine(msgs_lookup(p));
366   help_endHelp();
367 }
368
369 /*
370  * void window__mhRoot(tearoff_message m,int hit,void *handle)
371  *
372  * Use
373  *  Handles events on the root menu
374  *
375  * Parameters
376  *  tearoff_message m == what happened
377  *  int hit == what item it happened to
378  *  void *handle == nothing interesting
379  */
380
381 static void window__mhRoot(tearoff_message m,int hit,void *handle)
382 {
383   glass_windPointer *w=handle ? handle : window__menuWin;
384   unused(handle);
385
386   switch (m)
387   {
388     case tearoff_HELP:
389       window__thHelp("wmhRT",hit);
390       break;
391     case tearoff_SELECTION:
392     case tearoff_SUBMENU:
393       switch (hit)
394       {
395         case glass_TWSAVE:
396           if (w)
397             tfile_saveWindow(w);
398           break;
399         case glass_TWEDIT:
400           tearEdit_open();
401           break;
402         case glass_TWGRID:
403           #ifndef glass_DEMO
404             if (w && !w->renumber && !w->testMode)
405               window__gridBox(w);
406           #else
407             if (w && !w->renumber)
408               window__gridBox(w);
409           #endif
410           break;
411       }
412       break;
413   }
414 }
415
416 /*
417  * void window__mhMisc(tearoff_message m,int hit,void *handle)
418  *
419  * Use
420  *  Handles events on the misc submenu
421  *
422  * Parameters
423  *  tearoff_message m == what happened
424  *  int hit == what item it happened to
425  *  void *handle == nothing interesting
426  */
427
428 static void window__mhMisc(tearoff_message m,int hit,void *handle)
429 {
430   glass_windPointer *w=handle ? handle : window__menuWin;
431   int i;
432   int stop;
433   BOOL checked;
434   BOOL done;
435   int xoff,yoff;
436   wimp_box b;
437
438 #ifndef glass_DEMO
439   wimp_wstate s;
440   wimp_caretstr c;
441   wimp_icon icn;
442   wimp_w whand;
443   glass_windPointer *wso=window_selectionOwner();
444 #endif
445
446   unused(handle);
447
448   switch (m)
449   {
450     case tearoff_HELP:
451       window__thHelp("wmhMSC",hit);
452       break;
453     case tearoff_SELECTION:
454     case tearoff_SUBMENU:
455       switch (hit)
456       {
457         case glass_TWMINFO:
458           if (w)
459             tfile_windowInfo(w);
460           break;
461         case glass_TWMEDITWIN:
462           editWindow(w);
463           break;
464       #ifndef glass_DEMO
465         case glass_TWMTEST:
466           checked=!gPrefs_current()->cTest;
467           if (w->edit)
468           {
469             if (!checked)
470             {
471               if (!warning(msgs_lookup("wdTCEP"),msgs_lookup("wdTCE")))
472                 return;
473               checked=TRUE;
474             }
475             editWindow_close(w);
476           }
477           for (i=0;i<w->def->desc.w.nicons;i++)
478           {
479             if (w->def->i[i].edit)
480             {
481               if (!checked)
482               {
483                 if (!warning(msgs_lookup("wdTCEP"),msgs_lookup("wdTCE")))
484                   return;
485                 checked=TRUE;
486               }
487               editIcon_close(w,i);
488             }
489           }
490           if (w->testMode)         /* Are we coming out of test mode?      */
491           {
492             for (i=0;i<w->def->desc.w.nicons;i++)
493             {
494               wimpt_noerr(wimp_get_icon_info(w->h,i,&icn));
495               if (memcmp(&icn,&w->def->i[i].i,sizeof(wimp_icon)))
496               {
497                 tfile_markAsAltered(w->t);
498                 w->def->i[i].i=icn;
499               }
500             }
501           }
502           w->testMode=!w->testMode;
503           if (whand=window__recreate(w),!whand)
504           {
505             w->testMode=!w->testMode;
506             return;
507           }
508           wimpt_noerr(wimp_get_wind_state(w->h,&s));
509           if (w->ownPointer)
510           {
511             win_removeIdleClaimer(window__winIdles,w);
512             window__setPtrShape(window__SELECT);
513           }
514           wimpt_noerr(wimp_close_wind(w->h)); /* Closed, guv'nor           */
515           win_register_event_handler(w->h,0,0); /* Won't need this now     */
516           wimpt_noerr(wimp_delete_wind(w->h)); /* Delete the window        */
517           w->h=whand;
518           win_register_event_handler(w->h,
519                    w->testMode ? window__testEvents : window__events,w);
520           s.o.w=w->h;
521           if (w==wso)
522             window__toggleTest(w);
523           wimpt_noerr(wimp_open_wind(&s.o));
524           if (w==wso)
525           {
526             window__setToolBarPositions(0);
527             if (w->testMode)
528             {
529               if (window__selectedIcon()!=-1)
530                 tearEdit_update(0,-1);
531             }
532             else
533             {
534               c.w=w->h;
535               c.i=-1;
536               c.x=w->def->desc.w.ex.x0-50;
537               c.y=0;
538               c.height=0x02000000;
539               c.index=-1;
540               wimpt_noerr(wimp_set_caret_pos(&c));
541               tearEdit_update(w,window__selectedIcon());
542             }
543           }
544           window__updateMenu(w);
545
546           /* --- Our good mate the Window Manager --- *
547            *
548            * Because the RISC OS 3 Window Manager is about as braindead as
549            * it's possible to get without being written by Microsoft, it
550            * decides that it would be a simply super idea to move our window
551            * back on the screen at this point, screwing up the cached window
552            * position.
553            */
554
555           wimpt_noerr(wimp_get_wind_state(w->h,&s));
556           if (memcmp(&s.o.box,&w->def->desc.w,24))
557           {
558             w->def->desc.w.box=s.o.box;
559             w->def->desc.w.scx=s.o.x;
560             w->def->desc.w.scy=s.o.y;
561             if (!w->t->alts)
562               tfile_markAsAltered(w->t);
563           }
564
565           break;
566       #endif
567         case glass_TWMREMDEL:
568           stop=w->def->desc.w.nicons-1;
569           done=FALSE;
570           for (i=0;i<=stop;i++)
571           {
572             if (w->def->i[i].i.flags & wimp_IDELETED)
573             {
574               window_renumber(w,i--,stop--);
575               done=TRUE;
576             }
577           }
578           if (done)
579           {
580             window__removeTrailingDeleted(w);
581             tfile_markAsAltered(w->t);
582           }
583           break;
584         case glass_TWMBRINGBK:
585           for (i=0;i<w->def->desc.w.nicons;i++)
586           {
587             window_boundingBox(w,i,&b);
588             xoff=yoff=0;
589             if (b.x0<w->def->desc.w.ex.x0)
590               xoff=w->def->desc.w.ex.x0-b.x0;
591             if (b.x1>w->def->desc.w.ex.x1)
592               xoff=w->def->desc.w.ex.x1-b.x1;
593             if (b.y0<w->def->desc.w.ex.y0)
594               yoff=w->def->desc.w.ex.y0-b.y0;
595             if (b.y1>w->def->desc.w.ex.y1)
596               yoff=w->def->desc.w.ex.y1-b.y1;
597             if (xoff || yoff)
598             {
599               b.x0+=xoff;
600               b.x1+=xoff;
601               b.y0+=yoff;
602               b.y1+=yoff;
603               window_setBox(w,i,&b);
604               tfile_markAsAltered(w->t);
605             }
606           }
607           break;
608         case glass_TWMCLOSE:
609           event_clear_current_menu();
610           window_close(w);
611           break;
612       }
613       break;
614   }
615 }
616
617 /*
618  * void window__mhSelect(tearoff_message m,int hit,void *handle)
619  *
620  * Use
621  *  Handles events on the select submenu
622  *
623  * Parameters
624  *  tearoff_message m == what happened
625  *  int hit == what item it happened to
626  *  void *handle == nothing interesting
627  */
628
629 static void window__mhSelect(tearoff_message m,int hit,void *handle)
630 {
631   glass_windPointer *w=handle ? handle : window__menuWin;
632   int i;
633   BOOL stop;
634   BOOL checked;
635   wimp_box b;
636   int xoff,yoff;
637
638   unused(handle);
639
640   switch (m)
641   {
642     case tearoff_HELP:
643       window__thHelp("wmhSEL",hit);
644       break;
645     case tearoff_SELECTION:
646     case tearoff_SUBMENU:
647       switch (hit)
648       {
649         case glass_TWSALL:
650           window__gainSelection(w);
651           for (i=0;i<w->def->desc.w.nicons;i++)
652             window__select(w,i,TRUE);
653           window__updateMenu(w);
654           break;
655         case glass_TWSCLR:
656           window__gainSelection(w);
657           for (i=0;i<w->def->desc.w.nicons;i++)
658             window__select(w,i,FALSE);
659           window__updateMenu(w);
660           break;
661         case glass_TWSCOPY:
662           window__copyIcons(w);
663           window__updateMenu(w);
664           break;
665         case glass_TWSDEL:
666           if (gPrefs_current()->cDelIcon)
667           {
668             if (!warning(msgs_lookup("wdCDIP"),msgs_lookup("wdCDI")))
669               return;
670           }
671           i=0;
672           while (i<w->def->desc.w.nicons)
673           {
674             if (w->def->i[i].selected)
675               window_deleteIcon(w,i);
676             else
677               i++;
678           }
679           window__updateMenu(w);
680           break;
681         case glass_TWSFRONT:
682           stop=w->def->desc.w.nicons-1;
683           for (i=0;i<=stop;i++)
684           {
685             if (w->def->i[i].selected)
686             {
687               window_renumber(w,i,w->def->desc.w.nicons-1);
688               i--;
689               stop--;
690             }
691           }
692           tfile_markAsAltered(w->t);
693           break;
694         case glass_TWSRAISE:
695           if (w->def->i[w->def->desc.w.nicons - 1].selected) {
696             bbc_vdu(7);
697             break;
698           }
699           for (i=w->def->desc.w.nicons - 1; i >= 0; i--) {
700             if (w->def->i[i].selected)
701               window_renumber(w, i, i + 1);
702           }
703           tfile_markAsAltered(w->t);
704           break;
705         case glass_TWSLOWER:
706           if (w->def->i[0].selected) {
707             bbc_vdu(7);
708             break;
709           }
710           for (i = 0; i < w->def->desc.w.nicons ;i++) {
711             if (w->def->i[i].selected)
712               window_renumber(w, i, i - 1);
713           }
714           tfile_markAsAltered(w->t);
715           break;
716         case glass_TWSBACK:
717           stop=0;
718           for (i=w->def->desc.w.nicons-1;i>=stop;i--)
719           {
720             if (w->def->i[i].selected)
721             {
722               window_renumber(w,i,0);
723               i++;
724               stop++;
725             }
726           }
727           tfile_markAsAltered(w->t);
728           break;
729         case glass_TWSORDER:
730           checked=!gPrefs_current()->cTest;
731           if (w->edit)
732           {
733             if (!checked)
734             {
735               if (!warning(msgs_lookup("wdTCRP"),msgs_lookup("wdTCR")))
736                 return;
737               checked=TRUE;
738             }
739             editWindow_close(w);
740           }
741           for (i=0;i<w->def->desc.w.nicons;i++)
742           {
743             if (w->def->i[i].edit)
744             {
745               if (!checked)
746               {
747                 if (!warning(msgs_lookup("wdTCRP"),msgs_lookup("wdTCR")))
748                   return;
749                 checked=TRUE;
750               }
751               editIcon_close(w,i);
752             }
753           }
754           window__renumber(w,!w->renumber);
755           window__updateMenu(w);
756           break;
757         case glass_TWSPULL:
758           for (i=0;i<w->def->desc.w.nicons;i++)
759           {
760             if (w->def->i[i].selected)
761             {
762               window_boundingBox(w,i,&b);
763               xoff=b.x1-b.x0;
764               yoff=b.y1-b.y0;
765               window__align(w,&b.x0,&b.y1);
766               b.x1=b.x0+xoff;
767               b.y0=b.y1-yoff;
768               window_setBox(w,i,&b);
769               tfile_markAsAltered(w->t);
770             }
771           }
772           break;
773         case glass_TWSALIGN:
774           align();
775           break;
776         case glass_TWSEDIT:
777           for (i=0;i<w->def->desc.w.nicons;i++)
778           {
779             if (w->def->i[i].selected)
780               editIcon(w,i);
781           }
782           break;
783       }
784       break;
785   }
786 }
787
788 /*
789  * void window__mhButton(tearoff_message m,int hit,void *handle)
790  *
791  * Use
792  *  Handles events on the foo submenu
793  *
794  * Parameters
795  *  tearoff_message m == what happened
796  *  int hit == what item it happened to
797  *  void *handle == nothing interesting
798  */
799
800 static void window__mhButton(tearoff_message m,int hit,void *handle)
801 {
802   glass_windPointer *w=handle ? handle : window__menuWin;
803   int i;
804
805   unused(handle);
806
807   switch (m)
808   {
809     case tearoff_HELP:
810       window__thHelp("wmhBUT",hit);
811       break;
812     case tearoff_SELECTION:
813     case tearoff_SUBMENU:
814       if (hit)
815       {
816         for (i=0;i<w->def->desc.w.nicons;i++)
817         {
818           if (w->def->i[i].selected)
819           {
820             w->def->i[i].i.flags&=~0x0000f000;
821             w->def->i[i].i.flags|=(hit-1)<<12;
822             tfile_markAsAltered(w->t);
823           }
824         }
825       }
826       break;
827   }
828 }
829
830 /*
831  * void window__newIcon(int which,glass_windPointer *w)
832  *
833  * Use
834  *  Creates a new icon in the window.
835  *
836  * Parameters
837  *  int which == which icon type to use
838  *  glass_windPointer *w == the window to build it in
839  */
840
841 static void window__newIcon(int which,glass_windPointer *w)
842 {
843   int i;
844   wimp_wind *wdef;
845   wimp_icon *idef;
846   wimp_box b;
847   int xoff,yoff;
848   const static wimp_icon defidef={0,0,200,48,0x0f00603f,"<Untitled>"};
849
850   if (i=window__createIcon(w),i==-1)
851     return;
852   wdef=&template_find("default")->window;
853   idef=(wimp_icon *)(wdef+1);
854   switch (wdef->nicons)
855   {
856     case 0:
857       w->def->i[i].i=defidef;
858       break;
859     default:
860       w->def->i[i].i=idef[which];
861       break;
862   }
863   if (!iconData_handleFont(w,&w->def->i[i].i.flags))
864     werr(FALSE,msgs_lookup("wdFERCI"));
865   if (!iconData_processIcon(w,i,0,TRUE,0))
866   {
867     werr(FALSE,msgs_lookup("wdNEMCI"));
868     w->def->i[i].i.flags&=~wimp_INDIRECT;
869     window_deleteIcon(w,i);
870     return;
871   }
872   window_boundingBox(w,i,&b);
873   xoff=window__menuX-b.x0;
874   yoff=window__menuY-b.y1;
875   if (w->gridLock)
876     window__align(w,&xoff,&yoff);
877   w->def->i[i].i.box.x0+=xoff;
878   w->def->i[i].i.box.x1+=xoff;
879   w->def->i[i].i.box.y0+=yoff;
880   w->def->i[i].i.box.y1+=yoff;
881   window_redrawIcon(w,i);
882   tfile_markAsAltered(w->t);
883   window__menuX+=w->gridx;
884   window__menuY-=w->gridy;
885 }
886
887 /*
888  * void window__mhIcon(tearoff_message m,int hit,void *handle)
889  *
890  * Use
891  *  Handles events on the icon submenu
892  *
893  * Parameters
894  *  tearoff_message m == what happened
895  *  int hit == what item it happened to
896  *  void *handle == nothing interesting
897  */
898
899 static void window__mhIcon(tearoff_message m,int hit,void *handle)
900 {
901   glass_windPointer *w=handle ? handle : window__menuWin;
902   unused(handle);
903
904   switch (m)
905   {
906     case tearoff_HELP:
907       window__thHelp("wmhICN",hit);
908       break;
909     case tearoff_SELECTION:
910     case tearoff_SUBMENU:
911       switch (hit)
912       {
913         case glass_TWINEW:
914           window__newIcon(0,w);
915           window__updateMenu(w);
916           break;
917         case glass_TWIPAL:
918           window__showPalette();
919           break;
920         case glass_TWIGRAB:
921           window_grab(window__grabIcon,w);
922           break;
923       }
924       break;
925   }
926 }
927
928 /*
929  * void window__mhCreate(tearoff_message m,int hit,void *handle)
930  *
931  * Use
932  *  Handles events on the new icon submenu
933  *
934  * Parameters
935  *  tearoff_message m == what happened
936  *  int hit == what item it happened to
937  *  void *handle == nothing interesting
938  */
939
940 static void window__mhCreate(tearoff_message m,int hit,void *handle)
941 {
942   glass_windPointer *w=handle ? handle : window__menuWin;
943   unused(handle);
944
945   if (!w)
946   {
947     bbc_vdu(7);
948     return;
949   }
950
951   switch (m)
952   {
953     case tearoff_HELP:
954       help_startHelp();
955       help_addLine(msgs_lookup("wmhNI"));
956       help_endHelp();
957       break;
958     case tearoff_SELECTION:
959     case tearoff_SUBMENU:
960       if (hit)
961       {
962         window__newIcon(hit-1,w);
963         window__updateMenu(w);
964       }
965       break;
966   }
967 }
968
969 /*
970  * void window__mhGuide(tearoff_message m,int hit,void *handle)
971  *
972  * Use
973  *  Handles events on the guide submenu
974  *
975  * Parameters
976  *  tearoff_message m == what happened
977  *  int hit == what item it happened to
978  *  void *handle == nothing interesting
979  */
980
981 static void window__mhGuide(tearoff_message m,int hit,void *handle)
982 {
983   glass_windPointer *w=handle ? handle : window__menuWin;
984   int i;
985
986   unused(handle);
987
988   switch (m)
989   {
990     case tearoff_HELP:
991       window__thHelp("wmhGD",hit);
992       break;
993     case tearoff_SELECTION:
994     case tearoff_SUBMENU:
995       switch (hit)
996       {
997         case glass_TWGSELALL:
998           window__gainSelection(w);
999           for (i=0;i<glass_GUIDELIMIT;i++)
1000           {
1001             if (w->guide[i].active && !w->guide[i].selected)
1002             {
1003               w->guide[i].selected=TRUE;
1004               window__redrawGuide(w,i);
1005             }
1006           }
1007           window__updateMenu(w);
1008           break;
1009         case glass_TWGCLRSEL:
1010           for (i=0;i<glass_GUIDELIMIT;i++)
1011           {
1012             if (w->guide[i].active && w->guide[i].selected)
1013             {
1014               w->guide[i].selected=FALSE;
1015               window__redrawGuide(w,i);
1016             }
1017           }
1018           window__updateMenu(w);
1019           break;
1020         case glass_TWGHORIZ:
1021           for (i=0;i<glass_GUIDELIMIT;i++)
1022           {
1023             if (!w->guide[i].active)
1024             {
1025               w->guide[i].active=TRUE;
1026               w->guide[i].horiz=TRUE;
1027               w->guide[i].coord=window__menuY;
1028               w->guide[i].selected=FALSE;
1029               window__redrawGuide(w,i);
1030               window__menuY-=w->gridy;
1031               break;
1032             }
1033           }
1034           if (i==glass_GUIDELIMIT)
1035             note(msgs_lookup("wdTMG"),glass_GUIDELIMIT);
1036           window__updateMenu(w);
1037           break;
1038         case glass_TWGVERT:
1039           for (i=0;i<glass_GUIDELIMIT;i++)
1040           {
1041             if (!w->guide[i].active)
1042             {
1043               w->guide[i].active=TRUE;
1044               w->guide[i].horiz=FALSE;
1045               w->guide[i].coord=window__menuX;
1046               w->guide[i].selected=FALSE;
1047               window__redrawGuide(w,i);
1048               window__menuX+=w->gridx;
1049               break;
1050             }
1051           }
1052           if (i==glass_GUIDELIMIT)
1053             note(msgs_lookup("wdTMG"),glass_GUIDELIMIT);
1054           window__updateMenu(w);
1055           break;
1056         case glass_TWGDEL:
1057           for (i=0;i<glass_GUIDELIMIT;i++)
1058           {
1059             if (w->guide[i].active && w->guide[i].selected)
1060             {
1061               w->guide[i].active=w->guide[i].selected=FALSE;
1062               window__redrawGuide(w,i);
1063             }
1064           }
1065           window__updateMenu(w);
1066           break;
1067       }
1068       break;
1069   }
1070 }
1071
1072 /*
1073  * void window__simMenu(glass_windPointer *w,int hit1,int hit2)
1074  *
1075  * Use
1076  *  Simulates a menu hit on the specified item.  Gives a beep if the item
1077  *  is unavailable.  Otherwise, the hit is sent to the current selection
1078  *  owner.  [fixed to allow which window is used rather than only the
1079  *  selection owner, 1 November 1993]
1080  *
1081  * Use
1082  *  glass_windPointer *w == the window in which to simulate the event
1083  *  int hit1 == first hit in the sequence
1084  *  int hit2 == second hit in the sequence
1085  */
1086
1087 void window__simMenu(glass_windPointer *w,int hit1,int hit2)
1088 {
1089   /* --- A bit of a hack(tm) --- *
1090    *
1091    * The old Wimp-menu based code used to simulate menu events to try to
1092    * do key shortcuts and the button bar.  We try to emulate the old
1093    * behaviour, although the implementation is a /little/ different.  The
1094    * old code used to peek about in the menu blocks to find submenus.
1095    * We can't do this any more, because the tearoff structure is hidden,
1096    * so we keep a big table of our own to help us find our way around.
1097    * Actually, this makes the code /much/ smaller.
1098    */
1099
1100   const static struct
1101   {
1102     tearoff_selectProc p;
1103     tearoff *t;
1104   }
1105   table[]={ window__mhRoot,   &window__mRoot, /* Funny entry for root menu */
1106             window__mhMisc,   &window__mMisc,
1107             0,                0,
1108             window__mhSelect, &window__mSelect,
1109             window__mhIcon,   &window__mIcon,
1110             0,                0,
1111             window__mhButton, &window__mButton };
1112
1113
1114   if (!hit2)
1115     hit2=hit1;
1116
1117   if (table[hit1].t && !tearoff_isShaded(*table[hit1].t,hit2))
1118     table[hit1].p(tearoff_SELECTION,hit2,w);
1119   else
1120     bbc_vdu(7);
1121 }
1122
1123 /*
1124  * void window__showMenu(int x,int y,glass_windPointer *w)
1125  *
1126  * Use
1127  *  Displays the Template Window Menu
1128  *
1129  * Parameters
1130  *  int x,int y == the (window) position to display the menu
1131  *  glass_windPointer *w == the window to display the menu for
1132  */
1133
1134 void window__showMenu(int x,int y,glass_windPointer *w)
1135 {
1136   window__menuX=x;
1137   window__menuY=y;
1138   window__updateMenu(w);
1139   tearoff_displayMenu(window__mRoot,w);
1140 }
1141
1142 /*
1143  * void window__menuInit(void)
1144  *
1145  * Use
1146  *  Initialises the create icon menu
1147  */
1148
1149 void window__menuInit(void)
1150 {
1151   wimp_wind *wdef;
1152   wimp_icon *idef;
1153   int i;
1154   char *p;
1155   char buff[15];
1156
1157   /* --- First set up the create menu --- */
1158
1159   template_readfile(choices_name("Defaults.Templates",FALSE));
1160   wdef=&template_find("default")->window;
1161   idef=(wimp_icon *)(wdef+1);
1162   window__newIcons=wdef->nicons;
1163   switch (wdef->nicons)
1164   {
1165     case 0:
1166     case 1:
1167       break;
1168     default:
1169       for (i=0;i<wdef->nicons;i++)
1170       {
1171         if (idef[i].flags & wimp_INDIRECT)
1172         {
1173           p=idef[i].data.indirecttext.buffer;
1174           utils_ctermToNterm(p);
1175           if (*p=='`')
1176             p++;
1177           if (window__mCreate)
1178             window__mCreate=tearoff_extendMenu(window__mCreate,p);
1179           else
1180             window__mCreate=tearoff_create(msgs_lookup("wdCRTMT"),
1181                                            p,TRUE,window__mhCreate,800,0);
1182           if (p[-1]=='`')
1183           {
1184             p[-1]=0;
1185             idef[i].data.indirecttext.bufflen=1;
1186           }
1187         }
1188         else
1189         {
1190           memcpy(buff,idef[i].data.text,12);
1191           utils_ctermToNterm(buff);
1192           buff[12]=0;
1193           p=buff;
1194           if (*p=='`')
1195             p++;
1196           if (window__mCreate)
1197             window__mCreate=tearoff_extendMenu(window__mCreate,p);
1198           else
1199             window__mCreate=tearoff_create(msgs_lookup("wdCRTMT"),
1200                                            p,TRUE,window__mhCreate,800,0);
1201           if (p[-1]=='`')
1202             p[-1]=0;
1203         }
1204       }
1205       break;
1206   }
1207
1208   /* --- Create the main menu tree --- */
1209
1210   window__mRoot=tearoff_create(msgs_lookup("wdWMT"),
1211     msgs_lookup("wdWM"),
1212     TRUE,window__mhRoot,0,0);
1213
1214   window__mMisc=tearoff_create(msgs_lookup("wdMISCMT"),
1215     msgs_lookup("wdMISCM"),
1216     FALSE,window__mhMisc,0,0);
1217
1218   window__mSelect=tearoff_create(msgs_lookup("wdSELMT"),
1219     msgs_lookup("wdSELM"),
1220     TRUE,window__mhSelect,0,0);
1221
1222   window__mIcon=tearoff_create(msgs_lookup("wdICNMT"),
1223     msgs_lookup("wdICNM"),
1224     FALSE,window__mhIcon,0,0);
1225
1226   window__mGuide=tearoff_create(msgs_lookup("wdGDEMT"),
1227     msgs_lookup("wdGDEM"),
1228     TRUE,window__mhGuide,0,0);
1229
1230  window__mButton=tearoff_create(msgs_lookup("eiBTMT"),
1231                                  msgs_lookup("eiBTYPE0"),
1232                                  FALSE,
1233                                  window__mhButton,
1234                                  0,
1235                                  0);
1236   p=buffer_find();
1237   for (i=1;i<=15;i++)
1238   {
1239     sprintf(p,"eiBTYPE%i",i);
1240     window__mButton=tearoff_extendMenu(window__mButton,msgs_lookup(p));
1241   }
1242
1243   tearoff_attachSubMenu(window__mRoot,glass_TWMISC,window__mMisc);
1244   tearoff_attachSubMenu(window__mRoot,glass_TWSELECT,window__mSelect);
1245   tearoff_attachSubMenu(window__mRoot,glass_TWICON,window__mIcon);
1246   tearoff_attachSubMenu(window__mRoot,glass_TWGDE,window__mGuide);
1247   tearoff_attachSubMenu(window__mSelect,glass_TWSBTYPE,window__mButton);
1248   if (window__mCreate)
1249     tearoff_attachSubMenu(window__mIcon,glass_TWINEW,window__mCreate);
1250 }