4 * Handling of template file sprite windows and areas
6 * © 1994-1998 Straylight
9 /*----- Licensing note ----------------------------------------------------*
11 * This file is part of Straylight's Glass.
13 * Glass is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * Glass is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with Glass. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /*----- Header files ------------------------------------------------------*/
31 * ANSI standard headers
44 #include "steel/Steel.h"
46 #include "steel/viewer.h"
47 #include "steel/flex.h"
48 #include "steel/akbd.h"
49 #include "steel/bbc.h"
50 #include "steel/choices.h"
51 #include "steel/colourtran.h"
69 /*----- Macros ------------------------------------------------------------*/
71 #define gSprite__FILEHEIGHT 872 /* Height to open first sprite window */
72 #define gSprite__FILEX 220 /* x position of sprite windows */
73 #define gSprite__FILETOP 920 /* Height after files wrap around */
74 #define gSprite__CHUNK 2048 /* Size in bytes to allocate areas by */
75 #define gSprite__WINDHEIGHT 852 /* Height for individual sprite window */
76 #define gSprite__WINDX 240 /* x position of individual sprite window */
77 #define gSprite__WINDTOP 900 /* Height after wrap around */
78 #define gSprite__WINDMINX 340 /* Minimum width of a sprite window */
79 #define gSprite__WINDMINY 150 /* Minimum height of a sprite window */
80 #define gSprite__BOXX 200 /* Size of the box for sprite display (x) */
81 #define gSprite__BOXY 148 /* Size of the box for sprite display (y) */
83 /*----- Type definitions --------------------------------------------------*/
87 glass_tfile *t; /* Template file owner */
88 int serial; /* Order the icons were created in */
89 char name[15]; /* Name of the sprite */
90 viewer_icon i; /* My viewer icon */
91 wimp_w w; /* My window handle */
95 /*----- Static variables --------------------------------------------------*/
97 static int gSprite__fileHeight=gSprite__FILEHEIGHT;
98 /* Height to open next sprite window */
99 static int gSprite__windHeight=gSprite__WINDHEIGHT;
101 static int gSprite__size; /* Count up sprite sizes */
102 static void **gSprite__flex; /* The flex block for saving selections */
103 static sprite_area *gSprite__default; /* Default sprite file */
104 static int gSprite__serial; /* Monotonic time counter */
105 static glass_tfile *gSprite__selOwner; /* Which window owns selection? */
107 /*----- Support routines --------------------------------------------------*/
110 * BOOL gSprite__getMemory(glass_tfile *t,int size)
113 * Ensures that the specified quantity of memory is available in the sprite
114 * area given. If the memory is not there, it is allocated and the pointer
115 * is placed in the appropriate place. Messages are sent round as
119 * glass_tfile *t == the template file to alllcate memory in
120 * int size == the quantity of memory required to add to the area
123 * TRUE if the operation succeeded, or FALSE for not enough memory available
126 static BOOL gSprite__getMemory(glass_tfile *t,int size)
130 if (t->s->freeoff+size<t->s->size) /* Check that the memory is there */
132 aligned=(t->s->freeoff+size+gSprite__CHUNK-1) & ~(gSprite__CHUNK-1);
133 /* Qunatise by the chunk size */
134 if (s=indir_realloc(t->s,aligned),!s) /* Allocate memory required */
135 return (FALSE); /* Say we failed if we did */
136 s->size=aligned; /* Insert the new sprite area size */
137 t->s=s; /* And change the pointers to the new one */
142 * void gSprite__minimise(glass_tfile *t)
145 * Attempts to minimise the space taken up by template file t's sprite area
146 * if wasteful operations took upn too much memory, or sprites have been
147 * deleted. Ironically, this requires memory... However, failure to
148 * allocate sufficient memory is ignored.
151 * glass_tfile *t == the template file to minimise
154 static void gSprite__minimise(glass_tfile *t)
157 int aligned=(t->s->freeoff+gSprite__CHUNK-1) & ~(gSprite__CHUNK-1);
158 /* Get the size the area should be */
159 if (t->s->size==aligned)
161 if (s=indir_realloc(t->s,aligned),!s)
168 * int gSprite__compare(void *a,void *b)
171 * Compares creation times of two icons
174 * both pointers to data attached to icons
177 static int gSprite__compare(void *a,void *b)
181 return (x->serial-y->serial);
185 * void gSprite__gainSelection(glass_tfile *t)
188 * Hands the current sprite selection and the input focus to the specified
189 * template file sprite viewer.
191 * Note that the selection model here is more complex than it is in window,
192 * since the focus tfile may not coincide with the selection owner (since
193 * menu clicks move the selection owner, but not the focus).
196 * glass_tfile *t == the sprite viewer to which we give the selection
199 static void gSprite__gainSelection(glass_tfile *t)
202 if (t!=gSprite__selOwner)
204 if (gSprite__selOwner)
205 viewer_selectAll(gSprite__selOwner->vs,FALSE);
210 c.w=viewer_syshandle(t->vs);
216 wimpt_noerr(wimp_set_caret_pos(&c));
221 * void gSprite__closeWindows(void *handle)
224 * Destroys any windows open when the template file dies
227 * void *handle == pointer to window data
230 static void gSprite__closeWindows(void *handle)
232 gSprite__data *d=handle;
235 win_register_event_handler(d->w,0,0);
236 wimpt_noerr(wimp_delete_wind(d->w));
243 * void gSprite__sizes(viewer_icon i,void *handle)
246 * Adds the size of the given sprite to the total in gSprite__size.
249 * viewer_icon i == the icon number of the sprite (ignored)
250 * void *handle == pointer to sprite data
253 static void gSprite__sizes(viewer_icon i,void *handle)
257 gSprite__data *d=handle;
261 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
262 gSprite__size+=hdr->next;
266 * char *gSprite__lower(char *s)
269 * Translates the string given to lower case
272 * char *s == the string to convert
275 * A pointer to the string
278 static char *gSprite__lower(char *s)
290 * BOOL gSprite__saveArea(void *handle,char *filename)
293 * Saves a sprite area to disk
296 * char *filename == the filename to save to
297 * void *handle == pointer to owning template file
303 static BOOL gSprite__saveArea(char *filename,void *handle)
305 glass_tfile *t=handle;
306 if (gPrefs_current()->cSave &&
307 saveas_file_is_safe() &&
308 res_fileExists(filename))
310 if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
313 if (utils_complain(sprite_area_save(t->s,filename),msgs_lookup("spESS")))
320 * BOOL gSprite__sendArea(void *handle,int *maxbuf)
323 * Sends a sprite area via RAM transfer
326 * void *handle == pointer to owning template file
327 * int *maxbuf == pointer to buffer size of other application
330 static BOOL gSprite__sendArea(void *handle,int *maxbuf)
332 glass_tfile *t=handle;
333 return (xfersend_sendBlock(&t->s->number,t->s->freeoff-4,maxbuf));
337 * void gSprite__addToSelSave(viewer_icon i,void *handle)
340 * Adds the given sprite to the sprite area held in gSprite__flex
343 * viewer_icon i == the icon number of the sprite to add (ignored)
344 * void *handle == pointer to sprite data
347 static void gSprite__addToSelSave(viewer_icon i,void *handle)
349 gSprite__data *d=handle;
352 void *p=charptr(*gSprite__flex,0)+
353 _ptr(sprite_area,*gSprite__flex,0)->freeoff;
357 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
358 memcpy(p,hdr,hdr->next);
359 _ptr(sprite_area,*gSprite__flex,0)->freeoff+=hdr->next;
363 * BOOL gSprite__setupSelSave(glass_tfile *t,void **p)
366 * Sets up a sprite area to save in a flex block anchored on p. The flex
367 * block is allocaed here. The caller must free the block itself.
370 * glass_tfile *t == the template file owning the selection
371 * void **p == pointer to a flex anchor
377 static BOOL gSprite__setupSelSave(glass_tfile *t,void **p)
379 if (!flex_alloc(p,gSprite__size+16))
381 werr(FALSE,msgs_lookup("spNEMSLSV"));
385 _ptr(sprite_area,*p,0)->size=gSprite__size+16;
386 _ptr(sprite_area,*p,0)->number=viewer_selected(t->vs);
387 _ptr(sprite_area,*p,0)->freeoff=16;
388 _ptr(sprite_area,*p,0)->sproff=16;
389 viewer_doForIcons(t->vs,TRUE,gSprite__addToSelSave);
394 * BOOL gSprite__saveSelection(char *filename,void *handle)
397 * Saves a selection of sprite to a file
400 * char *filename == the file to save to
401 * void *handle == pointer to the owning template file
407 static BOOL gSprite__saveSelection(char *filename,void *handle)
409 glass_tfile *t=handle;
411 if (gPrefs_current()->cSave &&
412 saveas_file_is_safe() &&
413 res_fileExists(filename))
415 if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
418 if (!gSprite__setupSelSave(t,&p))
420 if (utils_complain(sprite_area_save((sprite_area *)p,filename),
421 msgs_lookup("spESS")))
434 * BOOL gSprite__sendSelection(void *handle,int *maxbuf)
437 * Sends a selection of sprite to another application in memory
440 * void *handle == pointer to the owning template file
441 * int *maxbuf == the size of the receiving application's buffer
447 static BOOL gSprite__sendSelection(void *handle,int *maxbuf)
449 glass_tfile *t=handle;
451 if (!gSprite__setupSelSave(t,&p))
453 if (!xfersend_sendBlock((char *)p+4,gSprite__size+12,maxbuf))
466 * BOOL gSprite__saveGrabbed(void *handle,char *filename)
469 * Saves a sprite area to disk
472 * char *filename == the filename to save to
473 * void *handle == pointer-to-pointer to sprite area
479 static BOOL gSprite__saveGrabbed(char *filename,void *handle)
481 sprite_area **s=handle;
482 if (gPrefs_current()->cSave &&
483 saveas_file_is_safe() &&
484 res_fileExists(filename))
486 if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
489 if (utils_complain(sprite_area_save(*s,filename),msgs_lookup("spESS")))
496 * BOOL gSprite__sendGrabbed(void *handle,int *maxbuf)
499 * Sends a sprite area via RAM transfer
502 * void *handle == pointer-to-pointer to sprite area
503 * int *maxbuf == pointer to buffer size of other application
506 static BOOL gSprite__sendGrabbed(void *handle,int *maxbuf)
508 sprite_area **s=handle;
509 return (xfersend_sendBlock(&(*s)->number,(*s)->freeoff-4,maxbuf));
513 * void gSprite__grab(wimp_mousestr *m,void *handle)
516 * Grabs a sprite area from a given window
519 * wimp_mousestr *m == info about the window/icon the pointer is over
520 * void *handle == a pointer (ignored)
523 static void gSprite__grab(wimp_mousestr *m,void *handle)
536 werr(FALSE,msgs_lookup("spCGS"));
539 if (wimpt_getVersion()>=300) /* RISC OS 3 allows 'safe' GetWindowInfos */
540 w=mem_alloc(sizeof(wimp_winfo));
542 w=mem_alloc(sizeof(wimp_winfo)+200*sizeof(wimp_icon));
545 werr(FALSE,msgs_lookup("spNEMGS"));
550 if (wimpt_getVersion()>=300)
551 r.r[1]+=1; /* RO3 - only window header, not icons */
552 wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Get the information */
553 q=w->info.spritearea; /* Get the window's sprite area */
554 mem_free(w); /* No longer needed */
557 note(msgs_lookup("spNAUSA"));
560 else if ((int)q>=0x01800000)
562 saveas(msgs_lookup("spSVSPR"),
563 msgs_lookup("spGRB"),
566 gSprite__saveGrabbed,
567 gSprite__sendGrabbed,
579 wimpt_noerr(os_swix(XWimp_SendMessage,&r)); /* Find the task's handle */
580 wimpt_noerr(wimp_transferblock(r.r[2],
584 sizeof(sprite_area)));
585 if (!flex_alloc(&p,s.freeoff))
587 werr(FALSE,msgs_lookup("spNEMGS"));
590 wimpt_noerr(wimp_transferblock(r.r[2],q,wimpt_task(),p,s.freeoff));
591 saveas(msgs_lookup("spSVSPR"),
592 msgs_lookup("spGRB"),
595 gSprite__saveGrabbed,
596 gSprite__sendGrabbed,
604 * BOOL gSprite__copy(char *buff,void *handle)
607 * Copies a sprite, ensuring that the name hasn't been duplicated etc.
610 * char *buff == pointer to the new name
611 * void *handle == pointer to data for the sprite
614 * TRUE if everything went OK
617 static BOOL gSprite__copy(char *buff,void *handle)
619 gSprite__data *d=handle;
623 viewer_icon i=viewer_findIcon(d->t->vs,buff);
626 gSprite__lower(buff);
627 if (i==viewer_NOICON || i==d->i)
629 mem_useUser(indir_alloc,indir_free);
630 if (new=mem_alloc(sizeof(gSprite__data)),!new)
632 werr(FALSE,msgs_lookup("spNEMCPY"));
636 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
637 if (!gSprite__getMemory(d->t,hdr->next+50))
641 werr(FALSE,msgs_lookup("spNEMCPY"));
644 wimpt_noerr(sprite_copy(d->t->s,&sid,buff));
645 gSprite__minimise(d->t);
646 strcpy(new->name,buff);
647 new->serial=gSprite__serial++;
648 new->i=viewer_addIcon(d->t->vs,buff,buff,TRUE,new);
649 viewer_setFiletype(new->i,0xff9);
653 if (!dbox_wasAdjustClick())
654 viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID);
655 intMsgs_send(glass_SPRITECHANGE,d->t);
658 note(msgs_lookup("spNAE"),
659 viewer_textOfIcon(i));
665 * BOOL gSprite__rename(char *buff,void *handle)
668 * Renames a sprite, ensuring that the name hasn't been duplicated etc.
671 * char *buff == pointer to the new name
672 * void *handle == pointer to data for the sprite
675 * TRUE if everything went OK
678 static BOOL gSprite__rename(char *buff,void *handle)
680 gSprite__data *d=handle;
682 viewer_icon i=viewer_findIcon(d->t->vs,buff);
685 gSprite__lower(buff);
686 if (i==viewer_NOICON || i==d->i)
688 mem_useUser(indir_alloc,indir_free);
689 i=viewer_addIcon(d->t->vs,buff,buff,TRUE,d);
693 viewer_setFiletype(i,0xff9);
694 wimpt_noerr(sprite_rename(d->t->s,&sid,buff));
695 viewer_removeIcon(d->i);
697 strcpy(d->name,buff);
698 intMsgs_send(glass_SPRITECHANGE,d->t);
699 if (!dbox_wasAdjustClick())
700 viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID);
701 event_clear_current_menu();
704 note(msgs_lookup("spNAE"),
705 viewer_textOfIcon(i));
710 * void gSprite__delSprites(viewer_icon i,void *handle)
713 * Deletes the given sprite.
716 * viewer_icon i == the icon handle that it is
717 * void *handle == the sprite data pointer
720 static void gSprite__delSprites(viewer_icon i,void *handle)
723 gSprite__data *d=handle;
727 wimpt_noerr(sprite_delete(d->t->s,&sid));
728 viewer_removeIcon(d->i);
731 win_register_event_handler(d->w,0,0);
733 wimpt_noerr(wimp_delete_wind(d->w));
739 * void gSprite__createWindow(viewer_icon i,void *handle)
742 * Opens a window to display a given sprite.
745 * viewer_icon i == the icon representing the sprite
746 * void *handle == the information to add to the window
749 static void gSprite__windowHandler(wimp_eventstr *e,void *handle);
751 static void gSprite__createWindow(viewer_icon i,void *handle)
754 gSprite__data *d=handle;
768 0,0,gSprite__WINDMINX,gSprite__WINDMINY,
769 wimp_ITEXT | wimp_IHCENTRE,
781 strcpy(w.title.text,d->name);
784 wimpt_noerr(sprite_readsize(d->t->s,&sid,&info));
785 info.width <<= bbc_modevar(info.mode,bbc_XEigFactor);
786 info.height <<= bbc_modevar(info.mode,bbc_YEigFactor);
787 if (info.width>gSprite__WINDMINX)
789 if (info.height>gSprite__WINDMINY)
791 w.box.x0=gSprite__WINDX;
792 w.box.x1=gSprite__WINDX+w.ex.x1;
793 w.box.y1=gSprite__windHeight;
794 w.box.y0=gSprite__windHeight-w.ex.y1;
796 w.box.x1=gSprite__WINDX+500;
798 w.box.y0=gSprite__windHeight-500;
799 if (wimpt_complain(wimp_create_wind(&w,&d->w)))
801 win_register_event_handler(d->w,gSprite__windowHandler,d);
803 gSprite__windHeight-=48;
804 if (gSprite__windHeight<612)
805 gSprite__windHeight=gSprite__WINDTOP;
807 wimpt_noerr(wimp_get_wind_state(d->w,&s));
808 wimpt_noerr(wimp_open_wind(&s.o));
811 /*----- Event handlers ----------------------------------------------------*/
814 * BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
817 * Handles unknown events during the period of dragging viewer icons
818 * around. It will respond to the following drags:
820 * A drag to a blank area of icon bar will open the windows.
822 * Otherwise, a selection save will be started, and the windows packaged
823 * off to another application.
826 * wimp_eventstr *e == the event to look at
827 * void *handle == the template file whose sprite area we're dragging from
830 * TRUE if the drag has been processed
833 static BOOL gSprite__dragUnknowns(wimp_eventstr *e,void *handle)
835 glass_tfile *t=handle;
842 win_remove_unknown_event_processor(gSprite__dragUnknowns,t);
843 wimpt_noerr(wimp_get_point_info(&m));
844 if (m.w==viewer_syshandle(t->vs))
846 if (m.w==-2 && m.i==-1)
847 viewer_doForIcons(t->vs,TRUE,gSprite__createWindow);
851 viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
852 wimpt_fake_event(e); /* Fool xfersend to send data */
854 msgs_lookup("spSEL"),
856 gSprite__saveSelection,
857 gSprite__sendSelection,
862 viewer_selectAll(t->vs,FALSE);
869 * void gSprite__viewerRedraw(viewer_icon i,
878 * Redraws an icon in the sprite viewer.
881 * viewer_icon i == the icon I'm redrawing
882 * wimp_redrawstr *r == the redraw structure
883 * wimp_box *box == the box to fit it in
884 * char *text == the text to draw
885 * char *sprite == the sprite to draw (ignored)
886 * BOOL selected == whether the icon is selected
887 * void *handle == pointer to the template file
890 static void gSprite__viewerRedraw(viewer_icon i,
898 int ox=r->box.x0-r->scx;
899 int oy=r->box.y1-r->scy;
902 sprite_pixtrans colbuff[256]; /* Colour translation table */
903 sprite_factors zoom; /* Zoomage table */
904 sprite_info info; /* Info about the sprite */
905 glass_tfile *t=handle;
906 int newy; /* Bodged height of the sprite */
907 int xoff,yoff; /* x and y offsets to display sprite */
908 wimp_icon spname; /* Virtual icon for sprite name */
912 spname.box.x0=box->x0;
913 spname.box.x1=box->x1;
914 spname.box.y0=box->y0;
915 spname.box.y1=box->y0+40;
916 spname.flags=0x1700010b+(selected<<21);
917 spname.data.indirecttext.buffer=text;
918 spname.data.indirecttext.validstring="Sblank";
919 wimpt_noerr(wimp_ploticon(&spname));
923 wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr));
925 sid.tag=sprite_id_addr;
926 wimpt_noerr(sprite_readsize(t->s,&sid,&info));
927 if (bbc_modevar(info.mode,bbc_NColour)==63) /* 256 colour mode - handle */
928 colourtran_select_table(info.mode,0,-1,(wimp_paletteword *)-1,colbuff);
930 wimpt_noerr(wimp_readpixtrans(t->s,&sid,&zoom,colbuff));
931 zoom.xmag=zoom.ymag=zoom.xdiv=zoom.ydiv=1;
932 info.width <<= bbc_modevar(info.mode,bbc_XEigFactor); /* Now OS units */
933 info.height <<= bbc_modevar(info.mode,bbc_YEigFactor);
935 /* --- Bodge the multipliers to fit the sprite in --- */
938 if (info.width>gSprite__BOXX)
940 zoom.xmag*=gSprite__BOXX;
941 zoom.ymag*=gSprite__BOXX;
942 zoom.xdiv*=info.width;
943 zoom.ydiv*=info.width;
944 newy=(newy*gSprite__BOXX)/info.width+1;
947 if (newy>gSprite__BOXY)
949 zoom.xmag*=gSprite__BOXY;
950 zoom.ymag*=gSprite__BOXY;
955 info.width=info.width*zoom.xmag/zoom.xdiv;
956 info.height=info.height*zoom.ymag/zoom.ydiv;
957 xoff=(gSprite__BOXX-info.width)/2;
958 yoff=(gSprite__BOXY-info.height)/2+48;
959 zoom.xmag <<= bbc_modevar(info.mode,bbc_XEigFactor);
960 zoom.ymag <<= bbc_modevar(info.mode,bbc_YEigFactor);
961 zoom.xdiv <<= bbc_vduvar(bbc_XEigFactor);
962 zoom.ydiv <<= bbc_vduvar(bbc_YEigFactor);
964 wimpt_noerr(sprite_put_scaled(t->s,
974 * void gSprite__windowHandler(wimp_eventstr *e,void *handle)
977 * Handles events for individual sprite windows
980 * wimp_eventstr *e == the event to handle
981 * void *handle == pointer to data structure
984 static void gSprite__windowHandler(wimp_eventstr *e,void *handle)
986 gSprite__data *d=handle;
992 sprite_pixtrans colbuff[256];
1000 wimpt_noerr(wimp_redraw_wind(&r,&more));
1007 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
1009 sid.tag=sprite_id_addr;
1010 wimpt_noerr(sprite_readsize(d->t->s,&sid,&info));
1011 if (bbc_modevar(info.mode,bbc_NColour)==63)
1013 colourtran_select_table(info.mode,
1016 (wimp_paletteword *)-1,
1020 wimpt_noerr(wimp_readpixtrans(d->t->s,&sid,&zoom,colbuff));
1021 zoom.xmag=zoom.ymag=zoom.xdiv=zoom.ydiv=1;
1022 info.width <<= bbc_modevar(info.mode,bbc_XEigFactor);
1023 info.height <<= bbc_modevar(info.mode,bbc_YEigFactor);
1025 info.width=info.width*zoom.xmag/zoom.xdiv;
1026 info.height=info.height*zoom.ymag/zoom.ydiv;
1027 zoom.xmag <<= bbc_modevar(info.mode,bbc_XEigFactor);
1028 zoom.ymag <<= bbc_modevar(info.mode,bbc_YEigFactor);
1029 zoom.xdiv <<= bbc_vduvar(bbc_XEigFactor);
1030 zoom.ydiv <<= bbc_vduvar(bbc_YEigFactor);
1032 wimpt_noerr(sprite_put_scaled(d->t->s,&sid,8,ox,oy,&zoom,colbuff));
1034 wimpt_noerr(wimp_get_rectangle(&r,&more));
1038 wimpt_noerr(wimp_open_wind(&e->data.o));
1041 win_register_event_handler(d->w,0,0);
1043 wimpt_noerr(wimp_delete_wind(d->w));
1047 case wimp_ESENDWANTACK:
1048 switch (e->data.msg.hdr.action)
1050 case wimp_MHELPREQUEST:
1052 help_addLine(msgs_lookup("sphSPDW"),d->name);
1061 * void gSprite__menuHelp(int hit[],void *handle)
1064 * Responds to help requests for the sprite viewer menu
1067 * int hit[] == array of menu selections
1068 * void *handle == pointer to owning template file (unused)
1071 static void gSprite__menuHelp(int hit[],void *handle)
1075 help_readFromMenu("spmhSPM",hit);
1080 * void gSprite__menuHandler(int hit[],void *handle)
1083 * Responds to menu selections from the sprite viewer menu
1086 * int hit[] == array of menu selections
1087 * void *handle == pointer to owning template file
1090 static void gSprite__menuHandler(int hit[],void *handle)
1092 glass_tfile *t=handle;
1102 viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID);
1105 if (d=dbox_create("sprFileInfo"),d)
1107 dbox_setfield(d,glass_SAOWNER,"%.%s",t->filename);
1111 utils_cvtSize(t->s->freeoff-4));
1112 dbox_setfield(d,glass_SASPRITES,"%i",t->s->number);
1119 case glass_SPSELINFO:
1120 if (viewer_selected(t->vs)==1)
1122 if (d=dbox_create("spriteInfo"),d)
1124 sid.s.name=((gSprite__data *)
1125 viewer_iconHandle(viewer_firstSelected(t->vs)))->name;
1127 wimpt_noerr(sprite_readsize(t->s,&sid,&info));
1128 wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr));
1129 dbox_setfield(d,glass_SPNAME,"%s",sid.s.name);
1130 dbox_setfield(d,glass_SPMODE,"%i",info.mode);
1131 dbox_setfield(d,glass_SPWIDTH,"%i",info.width);
1132 dbox_setfield(d,glass_SPHEIGHT,"%i",info.height);
1136 utils_cvtSize(hdr->next+16));
1140 msgs_lookup(info.mask ? "yes" : "no"));
1144 msgs_lookup(hdr->image!=0x2c ? "yes" : "no"));
1150 if (d=dbox_create("sprSelInfo"),d)
1152 dbox_setfield(d,glass_SSNUM,"%i",viewer_selected(t->vs));
1154 viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
1158 utils_cvtSize(gSprite__size+16));
1163 case glass_SPSELCOPY:
1166 msgs_lookup("spCOPY"),
1167 viewer_textOfIcon(viewer_firstSelected(t->vs)),
1170 viewer_iconHandle(viewer_firstSelected(t->vs))
1173 case glass_SPSELRENAME:
1174 writable(msgs_lookup("spREN"),
1175 viewer_textOfIcon(viewer_firstSelected(t->vs)),
1178 viewer_iconHandle(viewer_firstSelected(t->vs)));
1180 case glass_SPSELSAVE:
1182 viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
1183 saveas(msgs_lookup("spSVSEL"),
1184 msgs_lookup("spSEL"),
1187 gSprite__saveSelection,
1188 gSprite__sendSelection,
1192 case glass_SPSELDELETE:
1193 viewer_doForIcons(t->vs,TRUE,gSprite__delSprites);
1194 gSprite__minimise(t);
1195 intMsgs_send(glass_SPRITECHANGE,t);
1199 case glass_SPSELALL:
1200 viewer_selectAll(t->vs,TRUE);
1202 case glass_SPCLRSEL:
1203 viewer_selectAll(t->vs,FALSE);
1206 saveas(msgs_lookup("spSVSPR"),
1216 window_grab(gSprite__grab,0);
1219 if (wimpt_last_event()->e==wimp_EMENU)
1221 wimpt_noerr(wimp_get_point_info(&m));
1222 if (m.bbits!=wimp_BRIGHT)
1223 viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID);
1228 * menu gSprite__menuMaker(void *handle)
1231 * Creates a menu for the sprite file viewer
1234 * void *handle == pointer to owning template file
1237 * Pointer to the menu it has set up
1240 static menu gSprite__menuMaker(void *handle)
1242 static menu m; /* The main menu pointer */
1243 static menu sprsm; /* Submenu for sprite options */
1244 static char sprName[50]; /* Buffer for sprite name */
1245 glass_tfile *t=handle;
1246 if (!m) /* Do we have to create the menu? */
1248 m=menu_new("Sprites",msgs_lookup("spM"));
1249 sprsm=menu_new("_",msgs_lookup("spSS"));
1250 menu_submenu(m,glass_SPSEL,sprsm);
1251 menu_redirectItem(m,glass_SPSEL,sprName,50,0);
1254 viewer_setupMenu(t->vs,
1255 msgs_lookup("spSPR"),
1259 switch (viewer_selected(t->vs))
1262 menu_setflags(m,glass_SPCLRSEL,FALSE,TRUE);
1263 menu_setflags(m,glass_SPSELALL,FALSE,!viewer_icons(t->vs));
1264 menu_settitle(sprsm,msgs_lookup("spSPR"));
1265 menu_setflags(sprsm,glass_SPSELINFO,FALSE,TRUE);
1266 menu_setflags(sprsm,glass_SPSELCOPY,FALSE,TRUE);
1267 menu_setflags(sprsm,glass_SPSELRENAME,FALSE,TRUE);
1268 menu_setflags(sprsm,glass_SPSELSAVE,FALSE,TRUE);
1269 menu_setflags(sprsm,glass_SPSELDELETE,FALSE,TRUE);
1272 menu_setflags(m,glass_SPCLRSEL,FALSE,FALSE);
1273 menu_setflags(m,glass_SPSELALL,FALSE,FALSE);
1274 menu_settitle(sprsm,msgs_lookup("spSPR"));
1275 menu_setflags(sprsm,glass_SPSELINFO,FALSE,FALSE);
1276 menu_setflags(sprsm,glass_SPSELCOPY,FALSE,FALSE);
1277 menu_setflags(sprsm,glass_SPSELRENAME,FALSE,FALSE);
1278 menu_setflags(sprsm,glass_SPSELSAVE,FALSE,FALSE);
1279 menu_setflags(sprsm,glass_SPSELDELETE,FALSE,FALSE);
1282 menu_setflags(m,glass_SPCLRSEL,FALSE,FALSE);
1283 menu_setflags(m,glass_SPSELALL,FALSE,FALSE);
1284 menu_settitle(sprsm,msgs_lookup("spSEL"));
1285 menu_setflags(sprsm,glass_SPSELINFO,FALSE,FALSE);
1286 menu_setflags(sprsm,glass_SPSELCOPY,FALSE,TRUE);
1287 menu_setflags(sprsm,glass_SPSELRENAME,FALSE,TRUE);
1288 menu_setflags(sprsm,glass_SPSELSAVE,FALSE,FALSE);
1289 menu_setflags(sprsm,glass_SPSELDELETE,FALSE,FALSE);
1292 menu_setflags(m,glass_SPGRAB,FALSE,window_grabbing());
1297 * void gSprite__simMenu(glass_tfile *t,int hit1,int hit2)
1300 * Simulates a menu hit on a template file window
1303 * glass_tfile *t == the template file the event is destined for
1304 * int hit1 == the main menu entry number
1305 * int hit2 == the submenu entry number
1308 static void gSprite__simMenu(glass_tfile *t,int hit1,int hit2)
1310 wimp_menustr *m=menu_syshandle(gSprite__menuMaker(t));
1311 wimp_menuitem *i=(wimp_menuitem *)(m+1)+(hit1-1);
1317 if ((int)i->submenu==-1 || hit2==0)
1319 if (i->iconflags & wimp_INOSELECT)
1329 i=(wimp_menuitem *)(i->submenu+1)+(hit2-1);
1330 if (i->iconflags & wimp_INOSELECT)
1336 gSprite__menuHandler(mnu,t);
1340 * BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle)
1343 * Handles raw events destined for the viewer window, and picks out
1347 * viewer v == the viewer its going for
1348 * wimp_eventstr *e == what it is
1349 * void *handle == pointer to owning template file
1352 * TRUE if the event was worth waiting for
1355 static BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle)
1357 glass_tfile *t=handle;
1367 switch (e->data.key.chcode)
1369 case akbd_Fn+1+akbd_Sh: /* sF1 */
1370 gSprite__simMenu(t,glass_SPINFO,0);
1374 gSprite__simMenu(t,glass_SPSELALL,0);
1378 gSprite__simMenu(t,glass_SPCLRSEL,0);
1381 case akbd_Fn+3: /* F3 */
1382 gSprite__simMenu(t,glass_SPSAVE,0);
1386 gSprite__simMenu(t,glass_SPGRAB,0);
1390 case akbd_Fn+1+akbd_Ctl:/* ^F1 */
1391 gSprite__simMenu(t,glass_SPSEL,glass_SPSELINFO);
1395 gSprite__simMenu(t,glass_SPSEL,glass_SPSELCOPY);
1399 gSprite__simMenu(t,glass_SPSEL,glass_SPSELRENAME);
1402 case akbd_Fn+3+akbd_Sh: /* sF3 */
1403 gSprite__simMenu(t,glass_SPSEL,glass_SPSELSAVE);
1407 gSprite__simMenu(t,glass_SPSEL,glass_SPSELDELETE);
1411 case akbd_Fn+2+akbd_Ctl:/* ^F2 */
1419 case wimp_ESENDWANTACK:
1420 switch (e->data.msg.hdr.action)
1422 case wimp_MDATASAVE:
1423 filetype=xferrecv_checkimport(&estsize);
1427 if (xferrecv_returnImportedBlock(&p)!=-1)
1429 gSprite_mergeFromMemory(t,&p);
1436 case wimp_MDATALOAD:
1437 filetype=xferrecv_checkinsert(&filename);
1441 gSprite_mergeFromFile(t,filename);
1442 xferrecv_insertfileok();
1454 * void gSprite__viewerHandler(viewer v,
1461 * Handles events in a sprite viewer
1464 * viewer v == the handle for the viewer that got the event
1465 * viewer_icon i == the icon handle that was 'evented', or an event code
1466 * wimp_bbits b == the mouse button status, if relevant
1467 * void *vhandle == pointer to the owning template file
1468 * void *ihandle == an unused pointer
1471 static void gSprite__viewerHandler(viewer v,
1477 glass_tfile *t=vhandle;
1481 case (int)viewer_CLOSE:
1484 case (int)viewer_HELP:
1486 help_addLine(msgs_lookup("sphMVW"));
1492 gSprite__gainSelection(t);
1493 viewer_clickSelect(v,i,b);
1498 if (t==gSprite__selOwner ||
1499 !gSprite__selOwner ||
1500 !viewer_selected(gSprite__selOwner->vs))
1502 gSprite__selOwner=t;
1503 viewer_clickSelect(v,i,b);
1505 menu_make(gSprite__menuMaker,
1506 gSprite__menuHandler,
1512 if (i!=viewer_NOICON)
1514 gSprite__createWindow(i,viewer_iconHandle(i));
1515 viewer_selectIcon(i,FALSE);
1518 case wimp_BDRAGLEFT:
1519 case wimp_BDRAGRIGHT:
1520 if (i!=viewer_NOICON)
1522 tfile_dragSelected(i,b,"spackage");
1523 win_add_unknown_event_processor(gSprite__dragUnknowns,t);
1531 /*----- External routines -------------------------------------------------*/
1534 * void gSprite_kill(glass_tfile *t)
1537 * Closes the sprite viewer and frees the sprite area
1540 * glass_tfile *t == the template file that's closing
1543 void gSprite_kill(glass_tfile *t)
1546 viewer_delete(t->vs,gSprite__closeWindows);
1551 * void gSprite_display(glass_tfile *t)
1554 * Displays the sprite viewer for the specified template file.
1556 * glass_tfile *t == the template file whose sprites we want to see
1559 void gSprite_display(glass_tfile *t)
1561 viewer_selectAll(t->vs,FALSE);
1562 viewer_display(t->vs);
1566 * void gSprite_mergeFromMemory(glass_tfile *t,void **p)
1569 * Merges a sprite file which is stored in memory. This is so I can do
1570 * in-memory transfer of sprites.
1573 * glass_tfile *t == the template file owner of the sprite area
1574 * void **p == the flex block stroing the sprite file
1577 void gSprite_mergeFromMemory(glass_tfile *t,void **p)
1579 int sprites=_ptr(sprite_area,*p,-4)->number;
1581 int h=_ptr(sprite_area,*p,-4)->sproff-4;
1587 if (!gSprite__getMemory(t,_ptr(sprite_area,*p,-4)->freeoff))
1589 werr(FALSE,msgs_lookup("spNEMM"));
1592 for (i=1;i<=sprites;i++)
1594 length=_ptr(sprite_header,*p,h)->next;
1596 memcpy(buff,_ptr(sprite_header,*p,h)->name,12);
1600 /* --- Slight problem --- *
1602 * viewer is deadly cunning, because it uses a nice case-insensitive
1603 * string-compare for all this, which handles annoying things like
1604 * accents. Unfortunately, the RISC OS sprite system isn't as cunning,
1605 * and so, when viewer says that `Élite' and `élite' are the same,
1606 * RISC OS moans that it can't find the sprite when you delete it.
1608 * Hence we place the sprite deletion in there as a check that it really
1609 * does exist in there. Note that it only deletes the sprite if it
1613 if (icn=viewer_findIcon(t->vs,sid.s.name),
1614 icn && !sprite_delete(t->s,&sid))
1616 d=viewer_iconHandle(icn);
1619 win_register_event_handler(d->w,0,0);
1620 wimpt_noerr(wimp_delete_wind(d->w));
1624 viewer_removeIcon(icn);
1626 mem_useUser(indir_alloc,indir_free);
1627 if (d=mem_alloc(sizeof(gSprite__data)),!d)
1630 werr(FALSE,msgs_lookup("spNEMM"));
1633 strcpy(d->name,sid.s.name);
1636 d->serial=gSprite__serial++;
1637 if (d->i=viewer_addIcon(t->vs,sid.s.name,sid.s.name,TRUE,d),!d->i)
1644 viewer_setFiletype(d->i,0xff9);
1645 memcpy(((char *)t->s)+t->s->freeoff,_ptr(sprite_header,*p,h),length);
1646 t->s->freeoff+=length;
1650 gSprite__minimise(t);
1651 intMsgs_send(glass_SPRITECHANGE,t);
1655 * void gSprite_mergeFromFile(glass_tfile *t,char *name)
1658 * Merges the given file into the sprite area specified.
1661 * glass_tfile *t == the template file that we're going to load for
1662 * char *name == the name of the file to load
1665 void gSprite_mergeFromFile(glass_tfile *t,char *name)
1667 os_filestr f; /* Going to make some OS_File calls */
1668 void *p; /* p will point to the file in memory */
1669 f.action=17; /* Read catalogue information for file */
1670 f.name=name; /* Point to file name to find out about */
1671 if (utils_complain(os_file(&f),msgs_lookup("spEMF")))
1673 if (!flex_alloc(&p,f.start))
1675 werr(FALSE,msgs_lookup("spNEMM"));
1678 f.action=16; /* Load the file */
1679 f.loadaddr=(int)p; /* Where to load the file */
1680 f.execaddr=0; /* Load it there!!! */
1681 if (utils_complain(os_file(&f),msgs_lookup("spEMF")))
1686 gSprite_mergeFromMemory(t,&p); /* Now do the merge */
1691 * void gSprite_new(glass_tfile *t)
1694 * Creates a sprite file for the given template file. Initially, the file
1695 * is blank. On failure, an error is generated and sprite area 1 (WIMP
1696 * pool) is used instead. Note that at present, this section uses indir
1697 * for allocation of sprite areas.
1700 * glass_tfile *t == the file to use
1703 void gSprite_new(glass_tfile *t)
1707 if (t->s=indir_alloc(gSprite__CHUNK),!t->s)
1709 werr(FALSE,msgs_lookup("spNEMC"));
1710 t->s=(sprite_area *)1; /* Set the WIMP sprite area */
1711 t->vs=0; /* Tell the world something's wrong */
1714 sprintf(buff,msgs_lookup("spVT"),t->filename);
1715 mem_useUser(indir_alloc,indir_free);
1716 t->vs=viewer_create(gSprite__FILEX,
1717 gSprite__fileHeight,
1722 msgs_lookup("spBANR"));
1726 viewer_setCompare(t->vs,gSprite__compare);
1727 gSprite__fileHeight-=48;
1728 if (gSprite__fileHeight<632)
1729 gSprite__fileHeight=gSprite__FILETOP;
1730 viewer_eventHandler(t->vs,gSprite__viewerHandler,t);
1731 viewer_rawEventHandler(t->vs,gSprite__viewerRaw,t);
1732 viewer_redrawHandler(t->vs,gSprite__viewerRedraw,t);
1733 t->s->size=gSprite__CHUNK;
1737 if (gPrefs_current()->sLoadDef && gSprite__default)
1739 def=&gSprite__default->number;
1740 gSprite_mergeFromMemory(t,&def);
1745 * sprite_area *gSprite_area(void)
1748 * Returns the address of the Glass default sprite file, or 1 for the
1749 * WIMP sprite area if no default sprites are loaded
1752 sprite_area *gSprite_area(void)
1754 return (gSprite__default ? gSprite__default : (sprite_area *)1);
1758 * void gSprite_init(void)
1761 * Loads the Glass default sprite area into memory.
1764 void gSprite_init(void)
1766 os_filestr f; /* Going to make some OS_File calls */
1767 f.action=17; /* Read catalogue information for file */
1768 f.name=choices_name("Defaults.Sprites",FALSE);
1769 if (utils_complain(os_file(&f),msgs_lookup("spELD")))
1773 if (gSprite__default=mem_alloc(f.start+4),!gSprite__default)
1775 werr(FALSE,msgs_lookup("spNEMLD"));
1778 gSprite__default->size=f.start+4;
1779 gSprite__default->number=0;
1780 gSprite__default->sproff=16;
1781 gSprite__default->freeoff=16;
1782 if (utils_complain(sprite_area_load(gSprite__default,
1783 choices_name("Defaults.Sprites",FALSE)),
1784 msgs_lookup("spELD")))