4 * Straylight TMS Segment
5 * Nice tearoff menu system - impressive even if I do say so myself
7 * © 1995-1998 Straylight
10 /*----- Licensing note ----------------------------------------------------*
12 * This file is part of Straylight's Steel library.
14 * Steel is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
19 * Steel is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Steel. If not, write to the Free Software Foundation,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #define dbox__INTERNALS
45 #include "tearSupt/tearSupt.h"
47 /*----- Global defintions -------------------------------------------------*/
49 static int tearoff__x, tearoff__y; /* Position to open next menu */
52 tearoff__prevLevel = NULL, /* Most recent parent */
53 tearoff__currentMenu = NULL, /* Current Transient menu */
54 tearoff__originatingTearoff = NULL, /* Most recent tornoff parent */
55 tearoff__tornoffList = NULL, /* List of torn off menus */
56 tearoff__oldHandle = NULL; /* Idle event handle */
58 static wimp_w tearoff__currentDbox=0; /* Current dbox opened */
59 static BOOL tearoff__subMenuPending=FALSE,
60 riscos3, /* We are on risos3 */
61 tearoff__menuActive=TRUE; /* Are menus active */
62 static int tearoff__alarmTime, /* Time alarm was set */
63 tearoff__alarmTime2; /* Time 2nd alarm was set */
64 static tearoff__alarm tearoff__alm;
66 /*----- Icon handles for the tear bar -------------------------------------*/
68 #define tearIcon__tear 0
69 #define tearIcon__close 0
70 #define tearIcon__fold 1
72 /*----- Function prototypes for cyclic definitions ------------------------*/
74 static void tearoff__doIdles(void *handle);
75 static void tearoff__windowHandler(wimp_eventstr *e, void *handle);
77 /*----- Tearoff code - Not for the casual observer!! ----------------------*/
79 static void tearoff_closeMenus(void)
81 tearSupport_switch(1);
82 wimp_create_menu((wimp_menustr*)-1,0,0);
83 tearSupport_switch(0);
86 /*----- Window creation routines ----------------------------------------- */
88 /* --- Create the tear icon in the given window --- */
90 static void tearoff__createTearIcon(tearoff t /* was wimp_w w [mdw] */)
92 wimp_w w=t->w; /* [mdw] */
96 #ifdef notdef /* [mdw] */
106 ict.i.box.x1 = t->width;
112 ict.i.flags = wimp_IVCENTRE |
114 wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
117 (0x30000000) /* [mdw] */;
119 ict.i.data.indirectsprite.name = "tear";
120 ict.i.data.indirectsprite.spritearea = resspr_area();
121 ict.i.data.indirectsprite.nameisname = 4;
124 wimpt_noerr(wimp_create_icon(&ict, &i));
127 /* --- Create the close/fold icons in the menu */
129 static void tearoff__createTornIcons(tearoff t)
134 #ifdef notdef /* [mdw] */
144 ict.i.box.x1 = (t->width/2)-2;
150 ict.i.flags = wimp_IVCENTRE |
152 wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
155 (0x30000000) /* [mdw] */;
157 ict.i.data.indirectsprite.name = "close";
158 ict.i.data.indirectsprite.spritearea = resspr_area();
159 ict.i.data.indirectsprite.nameisname = 4;
162 wimpt_noerr(wimp_create_icon(&ict, &i));
164 /* wimp_set_icon_state(t->w, i, 0, 0); [mdw] */
166 /* Now create the fold icon */
168 #ifdef notdef /* [mdw] */
170 ict.i.box.x1 = t->width - 4;
171 ict.i.box.x0 = ict.i.box.x1 - 60;
177 ict.i.box.x0 = (t->width/2)+2;
178 ict.i.box.x1 = t->width;
184 ict.i.flags = wimp_IVCENTRE |
186 wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
187 wimp_ISPRITE | wimp_INDIRECT |
188 wimp_IRJUST | /* [mdw] */
189 (0x30000000) /* [mdw] */;
192 ict.i.data.indirectsprite.name = "fold";
193 ict.i.data.indirectsprite.spritearea = resspr_area();
194 ict.i.data.indirectsprite.nameisname = 4;
197 wimpt_noerr(wimp_create_icon(&ict, &i));
199 /* wimp_set_icon_state(t->w, i, 0, 0); [mdw] */
201 { /* --- start [mdw] --- */
207 r.box.x0=0; r.box.x1=t->width;
208 r.box.y0=-24; r.box.y1=0;
209 wimpt_noerr(wimp_update_wind(&r,&more));
213 bbc_rectanglefill(r.box.x0-r.scx+t->width/2-2,
216 wimpt_noerr(wimp_get_rectangle(&r,&more));
219 /* --- end [mdw] --- */ }
222 /* --- Called to calculate the width of a menu */
224 void tearoff_calculateMenuWidth(tearoff t)
230 i=(tearoff__item *)(t+1);
232 for (cnt=1;cnt<=t->numberOfItems;cnt++,i++)
234 w=wimpt_stringWidth(i->text);
240 i=(tearoff__item *)(t+1);
242 for (cnt=1;cnt<=t->numberOfItems;cnt++,i++)
246 w=wimpt_stringWidth(i->keys);
255 w=wimpt_stringWidth(t->menuTitle);
256 if (t->width<w) t->width=w;
257 if (t->width<150 && t->tearoff) t->width=150;
260 /* --- Creates a window for a menu --- */
262 static wimp_w tearoff__createWindow(tearoff t)
268 int extra = (t->tearoff)?tearoff__HEIGHT:0, h;
269 int scy=(bbc_vduvar(bbc_YWindLimit)+1)<<bbc_vduvar(bbc_YEigFactor);
271 /* First create the window itself */
273 tearoff_calculateMenuWidth(t);
276 wind.ex.x1 = t->width;
277 wind.ex.y0 = -t->numberOfItems * 44 - extra - t->dotted;
280 h = wind.ex.y1-wind.ex.y0; /* Height */
283 wind.box.x1 = t->width;
284 if (t->maxHeight && h > t->maxHeight)
285 wind.box.y0 = -t->maxHeight;
296 wind.flags = wimp_WMOVEABLE |
302 if (!t->folded && (t->maxHeight && h > t->maxHeight || (h+50)>scy))
304 wind.flags |= wimp_WVSCR;
308 wind.titleflags = wimp_ITEXT |
313 wind.workflags = wimp_IBTYPE * wimp_BCLICKDEBOUNCE;
315 wind.colours[wimp_WCTITLEFORE] = 7;
316 wind.colours[wimp_WCTITLEBACK] = 2;
317 wind.colours[wimp_WCWKAREAFORE] = 7;
318 wind.colours[wimp_WCWKAREABACK] = 0;
319 wind.colours[wimp_WCSCROLLOUTER] = 3;
320 wind.colours[wimp_WCSCROLLINNER] = 1;
321 wind.colours[wimp_WCTITLEHI] = 12;
322 wind.colours[wimp_WCRESERVED] = 0;
324 wind.spritearea = (void *)1;
326 wind.title.indirecttext.buffer = t->menuTitle;
327 wind.title.indirecttext.validstring = 0;
328 wind.title.indirecttext.bufflen = strlen(t->menuTitle + 1);
332 if (wimp_create_wind(&wind, &w)) return -1;
335 /* Create tearoff icon if needed */
340 #ifdef notdef /* [mdw] */
342 /* First the blank bar */
345 ict.i.box.x1 = t->width;
347 ict.i.box.y0 = -tearoff__HEIGHT;
349 ict.i.flags = wimp_IVCENTRE |
351 wimp_IBTYPE * wimp_BIGNORE |
355 ict.i.flags |= wimp_ITEXT;
357 strcpy(ict.i.data.text, "");
360 wimpt_noerr(wimp_create_icon(&ict, &i));
367 tearoff__createTearIcon(t /* was `w' [mdw] */);
369 tearoff__createTornIcons(t);
375 /*----- Functions to register with dbox -----------------------------------*/
377 /* --- Registered with dbox so that it can find out where to open dbox --- */
379 static void tearoff__finder(int *x,int *y)
385 /* --- Registered with dbox also, so that it can tell me to
388 static void tearoff__openDbox(wimp_openstr *o)
390 if (tearoff__subMenuPending)
392 tearoff__currentDbox = o->w;
394 if (!tearoff__currentMenu) tearSupport_opened(wimpt_task());
398 /* --- Registered with dbox so that it knows whether to open the next
399 dbox using above registered function */
401 static BOOL tearoff__wasSubmenu(void)
403 return tearoff__subMenuPending;
406 /*----- The tearoff menu handling routines - Yuk --------------------------*/
408 /* --- Used to either highlight or unhighlight a menu item.
409 The current status of the icon is checked and
410 no change is made if is doesn't need to be. */
412 void tearoff_highlightItem(int s, tearoff t, BOOL select)
414 wimp_icon textIcon,keyIcon;
420 if (!select && s!=t->selected) return;
422 item = (tearoff__item *)(t+1);
425 if (item->shaded) return;
427 r.box.x1=t->width-24;
432 textIcon.box.y0=item->y;
433 textIcon.box.y1=item->y+44;
434 textIcon.box.x0 = 24;
435 textIcon.box.x1 = 24 + t->width - 48;
436 textIcon.flags = wimp_ITEXT |
441 textIcon.flags |= wimp_IBACKCOL * 7 |
444 textIcon.flags |= wimp_IBACKCOL * 0 |
447 if (item->shaded) textIcon.flags |= wimp_INOSELECT;
448 textIcon.data.indirecttext.buffer = item->text;
449 textIcon.data.indirecttext.validstring = "";
450 textIcon.data.indirecttext.bufflen = strlen(item->text) + 1;
454 keyIcon.box.x1=t->width-24;
455 keyIcon.box.x0=keyIcon.box.x1-t->keyWidth;
456 keyIcon.box.y0=textIcon.box.y0;
457 keyIcon.box.y1=textIcon.box.y1;
458 keyIcon.flags=wimp_ITEXT |
463 keyIcon.flags |= wimp_IBACKCOL * 7 |
466 keyIcon.flags |= wimp_IBACKCOL * 0 |
469 if (item->shaded) keyIcon.flags |= wimp_INOSELECT;
470 keyIcon.data.indirecttext.buffer=item->keys;
471 keyIcon.data.indirecttext.validstring="";
472 keyIcon.data.indirecttext.bufflen=strlen(item->keys)+1;
475 wimp_update_wind(&r,&more);
478 wimp_ploticon(&textIcon);
479 if (item->keys) wimp_ploticon(&keyIcon);
481 wimp_get_rectangle(&r,&more);
485 /* --- Called to deselect the currently highlighted item
486 in a menu. Here, a selected item is one that has
487 been set up by going over a submenu arrow. */
489 static void tearoff__deselect(tearoff t)
492 tearoff_highlightItem(t->selected, t, FALSE);
497 /* --- Clean up after pointer has lewft a window etc --- */
499 static void tearoff__cleanUp(void)
501 win_removeIdleClaimer(tearoff__doIdles, tearoff__oldHandle);
502 alarm_remove(tearoff__alarmTime,0);
503 alarm_remove(tearoff__alarmTime2,0);
504 tearoff__alm.item=-1;
505 tearoff__menuActive=TRUE;
506 tearoff__oldHandle = NULL;
509 /* --- Closes the menu passed, and all sub menus off of it.
510 If the menu passed is top of the current transient
511 menu, then TearoffSupport is told to stop giving me
512 button pressed/menu created messages. */
514 static void tearoff__closeMenuStructure(tearoff t,tearoff nowOn)
518 /* Close dbox if opened */
520 if (tearoff__currentDbox)
522 wimp_close_wind(tearoff__currentDbox);
523 tearoff__currentDbox=0;
524 if (tearoff__prevLevel)
526 if (tearoff__prevLevel != nowOn)
528 tearoff__deselect(tearoff__prevLevel);
529 tearoff__prevLevel->selected = FALSE;
531 tearoff__prevLevel->warned = FALSE;
532 tearoff__prevLevel->sub = NULL;
534 if (!tearoff__currentMenu) tearSupport_closed();
542 tearoff__prevLevel = NULL;
543 tearoff__originatingTearoff = NULL;
544 if (t->prev->tornoff)
546 if (t->prev != nowOn) tearoff__deselect(t->prev);
548 t->prev->warned = FALSE;
552 if (t == tearoff__currentMenu)
554 tearoff__currentMenu = NULL;
555 tearSupport_closed(); /* Stop TearoffSupport Sending messages */
562 if (t->tornoff) return; /* Dont' close a torn off menu */
564 wimpt_noerr(wimp_close_wind(t->w));
565 wimpt_noerr(wimp_delete_wind(t->w));
566 win_register_event_handler(t->w, (win_event_handler)0, 0);
568 if (t->warned) p = t->sub; else p = NULL;
570 if (tearoff__oldHandle == t)
580 (t->selectProc)(tearoff_CLOSE, NULL, t->userHandle);
586 /* --- Called to shade a sub menu arrow --- */
588 #ifdef notdef /* [mdw] */
590 static void tearoff__shadeSub(tearoff t,int i,BOOL shade)
599 item=(tearoff__item *)(t+1);
602 item->subShaded=shade;
607 r.box.x1=icon.box.x1=t->width;
608 r.box.x0=icon.box.x0=t->width-24;
609 r.box.y0=icon.box.y0=item->y;
610 r.box.y1=icon.box.y1=item->y+44;
612 icon.flags = wimp_IVCENTRE |
618 if (item->shaded || item->subShaded) icon.flags |= wimp_INOSELECT;
622 icon.flags |= wimp_ITEXT;
623 strcpy(icon.data.text, "\x89");
627 icon.flags |= wimp_ISPRITE |
630 icon.data.indirecttext.validstring = "s\x89";
631 icon.data.indirecttext.bufflen = 1;
632 icon.data.indirecttext.buffer = "";
635 wimp_update_wind(&r,&more);
638 wimp_ploticon(&icon);
639 wimp_get_rectangle(&r,&more);
646 #define tearoff__shadeSub(x,y,z) ((void)0)
650 /* --- Called to 'tear' off the given menu --- */
652 static void tearoff__tearMenu(tearoff t, BOOL close)
656 if (t->tornoff) return;
660 tearoff__deselect(t->prev);
662 /* Do a window move drag */
665 d.type = wimp_MOVE_WIND;
668 /* Add it to the torn off list */
670 t->nextTornoff = tearoff__tornoffList;
671 tearoff__tornoffList = t;
672 if (tearoff__currentMenu==t)
674 tearoff__currentMenu=NULL;
675 tearSupport_closed();
678 /* Close the current menu structure if dragged with select */
680 if (close) tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
682 /* Shade the sub menu arrow of the previous menu */
684 if (t->prev) tearoff__shadeSub(t->prev,t->fromItem,TRUE);
686 /* Now we need to alter the tearoff icons at the top of the menu */
688 wimp_delete_icon(t->w, tearIcon__tear); /* Delete tear icon */
690 /* Create a close icon - this should be given the same
691 icon number as the tear icon had */
693 tearoff__createTornIcons(t);
696 /* --- Used to 'fold up' the given menu */
698 static void tearoff__foldMenu(tearoff t, BOOL close)
706 if (close) tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
708 /* Close any transient submenus opened from this menu */
712 tearoff__closeMenuStructure(t->sub,NULL);
713 tearoff__deselect(t);
716 /* Re-open the menu at the right size */
718 wimp_get_wind_state(t->w, &state);
719 wimp_get_point_info(&m);
720 if (m.w==t->w) sameMenu=TRUE;
722 t->folded = !t->folded;
728 wimpt_noerr(wimp_close_wind(t->w));
729 wimpt_noerr(wimp_delete_wind(t->w));
730 win_register_event_handler(t->w, (win_event_handler)0, 0);
731 if (tearoff__oldHandle==t)
733 tearoff__createWindow(t);
735 state.o.box.y0=state.o.box.y1-tearoff__HEIGHT;
736 win_register_event_handler(t->w, tearoff__windowHandler, t);
737 wimp_open_wind(&(state.o));
738 if (sameMenu && m.i>=-1)
740 win_addIdleClaimer(tearoff__doIdles, 0, t);
741 tearoff__oldHandle = t;
746 state.o.box.y0=state.o.box.y1-tearoff__HEIGHT;
747 wimp_open_wind(&(state.o));
752 int scy=(bbc_vduvar(bbc_YWindLimit)+1)<<bbc_vduvar(bbc_YEigFactor);
753 int h=(t->numberOfItems*44)+t->dotted+tearoff__HEIGHT;
755 if (t->maxHeight && h>t->maxHeight || (h+50)>scy)
757 wimpt_noerr(wimp_close_wind(t->w));
758 wimpt_noerr(wimp_delete_wind(t->w));
759 win_register_event_handler(t->w, (win_event_handler)0, 0);
760 if (tearoff__oldHandle==t)
762 tearoff__createWindow(t);
765 state.o.box.y0=state.o.box.y1-t->maxHeight;
767 state.o.box.y0=state.o.box.y1-tearoff__HEIGHT-
768 (t->numberOfItems*44)-t->dotted;
769 win_register_event_handler(t->w, tearoff__windowHandler, t);
770 win_adjustBox(&state.o);
771 wimp_open_wind(&state.o);
772 if (sameMenu && m.i>=-1)
774 win_addIdleClaimer(tearoff__doIdles, 0, t);
775 tearoff__oldHandle = t;
780 state.o.box.y0=state.o.box.y1-tearoff__HEIGHT-
781 (t->numberOfItems*44)-t->dotted;
782 win_adjustBox(&state.o);
783 wimp_open_wind(&(state.o));
788 /* --- Used to 'un-tear' the given menu - this will be called
789 if it is re-opened as a tranisent of another menu.
790 It is also called in the routine to close a torn off menu */
792 static wimp_w tearoff__unTearMenu(tearoff t, BOOL update)
796 tearoff ptr = tearoff__tornoffList, prev = NULL;
798 /* Go through the 'tornoff list', if the menu is found then
799 remove it, untear it, and return it's window handle */
805 /* remove it from list */
807 if (!prev) tearoff__tornoffList = t->nextTornoff;
808 else prev->nextTornoff = t->nextTornoff;
811 /* Close any transient menu opened from it */
815 tearoff__closeMenuStructure(t->sub,NULL);
816 tearoff__deselect(t);
819 /* Unshade the sub menu pointer for the previous menu */
821 tearoff__shadeSub(t->prev,t->fromItem,FALSE);
823 /* Unfold it if it needs to be */
825 if (t->folded) tearoff__foldMenu(t, FALSE);
827 /* Update if it is being moved - rather than just closed */
831 wimp_delete_icon(t->w, tearIcon__close);
832 wimp_delete_icon(t->w, tearIcon__fold);
834 /* Replace the tear icon */
836 tearoff__createTearIcon(t /* was t->w [mdw] */);
838 /* Now redraw top of menu */
844 r.box.y0 = -tearoff__HEIGHT;
846 wimp_update_wind(&r, &more);
849 wimp_get_rectangle(&r, &more);
855 ptr = ptr->nextTornoff;
860 /* --- Close a torn off menu --- */
862 static void tearoff__closeTornoff(tearoff t, BOOL close)
866 tearoff__unTearMenu(t,FALSE);
867 tearoff__closeMenuStructure(t,NULL);
869 if (tearoff__oldHandle == t)
871 if (close) tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
873 /* Let the user know about it being close */
875 (t->selectProc)(tearoff_CLOSE,t->selected,t->userHandle);
878 /* --- Called to automatically open a sub menu --- */
880 static void tearoff__alarmHandler2(int called_at,void *handle)
882 tearoff__menuActive=TRUE;
885 static void tearoff__alarmHandler(int called_at,void *handle)
888 tearoff t=tearoff__alm.t;
892 item=(tearoff__item *)(t+1);
893 item+=(tearoff__alm.item-1);
895 wimp_get_wind_state(t->w, &state);
896 tearoff__x = state.o.box.x1-24;
897 tearoff__y = state.o.box.y1 + tearoff__y;
899 tearoff__prevLevel=t;
901 if (t->tornoff) tearoff__originatingTearoff = t;
903 /* No current submenu opened */
907 /* Set up the second alarm */
909 os_swi3r(XOS_Byte,161,23,0,&dummy,&dummy,&delay);
912 tearoff__menuActive=FALSE;
913 tearoff__alarmTime2=alarm_timenow()+delay*10;
914 alarm_set(tearoff__alarmTime2,tearoff__alarmHandler2,0);
917 /* If item->subMenu is not FALSE, it contains a menu to
918 be opened automatically */
922 tearoff__subMenuPending = TRUE;
923 tearoff_displayMenu(item->sub,0);
924 tearoff__subMenuPending = FALSE;
927 /* Does the user want a tearoff_SUBMENU message? Note
928 that he can have one even if the menu is opened
929 automatically - unlike menu.c */
931 if (item->subMenuWarning)
933 tearoff__subMenuPending = TRUE;
934 (t->selectProc)(tearoff_SUBMENU,t->selected,t->userHandle);
935 tearoff__subMenuPending = FALSE;
939 /* --- The biggy - all button events are returned here for
940 dealing with - alter at your own risk. */
942 static void tearoff__buttons(tearoff t,
946 BOOL subPointer,justClickShadedArrow=FALSE;
948 tearoff__item *item = (tearoff__item *)(t + 1), *selItem;
950 /* First we deal with any type if button event - including the
951 'always' type. Don't bother doing anything if it is folded though */
953 if (!tearoff__menuActive) return;
954 selItem=(tearoff__item *)(t+1);
955 if (t->selected) selItem+=(t->selected-1);
959 BOOL wasDbox=!!tearoff__currentDbox;
964 wimp_get_wind_state(t->w, &state);
965 m->y = m->y+state.o.y-state.o.box.y1;
966 m->x = m->x+state.o.x-state.o.box.x0;
967 for (cnt = 1; cnt <= t->numberOfItems; cnt++, item++)
969 if (m->y >= item->y && m->y < item->y+44)
972 if (m->x >= t->width - 24) subPointer = TRUE;
973 tearoff__y = item->y+44;
978 item=(tearoff__item *)(t+1);
982 (item->subMenu || item->subMenuWarning) &&
983 (t->selected != itm)) ||
985 (item->subMenu || item->subMenuWarning)) &&
986 itm!=tearoff__alm.item) &&
989 /* We get here if we are over a sub menu arrow AND
990 we weren't over it before, OR we are not over
991 a sub menu arrow at all AND we are not over an
994 /* First close the RISCOS menu using tearoffSupport */
996 tearoff_closeMenus();
998 /* If this menu is torn off, then close any
999 transient menu opened at the moment */
1002 tearoff__closeMenuStructure(tearoff__currentMenu, t);
1004 /* If there is already a menu opened from this menu,
1005 then close it. NB This may already have been closed
1006 by the line above - but no harm done. */
1010 tearoff__closeMenuStructure(t->sub,t);
1014 /* Horrid hack because I can't do co-routines */
1021 wimpt_fake_event(&e);
1025 if (t->selected!=itm)
1027 if (t->selected && !selItem->shaded || itm == 0)
1028 tearoff_highlightItem(t->selected, t, FALSE);
1029 if (itm) tearoff_highlightItem(itm, t, TRUE);
1031 alarm_remove(tearoff__alarmTime,0);
1032 alarm_remove(tearoff__alarmTime2,0);
1033 tearoff__alm.item=-1;
1035 if (tearoff__alm.item==-1)
1037 if (riscos3 && itm && (item->subMenu || item->subMenuWarning))
1039 os_swi3r(XOS_Byte,161,197,0,&dummy,&dummy,&delay);
1042 os_swi3r(XOS_Byte,161,23,0,&dummy,&dummy,&delay);
1046 tearoff__alm.item=itm;
1047 tearoff__alarmTime=alarm_timenow()+delay*10;
1048 alarm_set(tearoff__alarmTime,tearoff__alarmHandler,0);
1054 /* Correct some variables */
1057 tearoff__prevLevel = NULL;
1058 tearoff__originatingTearoff = NULL;
1061 /* Did we go over the 'icon bar' ? */
1066 tearoff_highlightItem(t->selected, t, FALSE);
1068 if (t->warned) tearoff__closeMenuStructure(t->sub,NULL);
1070 tearoff__alm.item=0;
1071 tearoff__prevLevel = NULL;
1072 tearoff__originatingTearoff = NULL;
1075 /* We are over an arrow icon */
1077 if (m->i<0 && subPointer &&
1078 (item->subMenu || item->subMenuWarning) /* &&
1080 (item->subShaded && subPointer && m->bbits) [mdw] */)
1082 /* Get position at which to open next menu */
1084 wimp_get_wind_state(m->w, &state);
1085 tearoff__x = state.o.box.x1+2;
1086 tearoff__y = state.o.box.y1 + tearoff__y;
1088 if (!t->warned) /* This menu isn't opened yet, and/or submenu
1089 message hasn't been sent */
1091 if (item->subShaded && subPointer && m->bbits)
1092 justClickShadedArrow=TRUE;
1094 tearoff__prevLevel=t;
1096 if (t->tornoff) tearoff__originatingTearoff = t;
1098 /* No current submenu opened */
1102 /* If item->subMenu is not FALSE, it contains a menu to
1103 be opened automatically */
1107 tearoff__subMenuPending = TRUE;
1108 tearoff_displayMenu(item->sub,0);
1109 tearoff__subMenuPending = FALSE;
1112 /* Does the user want a tearoff_SUBMENU message? Note
1113 that he can have one even if the menu is opened
1114 automatically - unlike menu.c */
1116 if (item->subMenuWarning)
1118 tearoff__subMenuPending = TRUE;
1119 (t->selectProc)(tearoff_SUBMENU,t->selected,t->userHandle);
1120 tearoff__subMenuPending = FALSE;
1125 /* Since we are here, we know that the menu is already opened,
1126 if there is one that is */
1130 /* Close any submenus off of the submenu */
1134 tearoff__closeMenuStructure(t->sub->sub,NULL);
1135 tearoff__deselect(t->sub);
1138 /* And reposition submenu */
1140 wimp_get_wind_state(t->sub->w, &state);
1141 state.o.box.x0 = tearoff__x;
1142 state.o.box.x1 = tearoff__x + t->sub->width;
1143 if (t->sub->tearoff) tearoff__y += tearoff__HEIGHT;
1144 state.o.box.y0 = tearoff__y - (state.o.box.y1 - state.o.box.y0);
1145 state.o.box.y1 = tearoff__y;
1148 /* Mangle positional data so that it fits on the screen */
1150 win_adjustBox(&(state.o));
1152 /* Top and left to go here */
1154 wimp_open_wind(&state.o);
1160 /* Now we need to deal with actual button presses! */
1162 if (m->bbits && !justClickShadedArrow)
1166 /* Was click on tearoff bar */
1170 if (m->i == tearIcon__tear && !t->tornoff)
1171 tearoff__tearMenu(t, m->bbits & 6);
1172 else if (m->i == tearIcon__close && t->tornoff)
1173 tearoff__closeTornoff(t, m->bbits & 6);
1174 else if (m->i == tearIcon__fold && t->tornoff)
1175 tearoff__foldMenu(t, m->bbits & 6);
1178 /* No, so select item */
1182 int temp=t->selected;
1184 /* Don't select a shaded item :-)
1185 * (but do close the menu, if we need to [mdw])
1191 tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
1195 /* Flash icon in a similar way to the wimp - cunning */
1197 for (cnt = 1; cnt <= 3; cnt++)
1199 os_byte(19,&dummy,&dummy); /* Wait for Vsync */
1200 os_byte(19,&dummy,&dummy);
1202 tearoff_highlightItem(itm, t, FALSE);
1203 os_byte(19,&dummy,&dummy);
1204 os_byte(19,&dummy,&dummy);
1206 tearoff_highlightItem(itm, t, TRUE);
1210 /* Close menu structure if select used */
1213 tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
1215 /* Tell user about click */
1217 (t->selectProc)(tearoff_SELECTION,itm,t->userHandle);
1223 /* --- Called on Null events --- */
1225 static void tearoff__doIdles(void *handle)
1228 tearoff t = (tearoff)handle;
1231 wimp_get_point_info(&m);
1233 tearoff__buttons(t, &m);
1236 /* --- Routine to program the VDU dash pattern --- */
1238 static void tearoff__makeDashPattern(int ptn)
1243 wimpt_noerr(os_byte(163,&byte1,&byte2)); /* Dot-dash length */
1244 bbc_vduq(23,6,ptn,ptn,ptn,ptn,ptn,ptn,ptn,ptn);
1247 /* --- Menu redraw routine --- */
1249 void tearoff__doRedraw(tearoff t, wimp_redrawstr *r)
1255 i = (tearoff__item *)(t+1);
1258 /* Go through each item, and draw the dotted lines where
1261 for (c = 1; c <= t->numberOfItems; c++)
1265 icon.box.y1=i->y+44;
1268 if (i->selType != tearoff_NONE)
1272 icon.flags=wimp_IVCENTRE |
1277 if (i->shaded) icon.flags |= wimp_INOSELECT;
1278 if (!riscos3 && i->selType == tearoff_TICKED)
1280 icon.flags |= wimp_ITEXT;
1281 strcpy(icon.data.text, "\x80");
1283 if (riscos3 && i->selType == tearoff_TICKED)
1285 icon.flags |= wimp_ISPRITE | wimp_INDIRECT;
1286 icon.data.indirectsprite.name = "\x80";
1287 icon.data.indirectsprite.spritearea = (sprite_area *)1;
1288 icon.data.indirectsprite.nameisname = 4;
1290 if (i->selType == tearoff_RADIOED)
1292 icon.flags |= wimp_ITEXT;
1293 strcpy(icon.data.text, "\x8F");
1296 wimpt_noerr(wimp_ploticon(&icon));
1299 /* Main text part */
1302 icon.box.x1 = 24 + t->width - 48;
1303 if (i->keys) icon.box.x1-=16*(strlen(i->keys) + 1);
1305 icon.flags = wimp_ITEXT |
1310 if (t->selected == c && !i->shaded)
1311 icon.flags |= wimp_IBACKCOL * 7 |
1314 icon.flags |= wimp_IBACKCOL * 0 |
1317 if (i->shaded) icon.flags |= wimp_INOSELECT;
1319 icon.data.indirecttext.buffer = i->text;
1320 icon.data.indirecttext.validstring = "";
1321 icon.data.indirecttext.bufflen = strlen(i->text) + 1;
1322 wimpt_noerr(wimp_ploticon(&icon));
1326 /* Print the control key short cut - right justified of course! */
1328 icon.box.x0=t->width-24-t->keyWidth;
1329 icon.box.x1=t->width-24;
1330 icon.flags=wimp_ITEXT |
1334 if (t->selected==c && !i->shaded)
1335 icon.flags |= wimp_IBACKCOL * 7 |
1338 icon.flags |= wimp_IBACKCOL * 0 |
1340 if (i->shaded) icon.flags |= wimp_INOSELECT;
1341 icon.data.indirecttext.buffer=i->keys;
1342 icon.data.indirecttext.validstring="";
1343 icon.data.indirecttext.bufflen=strlen(i->keys)+1;
1344 wimpt_noerr(wimp_ploticon(&icon));
1349 if (i->subMenu || i->subMenuWarning)
1351 icon.box.x0 = t->width - 24;
1352 icon.box.x1 = t->width;
1354 icon.flags = wimp_IVCENTRE |
1360 if (i->shaded /* || i->subShaded [mdw] */)
1361 icon.flags |= wimp_INOSELECT;
1365 icon.flags |= wimp_ITEXT;
1366 strcpy(icon.data.text, "\x89");
1370 icon.flags |= wimp_ISPRITE |
1374 icon.data.indirecttext.validstring = "s\x89";
1375 icon.data.indirecttext.bufflen = 1;
1376 icon.data.indirecttext.buffer = "";
1378 wimpt_noerr(wimp_ploticon(&icon));
1383 bbc_move(r->box.x0,r->box.y1+i->y-12-r->scy);
1385 /* Plot the dotted line */
1387 tearoff__makeDashPattern(0xf0);
1389 bbc_plot(bbc_DottedBoth+bbc_DrawRelFore,t->width,0);
1395 /* --- Perform the redraw loop --- */
1397 static void tearoff__redrawMenu(tearoff t)
1403 wimp_redraw_wind(&r, &more);
1406 tearoff__doRedraw(t, &r);
1407 wimp_get_rectangle(&r, &more);
1411 /* --- Called to re-open the window - used when the window flags
1412 have changed, and for things such as titles changing */
1414 void tearoff_rebuildMenu(tearoff t)
1419 wimp_get_wind_state(t->w, &state);
1421 if (tearoff__oldHandle==t)
1426 wimpt_noerr(wimp_close_wind(t->w));
1427 wimpt_noerr(wimp_delete_wind(t->w));
1428 win_register_event_handler(t->w, (win_event_handler)0, 0);
1429 tearoff__createWindow(t);
1431 state.o.box.x1=state.o.box.x0+t->width;
1433 state.o.box.y0=state.o.box.y1-t->maxHeight;
1435 state.o.box.y0=state.o.box.y1-tearoff__HEIGHT-
1436 (t->numberOfItems*44)-t->dotted;
1437 wimp_open_wind(&(state.o));
1438 win_register_event_handler(t->w, tearoff__windowHandler, t);
1441 win_addIdleClaimer(tearoff__doIdles,0,t);
1442 tearoff__oldHandle=t;
1446 /* --- Adds/Removes a scrollbar from a menu --- */
1448 static void tearoff__checkForScrollBar(tearoff t)
1452 int scy=(bbc_vduvar(bbc_YWindLimit)+1)<<bbc_vduvar(bbc_YEigFactor);
1454 if (t->folded) return; /* Don't do anything to a folded menu */
1455 h = t->numberOfItems * 44 + t->dotted;
1456 if (t->tearoff) h += tearoff__HEIGHT;
1457 h += 50; /* Leave room for title bar */
1459 if (t->scrollBar && h <= scy &&
1460 (!t->maxHeight || (t->maxHeight && h < t->maxHeight)))
1462 /* remove scroll bar */
1464 wimp_get_wind_state(t->w, &state);
1465 wimpt_noerr(wimp_close_wind(t->w));
1466 wimpt_noerr(wimp_delete_wind(t->w));
1467 win_register_event_handler(t->w, (win_event_handler)0, 0);
1468 tearoff__createWindow(t);
1471 state.o.box.y0+(t->numberOfItems*44+t->dotted)+
1472 ((t->tearoff)?tearoff__HEIGHT:0);
1473 win_register_event_handler(t->w, tearoff__windowHandler, t);
1474 wimp_open_wind(&(state.o));
1477 if ((!t->scrollBar && h > scy) || wimpt_justChangedMode())
1479 /* Add scroll bar */
1481 wimp_get_wind_state(t->w, &state);
1482 wimpt_noerr(wimp_close_wind(t->w));
1483 wimpt_noerr(wimp_delete_wind(t->w));
1484 win_register_event_handler(t->w, (win_event_handler)0, 0);
1485 tearoff__createWindow(t);
1487 state.o.box.x1=state.o.box.x0+t->width;
1488 wimp_open_wind(&(state.o));
1489 win_register_event_handler(t->w, tearoff__windowHandler, t);
1494 /* --- Window handler for my psuedo-menus --- */
1496 static void tearoff__windowHandler(wimp_eventstr *e, void *handle)
1498 tearoff t = (tearoff)handle;
1500 BOOL ptrOverThisWindow=FALSE;
1505 if (wimpt_justChangedMode())
1507 wimp_get_point_info(&m);
1508 if (m.w==t->w) ptrOverThisWindow=TRUE;
1509 tearoff__checkForScrollBar(t);
1510 if (ptrOverThisWindow && m.i>=-1 && !tearoff__oldHandle)
1512 win_addIdleClaimer(tearoff__doIdles, 0, t);
1513 tearoff__oldHandle = t;
1517 wimpt_noerr(wimp_open_wind(&e->data.o));
1521 tearoff__redrawMenu(t);
1525 tearoff__buttons(t,&e->data.but.m);
1528 case wimp_EPTRENTER:
1529 if (tearoff__oldHandle)
1531 win_addIdleClaimer(tearoff__doIdles, 0, t);
1532 tearoff__oldHandle = t;
1535 case wimp_EPTRLEAVE:
1536 if (tearoff__oldHandle)
1538 if (!t->warned && t->selected)
1540 tearoff_highlightItem(t->selected, t, FALSE);
1546 case wimp_ESENDWANTACK:
1547 switch (e->data.msg.hdr.action)
1549 case wimp_MHELPREQUEST:
1553 tearoff__item *item;
1555 if (e->data.msg.data.helprequest.m.i>=0)
1558 if (e->data.msg.data.helprequest.m.i==1 && !t->tornoff)
1559 help_addLine("Drag to tear off this submenu");
1560 if (e->data.msg.data.helprequest.m.i==1 && t->tornoff)
1561 help_addLine("Click to close this menu");
1562 if (e->data.msg.data.helprequest.m.i==2)
1565 help_addLine("Click to un-fold this menu");
1567 help_addLine("Click to fold this menu");
1572 wimp_get_wind_state(t->w,&state);
1573 x=e->data.msg.data.helprequest.m.x+state.o.x-state.o.box.x0;
1574 y=e->data.msg.data.helprequest.m.y+state.o.y-state.o.box.y1;
1575 item=(tearoff__item *)(t+1);
1576 for (cnt = 1; cnt <= t->numberOfItems; cnt++, item++)
1578 if (y >= item->y && y < item->y+44)
1580 (t->selectProc)(tearoff_HELP,cnt,t->userHandle);
1592 /* --- Called to create a menu or a sub menu --- */
1594 BOOL tearoff_displayMenu(tearoff t1,void *handle)
1601 wimp_get_point_info(&m);
1603 /* If the window is not already torn off, then create
1604 the window for it */
1606 if (w = tearoff__unTearMenu(t1, TRUE), w == -1)
1610 w = tearoff__createWindow(t1);
1611 if (w == -1) return FALSE;
1612 win_register_event_handler(w, tearoff__windowHandler, t1);
1618 if (handle) t1->userHandle=handle;
1620 wimp_get_wind_state(w, &state);
1621 height = state.o.box.y1 - state.o.box.y0;
1624 if (t1->tearoff) tearoff__y += tearoff__HEIGHT;
1626 if (!tearoff__subMenuPending || !tearoff__currentMenu)
1628 /* Here it must be a new menu, not a sub menu of a transient
1631 tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
1633 if (tearoff__originatingTearoff && tearoff__subMenuPending)
1635 /* It is being opened from a torn off menu */
1637 t1->prev = tearoff__originatingTearoff;
1638 state.o.box.x0 = tearoff__x;
1639 state.o.box.x1 = tearoff__x + t1->width;
1640 state.o.box.y0 = tearoff__y - height;
1641 state.o.box.y1 = tearoff__y;
1642 tearoff__originatingTearoff->sub=t1;
1643 t1->fromItem=t1->prev->selected;
1647 /* Open over the pointer */
1649 state.o.box.x0 = m.x-64;
1650 state.o.box.x1 = state.o.box.x0 + t1->width;
1651 state.o.box.y0 = m.y - height;
1652 state.o.box.y1 = m.y;
1654 tearoff__currentMenu = t1;
1656 /* Tell TearoffSupport to send me messages */
1658 tearSupport_opened(wimpt_task());
1662 /* It is a sub menu of a transient menu */
1664 t1->prev = tearoff__prevLevel;
1665 state.o.box.x0 = tearoff__x;
1666 state.o.box.x1 = tearoff__x + t1->width;
1667 state.o.box.y0 = tearoff__y - height;
1668 state.o.box.y1 = tearoff__y;
1669 tearoff__prevLevel->sub=t1;
1670 t1->fromItem=t1->prev->selected;
1673 win_adjustBox(&(state.o));
1674 wimp_open_wind(&(state.o));
1678 void tearoff_displayAt(tearoff t,void *handle,int x,int y)
1684 /* If the window is not already torn off, then create
1685 the window for it */
1687 if (w = tearoff__unTearMenu(t, TRUE), w == -1)
1691 w = tearoff__createWindow(t);
1692 if (w == -1) return;
1693 win_register_event_handler(w, tearoff__windowHandler, t);
1699 if (handle) t->userHandle=handle;
1701 tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
1703 wimp_get_wind_state(w, &state);
1704 height = state.o.box.y1 - state.o.box.y0;
1706 state.o.box.x1 = x + t->width;
1707 state.o.box.y0 = y - height;
1709 tearoff__currentMenu = t;
1710 tearSupport_opened(wimpt_task());
1712 win_adjustBox(&(state.o));
1713 wimp_open_wind(&(state.o));
1716 int tearoff_height(tearoff t)
1720 height+=t->numberOfItems*44+t->dotted;
1721 if (t->tearoff) height+=tearoff__HEIGHT;
1725 /* --- Used to receive messages from TearoffSupport */
1727 static BOOL unknown_event(wimp_eventstr *e, void *handle)
1729 win_event_handler eh = 0;
1736 case wimp_ESENDWANTACK:
1737 switch (e->data.msg.hdr.action)
1739 case wimp_MMODECHANGE:
1740 if (tearoff__oldHandle)
1746 /* Button pressed message - close any transient menus
1747 iff button click was not in one of my menus */
1749 if (e->data.msg.data.helprequest.m.w == tearoff__currentDbox)
1751 win_read_eventhandler(e->data.msg.data.helprequest.m.w,
1754 if (eh != tearoff__windowHandler)
1755 tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
1760 /* A close menu message - close menus regardless.
1761 eg. escape pressed or wimp menu opened */
1763 tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
1771 /* --- Some Functions the give functionality to user of library */
1773 void tearoff_closeMenu(tearoff t)
1778 tearoff__closeMenuStructure(t,NULL);
1780 tearoff__closeTornoff(t,FALSE);
1784 static void tearoff__defaultmidb(wimp_w w,
1794 wimp_get_point_info(&m);
1795 tearoff_displayAt((tearoff)handlea,
1798 96+tearoff_height((tearoff)handlea));
1801 tearoff_displayMenu((tearoff)handlea,0);
1804 BOOL tearoff_attachMenu(wimp_w w,tearoff t,void *handle)
1806 if (handle) t->userHandle=handle;
1807 return (event_attachMidbHandler(w,
1808 tearoff__defaultmidb,
1816 void tearoff_init(void)
1818 static BOOL initialised=FALSE;
1820 if (initialised) return;
1822 riscos3=(wimpt_getVersion()>=300);
1823 win_add_unknown_event_processor(unknown_event, 0);
1824 dbox__rms(tearoff__finder,tearoff__wasSubmenu,tearoff__openDbox);
1826 tearoff__alm.item=-1;