/* * viewer * Allows creation of Filer-like windows which rearrange themselves. * * v. 1.00 (13 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. */ #include "wimp.h" #include "wimpt.h" #include "win.h" #include "viewer.h" #include "msgs.h" #include "bbc.h" #include "werr.h" #include "os.h" #include "xfersend.h" #include "mem.h" #include "coords.h" #include "utils.h" #include "help.h" #include "fileicon.h" #include "buffer.h" #include "swis.h" #include #include #include #include "dll.h" #ifndef _dll_NODLL extern void _dllEntry(viewer__events)(wimp_eventstr *e,void *handle); #endif /* * A structure of information about a viewer icon. */ typedef struct viewer__iconstr { viewer_icon next; viewer_icon last; char *text; char sprite[15]; void *handle; int filetype; BOOL selected; viewer v; } viewer__iconstr; /* * A structure of information about a viewer window. */ typedef struct viewer__viewerstr { wimp_w wind; int icons; viewer_eventhandler events; void *closeHandle; viewer_raweventhandler rawEvents; void *rawHandle; viewer_redrawhandler rdr; void *rdrHandle; viewer_compare cmp; sprite_area *spr; int width; int height; int across; int down; int selected; char banner[50]; char title[256]; viewer_icon iconlist; viewer_icon menuSel; wimp_openstr oldSize; } viewer__viewerstr; /* * Some constants for the things */ #define viewer__MINWIDTH 380 #define viewer__MINHEIGHT 160 #define viewer__GAP 16 #define viewer__BANNERHEIGHT 48 static viewer_saveproc viewer__usersave; static viewer_sendproc viewer__usersend; static viewer_printproc viewer__userprint; static viewer_icon viewer__currentIcon; static viewer viewer__currentViewer; static int viewer__filetype; #define max(x,y) ((x)>(y) ? (x) : (y)) #define min(x,y) ((x)<(y) ? (x) : (y)) /* * void viewer__resize(viewer v) * * Use * Resizes the viewer nicely, altering the extent if necessary. * * Parameters * viewer v == the viewer handle */ static void viewer__resize(viewer v) { wimp_wstate s; int w; int across; int down; int minw; int scw; int maxacc; wimp_redrawstr r; wimpt_noerr(wimp_get_wind_state(v->wind,&s)); w=s.o.box.x1-s.o.box.x0; scw=wimpt_scwidth()-40; across=w/(v->width+viewer__GAP); maxacc=scw/(v->width+viewer__GAP); if (across>v->icons) across=v->icons; if (maxacc>v->icons) maxacc=v->icons; if (across>maxacc) across=maxacc; if (across==0) across=1; down=v->icons/across; if (v->icons%across!=0) down++; if (down==0) down=1; if (v->across==across && v->down==down && (s.flags & wimp_WOPEN)) return; minw=wimpt_stringWidth(v->title)+164; if (v->banner[0]!='\0') { int l=wimpt_stringWidth(v->banner)+64; if (l>minw) minw=l; } if (minwwind; r.box.x0=0; r.box.y0=-(v->height+viewer__GAP)*down; if (v->banner[0]!='\0') r.box.y0-=viewer__BANNERHEIGHT; if (r.box.y0>-viewer__MINHEIGHT) r.box.y0=-viewer__MINHEIGHT; r.box.x1=(v->width+viewer__GAP)*maxacc; if (r.box.x1across=across; v->down=down; } /* * void viewer__redrawicon(wimp_redrawstr *r,viewer_icon icn,wimp_box *box) * * Use * Redraws an icon in the box specified. * * Parameters * viewer_icon icn == the icon to redraw * wimp_box *box == the box to draw it in */ static void viewer__redrawicon ( wimp_redrawstr *r, viewer_icon icn, wimp_box *box ) { wimp_icon i; char valid[256]; viewer v=icn->v; if (v->rdr) { (v->rdr)(icn,r,box,icn->text,icn->sprite,icn->selected,v->rdrHandle); return; } i.box=*box; if (icn->text!=0 && icn->sprite[0]!='\0') { i.flags=wimp_ITEXT|wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE; sprintf(valid,"S%s",icn->sprite); i.data.indirecttext.buffer=icn->text; i.data.indirecttext.validstring=valid; i.data.indirecttext.bufflen=1; } else if (icn->text!=0) { i.flags=wimp_ITEXT|wimp_INDIRECT|wimp_IHCENTRE|wimp_IVCENTRE; i.data.indirecttext.buffer=icn->text; i.data.indirecttext.validstring=(char *)-1; i.data.indirecttext.bufflen=1; } else { i.flags=wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE|wimp_IVCENTRE; i.data.indirectsprite.name=icn->sprite; i.data.indirectsprite.spritearea=v->spr; i.data.indirectsprite.nameisname=TRUE; } i.flags|=0x17000000; if (icn->selected) i.flags|=wimp_ISELECTED; wimpt_noerr(wimp_ploticon(&i)); } /* * void viewer_drawFileIcons * ( * viewer_icon icn, * wimp_redrawstr *r, * wimp_box *box, * char *text, * char *sprite, * BOOL selected, * void *handle * ) * * Use * Redraw handler which takes into account filetypes of icons. The icons * automatically get new sprites if the sprites for their filetypes change. * For applications, the text is considered to be a filename. Register * this function using viewer_redrawHandler(). * * Parameters * viewer_icon icn == the icon to paint * wimp_redrawstr *r == information about this redraw * wimp_box *box == the box to draw the icon in * char *text == the text to display * char *sprite == the sprite to display * BOOL selected == is the icon selected? * void *handle == a caller defined handle (ignored) */ void viewer_drawFileIcons ( viewer_icon icn, wimp_redrawstr *r, wimp_box *box, char *text, char *sprite, BOOL selected, void *handle ) { wimp_icon i; char valid[256]; handle=handle; r=r; i.box=*box; i.flags=wimp_ITEXT|wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE; if (icn->filetype!=-1) sprintf(valid,"S%s",fileicon_spriteName(icn->filetype,text)); else sprintf(valid,"S%s",sprite); i.data.indirecttext.buffer=text; i.data.indirecttext.validstring=valid; i.data.indirecttext.bufflen=1; i.flags|=0x17000000; if (selected) i.flags|=wimp_ISELECTED; wimpt_noerr(wimp_ploticon(&i)); } /* * viewer__redraw(wimp_redrawstr *r,void *handle) * * Use * Redraws a viewer window * * Parameters * wimp_redrawstr *r == the bit to redraw * void *handle == the viewer */ static void viewer__redraw(wimp_redrawstr *r,void *handle) { viewer v=(viewer)handle; viewer_icon icn=v->iconlist; int oy=r->box.y1-r->scy; int x=viewer__GAP/2; int y=-viewer__GAP/2; wimp_box box; coords_cvtstr c; wimp_box g; int cnt=0; wimp_icon banicn={28,-48,1000,0,0x037000131}; c.box=r->box; c.scx=r->scx; c.scy=r->scy; g=r->g; coords_box_toworkarea(&g,&c); wimp_setcolour(0x81); bbc_clg(); if (v->banner[0]!='\0') { if (g.y1>-viewer__BANNERHEIGHT) { wimp_setcolour(3); bbc_rectanglefill ( r->g.x0, oy-viewer__BANNERHEIGHT, r->g.x1-r->g.x0, viewer__BANNERHEIGHT ); wimp_setcolour(7); banicn.box.x1=100+wimpt_stringWidth(v->banner); banicn.data.indirecttext.buffer=v->banner; banicn.data.indirecttext.validstring=(char *)-1; wimpt_noerr(wimp_ploticon(&banicn)); } y-=viewer__BANNERHEIGHT; } while (icn) { box.x0=x; box.x1=x+v->width; box.y1=y; box.y0=y-v->height; if (coords_boxesoverlap(&box,&g)) viewer__redrawicon(r,icn,&box); icn=icn->next; if ((++cnt)==v->across) { x=viewer__GAP/2; y-=viewer__GAP+v->height; cnt=0; } else x+=viewer__GAP+v->width; } } /* * void viewer__events(wimp_eventstr *e,void *handle) * * Use * Window event handler for the viewer. * * Parameters * wimp_eventstr *e == the wimp event structure * void *handle == my data (i.e. a 'this' pointer to my viewer__viewerstr) */ _dll_static void viewer__events(wimp_eventstr *e,void *handle) { BOOL handled=FALSE; viewer v=(viewer)handle; wimp_wstate s; if (v->rawEvents) handled=(v->rawEvents)(v,e,v->rawHandle); if (handled) return; switch (e->e) { case wimp_EREDRAW: wimpt_redraw(viewer__redraw,v); break; case wimp_EOPEN: if (wimpt_justChangedMode()) viewer_settitle(v,0); wimpt_noerr(wimp_get_wind_state(v->wind,&s)); wimpt_noerr(wimp_open_wind(&e->data.o)); viewer__resize(v); if (s.flags & wimp_WCLICK_TOGGLE) { if (s.flags & wimp_WFULL) { e->data.o.box=v->oldSize.box; e->data.o.x=v->oldSize.x; e->data.o.y=v->oldSize.y; wimpt_noerr(wimp_open_wind(&e->data.o)); } else v->oldSize=s.o; } break; case wimp_ECLOSE: if (v->events) (v->events)(v,viewer_CLOSE,(wimp_bbits)0,v->closeHandle,0); break; case wimp_EBUT: { viewer_icon i=viewer_iconFromCoords ( v, e->data.but.m.x, e->data.but.m.y ); if (v->events) { (v->events) ( v, i, e->data.but.m.bbits, v->closeHandle, (i!=viewer_NOICON) ? i->handle : 0 ); } } break; case wimp_EKEY: wimpt_noerr(wimp_processkey(e->data.key.chcode)); break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e->data.msg.hdr.action) { case wimp_MHELPREQUEST: { viewer_icon i=viewer_iconFromCoords ( v, e->data.msg.data.helprequest.m.x, e->data.msg.data.helprequest.m.y ); if (v->events) { (v->events) ( v, viewer_HELP, 0, v->closeHandle, (i!=viewer_NOICON) ? i->handle : 0 ); } } break; } break; } } /* * viewer viewer_create * ( * int x, * int y, * int width, * int height, * sprite_area *spr, * char *title, * char *banner * ) * * Use * Creates a viewer window. Note that viewer windows don't need templates, * and don't contain real wimp icons, just yer normal redrawn-by- * application things (which can be handled by a caller-defined function if * necessary). The banner along the top is optional - if a null pointer is * passed, no banner is included. The sprite area passed applies to all * the icons in the window, although if you want to, you can use your own * redraw routine to handle different sprite areas for them. * * Parameters * int x,int y == the coordinates of the top-left corner of the window * (file windows for editors need good positioning here). * int width == the width of an icon * int height == the height of an icon * sprite_area *spr == the sprite area for the window * char *title == the title of the window * char *banner == the banner heading along the top (like 'Sprite file * window' or something) * * Returns * A handle to the viewer window. As usual, a NULL pointer indicates * something went wrong. */ viewer viewer_create ( int x, int y, int width, int height, sprite_area *spr, char *title, char *banner ) { viewer v=(viewer)mem_alloc(sizeof(viewer__viewerstr)); wimp_wind w= { {0,0,0,0}, 0,0, -1, ( wimp_WMOVEABLE | wimp_WBACK | wimp_WQUIT | wimp_WTITLE | wimp_WTOGGLE | wimp_WVSCR | wimp_WSIZE | wimp_WNEW ), {7,2,7,255,3,1,12,0}, {0,0,0,0}, wimp_ITEXT|wimp_IHCENTRE|wimp_INDIRECT, wimp_IBTYPE*wimp_BCLICKDRAGDOUBLE, 0, 1, "Yay", 0 }; w.box.x0=x; w.box.x1=x+900-(900%(width+viewer__GAP)); if (w.box.x1==x) w.box.x1=x+width+viewer__GAP; w.box.y0=y-500+(500%(height+viewer__GAP)); if (w.box.y0==y) w.box.y0=y-height+viewer__GAP; w.box.y1=y; w.spritearea=(void *)spr; if (!v) { werr(FALSE,msgs_lookup("viewerNEM:Not enough room to create viewer.")); return (0); } w.title.indirecttext.buffer=v->title; w.title.indirecttext.validstring=(char *)-1; w.title.indirecttext.bufflen=256; strcpy(v->title,title); if (banner) { strcpy(v->banner,banner); w.box.y0-=viewer__BANNERHEIGHT; } else v->banner[0]='\0'; v->icons=0; v->events=0; v->rawEvents=0; v->rdr=0; v->cmp=0; v->iconlist=0; v->width=width; v->height=height; v->spr=spr; v->across=-1; v->selected=0; v->menuSel=viewer_NOICON; v->oldSize.box=w.box; v->oldSize.x=w.scx; v->oldSize.y=w.scy; if (wimp_create_wind(&w,&v->wind)) { werr ( FALSE, msgs_lookup("viewerTMW:Too many windows - " "%s could not create viewer."), wimpt_programname() ); mem_free(v); return (0); } win_register_event_handler(v->wind,_dllEntry(viewer__events),v); win_activeinc(); return (v); } /* * void viewer_display(viewer v) * * Use * Displays a viewer on the screen. * * Parameters * viewer v == the viewer handle */ void viewer_display(viewer v) { wimp_wstate state; viewer__resize(v); wimpt_noerr(wimp_get_wind_state(v->wind,&state)); state.o.behind=-1; wimpt_noerr(wimp_open_wind(&state.o)); } /* * void viewer_hide(viewer v) * * Use * Hides an open viewer. * * Parameters * viewer v == the handle */ void viewer_hide(viewer v) { wimpt_noerr(wimp_close_wind(v->wind)); } /* * void viewer_delete(viewer v,void (*freeProc)(void *handle)) * * Use * Zaps a viewer and everything in it. The function you pass to this * routine is called with every icon handle the viewer has associated with * it, so you don't need to link all the structures together - I've already * done that here! * * Parameters * viewer v == the viewer to destroy * void (*freeProc)(void *handle) == a function to free one of the caller- * defined viewer icon structures. */ void viewer_delete(viewer v,void (*freeProc)(void *handle)) { viewer_icon icn=v->iconlist; viewer_icon i; while (icn) { if (icn->handle && freeProc) freeProc(icn->handle); i=icn; icn=i->next; mem_free(i->text); mem_free(i); } win_register_event_handler(v->wind,0,0); win_activedec(); wimpt_noerr(wimp_delete_wind(v->wind)); mem_free(v); } /* * void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle) * * Use * Attaches an event handler to the viewer. The handle passed to this * function is only used for close events, so you can take appropriate * action at the other end. Otherwise, the handle for the icon concerned * is used. Suggested code: * * void user_viewer(viewer v,viewer_icon i,wimp_bbits b,void *handle) * { * user_fileStructure *file=(user_fileStructure *)handle; * user_itemStructure *item=(user_itemStructure *)handle; * switch ((int)i) * { * case (int)viewer_CLOSE: * ... use 'file' for this bit of code ... * break; * case viewer_NOICON: * ... use 'file' for this bit as well ... * break; * default: * ... use 'item' for this bit of code ... * break; * } * } * * Parameters * viewer v == the viewer to attach the handler to * viewer_eventhandler proc == the event handler * void *handle == the handle */ void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle) { v->events=proc; v->closeHandle=handle; } /* * void viewer_rawEventHandler * ( * viewer v, * viewer_raweventhandler proc, * void *handle * ) * * Use * Attaches a raw event handler to a viewer. Same as always, this one. * * Parameters * viewer v == the viewer handle * viewer_raweventhandler proc == the handler routine * void *handle == the handle for the user's data */ void viewer_rawEventHandler ( viewer v, viewer_raweventhandler proc, void *handle ) { v->rawEvents=proc; v->rawHandle=handle; } /* * void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle) * * Use * Adds in a user-defined routine for redrawing icons in the window. * * Parameters * viewer v == the viewer handle * viewer_redrawhandler proc == the routine for doing the redraw * void *handle == a handle to be passed to the routine (a sprite area or * something) */ void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle) { v->rdr=proc; v->rdrHandle=handle; } /* * void viewer_setIconSize(viewer v,int width,int height) * * Use * Sets a new icon size for the viewer. This would normally be * accompanied by a chnge in redraw handler. It would be used e.g. when * using a menu option giving a choice between 'Large icons' and 'Small * icons'. * * Parameters * viewer v == the viewer which is to receive this change * int width == the new width * int height == the new height */ void viewer_setIconSize(viewer v,int width,int height) { v->width=width; v->height=height; v->across=-1; viewer__resize(v); } /* * void viewer_setCompare(viewer v,viewer_compare cmp) * * Use * Registers a compare function for the viewer specified. The function * is passed the caller-defined handles of two icons. The function must * return <0 if a0 if a>b, or ==0 if a==b (like strcmp does). The * viewer's icons are then resorted. Pass 0 to use the default sorting * system (a caseless compare on the icon text) * * The resorting algorithm is the link mergesort, originally implemented * in the Sapphire linklist manager. * * Parameters * viewer v == the viewer we're going to set the comparer up for * viewer_compare cmp == the function to do comparing */ void viewer_setCompare(viewer v,viewer_compare cmp) { v->cmp=cmp; if (!v->icons) return; v->across=-1; viewer__resize(v); /* --- Now we have to resort the list --- * * * This code is pretty much based on the mergesort code printed in * Sedgewick's Algorithms. */ #define next(p) ((p) ? (p)->next : (p)) { viewer_icon a,b,c,t,todo,x,y; int i,n,more; n=1; c=v->iconlist; do { todo=v->iconlist; more=FALSE; c=(viewer_icon)&v->iconlist; while (todo) { t=todo; a=t; if (a!=v->iconlist) more=TRUE; for (i=1;icmp) i=(v->cmp)(a->handle,b->handle); else i=utils_caselessCmp(a->text,b->text); if (i<=0) { c->next=a; c=a; a=next(a); } else { c->next=b; c=b; b=next(b); } } } c->next=0; n*=2; } while (more); } #undef next /* --- Now we have to sort out the back links --- */ { viewer_icon a=v->iconlist; a->last=0; while (a->next) { a->next->last=a; a=a->next; } } } /* * viewer_icon viewer_addIcon * ( * viewer v, * char *text, * char *sprite, * BOOL inOrder, * void *handle * ) * * Use * Adds a new icon to a viewer window. * * Parameters * viewer v == the handle of the viewer to use. * char *text == the text to put under the icon (may be null) * char *sprite == the sprite to use (may be null) * BOOL inOrder == whether you want the icons sorted into order according * to the text fields * void *handle == the handle you want to pass to the event handler routine * * Returns * A handle to the icon. If this is NULL, something went majorly wrong * (sorry, John) */ viewer_icon viewer_addIcon ( viewer v, char *text, char *sprite, BOOL inOrder, void *handle ) { viewer_icon icn=(viewer_icon)&(v->iconlist); viewer_icon new=(viewer_icon)mem_alloc(sizeof(viewer__iconstr)); if (!new) { werr(FALSE,msgs_lookup("viewerCCI:Not enough room to create new icon.")); return (0); } if (text) { if (new->text=mem_alloc(strlen(text)+1),!new->text) { mem_free(new); werr ( FALSE, msgs_lookup("viewerCCI:Not enough room to create new icon.") ); return (0); } strcpy(new->text,text); } else new->text=0; if (sprite) strcpy(new->sprite,sprite); else new->sprite[0]='\0'; while (icn->next) { if (v->cmp) { if ((v->cmp)(icn->next->handle,handle)>0 && inOrder==TRUE) break; } else { if (utils_caselessCmp(icn->next->text,text)>0 && inOrder==TRUE) break; } icn=icn->next; } new->next=icn->next; new->last=icn; icn->next=new; if (new->next) new->next->last=new; new->handle=handle; new->v=v; new->selected=FALSE; new->filetype=-1; v->icons++; v->across=-1; viewer__resize(v); return (new); } /* * void viewer_setFiletype(viewer_icon i,int type) * * Use * Sets the filetype of the icon - useful for bins and things. This * filetype overrides the setting given to viewer_exportSelected(). It can * also be used to display the correct icon in the viewer by changing the * redraw handler to viewer_drawFileIcons(). * * Parameters * viewer_icon i == the icon to change * int type == the filetype to give it (any valid WIMP filetype will do) */ void viewer_setFiletype(viewer_icon i,int type) { i->filetype=type; } /* * int viewer_readFiletype(viewer_icon i) * * Use * Returns the filetype attached to an icon. * * Parameters * viewer_icon i == the icon handle * * Returns * The type attached using viewer_setFiletype(), or -1 if none. */ int viewer_readFiletype(viewer_icon i) { return (i->filetype); } /* * viewer_icon viewer_findIcon(viewer v,char *text) * * Use * Searches through a viewer to find an icon with the same text as 'text'. * The search is case-insensitive. * * Parameters * viewer v == the viewer handle * char *text == text to search for * * Returns * The icon handle, or viewer_NOICON if unsuccessful. */ viewer_icon viewer_findIcon(viewer v,char *text) { viewer_icon i=v->iconlist; while (i) { if (utils_caselessCmp(text,i->text)==0) return (i); i=i->next; } return (viewer_NOICON); } /* * void viewer_removeIcon(viewer_icon i) * * Use * Removes the icon specified. This routine is real easy! * * Parameters * viewer_icon i == the icon to remove (they ALL have unique handles, so * this is OK) */ void viewer_removeIcon(viewer_icon i) { viewer v=i->v; if (i->selected) v->selected--; if (i->last) i->last->next=i->next; else v->iconlist=i->next; if (i->next) i->next->last=i->last; mem_free(i->text); mem_free(i); v->icons--; v->across=-1; v->menuSel=viewer_NOICON; viewer__resize(v); } /* * wimp_w viewer_syshandle(viewer v) * * Use * Returns the WIMP window handle used for the viewer (and much use may it * do you!) * * Parameters * viewer v == the viewer handle * * Returns * The wimp_w window handle */ wimp_w viewer_syshandle(viewer v) { return (v->wind); } /* * viewer_icon viewer_iconFromCoords(viewer v,int x,int y) * * Use * Given a set of (absolute) coordinates, this returns the icon in the * viewer specified that the point is on. This is mainly useful for menu * maker routines, which will want to be able to select items and so on. * * Parameters * viewer v == the viewer handle * int x == the x-coordinate of the point * int y == the y-coordinate of the point * * Returns * The icon handle, or viewer__NOICON if there isn't one. */ viewer_icon viewer_iconFromCoords(viewer v,int x,int y) { wimp_wstate s; int ix,iy; int i; int cnt; viewer_icon icn=v->iconlist; wimpt_noerr(wimp_get_wind_state(v->wind,&s)); x-=(s.o.box.x0-s.o.x); y-=(s.o.box.y1-s.o.y); y=-y; if (v->banner[0]!='\0') y-=viewer__BANNERHEIGHT; ix=x/(v->width+viewer__GAP); x-=(v->width+viewer__GAP)*ix; if (xv->width || ix>=v->across) return (viewer_NOICON); iy=y/(v->height+viewer__GAP); y-=(v->height+viewer__GAP)*iy; if (yv->height || iy>=v->down) return (viewer_NOICON); i=ix+iy*v->across; if (i>=v->icons) return (viewer_NOICON); for (cnt=0;cntnext; } return (icn); } /* * void viewer_iconToCoords(viewer_icon i,wimp_box *box) * * Use * Calculates the bounding box of the icon given. If there is an error, * nothing is written in the block. * * Parameters * viewer_icon i == the icon we're interested in * wimp_box *box == where to store the coordinates */ void viewer_iconToCoords(viewer_icon i,wimp_box *box) { int x,y; viewer v=i->v; BOOL end=FALSE; viewer_icon icn=v->iconlist; wimp_wstate s; wimpt_noerr(wimp_get_wind_state(v->wind,&s)); x=y=0; while (!end) { if (icn==0) return; if (icn==i) end=TRUE; else { if ((++x)==v->across) { x=0; y++; } } icn=icn->next; } box->x0=s.o.box.x0-s.o.x+viewer__GAP/2+(viewer__GAP+v->width)*x; box->x1=box->x0+v->width; box->y1=s.o.box.y1-s.o.y-viewer__GAP/2-(viewer__GAP+v->height)*y; if (v->banner[0]!='\0') box->y1-=viewer__BANNERHEIGHT; box->y0=box->y1-v->height; } /* * BOOL viewer_isSelected(viewer_icon i) * * Use * Returns whether an icon is selected or not. * * Parameters * viewer_icon i == the icon handle * * Returns * TRUE if the icon is selected, or FALSE otherwise. */ BOOL viewer_isSelected(viewer_icon i) { return (i->selected); } /* * void viewer_selectIcon(viewer_icon i,BOOL onOrOff) * * Use * Selects or deselects the icon specified. * * Parameters * viewer_icon i == the icon handle * BOOL onOrOff == TRUE to select, FALSE to deselect */ void viewer_selectIcon(viewer_icon i,BOOL onOrOff) { wimp_redrawstr r; viewer v; wimp_wstate s; int ox,oy; wimp_box box; BOOL more; if (i==viewer_NOICON) return; v=i->v; if (i->selected!=onOrOff) { if (onOrOff) v->selected++; else v->selected--; } else return; i->selected=onOrOff; r.w=v->wind; viewer_iconToCoords(i,&box); wimpt_noerr(wimp_get_wind_state(v->wind,&s)); ox=s.o.box.x0-s.o.x; oy=s.o.box.y1-s.o.y; box.x0-=ox; box.y0-=oy; box.x1-=ox; box.y1-=oy; r.box=box; wimpt_noerr(wimp_update_wind(&r,&more)); while (more) { viewer__redrawicon(&r,i,&box); wimpt_noerr(wimp_get_rectangle(&r,&more)); } } /* * viewer viewer_iconToViewer(viewer_icon i) * * Use * Returns the viewer in which an icon is contained. * * Parameters * viewer_icon i == the icon handle * * Returns * The viewer handle. */ viewer viewer_iconToViewer(viewer_icon i) { return (i->v); } /* * void *viewer_iconHandle(viewer_icon i) * * Use * Returns the handle attached to the icon when it was created * * Parameters * viewer_icon i == the icon in question * * Returns * The handle attached */ void *viewer_iconHandle(viewer_icon i) { return (i->handle); } /* * char *viewer_textOfIcon(viewer_icon i) * * Use * Returns the text of the icon given. * * Parameters * viewer_icon i == the icon * * Returns * Pointer to the string (read only!). */ char *viewer_textOfIcon(viewer_icon i) { return (i->text); } /* * int viewer_selected(viewer v) * * Use * Informs caller how many icons are selected. * * Parameters * viewer v == the viewer handle * * Returns * The number of icons selected. */ int viewer_selected(viewer v) { return (v->selected); } /* * int viewer_icons(viewer v) * * Use * Returns the number of icons in a viewer. * * Parameters * viewer v == the viewer * * Returns * The number of icons. */ int viewer_icons(viewer v) { return (v->icons); } /* * void viewer_doForIcons * ( * viewer v, * BOOL onlySelected, * void (*proc)(viewer_icon i,void *handle) * ) * * Use * Does the same thing for either all the icons in a viewer, or just the * selected ones. * * Parameters * viewer v == the viewer handle * BOOL onlySelected == whether you want to handle just the selected ones, * or the whole lot. * void (*proc)(viewer_icon i,void *handle) == the routine to do whatever * it is you want to do. */ void viewer_doForIcons ( viewer v, BOOL onlySelected, void (*proc)(viewer_icon i,void *handle) ) { viewer_icon i=v->iconlist; viewer_icon next; while (i) { next=i->next; if (i->selected || !onlySelected) proc(i,i->handle); i=next; } } /* * void viewer__select(viewer_icon i,void *handle) * * Use * Selects an icon. * * Parameters * viewer_icon i == the icon handle * void *handle == a handle (ignored) */ static void viewer__select(viewer_icon i,void *handle) { handle=handle; viewer_selectIcon(i,TRUE); } /* * void viewer__deselect(viewer_icon i,void *handle) * * Use * Deselects an icon. * * Parameters * viewer_icon i == the icon handle * void *handle == a handle (ignored) */ static void viewer__deselect(viewer_icon i,void *handle) { handle=handle; viewer_selectIcon(i,FALSE); } /* * void viewer_selectAll(viewer v,BOOL onOrOff) * * Use * Selects or deselects all the icons in a viewer. * * Parameters * viewer v == the viewer handle * BOOL onOrOff == whether you want the icons to be on or off */ void viewer_selectAll(viewer v,BOOL onOrOff) { viewer_doForIcons(v,FALSE,onOrOff ? viewer__select : viewer__deselect); v->menuSel=viewer_NOICON; } /* * BOOL viewer__selectUnknowns(wimp_eventstr *e,void *handle) * * Use * Selects the icons inside the rubber-band box created, RISC OS 3-like. * * Parameters * wimp_eventstr *e == the event that I might be interested in * void *handle == a (useless) handle * * Returns * TRUE if the event was interesting. */ static BOOL viewer__selectUnknowns(wimp_eventstr *e,void *handle) { BOOL handled=FALSE; wimp_box b; wimp_wstate s; coords_cvtstr c; viewer v=viewer__currentViewer; wimp_box vib; int i; int x,y; viewer_icon icn=v->iconlist; handle=handle; switch (e->e) { case wimp_EUSERDRAG: wimpt_noerr(wimp_get_wind_state(v->wind,&s)); c.box=s.o.box; c.scx=s.o.x; c.scy=s.o.y; b.x0=min(e->data.dragbox.x0,e->data.dragbox.x1); b.y0=min(e->data.dragbox.y0,e->data.dragbox.y1); b.x1=max(e->data.dragbox.x0,e->data.dragbox.x1); b.y1=max(e->data.dragbox.y0,e->data.dragbox.y1); b.x0+=viewer__GAP/2; b.x1-=viewer__GAP/2; b.y0+=viewer__GAP/2; b.y1-=viewer__GAP/2; coords_box_toworkarea(&b,&c); if (v->banner[0]!='\0') coords_offsetbox(&b,0,viewer__BANNERHEIGHT,&b); vib.x0=b.x0/(v->width+viewer__GAP); vib.y0=(-b.y1)/(v->height+viewer__GAP); vib.x1=b.x1/(v->width+viewer__GAP); vib.y1=(-b.y0)/(v->height+viewer__GAP); if (b.y1>0) vib.y0=-1; if (b.y0>0) vib.y1=-1; handled=TRUE; win_remove_unknown_event_processor(viewer__selectUnknowns,0); for (i=0;icn!=0;i++,icn=icn->next) { x=i%(v->across); y=i/(v->across); if (x>=vib.x0 && x<=vib.x1 && y>=vib.y0 && y<=vib.y1) viewer_selectIcon(icn,TRUE); } break; } return (handled); } /* * void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b) * * Use * Handles a click on an icon just like clicks in Filer windows. * * Parameters * viewer v == the viewer handle * viewer_icon i == the icon that was clicked * wimp_bbits b == the mouse button status */ void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b) { viewer_icon icn=v->iconlist; switch (b) { case wimp_BCLICKRIGHT: if (i!=viewer_NOICON) { viewer_selectIcon(v->menuSel,FALSE); v->menuSel=viewer_NOICON; viewer_selectIcon(i,!(i->selected)); } break; case wimp_BCLICKLEFT: v->menuSel=viewer_NOICON; if (i->selected==FALSE || i==viewer_NOICON) { while (icn) { if (icn->selected) viewer_selectIcon(icn,FALSE); icn=icn->next; } viewer_selectIcon(i,TRUE); } break; case wimp_BDRAGLEFT: case wimp_BDRAGRIGHT: if (i==viewer_NOICON) { wimp_mousestr m; wimp_wstate s; wimp_dragstr d; wimpt_noerr(wimp_get_point_info(&m)); wimpt_noerr(wimp_get_wind_state(v->wind,&s)); d.window=v->wind; d.type=wimp_USER_RUBBER; d.box.x0=m.x; d.box.y0=m.y; d.box.x1=m.x+wimpt_dx(); d.box.y1=m.y+wimpt_dy(); d.parent=s.o.box; wimpt_noerr(wimp_drag_box(&d)); viewer__currentViewer=v; win_add_unknown_event_processor(viewer__selectUnknowns,0); } else { v->menuSel=viewer_NOICON; viewer_selectIcon(i,TRUE); } break; case wimp_BMID: if ((v->menuSel!=viewer_NOICON || v->selected==0) && v->menuSel!=i) { viewer_selectIcon(v->menuSel,FALSE); v->menuSel=i; viewer_selectIcon(v->menuSel,TRUE); } } } /* * char *viewer_menuItem(viewer v,char *header) * * Use * Returns a menu item of the form either "~
''", * "
''", or "Selection", for inclusion in a menu * string. * * Parameters * viewer v == the viewer handle * char *header == the header for the menu item * * Returns * A pointer to a read-only string. */ char *viewer_menuItem(viewer v,char *header) { char *buffer=buffer_find(); char *ret; switch (v->selected) { case 0: sprintf(buffer,"~%s ''",header); ret=buffer; break; case 1: { viewer_icon i=v->iconlist; while (i->selected==FALSE) { i=i->next; } sprintf(buffer,"%s '%s'",header,i->text); ret=buffer; } break; default: strcpy(buffer,msgs_lookup("viewerMIS:Selection")); ret=buffer; break; } return (ret); } /* * void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff) * * Use * Writes a menu item out as for the previous routine, but implants it * directly into the menu, so you don't need to fiddle about with things * like that, and also means that the menu pointer changes. The menu item * must have been previously set up with menu_redirectItem. This call will * also set the menu to the correct width. However, ensure that you call * menu_minWidth(m,0) before fiddling with the width! * * Parameters * viewer v == the viewer handle pertaining to this request * menu m == the menu to doctor * int i == the menu item * char *buff == where the menu item wants the data */ void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff) { char *t=viewer_menuItem(v,header); if (*t=='~') { t++; menu_setflags(m,i,FALSE,TRUE); } else menu_setflags(m,i,FALSE,FALSE); strcpy(buff,t); menu_minWidth(m,strlen(buff)); } /* * viewer_icon viewer_firstSelected(viewer v) * * Use * Returns the handle of the first selected icon. * * Parameters * viewer v == the viewer handle * * Returns * A handle to the first one, or viewer_NOICON. */ viewer_icon viewer_firstSelected(viewer v) { viewer_icon i=v->iconlist; while (i) { if (i->selected) return (i); i=i->next; } return (viewer_NOICON); } /* * void viewer_settitle(viewer v,char *title) * * Use * Changes a viewer's title, so that the extent is updated as well. * * Parameters * viewer v == the viewer handle * char *title == the new title string * (internal: may be 0 to indicate just to resize the viewer) */ void viewer_settitle(viewer v,char *title) { wimp_wstate s; int minw; int scw; int maxacc; wimp_redrawstr r; if (title) win_settitle(v->wind,"%s",title); wimpt_noerr(wimp_get_wind_state(v->wind,&s)); scw=wimpt_scwidth(); maxacc=scw/(v->width+viewer__GAP); if (maxacc>v->icons) maxacc=v->icons; minw=wimpt_stringWidth(v->title)+164; if (v->banner[0]!='\0') /* Bug fix */ { int l=wimpt_stringWidth(v->banner)+64; if (l>minw) minw=l; } if (minwwind; r.box.x0=0; r.box.y0=-(v->height+viewer__GAP)*v->down; if (v->banner[0]!='\0') r.box.y0-=viewer__BANNERHEIGHT; if (r.box.y0>-viewer__MINHEIGHT) r.box.y0=-viewer__MINHEIGHT; r.box.x1=(v->width+viewer__GAP)*maxacc; if (r.box.x1v; wimpt_noerr(wimp_get_point_info(&m)); r.r[0]=161; r.r[1]=28; wimpt_noerr(os_swix(XOS_Byte,&r)); /* Support DragASprite? */ if (wimpt_getVersion()>=300 && (r.r[2] & 2)) { r.r[0]=0xC5; d.box.x0=m.x-50; d.box.x1=m.x+50; d.box.y0=m.y-50; d.box.y1=m.y+50; if (v->selected==1) { if (icn->filetype==-1) { r.r[2]=(int)icn->sprite; r.r[1]=(int)v->spr; } else { r.r[2]=(int)fileicon_spriteName(icn->filetype,icn->text); r.r[1]=1; } } else { r.r[2]=(int)"package"; r.r[1]=1; if ((int)v->spr>1) { sid.s.name="package"; sid.tag=0; if (!sprite_select(v->spr,&sid)) r.r[1]=(int)v->spr; } } r.r[3]=(int)&d.box; wimpt_noerr(os_swix(XDragASprite_Start,&r)); return; } i=v->iconlist; while (i) { if (i->selected==TRUE) { viewer_iconToCoords(i,&box); if (started) { if (d.box.x0>box.x0) d.box.x0=box.x0; if (d.box.y0>box.y0) d.box.y0=box.y0; if (d.box.x1next; } d.box.x0-=viewer__GAP/2; d.box.y0-=viewer__GAP/2; d.box.x1+=viewer__GAP/2; d.box.y1+=viewer__GAP/2; d.window=0; d.type=wimp_USER_FIXED; d.parent.x0=d.box.x0-m.x; d.parent.y0=d.box.y0-m.y; d.parent.x1=scWidth-m.x+d.box.x1; d.parent.y1=scHeight-m.y+d.box.y1; wimpt_noerr(wimp_drag_box(&d)); } /* * The routines for the data transfer. */ static BOOL viewer__save(char *name,void *handle) { handle=handle; return ( viewer__usersave(viewer__currentIcon,name,viewer__currentIcon->handle) ); } static BOOL viewer__send(void *handle,int *maxbuf) { handle=handle; return ( viewer__usersend(viewer__currentIcon,viewer__currentIcon->handle,maxbuf) ); } static int viewer__print(char *filename,void *handle) { handle=handle; return ( viewer__userprint ( viewer__currentIcon, filename, viewer__currentIcon->handle ) ); } /* * void viewer__export(viewer_icon i,void *handle) * * Use * Exports each icon in turn. * * Parameters * viewer_icon i == the icon handle * void *handle == a handle to the user's data (ignored) */ static void viewer__export(viewer_icon i,void *handle) { wimp_eventstr e; handle=handle; viewer__currentIcon=i; e.e=wimp_EUSERDRAG; wimpt_fake_event(&e); xfersend ( i->filetype==-1 ? viewer__filetype : i->filetype, i->text, 1, viewer__usersave==0 ? 0 : viewer__save, viewer__usersend==0 ? 0 : viewer__send, viewer__userprint==0 ? 0 : viewer__print, &e, 0 ); } /* * BOOL viewer__unknowns(wimp_eventstr *e,void *handle) * * Use * Unknown event processor - handles the end of the drag operation. * * Parameters * wimp_eventstr *e == a pointer to the event. * void *handle == a handle to some data (ignored). * * Returns * Whether the event was interesting. */ static BOOL viewer__exportUnknowns(wimp_eventstr *e,void *handle) { BOOL handled=FALSE; wimp_mousestr m; handle=handle; switch (e->e) { case wimp_EUSERDRAG: wimpt_noerr(wimp_get_point_info(&m)); if (m.w!=viewer__currentViewer->wind) viewer_doForIcons(viewer__currentViewer,TRUE,viewer__export); handled=TRUE; win_remove_unknown_event_processor(viewer__exportUnknowns,0); break; } return (handled); } /* * void viewer_exportSelected * ( * viewer_icon icn, * wimp_bbits b, * int filetype, * viewer_saveproc save, * viewer_sendproc send, * viewer_printproc print * ) * * Use * Allows you to export the data connected with each selected icon to * another application. The filename used is the icon's text. * * Parameters * viewer_icon icn == the icon on which the user clicked to start the drag * operation. * wimp_bbits b == the mouse buttons which started this up. * int filetype == the filetype of the data. * viewer_saveproc save == the save routine (saving and * transfer. * viewer_sendproc send == the send routine (RAM transfer). * viewer_printproc print == the print routine (printing etc.) */ void viewer_exportSelected ( viewer_icon icn, wimp_bbits b, int filetype, viewer_saveproc save, viewer_sendproc send, viewer_printproc print ) { if (icn==viewer_NOICON) return; if (b!=wimp_BDRAGLEFT && b!=wimp_BDRAGRIGHT) return; viewer_dragSelected(icn,b); viewer__filetype=filetype; viewer__usersave=save; viewer__usersend=send; viewer__userprint=print; viewer__currentViewer=icn->v; win_add_unknown_event_processor(viewer__exportUnknowns,0); } /* * viewer_icon viewer_helpIcon(viewer v) * * Use * Informs the caller which icon the Help system is interested in. * * Parameters * viewer v == the viewer handle * * Returns * The icon's handle (or maybe viewer_NOICON) */ viewer_icon viewer_helpIcon(viewer v) { wimp_eventstr *e=wimpt_last_event(); if (help_wasHelp()) return ( viewer_iconFromCoords ( v, e->data.msg.data.helprequest.m.x, e->data.msg.data.helprequest.m.y ) ); else werr(TRUE,msgs_lookup("viewerVIE:(viewer_helpIcon, caller fault): " "Not called on HELPREQUEST event.")); return (0); }