/* * dbox * further dialogue box routines for Straylight apps * * v. 1.02 (10 August 1993) * * © 1993-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Steel library. * * Steel is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * Steel is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Steel. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define dbox__INTERNALS #include "event.h" #include "wimpt.h" #include "wimp.h" #include "interface.h" #include "sculptrix.h" #include "werr.h" #include "template.h" #include "win.h" #include "dbox.h" #include "msgs.h" #include "bbc.h" #include "mem.h" #include "akbd.h" #include "os.h" #include "swiv.h" #include "swis.h" #include "help.h" #include "vsscanf.h" #include #include #include #include #include "dll.h" #ifndef _dll_NODLL extern void _dllEntry(dbox__eventhandler)(wimp_eventstr *e,void *handle); #endif wimp_w dbox_menuDboxWindow(void); /* * The big one - the data needed to manage the dbox system. This IS a dbox. */ typedef struct dbox__dboxstr { wimp_w wind; /* Real window handle */ dbox_eventhandler eventProc; /* User event handler procedure */ void *eventHandle; /* Pointer to handler information */ dbox_raweventhandler rawEventProc; /* Pointer to raw event handler */ void *rawEventHandle; /* Pointer to raw handler information */ wimp_caretstr oldCaret; /* Where the caret was before this opened */ wimp_wind *windDef; /* Pointer to complete window definiton */ wimp_wind *temp; /* Pointer to template for this window */ char *indirect; /* Pointer to indirected text */ int titleIcon; /* Icon for the window title, or -1 */ BOOL isOpen :1; /* Is the dbox open? */ BOOL isStatic :1; /* Is this a static or menu dbox */ BOOL restoreCaret :1; /* Do we return the caret when finished? */ BOOL moveDrag :1; /* Click on window starts window move */ } dbox__dboxstr; /* * A structure for passing to the dbox__fillinHandler() routine to make sure * that the thing runs smoothly. */ typedef struct { dbox_field f; /* The clicked field, or -2 */ } dbox__fillinstr; #define dbox__CLICKMAX 10 /* Number of clicks which fit in stack */ typedef struct { dbox d; sculptrix_slabDescriptor s; } dbox__cstackstr; static dbox__cstackstr dbox__clicked[dbox__CLICKMAX]; /* Click stack array */ static int dbox__click; /* Click stack stack pointer */ static dbox dbox__menuDbox; /* Currently open menu dbox (or 0) */ static BOOL dbox__closedForUs; /* Is this a 'real' close event? */ static BOOL dbox__shiftRet=FALSE; /* Is this a sh-RETURN press for a dbox? */ static dbox__mf dbox__tmsmf; /* Where to go to find menu coords */ static dbox__esm dbox__tmsesm; /* Are we expecting a submenu */ static dbox__ddb dbox__tmsddb; /* How do we display a dialogue box? */ /* This routine is for a bodge to get round menu help problems. It is */ /* to be used *only* by the event segment for its own processing of help */ /* requests. */ wimp_w dbox__menuDboxWindow(void) { return (dbox__menuDbox->wind); } /* * void dbox__rms(dbox__mf f,dbox__esm esm,dbox__ddb ddb) * * Use * Registers support functions for handling an alternative menu handling * system (e.g. TMS). */ void dbox__rms(dbox__mf f,dbox__esm esm,dbox__ddb ddb) { dbox__tmsmf=f; dbox__tmsesm=esm; dbox__tmsddb=ddb; } /* * BOOL wasAdjustClick(void) * * Use * Returns whether the last event was caused by a mouse click with the * adjust mouse button. Useful for deciding whether you want to bump a * value up or down, or for keeping a dbox on-screen. * * Returns * TRUE if the last event WAS caused by an adjust click. */ BOOL dbox_wasAdjustClick(void) { wimp_eventstr *e=wimpt_last_event(); if ((e->e==wimp_EBUT && e->data.but.m.bbits==wimp_BRIGHT)||dbox__shiftRet) return (TRUE); else return (FALSE); } /* * wimp_icon *dbox__idef(dbox d,wimp_i i) * * Use * This routine returns a pointer to the icon definition specified. * * Parameters * dbox d == dbox handle * wimp_i i == the icon handle * * Returns * A pointer to the icon definition. */ #define dbox__idef(d,i) ((wimp_icon *)((d)->windDef+1)+(i)) #ifdef notdef static wimp_icon *dbox__idef(dbox d,wimp_i i) { return ((wimp_icon *)(d->windDef+1)+i); } #endif /* * int dbox__fieldlength(dbox d,dbox_field f) * * Use * Returns the length of the text in field specified * * Parameters * dbox d == dbox handle * dbox_field f == field number (icon handle to the uninitiated!) * * Returns * The length of the field. Why isn't this a size_t? */ static int dbox__fieldlength(dbox d, dbox_field f) { char a[255]; dbox_getfield((dbox) d, f, a, 255); return(strlen(a)); } /* * void dbox__nextWritable(BOOL fromTop,dbox d,BOOL forward) * * Use * This call moves the caret around the window it is in. The fromTop * parameter says whether you want to move the caret either to one * extremity or the other, or just move it along. The routine, unlike the * standard RISC_OSlib one, actually scrolls the window to keep the caret * in view. * * Parameters * BOOL fromTop == whether you want to move to an extremity, or just up or * down one. * dbox d == the dbox you think the caret is in. If it isn't, you're in * deep sh*te. * BOOL forward == whether you want to search forward or backward from your * starting position. */ static void dbox__nextWritable(BOOL fromTop,dbox d,BOOL forwards) { wimp_caretstr c; wimp_icon idef; wimp_i i; int iterations; int dir; int bt; wimp_wstate state; int sw,sh,ox,oy; wimpt_noerr(wimp_get_caret_pos(&c)); if (forwards) dir=1; else dir=-1; if (fromTop) { if (forwards) i=0; else i=d->windDef->nicons; } else i=c.i+dir; for (iterations=0;iterationswindDef->nicons;iterations++,i+=dir) { if (i>d->windDef->nicons) { i=-1; iterations--; continue; } if (i<0) { i=d->windDef->nicons+1; iterations--; continue; } wimpt_noerr(wimp_get_icon_info(d->wind,i,&idef)); bt=(((int)idef.flags)>>12) & 15; if ( (bt==15 || bt==14) && ((idef.flags & wimp_INOSELECT)==0) && ((idef.flags & wimp_IDELETED)==0) ) break; } if (iterations==d->windDef->nicons) return; c.w=d->wind; c.i=i; c.height=-1; c.index=dbox__fieldlength(d,i); wimpt_noerr(wimp_set_caret_pos(&c)); wimpt_noerr(wimp_get_wind_state(d->wind,&state)); sw=state.o.box.x1-state.o.box.x0; sh=state.o.box.y1-state.o.box.y0; ox=state.o.box.x0-state.o.x; oy=state.o.box.y1-state.o.y; if (state.o.box.x0>idef.box.x0+ox) state.o.x=idef.box.x0-24; if (state.o.box.x1idef.box.y0+oy) state.o.y=idef.box.y0-24+sh; if (state.o.box.y1flags & 0x0000F000) == (wimp_BCLICKDEBOUNCE<<12)) { esg=idef->flags & 0x001F0000; if (esg) { dbox_selecticon(d,f,TRUE); idef=dbox__idef(d,0); for (i=0;iwindDef->nicons;i++,idef++) { if (i!=f && (idef->flags & 0x001F0000)==esg) dbox_selecticon(d,i,FALSE); } } } } /* * void dbox__eventhandler(wimp_eventstr *e,void *handle) * * Use * Event handler for dboxes. Handles ops as follows: * * * Clicks on icons are passed to dbox handler if present * * Key presses are dealt with: * cursor keys move caret * return reports a click on icon 0 * escape reports a click on icon 1 * a close operation reports a click on icon dbox_CLOSE * * If a menu dbox closes in the backgound (i.e. the WIMP makes off with * it), a close operation is passed to the dbox concerned. * * Parameters * wimp_eventstr *e == a pointer to the current WIMP event * void *handle == the jolly old handle, which is a pointer to the * dbox__dboxstr. */ _dll_static void dbox__eventhandler(wimp_eventstr *e,void *handle) { dbox d=(dbox)handle; BOOL handled=FALSE; dbox__shiftRet=FALSE; if (d->rawEventProc) handled=(d->rawEventProc)(d,e,(void *)d->rawEventHandle); if (!handled) { switch (e->e) { case wimp_EREDRAW: if (d->titleIcon!=-1) wimpt_redraw(dbox_drawEmbeddedTitle,d); else wimpt_redraw(0,0); break; case wimp_EOPEN: wimpt_noerr(wimp_open_wind(&e->data.o)); break; case wimp_ECLOSE: if (d->eventProc) (d->eventProc)(d,dbox_CLOSE,d->eventHandle); break; case wimp_EBUT: if (e->data.but.m.bbits==wimp_BRIGHT || e->data.but.m.bbits==wimp_BLEFT) { dbox__checkRadio(d,e->data.but.m.i); if (d->eventProc && e->data.but.m.i!=-1) (d->eventProc)(d,e->data.but.m.i,d->eventHandle); if (d->moveDrag) { wimp_dragstr dr; dr.window=d->wind; dr.type=wimp_MOVE_WIND; wimp_drag_box(&dr); } } break; case wimp_EKEY: switch (akbd_translate(e->data.key.chcode)) { case key_sReturn: case key_skEnter: dbox__shiftRet=TRUE; /* Treat as normal return */ case key_Return: case key_kEnter: if (d->eventProc && !dbox_shadeicon(d,0,dbox_READSTATE)) (d->eventProc)(d,0,d->eventHandle); break; case key_sEsc: dbox__shiftRet=TRUE; /* Treat as normal Escape */ case key_Esc: if (d->eventProc && !dbox_shadeicon(d,1,dbox_READSTATE)) (d->eventProc)(d,1,d->eventHandle); break; case key_Down: case key_Tab: dbox__nextWritable(FALSE,d,TRUE); break; case key_sTab: case key_Up: dbox__nextWritable(FALSE,d,FALSE); break; case key_cDown: dbox__nextWritable(TRUE,d,FALSE); break; case key_cUp: dbox__nextWritable(TRUE,d,TRUE); break; default: wimp_processkey(e->data.key.chcode); break; } break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e->data.msg.hdr.action) { case wimp_MHELPREQUEST: if (d->eventProc) (d->eventProc)(d,dbox_HELP,d->eventHandle); break; } break; } } } /* * dbox dbox_create(char *template) * * Use * Creates a dbox from a template and returns a handle to it. It calls * werr() sensibly with nice messages if it failed. * * Parameters * char *name == name of template to use * * Returns * Abstract handle to dbox or NULL if the dbox could not be * created */ dbox dbox_create(char *name) { template *temp=template_find(name); wimp_wind *w=template_syshandle(name); dbox d=(dbox)mem_alloc(sizeof(dbox__dboxstr)); wimp_icon *icn; int i; BOOL unshade=wimpt_options() & wimpt_ONOWIMPSHADE; if (d) { if (d->windDef=(wimp_wind *)mem_alloc ( sizeof(wimp_wind)+w->nicons*sizeof(wimp_icon) ), d->windDef==0) { mem_free(d); werr ( FALSE, msgs_lookup("dboxNEM:Not enough memory for new dialogue box.") ); return (0); } memcpy(d->windDef,w,sizeof(wimp_wind)+w->nicons*sizeof(wimp_icon)); if (temp->workspacesize!=0) { if (d->indirect=(char *)mem_alloc(temp->workspacesize),d->indirect==0) { mem_free(d->windDef); mem_free(d); werr ( FALSE, msgs_lookup("dboxNEM:Not enough memory for new dialogue box.") ); return (0); } memcpy(d->indirect,temp->workspace,temp->workspacesize); for (i=0;iwindDef->nicons;i++) { icn=dbox__idef(d,i); if (unshade) icn->flags &= 0xffbfffff; if ((icn->flags&wimp_INDIRECT)!=0) { icn->data.indirecttext.buffer+=d->indirect-temp->workspace; if ((icn->flags&3)==2) icn->data.indirectsprite.spritearea=(void *)1; else { if (icn->data.indirecttext.validstring!=(char *)-1) { icn->data.indirecttext.validstring+= d->indirect-temp->workspace; } } } } if (d->windDef->titleflags&wimp_INDIRECT) { d->windDef->title.indirecttext.buffer+=d->indirect-temp->workspace; if ((d->windDef->titleflags&3)==2) d->windDef->title.indirectsprite.spritearea=(void *)1; else { if (d->windDef->title.indirecttext.validstring!=(char *)-1) { d->windDef->title.indirecttext.validstring+= d->indirect-temp->workspace; } } } } else d->indirect=0; if (wimp_create_wind(d->windDef,&d->wind)==0) { d->eventProc=0; d->rawEventProc=0; d->isOpen=FALSE; d->isStatic=FALSE; d->titleIcon=-1; d->moveDrag=FALSE; d->temp=w; win_activeinc(); win_register_event_handler(d->wind,_dllEntry(dbox__eventhandler),d); } else { mem_free(d->windDef); mem_free(d->indirect); mem_free(d); d=0; werr ( FALSE, msgs_lookup("dboxTMW:Too many windows - " "%s could not create window/dialogue box."), wimpt_programname() ); } } else werr ( FALSE, msgs_lookup("dboxNEM:Not enough memory for new dialogue box.") ); return (d); } /* * void dbox__setMenuDbox(dbox d) * * Use * This routine handles the updating of the dbox__menuDbox variable. It * is needed 'cos if the user maniacally starts opening submenus, the thing * can get a bit confused. If there already is one, it gets a wimp_ECLOSE * event faked to it courtesy of a combination of wimpt_fake_event() and * event_process(). * * Parameters * dbox d == the new prospective menu dbox. */ static void dbox__setMenuDbox(dbox d) { dbox__menuDbox=d; } /* * void dbox_display(dbox d,dbox_openType how) * * Use * Displays a dbox on the screen. The new dbox_openType is compatible with * the old TRUE/FALSE system. Note that is the event was a submenu, then * the dbox will be opened as a submenu regardless of how you want it done. * * If the dbox conatins a writable icon, then the caret is placed within * the first one. This is handled automatically by the WIMP for submenu * dboxes, but not (unfortunately) for static ones. * * Parameters * dbox d == dbox handle * dbox_openType how == how you want the dbox opened */ void dbox_display(dbox d,dbox_openType how) { wimp_wstate state; int scx=wimpt_scwidth(); int scy=wimpt_scheight(); int w; int h; wimp_caretstr c; wimp_eventstr *e; int x; int y; wimpt_noerr(wimp_get_wind_state(d->wind,&state)); state.o.behind=(wimp_w)-1; w=state.o.box.x1-state.o.box.x0; h=state.o.box.y1-state.o.box.y0; d->isStatic=TRUE; switch (how) { case dbox_MENU_OVERPTR: d->isStatic=FALSE; case dbox_STATIC_OVERPTR: bbc_mouse(&x,&y,0,0); state.o.box.x0=x-w/2; state.o.box.x1=x+w/2; state.o.box.y0=y-h/2; state.o.box.y1=y+h/2; break; case dbox_MENU_LASTPOS: d->isStatic=FALSE; case dbox_STATIC_LASTPOS: /* Nothin' doin' */ break; case dbox_MENU_CENTRE: d->isStatic=FALSE; case dbox_STATIC_CENTRE: state.o.box.x0=(scx-w)/2; state.o.box.x1=(scx+w)/2; state.o.box.y0=(scy-h)/2; state.o.box.y1=(scy+h)/2; break; } win_adjustBox(&state.o); if (d->isStatic) { wimpt_noerr(wimp_open_wind(&state.o)); if (!d->isOpen) { d->isOpen=TRUE; d->isStatic=TRUE; wimpt_noerr(wimp_get_caret_pos(&d->oldCaret)); d->restoreCaret=TRUE; dbox__nextWritable(TRUE,d,TRUE); wimpt_noerr(wimp_get_caret_pos(&c)); if (c.w!=d->wind) d->restoreCaret=FALSE; else { c.i=-1; c.x=-500000; c.height=0x2000000; wimpt_noerr(wimp_set_caret_pos(&c)); } } } else { if (dbox_wasSubmenu() && (wimpt_last_event()->e==wimp_ESEND || wimpt_last_event()->e==wimp_ESENDWANTACK)) { e=wimpt_last_event(); x=e->data.msg.data.words[1]; y=e->data.msg.data.words[2]; wimpt_noerr(wimp_create_submenu((wimp_menustr *)d->wind,x,y)); d->restoreCaret=FALSE; } else if (dbox__tmsesm && dbox__tmsesm()) { dbox__tmsmf(&x,&y); state.o.box.x0=x; state.o.box.x1=x+w; state.o.box.y0=y-h; state.o.box.y1=y; dbox__tmsddb(&state.o); wimpt_noerr(wimp_get_caret_pos(&d->oldCaret)); d->restoreCaret=TRUE; dbox__nextWritable(TRUE,d,TRUE); } else { wimpt_noerr(wimp_create_menu( (wimp_menustr *)d->wind, state.o.box.x0, state.o.box.y1 )); d->restoreCaret=FALSE; } d->isOpen=TRUE; d->isStatic=FALSE; dbox__setMenuDbox(d); } } /* * void dbox_openDisplaced(dbox d) * * Use * Displaces the dbox from its original height by the statutory 48 OS * units. If it would overlap the icon bar, it gets moved up to a sensible * height. The dbox must be opened by this call once only. It must be * closed using dbox_deleteNoUpdate(). The dbox is opened as a static * dbox, of course. * * Parameters * dbox d == the dbox */ void dbox_openDisplaced(dbox d) { int new=0; wimp_wstate s; wimp_caretstr c; if (d->isOpen) { werr ( TRUE, msgs_lookup("dboxCOD:(dbox_openDisplaced): " "failed - dbox already open.") ); } if (d->temp->box.y0-48<132) { new=((976-d->temp->box.y1)/48-4)*48+d->temp->box.y1; d->temp->box.y0+=new-d->temp->box.y1; d->temp->box.y1=new; } else { d->temp->box.y0-=48; d->temp->box.y1-=48; } wimpt_noerr(wimp_get_wind_state(d->wind,&s)); s.o.box=d->temp->box; s.o.behind=-1; wimpt_noerr(wimp_open_wind(&s.o)); d->isOpen=TRUE; d->isStatic=TRUE; wimpt_noerr(wimp_get_caret_pos(&d->oldCaret)); d->restoreCaret=TRUE; dbox__nextWritable(TRUE,d,TRUE); wimpt_noerr(wimp_get_caret_pos(&c)); if (c.w!=d->wind) d->restoreCaret=FALSE; else { wimpt_noerr(wimp_open_wind(&s.o)); c.i=-1; c.x=-500000; wimpt_noerr(wimp_set_caret_pos(&c)); } } /* * void dbox_hide(dbox d) * * Use * Closes the dbox specified in whatever manner necessary to stop it being * seen. The window can still be created real easy. * * Parameters * dbox d == dialogue box handle */ void dbox_hide(dbox d) { if (d==dbox__menuDbox) { if (!dbox__closedForUs) event_clear_current_menu(); dbox__menuDbox=0; } wimpt_noerr(wimp_close_wind(d->wind)); if (d->restoreCaret) wimp_set_caret_pos(&d->oldCaret); d->isOpen=FALSE; } /* * void dbox_deleteNoUpdate(dbox d) * * Use * Zaps a dbox without storing the thing's position away, so it reappears * where you want it. * * Parameters * dbox d == the handle */ void dbox_deleteNoUpdate(dbox d) { if (d->isOpen) dbox_hide(d); win_register_event_handler(d->wind,0,0); win_activedec(); wimpt_noerr(wimp_delete_wind(d->wind)); mem_free(d->indirect); mem_free(d->windDef); mem_free(d); } /* * void dbox_updatePosition(dbox d) * * Use * Stores the position of the dialogue box away, so that next time a dbox * using the same template is opened, it goes to that place. * * Parameters * dbox d == the dbox handle */ void dbox_updatePosition(dbox d) { wimp_wstate s; wimp_get_wind_state(d->wind,&s); d->temp->box=s.o.box; } /* * void dbox_delete(dbox d) * * Use * Utterly zaps the dialogue box specified. Updates the template, so it's * right next time around, though. The window is deleted, and the dbox's * space is freed. * * Parameters * dbox d == dialogue box handle */ void dbox_delete(dbox d) { if (d->isStatic) dbox_updatePosition(d); dbox_deleteNoUpdate(d); } /* * void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle) * * Use * This routine attaches an event handler to a dbox. Pass 0 as the pointer * to the procedure if you want to remove the handler. Event handers are an * alternative to using dbox_fillin(). * * Parameters * dbox d == the dbox you want to attach a handler to. * dbox_eventhandler proc == the hander procedure. * void *handle == up to you. It gets passed to the procedure, though. */ void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle) { d->eventProc=proc; d->eventHandle=handle; } /* * void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle) * * Use * This routine attaches a raw event handler to a dbox. Pass 0 as the * pointer to the procedure if you want to remove the handler. A raw event * handler gets passed all the WIMP events received by the dbox. It should * return FALSE if it could not process the event itself, or TRUE if it * did. * * Parameters * dbox d == the dbox you want to attach a handler to. * dbox_eventhandler proc == the hander procedure. * void *handle == up to you. It gets passed to the procedure, though. */ void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle) { d->rawEventProc=proc; d->rawEventHandle=handle; } /* * void dbox__fillinHandler(dbox d,dbox_field clicked,void *handle) * * Use * This is the dbox handler used by dbox_fillin(). * * Parameters * dbox d == the dbox handle * dbox_field == the field that was clicked * void *handle == a pointer to a dbox__fillinstr */ static void dbox__fillinHandler(dbox d,dbox_field clicked,void *handle) { dbox__fillinstr *f=(dbox__fillinstr *)handle; d=d; f->f=clicked; } /* * dbox_field dbox_fillin(dbox d) * * Use * This is a nice simple way of handling a dbox. It means you can handle * everything from an in-line point of view. Functions can easily return * the results they need (like dbox_query()). Unfortunately, it will only * work with menu dboxes, and will complain bitterly at you if you try and * do anything different. * * Parameters * dbox d == the dbox handle * * Returns * The field number that was clicked. */ dbox_field dbox_fillin(dbox d) { dbox__fillinstr f; if (d->isStatic) { werr ( TRUE, msgs_lookup("dboxFRE:(dbox_fillin, caller fault): " "dbox_fillin only works with menu dboxes.") ); } f.f=dbox_ENDFILLIN; dbox_eventHandler(d,dbox__fillinHandler,&f); while (f.f==dbox_ENDFILLIN) event_process(); dbox_eventHandler(d,0,0); return (f.f); } /* * void dbox_eventProcess(void) * * Use * Part of the private interface between dbox and event for processing * dialogue box events. */ void dbox__eventProcess(void) { static wimp_eventstr real; static BOOL faking; wimp_eventstr fake; wimp_wstate state; dbox__closedForUs=FALSE; if (faking) { wimpt_fake_event(&real); faking=FALSE; event__process(); return; } if (dbox__menuDbox) { wimpt_noerr(wimpt_poll(event_getmask(),&real)); wimpt_noerr(wimp_get_wind_state(dbox__menuDbox->wind,&state)); if ((((state.flags & wimp_WOPEN)==0) || real.e==wimp_EMENU) && real.e!=wimp_EREDRAW) { fake.e=wimp_ECLOSE; fake.data.o.w=dbox__menuDbox->wind; wimpt_fake_event(&fake); dbox__closedForUs=TRUE /* (real.e!=wimp_EMENU) */ ; faking=TRUE; } else wimpt_fake_event(&real); } event__process(); } /* * void dbox_setfield(dbox d,dbox_field f,char *string,...) * * Use * This routine will write the string into the field specified, if and only * if the field's data is indirected. The icon is checked to make sure * it's been indirected, and if the string is too long, we hack off bits * until it fits. Normally, the end bit is chopped off. However, you can * set the icon's right-aligned bit to indicate that you want the * *beginning* bit chopped off. * * Parameters * dbox d == the dbox * dbox_field f == the field * char *string == a printf-style format string */ void dbox_setfield(dbox d,dbox_field f,char *string,...) { wimp_icon *i=dbox__idef(d,f); wimp_caretstr c; va_list ap; char field[1024]; int j; char *buff; BOOL different=FALSE; BOOL stop=FALSE; int max; char *fptr; BOOL dots=FALSE; char x,y; BOOL rJust=FALSE; /* --- Construct the string to fill in the buffer --- * * * If the buffer overflows here, we're pretty much stuffed. We can try * to chop the end off and hope it doesn't damage anything too badly, * though. If the format string is `%s', we can just use the string given * in the first variable arg, though, so we're safe there. */ va_start(ap,string); if (string[0]=='%' && string[1]=='.') { dots=TRUE; string+=2; } if (!strcmp(string,"%s")) fptr=va_arg(ap,char *); else { vsprintf(field,string,ap); field[1023]=0; fptr=field; } va_end(ap); /* --- Make sure the string's indirected --- */ if (!(i->flags & wimp_INDIRECT)) { werr(TRUE,msgs_lookup("dboxSFNIND:(dbox_setfield, caller fault): " "Icon is not indirected.")); } /* --- Write the string to the icon, noting differences --- * * * If the string is too long for the buffer, truncate it. Note that if * it's more than 1K long, we've already died horridly, because sprintf * will have overflowed our own buffer above. */ buff=i->data.indirecttext.buffer; max=i->data.indirecttext.bufflen-1; j=strlen(fptr); if (j>max) { if (rJust=(i->flags & wimp_IRJUST),rJust) fptr+=j-max; } else dots=FALSE; j=0; while (!stop) { x=*buff++; y=*fptr++; if (max==j || y<' ') y=0; else if (dots && ((rJust && j<3) || (!rJust && max-j<4))) y='.'; if (x<' ') x=0; if (x!=y) { different=TRUE; buff[-1]=y; } if (y) j++; else stop=TRUE; } /* --- If the icon has changed, redraw it, and move the caret --- */ if (different) { wimpt_noerr(wimp_set_icon_state(d->wind,f,0,0)); wimpt_noerr(wimp_get_caret_pos(&c)); if (c.w==d->wind && c.i==f) { if (c.index>j) { c.index=j; c.height=-1; } wimpt_noerr(wimp_set_caret_pos(&c)); } } } /* * void dbox_clickicon(dbox d,dbox_field f) * * Use * Informs a 3D button manager (e.g. Sculptrix) of a click on an icon. Icon * clicks are stacked, so that unclick calls unslab icons in reverse order * to slabbing. If any 3D button managers are loaded, it's assumed that * you will want to use them. Otherwise, icons are selected and unselected * (which fits in with RISC OS 3's inferior 3D button system) * * Parameters * dbox d == the dbox * dbox_field f == the field */ void dbox_clickicon(dbox d,dbox_field f) { wimp_mousestr m; if (dbox__click==dbox__CLICKMAX) { werr(FALSE, msgs_lookup("dboxSTK:Only enough stack space for %i icons."), dbox__CLICKMAX); return; } dbox__clicked[dbox__click].s.w=d->wind; dbox__clicked[dbox__click].s.i=f; dbox__clicked[dbox__click].d=d; if (wimpt_last_event()->e!=wimp_EKEY && !(wimpt_options() & 7)) { dbox__clicked[dbox__click].d=0; dbox__click++; return; } if (wimpt_options() & wimpt_OSCULPTRIX) wimpt_noerr(sculptrix_slabIcon(d->wind,f,&dbox__clicked[dbox__click].s)); if (wimpt_options() & wimpt_OINTERFACE) { m.w=d->wind; m.i=f; m.bbits=(dbox_wasAdjustClick() ? wimp_BRIGHT : wimp_BLEFT); m.x=m.y=0; wimpt_noerr(interface_slabButton(&m)); } if (!(wimpt_options() & 7)) dbox_selecticon(d,f,dbox_SETSTATE); dbox__click++; } /* * void dbox_unclick(void) * * Use * This routine declicks the last icon to be 'dbox_clickicon'ed. If you * intend to delete the dbox after the click, you should use code like * this: * * dbox_hide(d); * dbox_unclick(); * dbox_delete(d); */ void dbox_unclick(void) { wimp_mousestr m; if (dbox__click==0) { werr(TRUE,msgs_lookup("dboxCSU:(dbox_unclick): Click stack underflow.")); return; } dbox__click--; if (dbox__clicked[dbox__click].d) { if (wimpt_options() & wimpt_OSCULPTRIX) wimpt_noerr(sculptrix_unslabIcon(&dbox__clicked[dbox__click].s)); if (wimpt_options() & wimpt_OINTERFACE) { m.w=dbox__clicked[dbox__click].s.w; m.i=dbox__clicked[dbox__click].s.i; m.bbits=m.x=m.y=0; wimpt_noerr(interface_slabButton(&m)); } if (!(wimpt_options() & 7)) { dbox_selecticon(dbox__clicked[dbox__click].d, dbox__clicked[dbox__click].s.i, dbox_RESETSTATE); } } } /* * void dbox_unclickAll(void) * * Use * This call dbox_unclick()s all the 'dbox_clickicon'ed icons in the dbox. * You shouldn't really need to use it. It's mainly there for consistency * with Armen's WimpLib v. 3.00 (written ages ago, and only used by the * author). I've not needed to use it yet. */ void dbox_unclickAll(void) { while (dbox__click) dbox_unclick(); } /* * void dbox_getfield(dbox d,dbox_field f,char *buffer,int size) * * Use * This is the same routine as in RISC_OSlib. It returns the contents of * the icon text in the buffer. */ void dbox_getfield(dbox d, dbox_field f, char *buffer, int size) { wimp_icon *i = dbox__idef(d, f); int j = 0; char *from; if (i->flags & wimp_ITEXT) { if (i->flags & wimp_INDIRECT) { while (i->data.indirecttext.buffer[j] >= 32) j++; from=i->data.indirecttext.buffer; } else { while (i->data.text[j] >= 32 && j < 11) j++; from=&i->data.text[0]; } if (j>size) j=size; memcpy(buffer,from,j); } buffer[j]=0; } /* * void dbox_scanfield(dbox d,dbox_field f,char *format,...) * * Use * Reads in scanf()-style the contents of a field. * * Parameters * dbox d == the dbox handle * dbox_field f == the field number * char *format == a scanf() style format string */ void dbox_scanfield(dbox d,dbox_field f,char *format,...) { char field[1024]; va_list ap; va_start(ap,format); dbox_getfield(d,f,field,1024); vsscanf(field,format,ap); va_end(ap); } /* * BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a) * * Use * This call will read the icon's state of selection and return it, and * optionally alter it as specified in the dbox_action parameter. * * Parameters * dbox d == the dbox handle * dbox_field f == the field you're interested in * dbox_action a == what you want to do with it */ BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a) { wimp_icon icn; BOOL selected; wimpt_noerr(wimp_get_icon_info(d->wind,f,&icn)); selected=(icn.flags & wimp_ISELECTED) ? TRUE : FALSE; switch (a) { case dbox_READSTATE: return (selected); break; case dbox_SETSTATE: if (selected) return (TRUE); icn.flags |= wimp_ISELECTED; break; case dbox_RESETSTATE: if (!selected) return (FALSE); icn.flags &= ~wimp_ISELECTED; break; case dbox_TOGGLESTATE: icn.flags ^= wimp_ISELECTED; break; } wimpt_noerr(wimp_set_icon_state ( d->wind, f, icn.flags & wimp_ISELECTED, wimp_ISELECTED )); return (selected); } /* * BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a) * * Use * This call will read the icon's state of shading and return it, and * optionally alter it as specified in the dbox_action parameter. * * Parameters * dbox d == the dbox handle * dbox_field f == the field you're interested in * dbox_action a == what you want to do with it */ BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a) { BOOL shaded; /* The old value of the shading */ BOOL shade; /* Whether to shade the icon */ wimp_icon *icn=dbox__idef(d,f); /* Find the icon in the window def */ wimp_icon real; wimp_caretstr c; /* --- Get the current shading state --- */ wimpt_noerr(wimp_get_icon_info(d->wind,f,&real)); if (wimpt_options() & wimpt_ONOWIMPSHADE) shaded=!!(icn->flags & wimp_INOSELECT); else shaded=!!(real.flags & wimp_INOSELECT); /* --- Find the new shading state --- */ switch (a) { case dbox_SETSTATE: shade=TRUE; break; case dbox_RESETSTATE: shade=FALSE; break; case dbox_TOGGLESTATE: shade=!shaded; break; case dbox_READSTATE: default: shade=shaded; break; } /* --- If there's nothing to do, then don't do it --- */ if (shade==shaded) return (shaded); /* --- Do appropriate things to the icon --- */ if (wimpt_options() & wimpt_ONOWIMPSHADE) { wimp_iconflags old; wimp_iconflags new; int contents; int fhandle; if (shade) { old=new=real.flags; contents=old & 3; if (wimp_readsysinfo(wimp_IFONTHANDLE,&fhandle)) fhandle=0; if (fhandle && (contents&wimp_ISPRITE)) contents&=~wimp_ITEXT; if (contents!=wimp_ITEXT) new=new | 0x00400000; if (contents & wimp_ITEXT) new=(new & ~0x0f1ff000) | 0x021f0000; icn->flags=old | 0x00400000; wimpt_noerr(wimp_set_icon_state(d->wind,f,new,0xffffffff)); } else { icn->flags = (icn->flags & 0x0f1ff000) | (real.flags & 0xf0a00fff); wimpt_noerr(wimp_set_icon_state(d->wind,f,icn->flags,0xffffffff)); } if (wimpt_options() & wimpt_OSCULPTRIX) wimpt_noerr(sculptrix_updateIcon(d->wind,f)); } else wimpt_noerr(wimp_set_icon_state(d->wind,f,shade<<22,0x00400000)); if (shade) { wimpt_noerr(wimp_get_caret_pos(&c)); if (c.w==d->wind && c.i==f) { c.i=-1; c.x=-500000; wimpt_noerr(wimp_set_caret_pos(&c)); } } /* --- Now return the original value --- */ return (shaded); } /* * wimp_w dbox_syshandle(dbox d) * * Use * Returns the window handle used by the dbox specified, because your poor * underprivileged code can't access my nice data structure. This is for * setting up things like calls to event_attachmenu and suchlike, which * don't know about cunning things like dboxes. * * Parameters * dbox d == the dbox you're interested in * * Returns * The window handle, which is a wimp_w */ wimp_w dbox_syshandle(dbox d) { return (d->wind); } /* * int dbox_getNumeric(dbox d,dbox_field f) * * Use * Reads an integer from a field. If there is no semblance to a valid * integer, 0 is returned. * * Parameters * dbox d == the dbox handle * dbox_field f == the field to read from */ int dbox_getNumeric(dbox d,dbox_field f) { int val; dbox_scanfield(d,f,"%d",&val); return (val); } /* * void dbox_setNumeric(dbox d,dbox_field f,int val) * * Use * Writes the integer value specified into the field. * * Parameters * dbox d == the dbox handle * dbox_field f == the field to set * int val == the integer value to write */ void dbox_setNumeric(dbox d,dbox_field f,int val) { dbox_setfield(d,f,"%i",val); } /* * dbox_field dbox_helpField(void) * * Use * Returns field number that Help is interested in. * * Returns * Field number. */ dbox_field dbox_helpField(void) { wimp_eventstr *e=wimpt_last_event(); int icon; int win; wimp_icon icn; if (help_wasHelp()) { win=e->data.msg.data.helprequest.m.w; icon=e->data.msg.data.helprequest.m.i; wimpt_noerr(wimp_get_icon_info(win,icon,&icn)); if ((wimpt_options() & wimpt_ONOWIMPSHADE) && (icn.flags & 0x001f0000) == 0x001f0000) return (-1); else return (icon); } else werr ( TRUE, msgs_lookup("dboxHFE:(dbox_helpField, caller fault): " "Not called on HELPREQUEST event.") ); return (0); } /*----- Routines for Elite-style monologue boxes --------------------------*/ /* * void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag) * * Use * Gives the specified dialogue box an inbuilt title (in a group box, round * the outside, as seen in Elite). This is drawn automatically normally, * but raw event handlers might want to do extra drawing, so the entry * point to the redraw code is also supplied. * * Parameters * dbox d == the dialogue box to do this to * dbox_field icon == the icon around which the title is to be drawn * BOOL moveDrag == allow a click on any of the dialogue box to move it */ void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag) { d->titleIcon=icon; d->moveDrag=moveDrag; } /* * void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle) * * Use * Redraws an embedded title (as seen in Elite). This is for the use of * raw event handlers, which might want to do this sort of thing, because * the redraw is normally handled automatically. * * Parameters * wimp_redrawstr *r == the redraw information I need * void *handle == a dbox, really. This is for passing to wimpt_redraw. */ void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle) { dbox d=handle; char *t=d->windDef->title.indirecttext.buffer; wimp_icon title; wimp_icon border; int len; if (d->titleIcon==-1) return; for (len=0;t[len]>31;len++) /* blank */ ; if (wimpt_options() & wimpt_OSCULPTRIX) { /* --- We've got Sculptrix, so do a really good job --- * * * Since Sculptrix can do proper ridge/plinth intersections, we use this * in preference. * * It now does the whole job in one go. */ sculptrix_plotGroupBox(dbox__idef(d,d->titleIcon),r,0,t); return; } border.box=dbox__idef(d,d->titleIcon)->box; border.flags=wimp_ITEXT | wimp_INDIRECT; title.box.x0=border.box.x0+16; title.box.y0=border.box.y1-20; title.box.x1=border.box.x0+32+wimpt_stringWidth(t); title.box.y1=border.box.y1+28; title.flags=wimp_ITEXT | wimp_INDIRECT | wimp_IFILLED | wimp_IHCENTRE | 0x17000000; title.data.indirecttext.buffer=t; title.data.indirecttext.bufflen=len+1; if (wimpt_options() & wimpt_OINTERFACE) { /* --- We can make do with Interface, although it isn't as nice --- * * * Interface makes a passable job at ridge-and-plinth group borders, * though they're not as nice as Sculptrix's, because the ridged border * doesn't intersect the title plinth properly. */ border.data.indirecttext.validstring="Z1,0,0,4,0"; title.data.indirecttext.validstring="Z0,0,0,4,0"; _swi(XInterface_Plot3dIcon,_inr(0,1),r,&title); _swi(XInterface_Plot3dIcon,_inr(0,1),r,&border); } else { /* --- Use RISC OS 3 borders if available --- * * * If not, RISC OS 2 will just plot a black border, which should look OK * although not as nice. Note that we can't do the STASIS-conforming * ridge-and-plinth group box, although a channel will do at a pinch. */ border.box.x0-=8; border.box.y0-=8; border.box.x1+=8; border.box.y1+=8; border.flags |= wimp_IBORDER; border.data.indirecttext.validstring="r4"; border.data.indirecttext.buffer=""; border.data.indirecttext.bufflen=1; title.data.indirecttext.validstring=(char *)-1; wimp_ploticon(&border); } wimp_ploticon(&title); } /* * BOOL dbox_hasTitle(dbox d) * * Use * Returns TRUE if the given dialogue box has a window title bar. * * Parameters * dbox d == the dialogue box to check * * Returns * TRUE if the dialogue box has a title bar */ BOOL dbox_hasTitle(dbox d) { return (!!(d->windDef->flags & wimp_WTITLE)); }