chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / dbox
1 /*
2  * dbox
3  *  further dialogue box routines for Straylight apps
4  *
5  * v. 1.02 (10 August 1993)
6  *
7  * © 1993-1998 Straylight
8  */
9
10 /*----- Licensing note ----------------------------------------------------*
11  *
12  * This file is part of Straylight's Steel library.
13  *
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)
17  * any later version.
18  *
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.
23  *
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.
27  */
28
29 #define dbox__INTERNALS
30
31 #include "event.h"
32 #include "wimpt.h"
33 #include "wimp.h"
34 #include "interface.h"
35 #include "sculptrix.h"
36 #include "werr.h"
37 #include "template.h"
38 #include "win.h"
39 #include "dbox.h"
40 #include "msgs.h"
41 #include "bbc.h"
42 #include "mem.h"
43 #include "akbd.h"
44 #include "os.h"
45 #include "swiv.h"
46 #include "swis.h"
47 #include "help.h"
48 #include "vsscanf.h"
49 #include <string.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <stdarg.h>
53
54 #include "dll.h"
55
56 #ifndef _dll_NODLL
57   extern void _dllEntry(dbox__eventhandler)(wimp_eventstr *e,void *handle);
58 #endif
59
60 wimp_w dbox_menuDboxWindow(void);
61
62 /*
63  * The big one - the data needed to manage the dbox system.  This IS a dbox.
64  */
65 typedef struct dbox__dboxstr
66 {
67   wimp_w wind;                    /* Real window handle                    */
68   dbox_eventhandler eventProc;    /* User event handler procedure          */
69   void *eventHandle;              /* Pointer to handler information        */
70   dbox_raweventhandler rawEventProc; /* Pointer to raw event handler       */
71   void *rawEventHandle;           /* Pointer to raw handler information    */
72   wimp_caretstr oldCaret;        /* Where the caret was before this opened */
73   wimp_wind *windDef;             /* Pointer to complete window definiton  */
74   wimp_wind *temp;                /* Pointer to template for this window   */
75   char *indirect;                 /* Pointer to indirected text            */
76   int titleIcon;                  /* Icon for the window title, or -1      */
77   BOOL isOpen                 :1; /* Is the dbox open?                     */
78   BOOL isStatic               :1; /* Is this a static or menu dbox         */
79   BOOL restoreCaret           :1; /* Do we return the caret when finished? */
80   BOOL moveDrag               :1; /* Click on window starts window move    */
81 }
82 dbox__dboxstr;
83
84 /*
85  * A structure for passing to the dbox__fillinHandler() routine to make sure
86  * that the thing runs smoothly.
87  */
88 typedef struct
89 {
90   dbox_field f;                   /* The clicked field, or -2              */
91 }
92 dbox__fillinstr;
93
94 #define dbox__CLICKMAX 10         /* Number of clicks which fit in stack   */
95
96 typedef struct
97 {
98   dbox d;
99   sculptrix_slabDescriptor s;
100 }
101 dbox__cstackstr;
102
103 static dbox__cstackstr dbox__clicked[dbox__CLICKMAX];
104                                   /* Click stack array                     */
105 static int dbox__click;           /* Click stack stack pointer             */
106 static dbox dbox__menuDbox;       /* Currently open menu dbox (or 0)       */
107 static BOOL dbox__closedForUs;    /* Is this a 'real' close event?         */
108 static BOOL dbox__shiftRet=FALSE; /* Is this a sh-RETURN press for a dbox? */
109
110 static dbox__mf dbox__tmsmf;      /* Where to go to find menu coords       */
111 static dbox__esm dbox__tmsesm;    /* Are we expecting a submenu            */
112 static dbox__ddb dbox__tmsddb;    /* How do we display a dialogue box?     */
113
114 /* This routine is for a bodge to get round menu help problems.  It is     */
115 /* to be used *only* by the event segment for its own processing of help   */
116 /* requests.                                                               */
117 wimp_w dbox__menuDboxWindow(void)
118 {
119   return (dbox__menuDbox->wind);
120 }
121
122 /*
123  * void dbox__rms(dbox__mf f,dbox__esm esm,dbox__ddb ddb)
124  *
125  * Use
126  *  Registers support functions for handling an alternative menu handling
127  *  system (e.g. TMS).
128  */
129
130 void dbox__rms(dbox__mf f,dbox__esm esm,dbox__ddb ddb)
131 {
132   dbox__tmsmf=f;
133   dbox__tmsesm=esm;
134   dbox__tmsddb=ddb;
135 }
136
137 /*
138  * BOOL wasAdjustClick(void)
139  *
140  * Use
141  *  Returns whether the last event was caused by a mouse click with the
142  *  adjust mouse button.  Useful for deciding whether you want to bump a
143  *  value up or down, or for keeping a dbox on-screen.
144  *
145  * Returns
146  *  TRUE if the last event WAS caused by an adjust click.
147  */
148
149 BOOL dbox_wasAdjustClick(void)
150 {
151   wimp_eventstr *e=wimpt_last_event();
152   if ((e->e==wimp_EBUT && e->data.but.m.bbits==wimp_BRIGHT)||dbox__shiftRet)
153     return (TRUE);
154   else
155     return (FALSE);
156 }
157
158 /*
159  * wimp_icon *dbox__idef(dbox d,wimp_i i)
160  *
161  * Use
162  *  This routine returns a pointer to the icon definition specified.
163  *
164  * Parameters
165  *  dbox d == dbox handle
166  *  wimp_i i == the icon handle
167  *
168  * Returns
169  *  A pointer to the icon definition.
170  */
171
172 #define dbox__idef(d,i) ((wimp_icon *)((d)->windDef+1)+(i))
173
174 #ifdef notdef
175 static wimp_icon *dbox__idef(dbox d,wimp_i i)
176 {
177   return ((wimp_icon *)(d->windDef+1)+i);
178 }
179 #endif
180
181 /*
182  * int dbox__fieldlength(dbox d,dbox_field f)
183  *
184  * Use
185  *  Returns the length of the text in field specified
186  *
187  * Parameters
188  *  dbox d == dbox handle
189  *  dbox_field f == field number (icon handle to the uninitiated!)
190  *
191  * Returns
192  *  The length of the field.  Why isn't this a size_t?
193  */
194
195 static int dbox__fieldlength(dbox d, dbox_field f)
196 {
197   char a[255];
198   dbox_getfield((dbox) d, f, a, 255);
199   return(strlen(a));
200 }
201
202 /*
203  * void dbox__nextWritable(BOOL fromTop,dbox d,BOOL forward)
204  *
205  * Use
206  *  This call moves the caret around the window it is in.  The fromTop
207  *  parameter says whether you want to move the caret either to one
208  *  extremity or the other, or just move it along.  The routine, unlike the
209  *  standard RISC_OSlib one, actually scrolls the window to keep the caret
210  *  in view.
211  *
212  * Parameters
213  *  BOOL fromTop == whether you want to move to an extremity, or just up or
214  *    down one.
215  *  dbox d == the dbox you think the caret is in.  If it isn't, you're in
216  *    deep sh*te.
217  *  BOOL forward == whether you want to search forward or backward from your
218  *    starting position.
219  */
220
221 static void dbox__nextWritable(BOOL fromTop,dbox d,BOOL forwards)
222 {
223   wimp_caretstr c;
224   wimp_icon idef;
225   wimp_i i;
226   int iterations;
227   int dir;
228   int bt;
229   wimp_wstate state;
230   int sw,sh,ox,oy;
231   wimpt_noerr(wimp_get_caret_pos(&c));
232   if (forwards)
233     dir=1;
234   else
235     dir=-1;
236   if (fromTop)
237   {
238     if (forwards)
239       i=0;
240     else
241       i=d->windDef->nicons;
242   }
243   else
244     i=c.i+dir;
245   for (iterations=0;iterations<d->windDef->nicons;iterations++,i+=dir)
246   {
247     if (i>d->windDef->nicons)
248     {
249       i=-1;
250       iterations--;
251       continue;
252     }
253     if (i<0)
254     {
255       i=d->windDef->nicons+1;
256       iterations--;
257       continue;
258     }
259     wimpt_noerr(wimp_get_icon_info(d->wind,i,&idef));
260     bt=(((int)idef.flags)>>12) & 15;
261     if
262     (
263       (bt==15 || bt==14) &&
264       ((idef.flags & wimp_INOSELECT)==0) &&
265       ((idef.flags & wimp_IDELETED)==0)
266     )
267       break;
268   }
269   if (iterations==d->windDef->nicons)
270     return;
271   c.w=d->wind;
272   c.i=i;
273   c.height=-1;
274   c.index=dbox__fieldlength(d,i);
275   wimpt_noerr(wimp_set_caret_pos(&c));
276   wimpt_noerr(wimp_get_wind_state(d->wind,&state));
277   sw=state.o.box.x1-state.o.box.x0;
278   sh=state.o.box.y1-state.o.box.y0;
279   ox=state.o.box.x0-state.o.x;
280   oy=state.o.box.y1-state.o.y;
281   if (state.o.box.x0>idef.box.x0+ox)
282     state.o.x=idef.box.x0-24;
283   if (state.o.box.x1<idef.box.x1+ox)
284     state.o.x=idef.box.x1+24-sw;
285   if (state.o.box.y0>idef.box.y0+oy)
286     state.o.y=idef.box.y0-24+sh;
287   if (state.o.box.y1<idef.box.y1+oy)
288     state.o.y=idef.box.y1+24;
289   wimpt_noerr(wimp_open_wind(&state.o));
290 }
291
292 /*
293  * void dbox__checkRadio(dbox d,dbox_field f)
294  *
295  * Use
296  *  Checks to see if the specified dbox_field is a radio button (button type
297  *  debounced and nonzero ESG) and if so selects it and unselects other
298  *  fields with the same ESG number.
299  *
300  * Parameters
301  *  dbox d == the dbox containing the clicked field
302  *  dbox_field f == the field wot was clicked
303  */
304
305 static void dbox__checkRadio(dbox d,dbox_field f)
306 {
307   wimp_icon *idef=dbox__idef(d,f);
308   int esg;
309   int i;
310   if ((idef->flags & 0x0000F000) == (wimp_BCLICKDEBOUNCE<<12))
311   {
312     esg=idef->flags & 0x001F0000;
313     if (esg)
314     {
315       dbox_selecticon(d,f,TRUE);
316       idef=dbox__idef(d,0);
317       for (i=0;i<d->windDef->nicons;i++,idef++)
318       {
319         if (i!=f && (idef->flags & 0x001F0000)==esg)
320           dbox_selecticon(d,i,FALSE);
321       }
322     }
323   }
324 }
325
326 /*
327  * void dbox__eventhandler(wimp_eventstr *e,void *handle)
328  *
329  * Use
330  *  Event handler for dboxes.  Handles ops as follows:
331  *
332  *  * Clicks on icons are passed to dbox handler if present
333  *  * Key presses are dealt with:
334  *      cursor keys move caret
335  *      return reports a click on icon 0
336  *      escape reports a click on icon 1
337  *      a close operation reports a click on icon dbox_CLOSE
338  *  * If a menu dbox closes in the backgound (i.e. the WIMP makes off with
339  *    it), a close operation is passed to the dbox concerned.
340  *
341  * Parameters
342  *  wimp_eventstr *e == a pointer to the current WIMP event
343  *  void *handle == the jolly old handle, which is a pointer to the
344  *    dbox__dboxstr.
345  */
346
347 _dll_static void dbox__eventhandler(wimp_eventstr *e,void *handle)
348 {
349   dbox d=(dbox)handle;
350   BOOL handled=FALSE;
351
352   dbox__shiftRet=FALSE;
353   if (d->rawEventProc)
354     handled=(d->rawEventProc)(d,e,(void *)d->rawEventHandle);
355   if (!handled)
356   {
357     switch (e->e)
358     {
359       case wimp_EREDRAW:
360         if (d->titleIcon!=-1)
361           wimpt_redraw(dbox_drawEmbeddedTitle,d);
362         else
363           wimpt_redraw(0,0);
364         break;
365       case wimp_EOPEN:
366         wimpt_noerr(wimp_open_wind(&e->data.o));
367         break;
368       case wimp_ECLOSE:
369         if (d->eventProc)
370           (d->eventProc)(d,dbox_CLOSE,d->eventHandle);
371         break;
372       case wimp_EBUT:
373         if (e->data.but.m.bbits==wimp_BRIGHT ||
374             e->data.but.m.bbits==wimp_BLEFT)
375         {
376           dbox__checkRadio(d,e->data.but.m.i);
377           if (d->eventProc && e->data.but.m.i!=-1)
378             (d->eventProc)(d,e->data.but.m.i,d->eventHandle);
379           if (d->moveDrag)
380           {
381             wimp_dragstr dr;
382             dr.window=d->wind;
383             dr.type=wimp_MOVE_WIND;
384             wimp_drag_box(&dr);
385           }
386         }
387         break;
388       case wimp_EKEY:
389         switch (akbd_translate(e->data.key.chcode))
390         {
391           case key_sReturn:
392           case key_skEnter:
393             dbox__shiftRet=TRUE;
394             /* Treat as normal return */
395           case key_Return:
396           case key_kEnter:
397             if (d->eventProc && !dbox_shadeicon(d,0,dbox_READSTATE))
398               (d->eventProc)(d,0,d->eventHandle);
399             break;
400           case key_sEsc:
401             dbox__shiftRet=TRUE;
402             /* Treat as normal Escape */
403           case key_Esc:
404             if (d->eventProc && !dbox_shadeicon(d,1,dbox_READSTATE))
405               (d->eventProc)(d,1,d->eventHandle);
406             break;
407           case key_Down:
408           case key_Tab:
409             dbox__nextWritable(FALSE,d,TRUE);
410             break;
411           case key_sTab:
412           case key_Up:
413             dbox__nextWritable(FALSE,d,FALSE);
414             break;
415           case key_cDown:
416             dbox__nextWritable(TRUE,d,FALSE);
417             break;
418           case key_cUp:
419             dbox__nextWritable(TRUE,d,TRUE);
420             break;
421           default:
422             wimp_processkey(e->data.key.chcode);
423             break;
424         }
425         break;
426       case wimp_ESEND:
427       case wimp_ESENDWANTACK:
428         switch (e->data.msg.hdr.action)
429         {
430           case wimp_MHELPREQUEST:
431             if (d->eventProc)
432               (d->eventProc)(d,dbox_HELP,d->eventHandle);
433             break;
434         }
435         break;
436     }
437   }
438 }
439
440 /*
441  * dbox dbox_create(char *template)
442  *
443  * Use
444  *  Creates a dbox from a template and returns a handle to it.  It calls
445  *  werr() sensibly with nice messages if it failed.
446  *
447  * Parameters
448  *  char *name == name of template to use
449  *
450  * Returns
451  *  Abstract handle to dbox or NULL if the dbox could not be
452  *  created
453  */
454
455 dbox dbox_create(char *name)
456 {
457   template *temp=template_find(name);
458   wimp_wind *w=template_syshandle(name);
459   dbox d=(dbox)mem_alloc(sizeof(dbox__dboxstr));
460   wimp_icon *icn;
461   int i;
462   BOOL unshade=wimpt_options() & wimpt_ONOWIMPSHADE;
463   if (d)
464   {
465     if (d->windDef=(wimp_wind *)mem_alloc
466     (
467       sizeof(wimp_wind)+w->nicons*sizeof(wimp_icon)
468     ),
469     d->windDef==0)
470     {
471       mem_free(d);
472       werr
473       (
474         FALSE,
475         msgs_lookup("dboxNEM:Not enough memory for new dialogue box.")
476       );
477       return (0);
478     }
479     memcpy(d->windDef,w,sizeof(wimp_wind)+w->nicons*sizeof(wimp_icon));
480     if (temp->workspacesize!=0)
481     {
482       if (d->indirect=(char *)mem_alloc(temp->workspacesize),d->indirect==0)
483       {
484         mem_free(d->windDef);
485            mem_free(d);
486         werr
487         (
488           FALSE,
489           msgs_lookup("dboxNEM:Not enough memory for new dialogue box.")
490         );
491         return (0);
492       }
493       memcpy(d->indirect,temp->workspace,temp->workspacesize);
494       for (i=0;i<d->windDef->nicons;i++)
495       {
496         icn=dbox__idef(d,i);
497         if (unshade)
498           icn->flags &= 0xffbfffff;
499         if ((icn->flags&wimp_INDIRECT)!=0)
500         {
501           icn->data.indirecttext.buffer+=d->indirect-temp->workspace;
502           if ((icn->flags&3)==2)
503             icn->data.indirectsprite.spritearea=(void *)1;
504           else
505           {
506             if (icn->data.indirecttext.validstring!=(char *)-1)
507             {
508               icn->data.indirecttext.validstring+=
509                                                d->indirect-temp->workspace;
510             }
511           }
512         }
513       }
514       if (d->windDef->titleflags&wimp_INDIRECT)
515       {
516         d->windDef->title.indirecttext.buffer+=d->indirect-temp->workspace;
517         if ((d->windDef->titleflags&3)==2)
518           d->windDef->title.indirectsprite.spritearea=(void *)1;
519         else
520         {
521           if (d->windDef->title.indirecttext.validstring!=(char *)-1)
522           {
523             d->windDef->title.indirecttext.validstring+=
524                                                d->indirect-temp->workspace;
525           }
526         }
527       }
528     }
529     else
530       d->indirect=0;
531     if (wimp_create_wind(d->windDef,&d->wind)==0)
532     {
533       d->eventProc=0;
534       d->rawEventProc=0;
535       d->isOpen=FALSE;
536       d->isStatic=FALSE;
537       d->titleIcon=-1;
538       d->moveDrag=FALSE;
539       d->temp=w;
540       win_activeinc();
541       win_register_event_handler(d->wind,_dllEntry(dbox__eventhandler),d);
542     }
543     else
544     {
545       mem_free(d->windDef);
546       mem_free(d->indirect);
547       mem_free(d);
548       d=0;
549       werr
550       (
551         FALSE,
552         msgs_lookup("dboxTMW:Too many windows - "
553                                "%s could not create window/dialogue box."),
554         wimpt_programname()
555       );
556     }
557   }
558   else
559     werr
560     (
561       FALSE,
562       msgs_lookup("dboxNEM:Not enough memory for new dialogue box.")
563     );
564   return (d);
565 }
566
567 /*
568  * void dbox__setMenuDbox(dbox d)
569  *
570  * Use
571  *  This routine handles the updating of the dbox__menuDbox variable.  It
572  *  is needed 'cos if the user maniacally starts opening submenus, the thing
573  *  can get a bit confused.  If there already is one, it gets a wimp_ECLOSE
574  *  event faked to it courtesy of a combination of wimpt_fake_event() and
575  *  event_process().
576  *
577  * Parameters
578  *  dbox d == the new prospective menu dbox.
579  */
580
581 static void dbox__setMenuDbox(dbox d)
582 {
583   dbox__menuDbox=d;
584 }
585
586 /*
587  * void dbox_display(dbox d,dbox_openType how)
588  *
589  * Use
590  *  Displays a dbox on the screen.  The new dbox_openType is compatible with
591  *  the old TRUE/FALSE system.  Note that is the event was a submenu, then
592  *  the dbox will be opened as a submenu regardless of how you want it done.
593  *
594  *  If the dbox conatins a writable icon, then the caret is placed within
595  *  the first one.  This is handled automatically by the WIMP for submenu
596  *  dboxes, but not (unfortunately) for static ones.
597  *
598  * Parameters
599  *  dbox d == dbox handle
600  *  dbox_openType how == how you want the dbox opened
601  */
602
603 void dbox_display(dbox d,dbox_openType how)
604 {
605   wimp_wstate state;
606   int scx=wimpt_scwidth();
607   int scy=wimpt_scheight();
608   int w;
609   int h;
610   wimp_caretstr c;
611   wimp_eventstr *e;
612   int x;
613   int y;
614
615   wimpt_noerr(wimp_get_wind_state(d->wind,&state));
616   state.o.behind=(wimp_w)-1;
617   w=state.o.box.x1-state.o.box.x0;
618   h=state.o.box.y1-state.o.box.y0;
619   d->isStatic=TRUE;
620   switch (how)
621   {
622     case dbox_MENU_OVERPTR:
623       d->isStatic=FALSE;
624     case dbox_STATIC_OVERPTR:
625       bbc_mouse(&x,&y,0,0);
626       state.o.box.x0=x-w/2;
627       state.o.box.x1=x+w/2;
628       state.o.box.y0=y-h/2;
629       state.o.box.y1=y+h/2;
630       break;
631     case dbox_MENU_LASTPOS:
632       d->isStatic=FALSE;
633     case dbox_STATIC_LASTPOS:
634       /* Nothin' doin' */
635       break;
636     case dbox_MENU_CENTRE:
637       d->isStatic=FALSE;
638     case dbox_STATIC_CENTRE:
639       state.o.box.x0=(scx-w)/2;
640       state.o.box.x1=(scx+w)/2;
641       state.o.box.y0=(scy-h)/2;
642       state.o.box.y1=(scy+h)/2;
643       break;
644   }
645   win_adjustBox(&state.o);
646   if (d->isStatic)
647   {
648     wimpt_noerr(wimp_open_wind(&state.o));
649     if (!d->isOpen)
650     {
651       d->isOpen=TRUE;
652       d->isStatic=TRUE;
653       wimpt_noerr(wimp_get_caret_pos(&d->oldCaret));
654       d->restoreCaret=TRUE;
655       dbox__nextWritable(TRUE,d,TRUE);
656       wimpt_noerr(wimp_get_caret_pos(&c));
657       if (c.w!=d->wind)
658         d->restoreCaret=FALSE;
659       else
660       {
661         c.i=-1;
662         c.x=-500000;
663         c.height=0x2000000;
664         wimpt_noerr(wimp_set_caret_pos(&c));
665       }
666     }
667   }
668   else
669   {
670     if (dbox_wasSubmenu() && (wimpt_last_event()->e==wimp_ESEND ||
671                               wimpt_last_event()->e==wimp_ESENDWANTACK))
672     {
673       e=wimpt_last_event();
674       x=e->data.msg.data.words[1];
675       y=e->data.msg.data.words[2];
676       wimpt_noerr(wimp_create_submenu((wimp_menustr *)d->wind,x,y));
677       d->restoreCaret=FALSE;
678     }
679     else if (dbox__tmsesm && dbox__tmsesm())
680     {
681       dbox__tmsmf(&x,&y);
682       state.o.box.x0=x;
683       state.o.box.x1=x+w;
684       state.o.box.y0=y-h;
685       state.o.box.y1=y;
686       dbox__tmsddb(&state.o);
687       wimpt_noerr(wimp_get_caret_pos(&d->oldCaret));
688       d->restoreCaret=TRUE;
689       dbox__nextWritable(TRUE,d,TRUE);
690     }
691     else
692     {
693       wimpt_noerr(wimp_create_menu(
694         (wimp_menustr *)d->wind,
695         state.o.box.x0,
696         state.o.box.y1
697       ));
698       d->restoreCaret=FALSE;
699     }
700     d->isOpen=TRUE;
701     d->isStatic=FALSE;
702     dbox__setMenuDbox(d);
703   }
704 }
705
706 /*
707  * void dbox_openDisplaced(dbox d)
708  *
709  * Use
710  *  Displaces the dbox from its original height by the statutory 48 OS
711  *  units.  If it would overlap the icon bar, it gets moved up to a sensible
712  *  height.  The dbox must be opened by this call once only.  It must be
713  *  closed using dbox_deleteNoUpdate().  The dbox is opened as a static
714  *  dbox, of course.
715  *
716  * Parameters
717  *  dbox d == the dbox
718  */
719
720 void dbox_openDisplaced(dbox d)
721 {
722   int new=0;
723   wimp_wstate s;
724   wimp_caretstr c;
725   if (d->isOpen)
726   {
727     werr
728     (
729       TRUE,
730       msgs_lookup("dboxCOD:(dbox_openDisplaced): "
731                                              "failed - dbox already open.")
732     );
733   }
734   if (d->temp->box.y0-48<132)
735   {
736     new=((976-d->temp->box.y1)/48-4)*48+d->temp->box.y1;
737     d->temp->box.y0+=new-d->temp->box.y1;
738     d->temp->box.y1=new;
739   }
740   else
741   {
742     d->temp->box.y0-=48;
743     d->temp->box.y1-=48;
744   }
745   wimpt_noerr(wimp_get_wind_state(d->wind,&s));
746   s.o.box=d->temp->box;
747   s.o.behind=-1;
748   wimpt_noerr(wimp_open_wind(&s.o));
749   d->isOpen=TRUE;
750   d->isStatic=TRUE;
751   wimpt_noerr(wimp_get_caret_pos(&d->oldCaret));
752   d->restoreCaret=TRUE;
753   dbox__nextWritable(TRUE,d,TRUE);
754   wimpt_noerr(wimp_get_caret_pos(&c));
755   if (c.w!=d->wind)
756     d->restoreCaret=FALSE;
757   else
758   {
759     wimpt_noerr(wimp_open_wind(&s.o));
760     c.i=-1;
761     c.x=-500000;
762     wimpt_noerr(wimp_set_caret_pos(&c));
763   }
764 }
765
766 /*
767  * void dbox_hide(dbox d)
768  *
769  * Use
770  *  Closes the dbox specified in whatever manner necessary to stop it being
771  *  seen.  The window can still be created real easy.
772  *
773  * Parameters
774  *  dbox d == dialogue box handle
775  */
776
777 void dbox_hide(dbox d)
778 {
779   if (d==dbox__menuDbox)
780   {
781     if (!dbox__closedForUs)
782       event_clear_current_menu();
783     dbox__menuDbox=0;
784   }
785   wimpt_noerr(wimp_close_wind(d->wind));
786   if (d->restoreCaret)
787     wimp_set_caret_pos(&d->oldCaret);
788   d->isOpen=FALSE;
789 }
790
791 /*
792  * void dbox_deleteNoUpdate(dbox d)
793  *
794  * Use
795  *  Zaps a dbox without storing the thing's position away, so it reappears
796  *  where you want it.
797  *
798  * Parameters
799  *  dbox d == the handle
800  */
801
802 void dbox_deleteNoUpdate(dbox d)
803 {
804   if (d->isOpen)
805     dbox_hide(d);
806   win_register_event_handler(d->wind,0,0);
807   win_activedec();
808   wimpt_noerr(wimp_delete_wind(d->wind));
809   mem_free(d->indirect);
810   mem_free(d->windDef);
811   mem_free(d);
812 }
813
814 /*
815  * void dbox_updatePosition(dbox d)
816  *
817  * Use
818  *  Stores the position of the dialogue box away, so that next time a dbox
819  *  using the same template is opened, it goes to that place.
820  *
821  * Parameters
822  *  dbox d == the dbox handle
823  */
824
825 void dbox_updatePosition(dbox d)
826 {
827   wimp_wstate s;
828   wimp_get_wind_state(d->wind,&s);
829   d->temp->box=s.o.box;
830 }
831
832 /*
833  * void dbox_delete(dbox d)
834  *
835  * Use
836  *  Utterly zaps the dialogue box specified.  Updates the template, so it's
837  *  right next time around, though.  The window is deleted, and the dbox's
838  *  space is freed.
839  *
840  * Parameters
841  *  dbox d == dialogue box handle
842  */
843
844 void dbox_delete(dbox d)
845 {
846   if (d->isStatic)
847     dbox_updatePosition(d);
848   dbox_deleteNoUpdate(d);
849 }
850
851 /*
852  * void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle)
853  *
854  * Use
855  *  This routine attaches an event handler to a dbox.  Pass 0 as the pointer
856  *  to the procedure if you want to remove the handler. Event handers are an
857  *  alternative to using dbox_fillin().
858  *
859  * Parameters
860  *  dbox d == the dbox you want to attach a handler to.
861  *  dbox_eventhandler proc == the hander procedure.
862  *  void *handle == up to you.  It gets passed to the procedure, though.
863  */
864
865 void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle)
866 {
867   d->eventProc=proc;
868   d->eventHandle=handle;
869 }
870
871 /*
872  * void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle)
873  *
874  * Use
875  *  This routine attaches a raw event handler to a dbox.  Pass 0 as the
876  *  pointer to the procedure if you want to remove the handler.  A raw event
877  *  handler gets passed all the WIMP events received by the dbox.  It should
878  *  return FALSE if it could not process the event itself, or TRUE if it
879  *  did.
880  *
881  * Parameters
882  *  dbox d == the dbox you want to attach a handler to.
883  *  dbox_eventhandler proc == the hander procedure.
884  *  void *handle == up to you.  It gets passed to the procedure, though.
885  */
886
887 void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle)
888 {
889   d->rawEventProc=proc;
890   d->rawEventHandle=handle;
891 }
892
893 /*
894  * void dbox__fillinHandler(dbox d,dbox_field clicked,void *handle)
895  *
896  * Use
897  *  This is the dbox handler used by dbox_fillin().
898  *
899  * Parameters
900  *  dbox d == the dbox handle
901  *  dbox_field == the field that was clicked
902  *  void *handle == a pointer to a dbox__fillinstr
903  */
904
905 static void dbox__fillinHandler(dbox d,dbox_field clicked,void *handle)
906 {
907   dbox__fillinstr *f=(dbox__fillinstr *)handle;
908   d=d;
909   f->f=clicked;
910 }
911
912 /*
913  * dbox_field dbox_fillin(dbox d)
914  *
915  * Use
916  *  This is a nice simple way of handling a dbox.  It means you can handle
917  *  everything from an in-line point of view. Functions can easily return
918  *  the results they need (like dbox_query()).  Unfortunately, it will only
919  *  work with menu dboxes, and will complain bitterly at you if you try and
920  *  do anything different.
921  *
922  * Parameters
923  *  dbox d == the dbox handle
924  *
925  * Returns
926  *  The field number that was clicked.
927  */
928
929 dbox_field dbox_fillin(dbox d)
930 {
931   dbox__fillinstr f;
932   if (d->isStatic)
933   {
934     werr
935     (
936       TRUE,
937       msgs_lookup("dboxFRE:(dbox_fillin, caller fault): "
938                                 "dbox_fillin only works with menu dboxes.")
939     );
940   }
941   f.f=dbox_ENDFILLIN;
942   dbox_eventHandler(d,dbox__fillinHandler,&f);
943   while (f.f==dbox_ENDFILLIN)
944     event_process();
945   dbox_eventHandler(d,0,0);
946   return (f.f);
947 }
948
949 /*
950  * void dbox_eventProcess(void)
951  *
952  * Use
953  *  Part of the private interface between dbox and event for processing
954  *  dialogue box events.
955  */
956
957 void dbox__eventProcess(void)
958 {
959   static wimp_eventstr real;
960   static BOOL faking;
961   wimp_eventstr fake;
962   wimp_wstate state;
963
964   dbox__closedForUs=FALSE;
965   if (faking)
966   {
967     wimpt_fake_event(&real);
968     faking=FALSE;
969     event__process();
970     return;
971   }
972   if (dbox__menuDbox)
973   {
974     wimpt_noerr(wimpt_poll(event_getmask(),&real));
975     wimpt_noerr(wimp_get_wind_state(dbox__menuDbox->wind,&state));
976     if ((((state.flags & wimp_WOPEN)==0) || real.e==wimp_EMENU) &&
977                                                         real.e!=wimp_EREDRAW)
978     {
979       fake.e=wimp_ECLOSE;
980       fake.data.o.w=dbox__menuDbox->wind;
981       wimpt_fake_event(&fake);
982       dbox__closedForUs=TRUE /* (real.e!=wimp_EMENU) */ ;
983       faking=TRUE;
984     }
985     else
986       wimpt_fake_event(&real);
987   }
988   event__process();
989 }
990
991 /*
992  * void dbox_setfield(dbox d,dbox_field f,char *string,...)
993  *
994  * Use
995  *  This routine will write the string into the field specified, if and only
996  *  if the field's data is indirected.  The icon is checked to make sure
997  *  it's been indirected, and if the string is too long, we hack off bits
998  *  until it fits.  Normally, the end bit is chopped off.  However, you can
999  *  set the icon's right-aligned bit to indicate that you want the
1000  *  *beginning* bit chopped off.
1001  *
1002  * Parameters
1003  *  dbox d == the dbox
1004  *  dbox_field f == the field
1005  *  char *string == a printf-style format string
1006  */
1007
1008 void dbox_setfield(dbox d,dbox_field f,char *string,...)
1009 {
1010   wimp_icon *i=dbox__idef(d,f);
1011   wimp_caretstr c;
1012   va_list ap;
1013   char field[1024];
1014   int j;
1015   char *buff;
1016   BOOL different=FALSE;
1017   BOOL stop=FALSE;
1018   int max;
1019   char *fptr;
1020   BOOL dots=FALSE;
1021   char x,y;
1022   BOOL rJust=FALSE;
1023
1024   /* --- Construct the string to fill in the buffer --- *
1025    *
1026    * If the buffer overflows here, we're pretty much stuffed.  We can try
1027    * to chop the end off and hope it doesn't damage anything too badly,
1028    * though.  If the format string is `%s', we can just use the string given
1029    * in the first variable arg, though, so we're safe there.
1030    */
1031
1032   va_start(ap,string);
1033   if (string[0]=='%' && string[1]=='.')
1034   {
1035     dots=TRUE;
1036     string+=2;
1037   }
1038   if (!strcmp(string,"%s"))
1039     fptr=va_arg(ap,char *);
1040   else
1041   {
1042     vsprintf(field,string,ap);
1043     field[1023]=0;
1044     fptr=field;
1045   }
1046   va_end(ap);
1047
1048   /* --- Make sure the string's indirected --- */
1049
1050   if (!(i->flags & wimp_INDIRECT))
1051   {
1052     werr(TRUE,msgs_lookup("dboxSFNIND:(dbox_setfield, caller fault): "
1053                           "Icon is not indirected."));
1054   }
1055
1056   /* --- Write the string to the icon, noting differences --- *
1057    *
1058    * If the string is too long for the buffer, truncate it.  Note that if
1059    * it's more than 1K long, we've already died horridly, because sprintf
1060    * will have overflowed our own buffer above.
1061    */
1062
1063   buff=i->data.indirecttext.buffer;
1064   max=i->data.indirecttext.bufflen-1;
1065   j=strlen(fptr);
1066   if (j>max)
1067   {
1068     if (rJust=(i->flags & wimp_IRJUST),rJust)
1069       fptr+=j-max;
1070   }
1071   else
1072     dots=FALSE;
1073   j=0;
1074   while (!stop)
1075   {
1076     x=*buff++;
1077     y=*fptr++;
1078     if (max==j || y<' ')
1079       y=0;
1080     else if (dots && ((rJust && j<3) || (!rJust && max-j<4)))
1081       y='.';
1082     if (x<' ')
1083       x=0;
1084     if (x!=y)
1085     {
1086       different=TRUE;
1087       buff[-1]=y;
1088     }
1089     if (y)
1090       j++;
1091     else
1092       stop=TRUE;
1093   }
1094
1095   /* --- If the icon has changed, redraw it, and move the caret --- */
1096
1097   if (different)
1098   {
1099     wimpt_noerr(wimp_set_icon_state(d->wind,f,0,0));
1100     wimpt_noerr(wimp_get_caret_pos(&c));
1101     if (c.w==d->wind && c.i==f)
1102     {
1103       if (c.index>j)
1104       {
1105         c.index=j;
1106         c.height=-1;
1107       }
1108       wimpt_noerr(wimp_set_caret_pos(&c));
1109     }
1110   }
1111 }
1112
1113 /*
1114  * void dbox_clickicon(dbox d,dbox_field f)
1115  *
1116  * Use
1117  *  Informs a 3D button manager (e.g. Sculptrix) of a click on an icon.  Icon
1118  *  clicks are stacked, so that unclick calls unslab icons in reverse order
1119  *  to slabbing.  If any 3D button managers are loaded, it's assumed that
1120  *  you will want to use them.  Otherwise, icons are selected and unselected
1121  *  (which fits in with RISC OS 3's inferior 3D button system)
1122  *
1123  * Parameters
1124  *  dbox d == the dbox
1125  *  dbox_field f == the field
1126  */
1127
1128 void dbox_clickicon(dbox d,dbox_field f)
1129 {
1130   wimp_mousestr m;
1131
1132   if (dbox__click==dbox__CLICKMAX)
1133   {
1134     werr(FALSE,
1135          msgs_lookup("dboxSTK:Only enough stack space for %i icons."),
1136          dbox__CLICKMAX);
1137     return;
1138   }
1139
1140   dbox__clicked[dbox__click].s.w=d->wind;
1141   dbox__clicked[dbox__click].s.i=f;
1142   dbox__clicked[dbox__click].d=d;
1143
1144   if (wimpt_last_event()->e!=wimp_EKEY && !(wimpt_options() & 7))
1145   {
1146     dbox__clicked[dbox__click].d=0;
1147     dbox__click++;
1148     return;
1149   }
1150
1151   if (wimpt_options() & wimpt_OSCULPTRIX)
1152     wimpt_noerr(sculptrix_slabIcon(d->wind,f,&dbox__clicked[dbox__click].s));
1153   if (wimpt_options() & wimpt_OINTERFACE)
1154   {
1155     m.w=d->wind;
1156     m.i=f;
1157     m.bbits=(dbox_wasAdjustClick() ? wimp_BRIGHT : wimp_BLEFT);
1158     m.x=m.y=0;
1159     wimpt_noerr(interface_slabButton(&m));
1160   }
1161   if (!(wimpt_options() & 7))
1162     dbox_selecticon(d,f,dbox_SETSTATE);
1163   dbox__click++;
1164 }
1165
1166 /*
1167  * void dbox_unclick(void)
1168  *
1169  * Use
1170  *  This routine declicks the last icon to be 'dbox_clickicon'ed.  If you
1171  *  intend to delete the dbox after the click, you should use code like
1172  *  this:
1173  *
1174  *    dbox_hide(d);
1175  *    dbox_unclick();
1176  *    dbox_delete(d);
1177  */
1178
1179 void dbox_unclick(void)
1180 {
1181   wimp_mousestr m;
1182
1183   if (dbox__click==0)
1184   {
1185     werr(TRUE,msgs_lookup("dboxCSU:(dbox_unclick): Click stack underflow."));
1186     return;
1187   }
1188
1189   dbox__click--;
1190   if (dbox__clicked[dbox__click].d)
1191   {
1192     if (wimpt_options() & wimpt_OSCULPTRIX)
1193       wimpt_noerr(sculptrix_unslabIcon(&dbox__clicked[dbox__click].s));
1194     if (wimpt_options() & wimpt_OINTERFACE)
1195     {
1196       m.w=dbox__clicked[dbox__click].s.w;
1197       m.i=dbox__clicked[dbox__click].s.i;
1198       m.bbits=m.x=m.y=0;
1199       wimpt_noerr(interface_slabButton(&m));
1200     }
1201     if (!(wimpt_options() & 7))
1202     {
1203       dbox_selecticon(dbox__clicked[dbox__click].d,
1204                       dbox__clicked[dbox__click].s.i,
1205                       dbox_RESETSTATE);
1206     }
1207   }
1208 }
1209
1210 /*
1211  * void dbox_unclickAll(void)
1212  *
1213  * Use
1214  *  This call dbox_unclick()s all the 'dbox_clickicon'ed icons in the dbox.
1215  *  You shouldn't really need to use it.  It's mainly there for consistency
1216  *  with Armen's WimpLib v. 3.00 (written ages ago, and only used by the
1217  *  author).  I've not needed to use it yet.
1218  */
1219
1220 void dbox_unclickAll(void)
1221 {
1222   while (dbox__click)
1223     dbox_unclick();
1224 }
1225
1226 /*
1227  * void dbox_getfield(dbox d,dbox_field f,char *buffer,int size)
1228  *
1229  * Use
1230  *  This is the same routine as in RISC_OSlib.  It returns the contents of
1231  *  the icon text in the buffer.
1232  */
1233
1234 void dbox_getfield(dbox d, dbox_field f, char *buffer, int size)
1235 {
1236   wimp_icon *i = dbox__idef(d, f);
1237   int j = 0;
1238   char *from;
1239
1240   if (i->flags & wimp_ITEXT)
1241   {
1242     if (i->flags & wimp_INDIRECT)
1243     {
1244       while (i->data.indirecttext.buffer[j] >= 32)
1245         j++;
1246       from=i->data.indirecttext.buffer;
1247     }
1248     else
1249     {
1250       while (i->data.text[j] >= 32 && j < 11)
1251         j++;
1252       from=&i->data.text[0];
1253     }
1254     if (j>size)
1255       j=size;
1256     memcpy(buffer,from,j);
1257   }
1258   buffer[j]=0;
1259 }
1260
1261 /*
1262  * void dbox_scanfield(dbox d,dbox_field f,char *format,...)
1263  *
1264  * Use
1265  *  Reads in scanf()-style the contents of a field.
1266  *
1267  * Parameters
1268  *  dbox d == the dbox handle
1269  *  dbox_field f == the field number
1270  *  char *format == a scanf() style format string
1271  */
1272
1273 void dbox_scanfield(dbox d,dbox_field f,char *format,...)
1274 {
1275   char field[1024];
1276   va_list ap;
1277   va_start(ap,format);
1278   dbox_getfield(d,f,field,1024);
1279   vsscanf(field,format,ap);
1280   va_end(ap);
1281 }
1282
1283 /*
1284  * BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a)
1285  *
1286  * Use
1287  *  This call will read the icon's state of selection and return it, and
1288  *  optionally alter it as specified in the dbox_action parameter.
1289  *
1290  * Parameters
1291  *  dbox d == the dbox handle
1292  *  dbox_field f == the field you're interested in
1293  *  dbox_action a == what you want to do with it
1294  */
1295
1296 BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a)
1297 {
1298   wimp_icon icn;
1299   BOOL selected;
1300   wimpt_noerr(wimp_get_icon_info(d->wind,f,&icn));
1301
1302   selected=(icn.flags & wimp_ISELECTED) ? TRUE : FALSE;
1303   switch (a)
1304   {
1305     case dbox_READSTATE:
1306       return (selected);
1307       break;
1308     case dbox_SETSTATE:
1309       if (selected)
1310         return (TRUE);
1311       icn.flags |= wimp_ISELECTED;
1312       break;
1313     case dbox_RESETSTATE:
1314       if (!selected)
1315         return (FALSE);
1316       icn.flags &= ~wimp_ISELECTED;
1317       break;
1318     case dbox_TOGGLESTATE:
1319       icn.flags ^= wimp_ISELECTED;
1320       break;
1321   }
1322   wimpt_noerr(wimp_set_icon_state
1323   (
1324     d->wind,
1325     f,
1326     icn.flags & wimp_ISELECTED,
1327     wimp_ISELECTED
1328   ));
1329   return (selected);
1330 }
1331
1332 /*
1333  * BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a)
1334  *
1335  * Use
1336  *  This call will read the icon's state of shading and return it, and
1337  *  optionally alter it as specified in the dbox_action parameter.
1338  *
1339  * Parameters
1340  *  dbox d == the dbox handle
1341  *  dbox_field f == the field you're interested in
1342  *  dbox_action a == what you want to do with it
1343  */
1344
1345 BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a)
1346 {
1347   BOOL shaded;                          /* The old value of the shading    */
1348   BOOL shade;                           /* Whether to shade the icon       */
1349   wimp_icon *icn=dbox__idef(d,f);       /* Find the icon in the window def */
1350   wimp_icon real;
1351   wimp_caretstr c;
1352
1353   /* --- Get the current shading state --- */
1354
1355   wimpt_noerr(wimp_get_icon_info(d->wind,f,&real));
1356
1357   if (wimpt_options() & wimpt_ONOWIMPSHADE)
1358     shaded=!!(icn->flags & wimp_INOSELECT);
1359   else
1360     shaded=!!(real.flags & wimp_INOSELECT);
1361
1362   /* --- Find the new shading state --- */
1363
1364   switch (a)
1365   {
1366     case dbox_SETSTATE:
1367       shade=TRUE;
1368       break;
1369     case dbox_RESETSTATE:
1370       shade=FALSE;
1371       break;
1372     case dbox_TOGGLESTATE:
1373       shade=!shaded;
1374       break;
1375     case dbox_READSTATE:
1376     default:
1377       shade=shaded;
1378       break;
1379   }
1380
1381   /* --- If there's nothing to do, then don't do it --- */
1382
1383   if (shade==shaded)
1384     return (shaded);
1385
1386   /* --- Do appropriate things to the icon --- */
1387
1388   if (wimpt_options() & wimpt_ONOWIMPSHADE)
1389   {
1390     wimp_iconflags old;
1391     wimp_iconflags new;
1392     int contents;
1393     int fhandle;
1394
1395     if (shade)
1396     {
1397       old=new=real.flags;
1398       contents=old & 3;
1399
1400       if (wimp_readsysinfo(wimp_IFONTHANDLE,&fhandle))
1401         fhandle=0;
1402       if (fhandle && (contents&wimp_ISPRITE))
1403         contents&=~wimp_ITEXT;
1404
1405       if (contents!=wimp_ITEXT)
1406         new=new | 0x00400000;
1407       if (contents & wimp_ITEXT)
1408         new=(new & ~0x0f1ff000) | 0x021f0000;
1409       icn->flags=old | 0x00400000;
1410       wimpt_noerr(wimp_set_icon_state(d->wind,f,new,0xffffffff));
1411     }
1412     else
1413     {
1414       icn->flags = (icn->flags & 0x0f1ff000) | (real.flags & 0xf0a00fff);
1415       wimpt_noerr(wimp_set_icon_state(d->wind,f,icn->flags,0xffffffff));
1416     }
1417     if (wimpt_options() & wimpt_OSCULPTRIX)
1418       wimpt_noerr(sculptrix_updateIcon(d->wind,f));
1419   }
1420   else
1421     wimpt_noerr(wimp_set_icon_state(d->wind,f,shade<<22,0x00400000));
1422
1423   if (shade)
1424   {
1425     wimpt_noerr(wimp_get_caret_pos(&c));
1426     if (c.w==d->wind && c.i==f)
1427     {
1428         c.i=-1;
1429         c.x=-500000;
1430         wimpt_noerr(wimp_set_caret_pos(&c));
1431     }
1432   }
1433
1434   /* --- Now return the original value --- */
1435
1436   return (shaded);
1437 }
1438
1439 /*
1440  * wimp_w dbox_syshandle(dbox d)
1441  *
1442  * Use
1443  *  Returns the window handle used by the dbox specified, because your poor
1444  *  underprivileged code can't access my nice data structure.  This is for
1445  *  setting up things like calls to event_attachmenu and suchlike, which
1446  *  don't know about cunning things like dboxes.
1447  *
1448  * Parameters
1449  *  dbox d == the dbox you're interested in
1450  *
1451  * Returns
1452  *  The window handle, which is a wimp_w
1453  */
1454
1455 wimp_w dbox_syshandle(dbox d)
1456 {
1457   return (d->wind);
1458 }
1459
1460 /*
1461  * int dbox_getNumeric(dbox d,dbox_field f)
1462  *
1463  * Use
1464  *  Reads an integer from a field.  If there is no semblance to a valid
1465  *  integer, 0 is returned.
1466  *
1467  * Parameters
1468  *  dbox d == the dbox handle
1469  *  dbox_field f == the field to read from
1470  */
1471
1472 int dbox_getNumeric(dbox d,dbox_field f)
1473 {
1474   int val;
1475   dbox_scanfield(d,f,"%d",&val);
1476   return (val);
1477 }
1478
1479 /*
1480  * void dbox_setNumeric(dbox d,dbox_field f,int val)
1481  *
1482  * Use
1483  *  Writes the integer value specified into the field.
1484  *
1485  * Parameters
1486  *  dbox d == the dbox handle
1487  *  dbox_field f == the field to set
1488  *  int val == the integer value to write
1489  */
1490
1491 void dbox_setNumeric(dbox d,dbox_field f,int val)
1492 {
1493   dbox_setfield(d,f,"%i",val);
1494 }
1495
1496 /*
1497  * dbox_field dbox_helpField(void)
1498  *
1499  * Use
1500  *  Returns field number that Help is interested in.
1501  *
1502  * Returns
1503  *  Field number.
1504  */
1505
1506 dbox_field dbox_helpField(void)
1507 {
1508   wimp_eventstr *e=wimpt_last_event();
1509   int icon;
1510   int win;
1511   wimp_icon icn;
1512   if (help_wasHelp())
1513   {
1514     win=e->data.msg.data.helprequest.m.w;
1515     icon=e->data.msg.data.helprequest.m.i;
1516     wimpt_noerr(wimp_get_icon_info(win,icon,&icn));
1517     if ((wimpt_options() & wimpt_ONOWIMPSHADE) &&
1518         (icn.flags & 0x001f0000) == 0x001f0000)
1519       return (-1);
1520     else
1521       return (icon);
1522   }
1523   else
1524     werr
1525     (
1526       TRUE,
1527       msgs_lookup("dboxHFE:(dbox_helpField, caller fault): "
1528                                         "Not called on HELPREQUEST event.")
1529     );
1530   return (0);
1531 }
1532
1533 /*----- Routines for Elite-style monologue boxes --------------------------*/
1534
1535 /*
1536  * void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag)
1537  *
1538  * Use
1539  *  Gives the specified dialogue box an inbuilt title (in a group box, round
1540  *  the outside, as seen in Elite).  This is drawn automatically normally,
1541  *  but raw event handlers might want to do extra drawing, so the entry
1542  *  point to the redraw code is also supplied.
1543  *
1544  * Parameters
1545  *  dbox d == the dialogue box to do this to
1546  *  dbox_field icon == the icon around which the title is to be drawn
1547  *  BOOL moveDrag == allow a click on any of the dialogue box to move it
1548  */
1549
1550 void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag)
1551 {
1552   d->titleIcon=icon;
1553   d->moveDrag=moveDrag;
1554 }
1555
1556 /*
1557  * void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle)
1558  *
1559  * Use
1560  *  Redraws an embedded title (as seen in Elite).  This is for the use of
1561  *  raw event handlers, which might want to do this sort of thing, because
1562  *  the redraw is normally handled automatically.
1563  *
1564  * Parameters
1565  *  wimp_redrawstr *r == the redraw information I need
1566  *  void *handle == a dbox, really.  This is for passing to wimpt_redraw.
1567  */
1568
1569 void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle)
1570 {
1571   dbox d=handle;
1572   char *t=d->windDef->title.indirecttext.buffer;
1573   wimp_icon title;
1574   wimp_icon border;
1575   int len;
1576   if (d->titleIcon==-1)
1577     return;
1578   for (len=0;t[len]>31;len++)
1579     /* blank */ ;
1580
1581   if (wimpt_options() & wimpt_OSCULPTRIX)
1582   {
1583     /* --- We've got Sculptrix, so do a really good job --- *
1584      *
1585      * Since Sculptrix can do proper ridge/plinth intersections, we use this
1586      * in preference.
1587      *
1588      * It now does the whole job in one go.
1589      */
1590
1591     sculptrix_plotGroupBox(dbox__idef(d,d->titleIcon),r,0,t);
1592     return;
1593   }
1594
1595   border.box=dbox__idef(d,d->titleIcon)->box;
1596   border.flags=wimp_ITEXT | wimp_INDIRECT;
1597
1598   title.box.x0=border.box.x0+16;
1599   title.box.y0=border.box.y1-20;
1600   title.box.x1=border.box.x0+32+wimpt_stringWidth(t);
1601   title.box.y1=border.box.y1+28;
1602   title.flags=wimp_ITEXT |
1603               wimp_INDIRECT |
1604               wimp_IFILLED |
1605               wimp_IHCENTRE |
1606               0x17000000;
1607   title.data.indirecttext.buffer=t;
1608   title.data.indirecttext.bufflen=len+1;
1609
1610   if (wimpt_options() & wimpt_OINTERFACE)
1611   {
1612     /* --- We can make do with Interface, although it isn't as nice --- *
1613      *
1614      * Interface makes a passable job at ridge-and-plinth group borders,
1615      * though they're not as nice as Sculptrix's, because the ridged border
1616      * doesn't intersect the title plinth properly.
1617      */
1618
1619     border.data.indirecttext.validstring="Z1,0,0,4,0";
1620     title.data.indirecttext.validstring="Z0,0,0,4,0";
1621
1622     _swi(XInterface_Plot3dIcon,_inr(0,1),r,&title);
1623     _swi(XInterface_Plot3dIcon,_inr(0,1),r,&border);
1624   }
1625   else
1626   {
1627     /* --- Use RISC OS 3 borders if available --- *
1628      *
1629      * If not, RISC OS 2 will just plot a black border, which should look OK
1630      * although not as nice.  Note that we can't do the STASIS-conforming
1631      * ridge-and-plinth group box, although a channel will do at a pinch.
1632      */
1633
1634     border.box.x0-=8;
1635     border.box.y0-=8;
1636     border.box.x1+=8;
1637     border.box.y1+=8;
1638     border.flags |= wimp_IBORDER;
1639     border.data.indirecttext.validstring="r4";
1640     border.data.indirecttext.buffer="";
1641     border.data.indirecttext.bufflen=1;
1642     title.data.indirecttext.validstring=(char *)-1;
1643     wimp_ploticon(&border);
1644   }
1645   wimp_ploticon(&title);
1646 }
1647
1648 /*
1649  * BOOL dbox_hasTitle(dbox d)
1650  *
1651  * Use
1652  *  Returns TRUE if the given dialogue box has a window title bar.
1653  *
1654  * Parameters
1655  *  dbox d == the dialogue box to check
1656  *
1657  * Returns
1658  *  TRUE if the dialogue box has a title bar
1659  */
1660
1661 BOOL dbox_hasTitle(dbox d)
1662 {
1663   return (!!(d->windDef->flags & wimp_WTITLE));
1664 }