/* * gSprite.c * * Handling of template file sprite windows and areas * * © 1994-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Glass. * * Glass 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. * * Glass 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 Glass. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*----- Header files ------------------------------------------------------*/ /* * ANSI standard headers */ #include #include /* * Steel headers */ #define _STDAPP #define _XFER #define _LOWLVL #include "steel/Steel.h" #include "steel/viewer.h" #include "steel/flex.h" #include "steel/akbd.h" #include "steel/bbc.h" #include "steel/choices.h" #include "steel/colourtran.h" /* * Glass headers */ #include "gStruct.h" #include "gMenus.h" #include "gIcons.h" #include "glass.h" #include "intMsgs.h" #include "gSprite.h" #include "gPrefs.h" #include "indir.h" #include "window.h" #include "tfile.h" /*----- Macros ------------------------------------------------------------*/ #define gSprite__FILEHEIGHT 872 /* Height to open first sprite window */ #define gSprite__FILEX 220 /* x position of sprite windows */ #define gSprite__FILETOP 920 /* Height after files wrap around */ #define gSprite__CHUNK 2048 /* Size in bytes to allocate areas by */ #define gSprite__WINDHEIGHT 852 /* Height for individual sprite window */ #define gSprite__WINDX 240 /* x position of individual sprite window */ #define gSprite__WINDTOP 900 /* Height after wrap around */ #define gSprite__WINDMINX 340 /* Minimum width of a sprite window */ #define gSprite__WINDMINY 150 /* Minimum height of a sprite window */ #define gSprite__BOXX 200 /* Size of the box for sprite display (x) */ #define gSprite__BOXY 148 /* Size of the box for sprite display (y) */ /*----- Type definitions --------------------------------------------------*/ typedef struct { glass_tfile *t; /* Template file owner */ int serial; /* Order the icons were created in */ char name[15]; /* Name of the sprite */ viewer_icon i; /* My viewer icon */ wimp_w w; /* My window handle */ } gSprite__data; /*----- Static variables --------------------------------------------------*/ static int gSprite__fileHeight=gSprite__FILEHEIGHT; /* Height to open next sprite window */ static int gSprite__windHeight=gSprite__WINDHEIGHT; static int gSprite__size; /* Count up sprite sizes */ static void **gSprite__flex; /* The flex block for saving selections */ static sprite_area *gSprite__default; /* Default sprite file */ static int gSprite__serial; /* Monotonic time counter */ static glass_tfile *gSprite__selOwner; /* Which window owns selection? */ /*----- Support routines --------------------------------------------------*/ /* * BOOL gSprite__getMemory(glass_tfile *t,int size) * * Use * Ensures that the specified quantity of memory is available in the sprite * area given. If the memory is not there, it is allocated and the pointer * is placed in the appropriate place. Messages are sent round as * applicable. * * Parameters * glass_tfile *t == the template file to alllcate memory in * int size == the quantity of memory required to add to the area * * Returns * TRUE if the operation succeeded, or FALSE for not enough memory available */ static BOOL gSprite__getMemory(glass_tfile *t,int size) { int aligned; sprite_area *s; if (t->s->freeoff+sizes->size) /* Check that the memory is there */ return (TRUE); aligned=(t->s->freeoff+size+gSprite__CHUNK-1) & ~(gSprite__CHUNK-1); /* Qunatise by the chunk size */ if (s=indir_realloc(t->s,aligned),!s) /* Allocate memory required */ return (FALSE); /* Say we failed if we did */ s->size=aligned; /* Insert the new sprite area size */ t->s=s; /* And change the pointers to the new one */ return (TRUE); } /* * void gSprite__minimise(glass_tfile *t) * * Use * Attempts to minimise the space taken up by template file t's sprite area * if wasteful operations took upn too much memory, or sprites have been * deleted. Ironically, this requires memory... However, failure to * allocate sufficient memory is ignored. * * Parameters * glass_tfile *t == the template file to minimise */ static void gSprite__minimise(glass_tfile *t) { sprite_area *s; int aligned=(t->s->freeoff+gSprite__CHUNK-1) & ~(gSprite__CHUNK-1); /* Get the size the area should be */ if (t->s->size==aligned) return; if (s=indir_realloc(t->s,aligned),!s) return; s->size=aligned; t->s=s; } /* * int gSprite__compare(void *a,void *b) * * Use * Compares creation times of two icons * * Parameters * both pointers to data attached to icons */ static int gSprite__compare(void *a,void *b) { gSprite__data *x=a; gSprite__data *y=b; return (x->serial-y->serial); } /* * void gSprite__gainSelection(glass_tfile *t) * * Use * Hands the current sprite selection and the input focus to the specified * template file sprite viewer. * * Note that the selection model here is more complex than it is in window, * since the focus tfile may not coincide with the selection owner (since * menu clicks move the selection owner, but not the focus). * * Parameters * glass_tfile *t == the sprite viewer to which we give the selection */ static void gSprite__gainSelection(glass_tfile *t) { wimp_caretstr c; if (t!=gSprite__selOwner) { if (gSprite__selOwner) viewer_selectAll(gSprite__selOwner->vs,FALSE); gSprite__selOwner=t; } if (t) { c.w=viewer_syshandle(t->vs); c.i=-1; c.x=-250; c.y=0; c.index=-1; c.height=0x02000000; wimpt_noerr(wimp_set_caret_pos(&c)); } } /* * void gSprite__closeWindows(void *handle) * * Use * Destroys any windows open when the template file dies * * Parameters * void *handle == pointer to window data */ static void gSprite__closeWindows(void *handle) { gSprite__data *d=handle; if (d->w) { win_register_event_handler(d->w,0,0); wimpt_noerr(wimp_delete_wind(d->w)); win_activedec(); } mem_free(d); } /* * void gSprite__sizes(viewer_icon i,void *handle) * * Use * Adds the size of the given sprite to the total in gSprite__size. * * Parameters * viewer_icon i == the icon number of the sprite (ignored) * void *handle == pointer to sprite data */ static void gSprite__sizes(viewer_icon i,void *handle) { sprite_id sid; sprite_header *hdr; gSprite__data *d=handle; unused(i); sid.s.name=d->name; sid.tag=0; wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr)); gSprite__size+=hdr->next; } /* * char *gSprite__lower(char *s) * * Use * Translates the string given to lower case * * Parameters * char *s == the string to convert * * Returns * A pointer to the string */ static char *gSprite__lower(char *s) { char *p=s; while (*p) { *p=tolower(*p); p++; } return (s); } /* * BOOL gSprite__saveArea(void *handle,char *filename) * * Use * Saves a sprite area to disk * * Parameters * char *filename == the filename to save to * void *handle == pointer to owning template file * * Returns * TRUE for success */ static BOOL gSprite__saveArea(char *filename,void *handle) { glass_tfile *t=handle; if (gPrefs_current()->cSave && saveas_file_is_safe() && res_fileExists(filename)) { if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename)) return (FALSE); } if (utils_complain(sprite_area_save(t->s,filename),msgs_lookup("spESS"))) return (FALSE); else return (TRUE); } /* * BOOL gSprite__sendArea(void *handle,int *maxbuf) * * Use * Sends a sprite area via RAM transfer * * Parameters * void *handle == pointer to owning template file * int *maxbuf == pointer to buffer size of other application */ static BOOL gSprite__sendArea(void *handle,int *maxbuf) { glass_tfile *t=handle; return (xfersend_sendBlock(&t->s->number,t->s->freeoff-4,maxbuf)); } /* * void gSprite__addToSelSave(viewer_icon i,void *handle) * * Use * Adds the given sprite to the sprite area held in gSprite__flex * * Parameters * viewer_icon i == the icon number of the sprite to add (ignored) * void *handle == pointer to sprite data */ static void gSprite__addToSelSave(viewer_icon i,void *handle) { gSprite__data *d=handle; sprite_header *hdr; sprite_id sid; void *p=charptr(*gSprite__flex,0)+ _ptr(sprite_area,*gSprite__flex,0)->freeoff; unused(i); sid.s.name=d->name; sid.tag=0; wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr)); memcpy(p,hdr,hdr->next); _ptr(sprite_area,*gSprite__flex,0)->freeoff+=hdr->next; } /* * BOOL gSprite__setupSelSave(glass_tfile *t,void **p) * * Use * Sets up a sprite area to save in a flex block anchored on p. The flex * block is allocaed here. The caller must free the block itself. * * Parameters * glass_tfile *t == the template file owning the selection * void **p == pointer to a flex anchor * * Returns * TRUE if successful */ static BOOL gSprite__setupSelSave(glass_tfile *t,void **p) { if (!flex_alloc(p,gSprite__size+16)) { werr(FALSE,msgs_lookup("spNEMSLSV")); return (FALSE); } gSprite__flex=p; _ptr(sprite_area,*p,0)->size=gSprite__size+16; _ptr(sprite_area,*p,0)->number=viewer_selected(t->vs); _ptr(sprite_area,*p,0)->freeoff=16; _ptr(sprite_area,*p,0)->sproff=16; viewer_doForIcons(t->vs,TRUE,gSprite__addToSelSave); return (TRUE); } /* * BOOL gSprite__saveSelection(char *filename,void *handle) * * Use * Saves a selection of sprite to a file * * Parameters * char *filename == the file to save to * void *handle == pointer to the owning template file * * Returns * TRUE for success */ static BOOL gSprite__saveSelection(char *filename,void *handle) { glass_tfile *t=handle; void *p; if (gPrefs_current()->cSave && saveas_file_is_safe() && res_fileExists(filename)) { if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename)) return (FALSE); } if (!gSprite__setupSelSave(t,&p)) return (FALSE); if (utils_complain(sprite_area_save((sprite_area *)p,filename), msgs_lookup("spESS"))) { flex_free(&p); return (FALSE); } else { flex_free(&p); return (TRUE); } } /* * BOOL gSprite__sendSelection(void *handle,int *maxbuf) * * Use * Sends a selection of sprite to another application in memory * * Parameters * void *handle == pointer to the owning template file * int *maxbuf == the size of the receiving application's buffer * * Returns * TRUE for success */ static BOOL gSprite__sendSelection(void *handle,int *maxbuf) { glass_tfile *t=handle; void *p; if (!gSprite__setupSelSave(t,&p)) return (FALSE); if (!xfersend_sendBlock((char *)p+4,gSprite__size+12,maxbuf)) { flex_free(&p); return (FALSE); } else { flex_free(&p); return (TRUE); } } /* * BOOL gSprite__saveGrabbed(void *handle,char *filename) * * Use * Saves a sprite area to disk * * Parameters * char *filename == the filename to save to * void *handle == pointer-to-pointer to sprite area * * Returns * TRUE for success */ static BOOL gSprite__saveGrabbed(char *filename,void *handle) { sprite_area **s=handle; if (gPrefs_current()->cSave && saveas_file_is_safe() && res_fileExists(filename)) { if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename)) return (FALSE); } if (utils_complain(sprite_area_save(*s,filename),msgs_lookup("spESS"))) return (FALSE); else return (TRUE); } /* * BOOL gSprite__sendGrabbed(void *handle,int *maxbuf) * * Use * Sends a sprite area via RAM transfer * * Parameters * void *handle == pointer-to-pointer to sprite area * int *maxbuf == pointer to buffer size of other application */ static BOOL gSprite__sendGrabbed(void *handle,int *maxbuf) { sprite_area **s=handle; return (xfersend_sendBlock(&(*s)->number,(*s)->freeoff-4,maxbuf)); } /* * void gSprite__grab(wimp_mousestr *m,void *handle) * * Use * Grabs a sprite area from a given window * * Parameters * wimp_mousestr *m == info about the window/icon the pointer is over * void *handle == a pointer (ignored) */ static void gSprite__grab(wimp_mousestr *m,void *handle) { wimp_winfo *w; os_regset r; void *p; void *q; sprite_area s; wimp_msgstr msg; unused(handle); switch (m->w) { case -1: case -2: werr(FALSE,msgs_lookup("spCGS")); return; } if (wimpt_getVersion()>=300) /* RISC OS 3 allows 'safe' GetWindowInfos */ w=mem_alloc(sizeof(wimp_winfo)); else w=mem_alloc(sizeof(wimp_winfo)+200*sizeof(wimp_icon)); if (!w) { werr(FALSE,msgs_lookup("spNEMGS")); return; } w->w=m->w; r.r[1]=(int)w; if (wimpt_getVersion()>=300) r.r[1]+=1; /* RO3 - only window header, not icons */ wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Get the information */ q=w->info.spritearea; /* Get the window's sprite area */ mem_free(w); /* No longer needed */ if ((int)q<0x8000) { note(msgs_lookup("spNAUSA")); return; } else if ((int)q>=0x01800000) { saveas(msgs_lookup("spSVSPR"), msgs_lookup("spGRB"), 0xff9, s.freeoff, gSprite__saveGrabbed, gSprite__sendGrabbed, 0, &q); } else { msg.hdr.size=20; msg.hdr.your_ref=0; r.r[0]=19; r.r[1]=(int)&msg; r.r[2]=m->w; r.r[3]=m->i; wimpt_noerr(os_swix(XWimp_SendMessage,&r)); /* Find the task's handle */ wimpt_noerr(wimp_transferblock(r.r[2], q, wimpt_task(), (char *)&s, sizeof(sprite_area))); if (!flex_alloc(&p,s.freeoff)) { werr(FALSE,msgs_lookup("spNEMGS")); return; } wimpt_noerr(wimp_transferblock(r.r[2],q,wimpt_task(),p,s.freeoff)); saveas(msgs_lookup("spSVSPR"), msgs_lookup("spGRB"), 0xff9, s.freeoff, gSprite__saveGrabbed, gSprite__sendGrabbed, 0, &p); flex_free(&p); } } /* * BOOL gSprite__copy(char *buff,void *handle) * * Use * Copies a sprite, ensuring that the name hasn't been duplicated etc. * * Parameters * char *buff == pointer to the new name * void *handle == pointer to data for the sprite * * Returns * TRUE if everything went OK */ static BOOL gSprite__copy(char *buff,void *handle) { gSprite__data *d=handle; gSprite__data *new; sprite_id sid; sprite_header *hdr; viewer_icon i=viewer_findIcon(d->t->vs,buff); sid.s.name=d->name; sid.tag=0; gSprite__lower(buff); if (i==viewer_NOICON || i==d->i) { mem_useUser(indir_alloc,indir_free); if (new=mem_alloc(sizeof(gSprite__data)),!new) { werr(FALSE,msgs_lookup("spNEMCPY")); mem_useMalloc(); return (FALSE); } wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr)); if (!gSprite__getMemory(d->t,hdr->next+50)) { mem_free(new); mem_useMalloc(); werr(FALSE,msgs_lookup("spNEMCPY")); return (FALSE); } wimpt_noerr(sprite_copy(d->t->s,&sid,buff)); gSprite__minimise(d->t); strcpy(new->name,buff); new->serial=gSprite__serial++; new->i=viewer_addIcon(d->t->vs,buff,buff,TRUE,new); viewer_setFiletype(new->i,0xff9); mem_useMalloc(); new->w=0; new->t=d->t; if (!dbox_wasAdjustClick()) viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID); intMsgs_send(glass_SPRITECHANGE,d->t); return (TRUE); } note(msgs_lookup("spNAE"), viewer_textOfIcon(i)); return (FALSE); } /* * BOOL gSprite__rename(char *buff,void *handle) * * Use * Renames a sprite, ensuring that the name hasn't been duplicated etc. * * Parameters * char *buff == pointer to the new name * void *handle == pointer to data for the sprite * * Returns * TRUE if everything went OK */ static BOOL gSprite__rename(char *buff,void *handle) { gSprite__data *d=handle; sprite_id sid; viewer_icon i=viewer_findIcon(d->t->vs,buff); sid.s.name=d->name; sid.tag=0; gSprite__lower(buff); if (i==viewer_NOICON || i==d->i) { mem_useUser(indir_alloc,indir_free); i=viewer_addIcon(d->t->vs,buff,buff,TRUE,d); mem_useMalloc(); if (!i) return (FALSE); viewer_setFiletype(i,0xff9); wimpt_noerr(sprite_rename(d->t->s,&sid,buff)); viewer_removeIcon(d->i); d->i=i; strcpy(d->name,buff); intMsgs_send(glass_SPRITECHANGE,d->t); if (!dbox_wasAdjustClick()) viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID); event_clear_current_menu(); return (TRUE); } note(msgs_lookup("spNAE"), viewer_textOfIcon(i)); return (FALSE); } /* * void gSprite__delSprites(viewer_icon i,void *handle) * * Use * Deletes the given sprite. * * Parameters * viewer_icon i == the icon handle that it is * void *handle == the sprite data pointer */ static void gSprite__delSprites(viewer_icon i,void *handle) { sprite_id sid; gSprite__data *d=handle; unused(i); sid.s.name=d->name; sid.tag=0; wimpt_noerr(sprite_delete(d->t->s,&sid)); viewer_removeIcon(d->i); if (d->w) { win_register_event_handler(d->w,0,0); win_activedec(); wimpt_noerr(wimp_delete_wind(d->w)); } mem_free(d); } /* * void gSprite__createWindow(viewer_icon i,void *handle) * * Use * Opens a window to display a given sprite. * * Parameters * viewer_icon i == the icon representing the sprite * void *handle == the information to add to the window */ static void gSprite__windowHandler(wimp_eventstr *e,void *handle); static void gSprite__createWindow(viewer_icon i,void *handle) { wimp_wstate s; gSprite__data *d=handle; wimp_wind w= { 0,0,0,0, 0,0, -1, wimp_WMOVEABLE | wimp_WNEW | wimp_WTITLE | wimp_WTOGGLE | wimp_WVSCR | wimp_WHSCR | wimp_WSIZE | wimp_WBACK | wimp_WQUIT, 7,2,7,1,3,1,12,0, 0,0,gSprite__WINDMINX,gSprite__WINDMINY, wimp_ITEXT | wimp_IHCENTRE, 0, 0, 0x00010001, "", 0, }; sprite_id sid; sprite_info info; unused(i); if (!d->w) { strcpy(w.title.text,d->name); sid.s.name=d->name; sid.tag=0; wimpt_noerr(sprite_readsize(d->t->s,&sid,&info)); info.width <<= bbc_modevar(info.mode,bbc_XEigFactor); info.height <<= bbc_modevar(info.mode,bbc_YEigFactor); if (info.width>gSprite__WINDMINX) w.ex.x1=info.width; if (info.height>gSprite__WINDMINY) w.ex.y1=info.height; w.box.x0=gSprite__WINDX; w.box.x1=gSprite__WINDX+w.ex.x1; w.box.y1=gSprite__windHeight; w.box.y0=gSprite__windHeight-w.ex.y1; if (w.ex.x1>500) w.box.x1=gSprite__WINDX+500; if (w.ex.y1>500) w.box.y0=gSprite__windHeight-500; if (wimpt_complain(wimp_create_wind(&w,&d->w))) return; win_register_event_handler(d->w,gSprite__windowHandler,d); win_activeinc(); gSprite__windHeight-=48; if (gSprite__windHeight<612) gSprite__windHeight=gSprite__WINDTOP; } wimpt_noerr(wimp_get_wind_state(d->w,&s)); wimpt_noerr(wimp_open_wind(&s.o)); } /*----- Event handlers ----------------------------------------------------*/ /* * BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle) * * Use * Handles unknown events during the period of dragging viewer icons * around. It will respond to the following drags: * * A drag to a blank area of icon bar will open the windows. * * Otherwise, a selection save will be started, and the windows packaged * off to another application. * * Parameters * wimp_eventstr *e == the event to look at * void *handle == the template file whose sprite area we're dragging from * * Returns * TRUE if the drag has been processed */ static BOOL gSprite__dragUnknowns(wimp_eventstr *e,void *handle) { glass_tfile *t=handle; wimp_mousestr m; BOOL handled=FALSE; switch (e->e) { case wimp_EUSERDRAG: handled=TRUE; win_remove_unknown_event_processor(gSprite__dragUnknowns,t); wimpt_noerr(wimp_get_point_info(&m)); if (m.w==viewer_syshandle(t->vs)) break; if (m.w==-2 && m.i==-1) viewer_doForIcons(t->vs,TRUE,gSprite__createWindow); else { gSprite__size=0; viewer_doForIcons(t->vs,TRUE,gSprite__sizes); wimpt_fake_event(e); /* Fool xfersend to send data */ xfersend(0xFF9, msgs_lookup("spSEL"), gSprite__size+16, gSprite__saveSelection, gSprite__sendSelection, 0, e, t); } viewer_selectAll(t->vs,FALSE); break; } return (handled); } /* * void gSprite__viewerRedraw(viewer_icon i, * wimp_redrawstr *r, * wimp_box *box, * char *text, * char *sprite, * BOOL selected, * void *handle) * * Use * Redraws an icon in the sprite viewer. * * Parameters * viewer_icon i == the icon I'm redrawing * wimp_redrawstr *r == the redraw structure * wimp_box *box == the box to fit it in * char *text == the text to draw * char *sprite == the sprite to draw (ignored) * BOOL selected == whether the icon is selected * void *handle == pointer to the template file */ static void gSprite__viewerRedraw(viewer_icon i, wimp_redrawstr *r, wimp_box *box, char *text, char *sprite, BOOL selected, void *handle) { int ox=r->box.x0-r->scx; int oy=r->box.y1-r->scy; sprite_id sid; sprite_header *hdr; sprite_pixtrans colbuff[256]; /* Colour translation table */ sprite_factors zoom; /* Zoomage table */ sprite_info info; /* Info about the sprite */ glass_tfile *t=handle; int newy; /* Bodged height of the sprite */ int xoff,yoff; /* x and y offsets to display sprite */ wimp_icon spname; /* Virtual icon for sprite name */ unused(i); unused(sprite); spname.box.x0=box->x0; spname.box.x1=box->x1; spname.box.y0=box->y0; spname.box.y1=box->y0+40; spname.flags=0x1700010b+(selected<<21); spname.data.indirecttext.buffer=text; spname.data.indirecttext.validstring="Sblank"; wimpt_noerr(wimp_ploticon(&spname)); sid.s.name=text; sid.tag=0; wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr)); sid.s.addr=hdr; sid.tag=sprite_id_addr; wimpt_noerr(sprite_readsize(t->s,&sid,&info)); if (bbc_modevar(info.mode,bbc_NColour)==63) /* 256 colour mode - handle */ colourtran_select_table(info.mode,0,-1,(wimp_paletteword *)-1,colbuff); else wimpt_noerr(wimp_readpixtrans(t->s,&sid,&zoom,colbuff)); zoom.xmag=zoom.ymag=zoom.xdiv=zoom.ydiv=1; info.width <<= bbc_modevar(info.mode,bbc_XEigFactor); /* Now OS units */ info.height <<= bbc_modevar(info.mode,bbc_YEigFactor); /* --- Bodge the multipliers to fit the sprite in --- */ newy=info.height; if (info.width>gSprite__BOXX) { zoom.xmag*=gSprite__BOXX; zoom.ymag*=gSprite__BOXX; zoom.xdiv*=info.width; zoom.ydiv*=info.width; newy=(newy*gSprite__BOXX)/info.width+1; } if (newy>gSprite__BOXY) { zoom.xmag*=gSprite__BOXY; zoom.ymag*=gSprite__BOXY; zoom.xdiv*=newy; zoom.ydiv*=newy; } info.width=info.width*zoom.xmag/zoom.xdiv; info.height=info.height*zoom.ymag/zoom.ydiv; xoff=(gSprite__BOXX-info.width)/2; yoff=(gSprite__BOXY-info.height)/2+48; zoom.xmag <<= bbc_modevar(info.mode,bbc_XEigFactor); zoom.ymag <<= bbc_modevar(info.mode,bbc_YEigFactor); zoom.xdiv <<= bbc_vduvar(bbc_XEigFactor); zoom.ydiv <<= bbc_vduvar(bbc_YEigFactor); wimpt_noerr(sprite_put_scaled(t->s, &sid, 8, ox+box->x0+xoff, oy+box->y0+yoff, &zoom, colbuff)); } /* * void gSprite__windowHandler(wimp_eventstr *e,void *handle) * * Use * Handles events for individual sprite windows * * Parameters * wimp_eventstr *e == the event to handle * void *handle == pointer to data structure */ static void gSprite__windowHandler(wimp_eventstr *e,void *handle) { gSprite__data *d=handle; wimp_redrawstr r; int ox,oy; BOOL more; sprite_id sid; sprite_factors zoom; sprite_pixtrans colbuff[256]; sprite_header *hdr; sprite_info info; switch (e->e) { case wimp_EREDRAW: r.w=d->w; wimpt_noerr(wimp_redraw_wind(&r,&more)); ox=r.box.x0-r.scx; oy=r.box.y1-r.scy; while (more) { sid.s.name=d->name; sid.tag=0; wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr)); sid.s.addr=hdr; sid.tag=sprite_id_addr; wimpt_noerr(sprite_readsize(d->t->s,&sid,&info)); if (bbc_modevar(info.mode,bbc_NColour)==63) { colourtran_select_table(info.mode, 0, -1, (wimp_paletteword *)-1, colbuff); } else wimpt_noerr(wimp_readpixtrans(d->t->s,&sid,&zoom,colbuff)); zoom.xmag=zoom.ymag=zoom.xdiv=zoom.ydiv=1; info.width <<= bbc_modevar(info.mode,bbc_XEigFactor); info.height <<= bbc_modevar(info.mode,bbc_YEigFactor); info.width=info.width*zoom.xmag/zoom.xdiv; info.height=info.height*zoom.ymag/zoom.ydiv; zoom.xmag <<= bbc_modevar(info.mode,bbc_XEigFactor); zoom.ymag <<= bbc_modevar(info.mode,bbc_YEigFactor); zoom.xdiv <<= bbc_vduvar(bbc_XEigFactor); zoom.ydiv <<= bbc_vduvar(bbc_YEigFactor); wimpt_noerr(sprite_put_scaled(d->t->s,&sid,8,ox,oy,&zoom,colbuff)); wimpt_noerr(wimp_get_rectangle(&r,&more)); } break; case wimp_EOPEN: wimpt_noerr(wimp_open_wind(&e->data.o)); break; case wimp_ECLOSE: win_register_event_handler(d->w,0,0); win_activedec(); wimpt_noerr(wimp_delete_wind(d->w)); d->w=0; break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e->data.msg.hdr.action) { case wimp_MHELPREQUEST: help_startHelp(); help_addLine(msgs_lookup("sphSPDW"),d->name); help_endHelp(); break; } break; } } /* * void gSprite__menuHelp(int hit[],void *handle) * * Use * Responds to help requests for the sprite viewer menu * * Parameters * int hit[] == array of menu selections * void *handle == pointer to owning template file (unused) */ static void gSprite__menuHelp(int hit[],void *handle) { unused(handle); help_startHelp(); help_readFromMenu("spmhSPM",hit); help_endHelp(); } /* * void gSprite__menuHandler(int hit[],void *handle) * * Use * Responds to menu selections from the sprite viewer menu * * Parameters * int hit[] == array of menu selections * void *handle == pointer to owning template file */ static void gSprite__menuHandler(int hit[],void *handle) { glass_tfile *t=handle; wimp_mousestr m; char buff[50]; dbox d; sprite_id sid; sprite_info info; sprite_header *hdr; switch (hit[0]) { case 0: viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID); break; case glass_SPINFO: if (d=dbox_create("sprFileInfo"),d) { dbox_setfield(d,glass_SAOWNER,"%.%s",t->filename); dbox_setfield(d, glass_SASIZE, "%s", utils_cvtSize(t->s->freeoff-4)); dbox_setfield(d,glass_SASPRITES,"%i",t->s->number); mbox(d,"sphSAINF"); } break; case glass_SPSEL: switch (hit[1]) { case glass_SPSELINFO: if (viewer_selected(t->vs)==1) { if (d=dbox_create("spriteInfo"),d) { sid.s.name=((gSprite__data *) viewer_iconHandle(viewer_firstSelected(t->vs)))->name; sid.tag=0; wimpt_noerr(sprite_readsize(t->s,&sid,&info)); wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr)); dbox_setfield(d,glass_SPNAME,"%s",sid.s.name); dbox_setfield(d,glass_SPMODE,"%i",info.mode); dbox_setfield(d,glass_SPWIDTH,"%i",info.width); dbox_setfield(d,glass_SPHEIGHT,"%i",info.height); dbox_setfield(d, glass_SPSIZE, "%s", utils_cvtSize(hdr->next+16)); dbox_setfield(d, glass_SPMASK, "%s", msgs_lookup(info.mask ? "yes" : "no")); dbox_setfield(d, glass_SPPALETTE, "%s", msgs_lookup(hdr->image!=0x2c ? "yes" : "no")); mbox(d,"sphSPINF"); } } else { if (d=dbox_create("sprSelInfo"),d) { dbox_setfield(d,glass_SSNUM,"%i",viewer_selected(t->vs)); gSprite__size=0; viewer_doForIcons(t->vs,TRUE,gSprite__sizes); dbox_setfield(d, glass_SPSIZE, "%s", utils_cvtSize(gSprite__size+16)); mbox(d,"sphSSINF"); } } break; case glass_SPSELCOPY: writable ( msgs_lookup("spCOPY"), viewer_textOfIcon(viewer_firstSelected(t->vs)), buff, gSprite__copy, viewer_iconHandle(viewer_firstSelected(t->vs)) ); break; case glass_SPSELRENAME: writable(msgs_lookup("spREN"), viewer_textOfIcon(viewer_firstSelected(t->vs)), buff, gSprite__rename, viewer_iconHandle(viewer_firstSelected(t->vs))); break; case glass_SPSELSAVE: gSprite__size=0; viewer_doForIcons(t->vs,TRUE,gSprite__sizes); saveas(msgs_lookup("spSVSEL"), msgs_lookup("spSEL"), 0xff9, gSprite__size+16, gSprite__saveSelection, gSprite__sendSelection, 0, t); break; case glass_SPSELDELETE: viewer_doForIcons(t->vs,TRUE,gSprite__delSprites); gSprite__minimise(t); intMsgs_send(glass_SPRITECHANGE,t); break; } break; case glass_SPSELALL: viewer_selectAll(t->vs,TRUE); break; case glass_SPCLRSEL: viewer_selectAll(t->vs,FALSE); break; case glass_SPSAVE: saveas(msgs_lookup("spSVSPR"), "Sprites", 0xff9, t->s->freeoff-4, gSprite__saveArea, gSprite__sendArea, 0, t); break; case glass_SPGRAB: window_grab(gSprite__grab,0); break; } if (wimpt_last_event()->e==wimp_EMENU) { wimpt_noerr(wimp_get_point_info(&m)); if (m.bbits!=wimp_BRIGHT) viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID); } } /* * menu gSprite__menuMaker(void *handle) * * Use * Creates a menu for the sprite file viewer * * Parameters * void *handle == pointer to owning template file * * Returns * Pointer to the menu it has set up */ static menu gSprite__menuMaker(void *handle) { static menu m; /* The main menu pointer */ static menu sprsm; /* Submenu for sprite options */ static char sprName[50]; /* Buffer for sprite name */ glass_tfile *t=handle; if (!m) /* Do we have to create the menu? */ { m=menu_new("Sprites",msgs_lookup("spM")); sprsm=menu_new("_",msgs_lookup("spSS")); menu_submenu(m,glass_SPSEL,sprsm); menu_redirectItem(m,glass_SPSEL,sprName,50,0); } menu_minWidth(m,0); viewer_setupMenu(t->vs, msgs_lookup("spSPR"), m, glass_SPSEL, sprName); switch (viewer_selected(t->vs)) { case 0: menu_setflags(m,glass_SPCLRSEL,FALSE,TRUE); menu_setflags(m,glass_SPSELALL,FALSE,!viewer_icons(t->vs)); menu_settitle(sprsm,msgs_lookup("spSPR")); menu_setflags(sprsm,glass_SPSELINFO,FALSE,TRUE); menu_setflags(sprsm,glass_SPSELCOPY,FALSE,TRUE); menu_setflags(sprsm,glass_SPSELRENAME,FALSE,TRUE); menu_setflags(sprsm,glass_SPSELSAVE,FALSE,TRUE); menu_setflags(sprsm,glass_SPSELDELETE,FALSE,TRUE); break; case 1: menu_setflags(m,glass_SPCLRSEL,FALSE,FALSE); menu_setflags(m,glass_SPSELALL,FALSE,FALSE); menu_settitle(sprsm,msgs_lookup("spSPR")); menu_setflags(sprsm,glass_SPSELINFO,FALSE,FALSE); menu_setflags(sprsm,glass_SPSELCOPY,FALSE,FALSE); menu_setflags(sprsm,glass_SPSELRENAME,FALSE,FALSE); menu_setflags(sprsm,glass_SPSELSAVE,FALSE,FALSE); menu_setflags(sprsm,glass_SPSELDELETE,FALSE,FALSE); break; default: menu_setflags(m,glass_SPCLRSEL,FALSE,FALSE); menu_setflags(m,glass_SPSELALL,FALSE,FALSE); menu_settitle(sprsm,msgs_lookup("spSEL")); menu_setflags(sprsm,glass_SPSELINFO,FALSE,FALSE); menu_setflags(sprsm,glass_SPSELCOPY,FALSE,TRUE); menu_setflags(sprsm,glass_SPSELRENAME,FALSE,TRUE); menu_setflags(sprsm,glass_SPSELSAVE,FALSE,FALSE); menu_setflags(sprsm,glass_SPSELDELETE,FALSE,FALSE); break; } menu_setflags(m,glass_SPGRAB,FALSE,window_grabbing()); return (m); } /* * void gSprite__simMenu(glass_tfile *t,int hit1,int hit2) * * Use * Simulates a menu hit on a template file window * * Parameters * glass_tfile *t == the template file the event is destined for * int hit1 == the main menu entry number * int hit2 == the submenu entry number */ static void gSprite__simMenu(glass_tfile *t,int hit1,int hit2) { wimp_menustr *m=menu_syshandle(gSprite__menuMaker(t)); wimp_menuitem *i=(wimp_menuitem *)(m+1)+(hit1-1); int mnu[3]; mnu[0]=hit1; mnu[1]=hit2; mnu[2]=0; if ((int)i->submenu==-1 || hit2==0) { if (i->iconflags & wimp_INOSELECT) { bbc_vdu(7); return; } else mnu[1]=0; } else { i=(wimp_menuitem *)(i->submenu+1)+(hit2-1); if (i->iconflags & wimp_INOSELECT) { bbc_vdu(7); return; } } gSprite__menuHandler(mnu,t); } /* * BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle) * * Use * Handles raw events destined for the viewer window, and picks out * interesting ones. * * Parameters * viewer v == the viewer its going for * wimp_eventstr *e == what it is * void *handle == pointer to owning template file * * Returns * TRUE if the event was worth waiting for */ static BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle) { glass_tfile *t=handle; char *filename; int filetype; int estsize; void *p; BOOL handled=FALSE; unused(v); switch (e->e) { case wimp_EKEY: switch (e->data.key.chcode) { case akbd_Fn+1+akbd_Sh: /* sF1 */ gSprite__simMenu(t,glass_SPINFO,0); handled=TRUE; break; case 1: /* ^A */ gSprite__simMenu(t,glass_SPSELALL,0); handled=TRUE; break; case 26: /* ^Z */ gSprite__simMenu(t,glass_SPCLRSEL,0); handled=TRUE; break; case akbd_Fn+3: /* F3 */ gSprite__simMenu(t,glass_SPSAVE,0); handled=TRUE; break; case 7: /* ^G */ gSprite__simMenu(t,glass_SPGRAB,0); handled=TRUE; break; case akbd_Fn+1+akbd_Ctl:/* ^F1 */ gSprite__simMenu(t,glass_SPSEL,glass_SPSELINFO); handled=TRUE; break; case 3: /* ^C */ gSprite__simMenu(t,glass_SPSEL,glass_SPSELCOPY); handled=TRUE; break; case 18: /* ^R */ gSprite__simMenu(t,glass_SPSEL,glass_SPSELRENAME); handled=TRUE; break; case akbd_Fn+3+akbd_Sh: /* sF3 */ gSprite__simMenu(t,glass_SPSEL,glass_SPSELSAVE); handled=TRUE; break; case 24: /* ^X */ gSprite__simMenu(t,glass_SPSEL,glass_SPSELDELETE); handled=TRUE; break; case akbd_Fn+2+akbd_Ctl:/* ^F2 */ viewer_hide(v); handled=TRUE; break; } break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e->data.msg.hdr.action) { case wimp_MDATASAVE: filetype=xferrecv_checkimport(&estsize); switch (filetype) { case 0xff9: if (xferrecv_returnImportedBlock(&p)!=-1) { gSprite_mergeFromMemory(t,&p); flex_free(&p); } break; } handled=TRUE; break; case wimp_MDATALOAD: filetype=xferrecv_checkinsert(&filename); switch (filetype) { case 0xff9: gSprite_mergeFromFile(t,filename); xferrecv_insertfileok(); break; } handled=TRUE; break; } break; } return (handled); } /* * void gSprite__viewerHandler(viewer v, * viewer_icon i, * wimp_bbits b, * void *vhandle, * void *ihandle) * * Use * Handles events in a sprite viewer * * Parameters * viewer v == the handle for the viewer that got the event * viewer_icon i == the icon handle that was 'evented', or an event code * wimp_bbits b == the mouse button status, if relevant * void *vhandle == pointer to the owning template file * void *ihandle == an unused pointer */ static void gSprite__viewerHandler(viewer v, viewer_icon i, wimp_bbits b, void *vhandle, void *ihandle) { glass_tfile *t=vhandle; unused(ihandle); switch ((int)i) { case (int)viewer_CLOSE: viewer_hide(v); break; case (int)viewer_HELP: help_startHelp(); help_addLine(msgs_lookup("sphMVW")); help_endHelp(); break; default: if (b!=wimp_BMID) { gSprite__gainSelection(t); viewer_clickSelect(v,i,b); } switch (b) { case wimp_BMID: if (t==gSprite__selOwner || !gSprite__selOwner || !viewer_selected(gSprite__selOwner->vs)) { gSprite__selOwner=t; viewer_clickSelect(v,i,b); } menu_make(gSprite__menuMaker, gSprite__menuHandler, gSprite__menuHelp, t); break; case wimp_BLEFT: case wimp_BRIGHT: if (i!=viewer_NOICON) { gSprite__createWindow(i,viewer_iconHandle(i)); viewer_selectIcon(i,FALSE); } break; case wimp_BDRAGLEFT: case wimp_BDRAGRIGHT: if (i!=viewer_NOICON) { tfile_dragSelected(i,b,"spackage"); win_add_unknown_event_processor(gSprite__dragUnknowns,t); } break; } break; } } /*----- External routines -------------------------------------------------*/ /* * void gSprite_kill(glass_tfile *t) * * Use * Closes the sprite viewer and frees the sprite area * * Parameters * glass_tfile *t == the template file that's closing */ void gSprite_kill(glass_tfile *t) { if (t->vs) viewer_delete(t->vs,gSprite__closeWindows); indir_free(t->s); } /* * void gSprite_display(glass_tfile *t) * * Use * Displays the sprite viewer for the specified template file. * * glass_tfile *t == the template file whose sprites we want to see */ void gSprite_display(glass_tfile *t) { viewer_selectAll(t->vs,FALSE); viewer_display(t->vs); } /* * void gSprite_mergeFromMemory(glass_tfile *t,void **p) * * Use * Merges a sprite file which is stored in memory. This is so I can do * in-memory transfer of sprites. * * Parameters * glass_tfile *t == the template file owner of the sprite area * void **p == the flex block stroing the sprite file */ void gSprite_mergeFromMemory(glass_tfile *t,void **p) { int sprites=_ptr(sprite_area,*p,-4)->number; int i; int h=_ptr(sprite_area,*p,-4)->sproff-4; int length; sprite_id sid; viewer_icon icn; char buff[15]; gSprite__data *d; if (!gSprite__getMemory(t,_ptr(sprite_area,*p,-4)->freeoff)) { werr(FALSE,msgs_lookup("spNEMM")); return; } for (i=1;i<=sprites;i++) { length=_ptr(sprite_header,*p,h)->next; buff[12]=0; memcpy(buff,_ptr(sprite_header,*p,h)->name,12); sid.s.name=buff; sid.tag=0; /* --- Slight problem --- * * * viewer is deadly cunning, because it uses a nice case-insensitive * string-compare for all this, which handles annoying things like * accents. Unfortunately, the RISC OS sprite system isn't as cunning, * and so, when viewer says that `Élite' and `élite' are the same, * RISC OS moans that it can't find the sprite when you delete it. * * Hence we place the sprite deletion in there as a check that it really * does exist in there. Note that it only deletes the sprite if it * found the icon. */ if (icn=viewer_findIcon(t->vs,sid.s.name), icn && !sprite_delete(t->s,&sid)) { d=viewer_iconHandle(icn); if (d->w) { win_register_event_handler(d->w,0,0); wimpt_noerr(wimp_delete_wind(d->w)); d->w=0; } mem_free(d); viewer_removeIcon(icn); } mem_useUser(indir_alloc,indir_free); if (d=mem_alloc(sizeof(gSprite__data)),!d) { mem_useMalloc(); werr(FALSE,msgs_lookup("spNEMM")); return; } strcpy(d->name,sid.s.name); d->t=t; d->w=0; d->serial=gSprite__serial++; if (d->i=viewer_addIcon(t->vs,sid.s.name,sid.s.name,TRUE,d),!d->i) { mem_useMalloc(); mem_free(d); return; } mem_useMalloc(); viewer_setFiletype(d->i,0xff9); memcpy(((char *)t->s)+t->s->freeoff,_ptr(sprite_header,*p,h),length); t->s->freeoff+=length; t->s->number++; h+=length; } gSprite__minimise(t); intMsgs_send(glass_SPRITECHANGE,t); } /* * void gSprite_mergeFromFile(glass_tfile *t,char *name) * * Use * Merges the given file into the sprite area specified. * * Parameters * glass_tfile *t == the template file that we're going to load for * char *name == the name of the file to load */ void gSprite_mergeFromFile(glass_tfile *t,char *name) { os_filestr f; /* Going to make some OS_File calls */ void *p; /* p will point to the file in memory */ f.action=17; /* Read catalogue information for file */ f.name=name; /* Point to file name to find out about */ if (utils_complain(os_file(&f),msgs_lookup("spEMF"))) return; if (!flex_alloc(&p,f.start)) { werr(FALSE,msgs_lookup("spNEMM")); return; } f.action=16; /* Load the file */ f.loadaddr=(int)p; /* Where to load the file */ f.execaddr=0; /* Load it there!!! */ if (utils_complain(os_file(&f),msgs_lookup("spEMF"))) { flex_free(&p); return; } gSprite_mergeFromMemory(t,&p); /* Now do the merge */ flex_free(&p); } /* * void gSprite_new(glass_tfile *t) * * Use * Creates a sprite file for the given template file. Initially, the file * is blank. On failure, an error is generated and sprite area 1 (WIMP * pool) is used instead. Note that at present, this section uses indir * for allocation of sprite areas. * * Parameters * glass_tfile *t == the file to use */ void gSprite_new(glass_tfile *t) { char buff[256]; void *def; if (t->s=indir_alloc(gSprite__CHUNK),!t->s) { werr(FALSE,msgs_lookup("spNEMC")); t->s=(sprite_area *)1; /* Set the WIMP sprite area */ t->vs=0; /* Tell the world something's wrong */ return; } sprintf(buff,msgs_lookup("spVT"),t->filename); mem_useUser(indir_alloc,indir_free); t->vs=viewer_create(gSprite__FILEX, gSprite__fileHeight, gSprite__BOXX, gSprite__BOXY+48, resspr_area(), buff, msgs_lookup("spBANR")); mem_useMalloc(); if (!t->vs) return; viewer_setCompare(t->vs,gSprite__compare); gSprite__fileHeight-=48; if (gSprite__fileHeight<632) gSprite__fileHeight=gSprite__FILETOP; viewer_eventHandler(t->vs,gSprite__viewerHandler,t); viewer_rawEventHandler(t->vs,gSprite__viewerRaw,t); viewer_redrawHandler(t->vs,gSprite__viewerRedraw,t); t->s->size=gSprite__CHUNK; t->s->number=0; t->s->sproff=16; t->s->freeoff=16; if (gPrefs_current()->sLoadDef && gSprite__default) { def=&gSprite__default->number; gSprite_mergeFromMemory(t,&def); } } /* * sprite_area *gSprite_area(void) * * Use * Returns the address of the Glass default sprite file, or 1 for the * WIMP sprite area if no default sprites are loaded */ sprite_area *gSprite_area(void) { return (gSprite__default ? gSprite__default : (sprite_area *)1); } /* * void gSprite_init(void) * * Use * Loads the Glass default sprite area into memory. */ void gSprite_init(void) { os_filestr f; /* Going to make some OS_File calls */ f.action=17; /* Read catalogue information for file */ f.name=choices_name("Defaults.Sprites",FALSE); if (utils_complain(os_file(&f),msgs_lookup("spELD"))) return; if (f.action==0) return; if (gSprite__default=mem_alloc(f.start+4),!gSprite__default) { werr(FALSE,msgs_lookup("spNEMLD")); return; } gSprite__default->size=f.start+4; gSprite__default->number=0; gSprite__default->sproff=16; gSprite__default->freeoff=16; if (utils_complain(sprite_area_load(gSprite__default, choices_name("Defaults.Sprites",FALSE)), msgs_lookup("spELD"))) gSprite__default=0; }