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 }