Initial revision
[ssr] / StraySrc / Glass / !Glass / c / gSprite
1 /*
2 * gSprite.c
3 *
4 * Handling of template file sprite windows and areas
5 *
6 * © 1994-1998 Straylight
7 */
8
9 /*----- Licensing note ----------------------------------------------------*
10 *
11 * This file is part of Straylight's Glass.
12 *
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)
16 * any later version.
17 *
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.
22 *
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.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 /*
31 * ANSI standard headers
32 */
33
34 #include <string.h>
35 #include <ctype.h>
36
37 /*
38 * Steel headers
39 */
40
41 #define _STDAPP
42 #define _XFER
43 #define _LOWLVL
44 #include "steel/Steel.h"
45
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"
52
53 /*
54 * Glass headers
55 */
56
57 #include "gStruct.h"
58 #include "gMenus.h"
59 #include "gIcons.h"
60
61 #include "glass.h"
62 #include "intMsgs.h"
63 #include "gSprite.h"
64 #include "gPrefs.h"
65 #include "indir.h"
66 #include "window.h"
67 #include "tfile.h"
68
69 /*----- Macros ------------------------------------------------------------*/
70
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) */
82
83 /*----- Type definitions --------------------------------------------------*/
84
85 typedef struct
86 {
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 */
92 }
93 gSprite__data;
94
95 /*----- Static variables --------------------------------------------------*/
96
97 static int gSprite__fileHeight=gSprite__FILEHEIGHT;
98 /* Height to open next sprite window */
99 static int gSprite__windHeight=gSprite__WINDHEIGHT;
100
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? */
106
107 /*----- Support routines --------------------------------------------------*/
108
109 /*
110 * BOOL gSprite__getMemory(glass_tfile *t,int size)
111 *
112 * Use
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
116 * applicable.
117 *
118 * Parameters
119 * glass_tfile *t == the template file to alllcate memory in
120 * int size == the quantity of memory required to add to the area
121 *
122 * Returns
123 * TRUE if the operation succeeded, or FALSE for not enough memory available
124 */
125
126 static BOOL gSprite__getMemory(glass_tfile *t,int size)
127 {
128 int aligned;
129 sprite_area *s;
130 if (t->s->freeoff+size<t->s->size) /* Check that the memory is there */
131 return (TRUE);
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 */
138 return (TRUE);
139 }
140
141 /*
142 * void gSprite__minimise(glass_tfile *t)
143 *
144 * Use
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.
149 *
150 * Parameters
151 * glass_tfile *t == the template file to minimise
152 */
153
154 static void gSprite__minimise(glass_tfile *t)
155 {
156 sprite_area *s;
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)
160 return;
161 if (s=indir_realloc(t->s,aligned),!s)
162 return;
163 s->size=aligned;
164 t->s=s;
165 }
166
167 /*
168 * int gSprite__compare(void *a,void *b)
169 *
170 * Use
171 * Compares creation times of two icons
172 *
173 * Parameters
174 * both pointers to data attached to icons
175 */
176
177 static int gSprite__compare(void *a,void *b)
178 {
179 gSprite__data *x=a;
180 gSprite__data *y=b;
181 return (x->serial-y->serial);
182 }
183
184 /*
185 * void gSprite__gainSelection(glass_tfile *t)
186 *
187 * Use
188 * Hands the current sprite selection and the input focus to the specified
189 * template file sprite viewer.
190 *
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).
194 *
195 * Parameters
196 * glass_tfile *t == the sprite viewer to which we give the selection
197 */
198
199 static void gSprite__gainSelection(glass_tfile *t)
200 {
201 wimp_caretstr c;
202 if (t!=gSprite__selOwner)
203 {
204 if (gSprite__selOwner)
205 viewer_selectAll(gSprite__selOwner->vs,FALSE);
206 gSprite__selOwner=t;
207 }
208 if (t)
209 {
210 c.w=viewer_syshandle(t->vs);
211 c.i=-1;
212 c.x=-250;
213 c.y=0;
214 c.index=-1;
215 c.height=0x02000000;
216 wimpt_noerr(wimp_set_caret_pos(&c));
217 }
218 }
219
220 /*
221 * void gSprite__closeWindows(void *handle)
222 *
223 * Use
224 * Destroys any windows open when the template file dies
225 *
226 * Parameters
227 * void *handle == pointer to window data
228 */
229
230 static void gSprite__closeWindows(void *handle)
231 {
232 gSprite__data *d=handle;
233 if (d->w)
234 {
235 win_register_event_handler(d->w,0,0);
236 wimpt_noerr(wimp_delete_wind(d->w));
237 win_activedec();
238 }
239 mem_free(d);
240 }
241
242 /*
243 * void gSprite__sizes(viewer_icon i,void *handle)
244 *
245 * Use
246 * Adds the size of the given sprite to the total in gSprite__size.
247 *
248 * Parameters
249 * viewer_icon i == the icon number of the sprite (ignored)
250 * void *handle == pointer to sprite data
251 */
252
253 static void gSprite__sizes(viewer_icon i,void *handle)
254 {
255 sprite_id sid;
256 sprite_header *hdr;
257 gSprite__data *d=handle;
258 unused(i);
259 sid.s.name=d->name;
260 sid.tag=0;
261 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
262 gSprite__size+=hdr->next;
263 }
264
265 /*
266 * char *gSprite__lower(char *s)
267 *
268 * Use
269 * Translates the string given to lower case
270 *
271 * Parameters
272 * char *s == the string to convert
273 *
274 * Returns
275 * A pointer to the string
276 */
277
278 static char *gSprite__lower(char *s)
279 {
280 char *p=s;
281 while (*p)
282 {
283 *p=tolower(*p);
284 p++;
285 }
286 return (s);
287 }
288
289 /*
290 * BOOL gSprite__saveArea(void *handle,char *filename)
291 *
292 * Use
293 * Saves a sprite area to disk
294 *
295 * Parameters
296 * char *filename == the filename to save to
297 * void *handle == pointer to owning template file
298 *
299 * Returns
300 * TRUE for success
301 */
302
303 static BOOL gSprite__saveArea(char *filename,void *handle)
304 {
305 glass_tfile *t=handle;
306 if (gPrefs_current()->cSave &&
307 saveas_file_is_safe() &&
308 res_fileExists(filename))
309 {
310 if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
311 return (FALSE);
312 }
313 if (utils_complain(sprite_area_save(t->s,filename),msgs_lookup("spESS")))
314 return (FALSE);
315 else
316 return (TRUE);
317 }
318
319 /*
320 * BOOL gSprite__sendArea(void *handle,int *maxbuf)
321 *
322 * Use
323 * Sends a sprite area via RAM transfer
324 *
325 * Parameters
326 * void *handle == pointer to owning template file
327 * int *maxbuf == pointer to buffer size of other application
328 */
329
330 static BOOL gSprite__sendArea(void *handle,int *maxbuf)
331 {
332 glass_tfile *t=handle;
333 return (xfersend_sendBlock(&t->s->number,t->s->freeoff-4,maxbuf));
334 }
335
336 /*
337 * void gSprite__addToSelSave(viewer_icon i,void *handle)
338 *
339 * Use
340 * Adds the given sprite to the sprite area held in gSprite__flex
341 *
342 * Parameters
343 * viewer_icon i == the icon number of the sprite to add (ignored)
344 * void *handle == pointer to sprite data
345 */
346
347 static void gSprite__addToSelSave(viewer_icon i,void *handle)
348 {
349 gSprite__data *d=handle;
350 sprite_header *hdr;
351 sprite_id sid;
352 void *p=charptr(*gSprite__flex,0)+
353 _ptr(sprite_area,*gSprite__flex,0)->freeoff;
354 unused(i);
355 sid.s.name=d->name;
356 sid.tag=0;
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;
360 }
361
362 /*
363 * BOOL gSprite__setupSelSave(glass_tfile *t,void **p)
364 *
365 * Use
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.
368 *
369 * Parameters
370 * glass_tfile *t == the template file owning the selection
371 * void **p == pointer to a flex anchor
372 *
373 * Returns
374 * TRUE if successful
375 */
376
377 static BOOL gSprite__setupSelSave(glass_tfile *t,void **p)
378 {
379 if (!flex_alloc(p,gSprite__size+16))
380 {
381 werr(FALSE,msgs_lookup("spNEMSLSV"));
382 return (FALSE);
383 }
384 gSprite__flex=p;
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);
390 return (TRUE);
391 }
392
393 /*
394 * BOOL gSprite__saveSelection(char *filename,void *handle)
395 *
396 * Use
397 * Saves a selection of sprite to a file
398 *
399 * Parameters
400 * char *filename == the file to save to
401 * void *handle == pointer to the owning template file
402 *
403 * Returns
404 * TRUE for success
405 */
406
407 static BOOL gSprite__saveSelection(char *filename,void *handle)
408 {
409 glass_tfile *t=handle;
410 void *p;
411 if (gPrefs_current()->cSave &&
412 saveas_file_is_safe() &&
413 res_fileExists(filename))
414 {
415 if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
416 return (FALSE);
417 }
418 if (!gSprite__setupSelSave(t,&p))
419 return (FALSE);
420 if (utils_complain(sprite_area_save((sprite_area *)p,filename),
421 msgs_lookup("spESS")))
422 {
423 flex_free(&p);
424 return (FALSE);
425 }
426 else
427 {
428 flex_free(&p);
429 return (TRUE);
430 }
431 }
432
433 /*
434 * BOOL gSprite__sendSelection(void *handle,int *maxbuf)
435 *
436 * Use
437 * Sends a selection of sprite to another application in memory
438 *
439 * Parameters
440 * void *handle == pointer to the owning template file
441 * int *maxbuf == the size of the receiving application's buffer
442 *
443 * Returns
444 * TRUE for success
445 */
446
447 static BOOL gSprite__sendSelection(void *handle,int *maxbuf)
448 {
449 glass_tfile *t=handle;
450 void *p;
451 if (!gSprite__setupSelSave(t,&p))
452 return (FALSE);
453 if (!xfersend_sendBlock((char *)p+4,gSprite__size+12,maxbuf))
454 {
455 flex_free(&p);
456 return (FALSE);
457 }
458 else
459 {
460 flex_free(&p);
461 return (TRUE);
462 }
463 }
464
465 /*
466 * BOOL gSprite__saveGrabbed(void *handle,char *filename)
467 *
468 * Use
469 * Saves a sprite area to disk
470 *
471 * Parameters
472 * char *filename == the filename to save to
473 * void *handle == pointer-to-pointer to sprite area
474 *
475 * Returns
476 * TRUE for success
477 */
478
479 static BOOL gSprite__saveGrabbed(char *filename,void *handle)
480 {
481 sprite_area **s=handle;
482 if (gPrefs_current()->cSave &&
483 saveas_file_is_safe() &&
484 res_fileExists(filename))
485 {
486 if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
487 return (FALSE);
488 }
489 if (utils_complain(sprite_area_save(*s,filename),msgs_lookup("spESS")))
490 return (FALSE);
491 else
492 return (TRUE);
493 }
494
495 /*
496 * BOOL gSprite__sendGrabbed(void *handle,int *maxbuf)
497 *
498 * Use
499 * Sends a sprite area via RAM transfer
500 *
501 * Parameters
502 * void *handle == pointer-to-pointer to sprite area
503 * int *maxbuf == pointer to buffer size of other application
504 */
505
506 static BOOL gSprite__sendGrabbed(void *handle,int *maxbuf)
507 {
508 sprite_area **s=handle;
509 return (xfersend_sendBlock(&(*s)->number,(*s)->freeoff-4,maxbuf));
510 }
511
512 /*
513 * void gSprite__grab(wimp_mousestr *m,void *handle)
514 *
515 * Use
516 * Grabs a sprite area from a given window
517 *
518 * Parameters
519 * wimp_mousestr *m == info about the window/icon the pointer is over
520 * void *handle == a pointer (ignored)
521 */
522
523 static void gSprite__grab(wimp_mousestr *m,void *handle)
524 {
525 wimp_winfo *w;
526 os_regset r;
527 void *p;
528 void *q;
529 sprite_area s;
530 wimp_msgstr msg;
531 unused(handle);
532 switch (m->w)
533 {
534 case -1:
535 case -2:
536 werr(FALSE,msgs_lookup("spCGS"));
537 return;
538 }
539 if (wimpt_getVersion()>=300) /* RISC OS 3 allows 'safe' GetWindowInfos */
540 w=mem_alloc(sizeof(wimp_winfo));
541 else
542 w=mem_alloc(sizeof(wimp_winfo)+200*sizeof(wimp_icon));
543 if (!w)
544 {
545 werr(FALSE,msgs_lookup("spNEMGS"));
546 return;
547 }
548 w->w=m->w;
549 r.r[1]=(int)w;
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 */
555 if ((int)q<0x8000)
556 {
557 note(msgs_lookup("spNAUSA"));
558 return;
559 }
560 else if ((int)q>=0x01800000)
561 {
562 saveas(msgs_lookup("spSVSPR"),
563 msgs_lookup("spGRB"),
564 0xff9,
565 s.freeoff,
566 gSprite__saveGrabbed,
567 gSprite__sendGrabbed,
568 0,
569 &q);
570 }
571 else
572 {
573 msg.hdr.size=20;
574 msg.hdr.your_ref=0;
575 r.r[0]=19;
576 r.r[1]=(int)&msg;
577 r.r[2]=m->w;
578 r.r[3]=m->i;
579 wimpt_noerr(os_swix(XWimp_SendMessage,&r)); /* Find the task's handle */
580 wimpt_noerr(wimp_transferblock(r.r[2],
581 q,
582 wimpt_task(),
583 (char *)&s,
584 sizeof(sprite_area)));
585 if (!flex_alloc(&p,s.freeoff))
586 {
587 werr(FALSE,msgs_lookup("spNEMGS"));
588 return;
589 }
590 wimpt_noerr(wimp_transferblock(r.r[2],q,wimpt_task(),p,s.freeoff));
591 saveas(msgs_lookup("spSVSPR"),
592 msgs_lookup("spGRB"),
593 0xff9,
594 s.freeoff,
595 gSprite__saveGrabbed,
596 gSprite__sendGrabbed,
597 0,
598 &p);
599 flex_free(&p);
600 }
601 }
602
603 /*
604 * BOOL gSprite__copy(char *buff,void *handle)
605 *
606 * Use
607 * Copies a sprite, ensuring that the name hasn't been duplicated etc.
608 *
609 * Parameters
610 * char *buff == pointer to the new name
611 * void *handle == pointer to data for the sprite
612 *
613 * Returns
614 * TRUE if everything went OK
615 */
616
617 static BOOL gSprite__copy(char *buff,void *handle)
618 {
619 gSprite__data *d=handle;
620 gSprite__data *new;
621 sprite_id sid;
622 sprite_header *hdr;
623 viewer_icon i=viewer_findIcon(d->t->vs,buff);
624 sid.s.name=d->name;
625 sid.tag=0;
626 gSprite__lower(buff);
627 if (i==viewer_NOICON || i==d->i)
628 {
629 mem_useUser(indir_alloc,indir_free);
630 if (new=mem_alloc(sizeof(gSprite__data)),!new)
631 {
632 werr(FALSE,msgs_lookup("spNEMCPY"));
633 mem_useMalloc();
634 return (FALSE);
635 }
636 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
637 if (!gSprite__getMemory(d->t,hdr->next+50))
638 {
639 mem_free(new);
640 mem_useMalloc();
641 werr(FALSE,msgs_lookup("spNEMCPY"));
642 return (FALSE);
643 }
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);
650 mem_useMalloc();
651 new->w=0;
652 new->t=d->t;
653 if (!dbox_wasAdjustClick())
654 viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID);
655 intMsgs_send(glass_SPRITECHANGE,d->t);
656 return (TRUE);
657 }
658 note(msgs_lookup("spNAE"),
659 viewer_textOfIcon(i));
660 return (FALSE);
661
662 }
663
664 /*
665 * BOOL gSprite__rename(char *buff,void *handle)
666 *
667 * Use
668 * Renames a sprite, ensuring that the name hasn't been duplicated etc.
669 *
670 * Parameters
671 * char *buff == pointer to the new name
672 * void *handle == pointer to data for the sprite
673 *
674 * Returns
675 * TRUE if everything went OK
676 */
677
678 static BOOL gSprite__rename(char *buff,void *handle)
679 {
680 gSprite__data *d=handle;
681 sprite_id sid;
682 viewer_icon i=viewer_findIcon(d->t->vs,buff);
683 sid.s.name=d->name;
684 sid.tag=0;
685 gSprite__lower(buff);
686 if (i==viewer_NOICON || i==d->i)
687 {
688 mem_useUser(indir_alloc,indir_free);
689 i=viewer_addIcon(d->t->vs,buff,buff,TRUE,d);
690 mem_useMalloc();
691 if (!i)
692 return (FALSE);
693 viewer_setFiletype(i,0xff9);
694 wimpt_noerr(sprite_rename(d->t->s,&sid,buff));
695 viewer_removeIcon(d->i);
696 d->i=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();
702 return (TRUE);
703 }
704 note(msgs_lookup("spNAE"),
705 viewer_textOfIcon(i));
706 return (FALSE);
707 }
708
709 /*
710 * void gSprite__delSprites(viewer_icon i,void *handle)
711 *
712 * Use
713 * Deletes the given sprite.
714 *
715 * Parameters
716 * viewer_icon i == the icon handle that it is
717 * void *handle == the sprite data pointer
718 */
719
720 static void gSprite__delSprites(viewer_icon i,void *handle)
721 {
722 sprite_id sid;
723 gSprite__data *d=handle;
724 unused(i);
725 sid.s.name=d->name;
726 sid.tag=0;
727 wimpt_noerr(sprite_delete(d->t->s,&sid));
728 viewer_removeIcon(d->i);
729 if (d->w)
730 {
731 win_register_event_handler(d->w,0,0);
732 win_activedec();
733 wimpt_noerr(wimp_delete_wind(d->w));
734 }
735 mem_free(d);
736 }
737
738 /*
739 * void gSprite__createWindow(viewer_icon i,void *handle)
740 *
741 * Use
742 * Opens a window to display a given sprite.
743 *
744 * Parameters
745 * viewer_icon i == the icon representing the sprite
746 * void *handle == the information to add to the window
747 */
748
749 static void gSprite__windowHandler(wimp_eventstr *e,void *handle);
750
751 static void gSprite__createWindow(viewer_icon i,void *handle)
752 {
753 wimp_wstate s;
754 gSprite__data *d=handle;
755 wimp_wind w=
756 {
757 0,0,0,0, 0,0, -1,
758 wimp_WMOVEABLE |
759 wimp_WNEW |
760 wimp_WTITLE |
761 wimp_WTOGGLE |
762 wimp_WVSCR |
763 wimp_WHSCR |
764 wimp_WSIZE |
765 wimp_WBACK |
766 wimp_WQUIT,
767 7,2,7,1,3,1,12,0,
768 0,0,gSprite__WINDMINX,gSprite__WINDMINY,
769 wimp_ITEXT | wimp_IHCENTRE,
770 0,
771 0,
772 0x00010001,
773 "",
774 0,
775 };
776 sprite_id sid;
777 sprite_info info;
778 unused(i);
779 if (!d->w)
780 {
781 strcpy(w.title.text,d->name);
782 sid.s.name=d->name;
783 sid.tag=0;
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)
788 w.ex.x1=info.width;
789 if (info.height>gSprite__WINDMINY)
790 w.ex.y1=info.height;
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;
795 if (w.ex.x1>500)
796 w.box.x1=gSprite__WINDX+500;
797 if (w.ex.y1>500)
798 w.box.y0=gSprite__windHeight-500;
799 if (wimpt_complain(wimp_create_wind(&w,&d->w)))
800 return;
801 win_register_event_handler(d->w,gSprite__windowHandler,d);
802 win_activeinc();
803 gSprite__windHeight-=48;
804 if (gSprite__windHeight<612)
805 gSprite__windHeight=gSprite__WINDTOP;
806 }
807 wimpt_noerr(wimp_get_wind_state(d->w,&s));
808 wimpt_noerr(wimp_open_wind(&s.o));
809 }
810
811 /*----- Event handlers ----------------------------------------------------*/
812
813 /*
814 * BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
815 *
816 * Use
817 * Handles unknown events during the period of dragging viewer icons
818 * around. It will respond to the following drags:
819 *
820 * A drag to a blank area of icon bar will open the windows.
821 *
822 * Otherwise, a selection save will be started, and the windows packaged
823 * off to another application.
824 *
825 * Parameters
826 * wimp_eventstr *e == the event to look at
827 * void *handle == the template file whose sprite area we're dragging from
828 *
829 * Returns
830 * TRUE if the drag has been processed
831 */
832
833 static BOOL gSprite__dragUnknowns(wimp_eventstr *e,void *handle)
834 {
835 glass_tfile *t=handle;
836 wimp_mousestr m;
837 BOOL handled=FALSE;
838 switch (e->e)
839 {
840 case wimp_EUSERDRAG:
841 handled=TRUE;
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))
845 break;
846 if (m.w==-2 && m.i==-1)
847 viewer_doForIcons(t->vs,TRUE,gSprite__createWindow);
848 else
849 {
850 gSprite__size=0;
851 viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
852 wimpt_fake_event(e); /* Fool xfersend to send data */
853 xfersend(0xFF9,
854 msgs_lookup("spSEL"),
855 gSprite__size+16,
856 gSprite__saveSelection,
857 gSprite__sendSelection,
858 0,
859 e,
860 t);
861 }
862 viewer_selectAll(t->vs,FALSE);
863 break;
864 }
865 return (handled);
866 }
867
868 /*
869 * void gSprite__viewerRedraw(viewer_icon i,
870 * wimp_redrawstr *r,
871 * wimp_box *box,
872 * char *text,
873 * char *sprite,
874 * BOOL selected,
875 * void *handle)
876 *
877 * Use
878 * Redraws an icon in the sprite viewer.
879 *
880 * Parameters
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
888 */
889
890 static void gSprite__viewerRedraw(viewer_icon i,
891 wimp_redrawstr *r,
892 wimp_box *box,
893 char *text,
894 char *sprite,
895 BOOL selected,
896 void *handle)
897 {
898 int ox=r->box.x0-r->scx;
899 int oy=r->box.y1-r->scy;
900 sprite_id sid;
901 sprite_header *hdr;
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 */
909 unused(i);
910 unused(sprite);
911
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));
920
921 sid.s.name=text;
922 sid.tag=0;
923 wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr));
924 sid.s.addr=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);
929 else
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);
934
935 /* --- Bodge the multipliers to fit the sprite in --- */
936
937 newy=info.height;
938 if (info.width>gSprite__BOXX)
939 {
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;
945 }
946
947 if (newy>gSprite__BOXY)
948 {
949 zoom.xmag*=gSprite__BOXY;
950 zoom.ymag*=gSprite__BOXY;
951 zoom.xdiv*=newy;
952 zoom.ydiv*=newy;
953 }
954
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);
963
964 wimpt_noerr(sprite_put_scaled(t->s,
965 &sid,
966 8,
967 ox+box->x0+xoff,
968 oy+box->y0+yoff,
969 &zoom,
970 colbuff));
971 }
972
973 /*
974 * void gSprite__windowHandler(wimp_eventstr *e,void *handle)
975 *
976 * Use
977 * Handles events for individual sprite windows
978 *
979 * Parameters
980 * wimp_eventstr *e == the event to handle
981 * void *handle == pointer to data structure
982 */
983
984 static void gSprite__windowHandler(wimp_eventstr *e,void *handle)
985 {
986 gSprite__data *d=handle;
987 wimp_redrawstr r;
988 int ox,oy;
989 BOOL more;
990 sprite_id sid;
991 sprite_factors zoom;
992 sprite_pixtrans colbuff[256];
993 sprite_header *hdr;
994 sprite_info info;
995
996 switch (e->e)
997 {
998 case wimp_EREDRAW:
999 r.w=d->w;
1000 wimpt_noerr(wimp_redraw_wind(&r,&more));
1001 ox=r.box.x0-r.scx;
1002 oy=r.box.y1-r.scy;
1003 while (more)
1004 {
1005 sid.s.name=d->name;
1006 sid.tag=0;
1007 wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
1008 sid.s.addr=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)
1012 {
1013 colourtran_select_table(info.mode,
1014 0,
1015 -1,
1016 (wimp_paletteword *)-1,
1017 colbuff);
1018 }
1019 else
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);
1024
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);
1031
1032 wimpt_noerr(sprite_put_scaled(d->t->s,&sid,8,ox,oy,&zoom,colbuff));
1033
1034 wimpt_noerr(wimp_get_rectangle(&r,&more));
1035 }
1036 break;
1037 case wimp_EOPEN:
1038 wimpt_noerr(wimp_open_wind(&e->data.o));
1039 break;
1040 case wimp_ECLOSE:
1041 win_register_event_handler(d->w,0,0);
1042 win_activedec();
1043 wimpt_noerr(wimp_delete_wind(d->w));
1044 d->w=0;
1045 break;
1046 case wimp_ESEND:
1047 case wimp_ESENDWANTACK:
1048 switch (e->data.msg.hdr.action)
1049 {
1050 case wimp_MHELPREQUEST:
1051 help_startHelp();
1052 help_addLine(msgs_lookup("sphSPDW"),d->name);
1053 help_endHelp();
1054 break;
1055 }
1056 break;
1057 }
1058 }
1059
1060 /*
1061 * void gSprite__menuHelp(int hit[],void *handle)
1062 *
1063 * Use
1064 * Responds to help requests for the sprite viewer menu
1065 *
1066 * Parameters
1067 * int hit[] == array of menu selections
1068 * void *handle == pointer to owning template file (unused)
1069 */
1070
1071 static void gSprite__menuHelp(int hit[],void *handle)
1072 {
1073 unused(handle);
1074 help_startHelp();
1075 help_readFromMenu("spmhSPM",hit);
1076 help_endHelp();
1077 }
1078
1079 /*
1080 * void gSprite__menuHandler(int hit[],void *handle)
1081 *
1082 * Use
1083 * Responds to menu selections from the sprite viewer menu
1084 *
1085 * Parameters
1086 * int hit[] == array of menu selections
1087 * void *handle == pointer to owning template file
1088 */
1089
1090 static void gSprite__menuHandler(int hit[],void *handle)
1091 {
1092 glass_tfile *t=handle;
1093 wimp_mousestr m;
1094 char buff[50];
1095 dbox d;
1096 sprite_id sid;
1097 sprite_info info;
1098 sprite_header *hdr;
1099 switch (hit[0])
1100 {
1101 case 0:
1102 viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID);
1103 break;
1104 case glass_SPINFO:
1105 if (d=dbox_create("sprFileInfo"),d)
1106 {
1107 dbox_setfield(d,glass_SAOWNER,"%.%s",t->filename);
1108 dbox_setfield(d,
1109 glass_SASIZE,
1110 "%s",
1111 utils_cvtSize(t->s->freeoff-4));
1112 dbox_setfield(d,glass_SASPRITES,"%i",t->s->number);
1113 mbox(d,"sphSAINF");
1114 }
1115 break;
1116 case glass_SPSEL:
1117 switch (hit[1])
1118 {
1119 case glass_SPSELINFO:
1120 if (viewer_selected(t->vs)==1)
1121 {
1122 if (d=dbox_create("spriteInfo"),d)
1123 {
1124 sid.s.name=((gSprite__data *)
1125 viewer_iconHandle(viewer_firstSelected(t->vs)))->name;
1126 sid.tag=0;
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);
1133 dbox_setfield(d,
1134 glass_SPSIZE,
1135 "%s",
1136 utils_cvtSize(hdr->next+16));
1137 dbox_setfield(d,
1138 glass_SPMASK,
1139 "%s",
1140 msgs_lookup(info.mask ? "yes" : "no"));
1141 dbox_setfield(d,
1142 glass_SPPALETTE,
1143 "%s",
1144 msgs_lookup(hdr->image!=0x2c ? "yes" : "no"));
1145 mbox(d,"sphSPINF");
1146 }
1147 }
1148 else
1149 {
1150 if (d=dbox_create("sprSelInfo"),d)
1151 {
1152 dbox_setfield(d,glass_SSNUM,"%i",viewer_selected(t->vs));
1153 gSprite__size=0;
1154 viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
1155 dbox_setfield(d,
1156 glass_SPSIZE,
1157 "%s",
1158 utils_cvtSize(gSprite__size+16));
1159 mbox(d,"sphSSINF");
1160 }
1161 }
1162 break;
1163 case glass_SPSELCOPY:
1164 writable
1165 (
1166 msgs_lookup("spCOPY"),
1167 viewer_textOfIcon(viewer_firstSelected(t->vs)),
1168 buff,
1169 gSprite__copy,
1170 viewer_iconHandle(viewer_firstSelected(t->vs))
1171 );
1172 break;
1173 case glass_SPSELRENAME:
1174 writable(msgs_lookup("spREN"),
1175 viewer_textOfIcon(viewer_firstSelected(t->vs)),
1176 buff,
1177 gSprite__rename,
1178 viewer_iconHandle(viewer_firstSelected(t->vs)));
1179 break;
1180 case glass_SPSELSAVE:
1181 gSprite__size=0;
1182 viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
1183 saveas(msgs_lookup("spSVSEL"),
1184 msgs_lookup("spSEL"),
1185 0xff9,
1186 gSprite__size+16,
1187 gSprite__saveSelection,
1188 gSprite__sendSelection,
1189 0,
1190 t);
1191 break;
1192 case glass_SPSELDELETE:
1193 viewer_doForIcons(t->vs,TRUE,gSprite__delSprites);
1194 gSprite__minimise(t);
1195 intMsgs_send(glass_SPRITECHANGE,t);
1196 break;
1197 }
1198 break;
1199 case glass_SPSELALL:
1200 viewer_selectAll(t->vs,TRUE);
1201 break;
1202 case glass_SPCLRSEL:
1203 viewer_selectAll(t->vs,FALSE);
1204 break;
1205 case glass_SPSAVE:
1206 saveas(msgs_lookup("spSVSPR"),
1207 "Sprites",
1208 0xff9,
1209 t->s->freeoff-4,
1210 gSprite__saveArea,
1211 gSprite__sendArea,
1212 0,
1213 t);
1214 break;
1215 case glass_SPGRAB:
1216 window_grab(gSprite__grab,0);
1217 break;
1218 }
1219 if (wimpt_last_event()->e==wimp_EMENU)
1220 {
1221 wimpt_noerr(wimp_get_point_info(&m));
1222 if (m.bbits!=wimp_BRIGHT)
1223 viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID);
1224 }
1225 }
1226
1227 /*
1228 * menu gSprite__menuMaker(void *handle)
1229 *
1230 * Use
1231 * Creates a menu for the sprite file viewer
1232 *
1233 * Parameters
1234 * void *handle == pointer to owning template file
1235 *
1236 * Returns
1237 * Pointer to the menu it has set up
1238 */
1239
1240 static menu gSprite__menuMaker(void *handle)
1241 {
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? */
1247 {
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);
1252 }
1253 menu_minWidth(m,0);
1254 viewer_setupMenu(t->vs,
1255 msgs_lookup("spSPR"),
1256 m,
1257 glass_SPSEL,
1258 sprName);
1259 switch (viewer_selected(t->vs))
1260 {
1261 case 0:
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);
1270 break;
1271 case 1:
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);
1280 break;
1281 default:
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);
1290 break;
1291 }
1292 menu_setflags(m,glass_SPGRAB,FALSE,window_grabbing());
1293 return (m);
1294 }
1295
1296 /*
1297 * void gSprite__simMenu(glass_tfile *t,int hit1,int hit2)
1298 *
1299 * Use
1300 * Simulates a menu hit on a template file window
1301 *
1302 * Parameters
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
1306 */
1307
1308 static void gSprite__simMenu(glass_tfile *t,int hit1,int hit2)
1309 {
1310 wimp_menustr *m=menu_syshandle(gSprite__menuMaker(t));
1311 wimp_menuitem *i=(wimp_menuitem *)(m+1)+(hit1-1);
1312 int mnu[3];
1313 mnu[0]=hit1;
1314 mnu[1]=hit2;
1315 mnu[2]=0;
1316
1317 if ((int)i->submenu==-1 || hit2==0)
1318 {
1319 if (i->iconflags & wimp_INOSELECT)
1320 {
1321 bbc_vdu(7);
1322 return;
1323 }
1324 else
1325 mnu[1]=0;
1326 }
1327 else
1328 {
1329 i=(wimp_menuitem *)(i->submenu+1)+(hit2-1);
1330 if (i->iconflags & wimp_INOSELECT)
1331 {
1332 bbc_vdu(7);
1333 return;
1334 }
1335 }
1336 gSprite__menuHandler(mnu,t);
1337 }
1338
1339 /*
1340 * BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle)
1341 *
1342 * Use
1343 * Handles raw events destined for the viewer window, and picks out
1344 * interesting ones.
1345 *
1346 * Parameters
1347 * viewer v == the viewer its going for
1348 * wimp_eventstr *e == what it is
1349 * void *handle == pointer to owning template file
1350 *
1351 * Returns
1352 * TRUE if the event was worth waiting for
1353 */
1354
1355 static BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle)
1356 {
1357 glass_tfile *t=handle;
1358 char *filename;
1359 int filetype;
1360 int estsize;
1361 void *p;
1362 BOOL handled=FALSE;
1363 unused(v);
1364 switch (e->e)
1365 {
1366 case wimp_EKEY:
1367 switch (e->data.key.chcode)
1368 {
1369 case akbd_Fn+1+akbd_Sh: /* sF1 */
1370 gSprite__simMenu(t,glass_SPINFO,0);
1371 handled=TRUE;
1372 break;
1373 case 1: /* ^A */
1374 gSprite__simMenu(t,glass_SPSELALL,0);
1375 handled=TRUE;
1376 break;
1377 case 26: /* ^Z */
1378 gSprite__simMenu(t,glass_SPCLRSEL,0);
1379 handled=TRUE;
1380 break;
1381 case akbd_Fn+3: /* F3 */
1382 gSprite__simMenu(t,glass_SPSAVE,0);
1383 handled=TRUE;
1384 break;
1385 case 7: /* ^G */
1386 gSprite__simMenu(t,glass_SPGRAB,0);
1387 handled=TRUE;
1388 break;
1389
1390 case akbd_Fn+1+akbd_Ctl:/* ^F1 */
1391 gSprite__simMenu(t,glass_SPSEL,glass_SPSELINFO);
1392 handled=TRUE;
1393 break;
1394 case 3: /* ^C */
1395 gSprite__simMenu(t,glass_SPSEL,glass_SPSELCOPY);
1396 handled=TRUE;
1397 break;
1398 case 18: /* ^R */
1399 gSprite__simMenu(t,glass_SPSEL,glass_SPSELRENAME);
1400 handled=TRUE;
1401 break;
1402 case akbd_Fn+3+akbd_Sh: /* sF3 */
1403 gSprite__simMenu(t,glass_SPSEL,glass_SPSELSAVE);
1404 handled=TRUE;
1405 break;
1406 case 24: /* ^X */
1407 gSprite__simMenu(t,glass_SPSEL,glass_SPSELDELETE);
1408 handled=TRUE;
1409 break;
1410
1411 case akbd_Fn+2+akbd_Ctl:/* ^F2 */
1412 viewer_hide(v);
1413 handled=TRUE;
1414 break;
1415 }
1416 break;
1417
1418 case wimp_ESEND:
1419 case wimp_ESENDWANTACK:
1420 switch (e->data.msg.hdr.action)
1421 {
1422 case wimp_MDATASAVE:
1423 filetype=xferrecv_checkimport(&estsize);
1424 switch (filetype)
1425 {
1426 case 0xff9:
1427 if (xferrecv_returnImportedBlock(&p)!=-1)
1428 {
1429 gSprite_mergeFromMemory(t,&p);
1430 flex_free(&p);
1431 }
1432 break;
1433 }
1434 handled=TRUE;
1435 break;
1436 case wimp_MDATALOAD:
1437 filetype=xferrecv_checkinsert(&filename);
1438 switch (filetype)
1439 {
1440 case 0xff9:
1441 gSprite_mergeFromFile(t,filename);
1442 xferrecv_insertfileok();
1443 break;
1444 }
1445 handled=TRUE;
1446 break;
1447 }
1448 break;
1449 }
1450 return (handled);
1451 }
1452
1453 /*
1454 * void gSprite__viewerHandler(viewer v,
1455 * viewer_icon i,
1456 * wimp_bbits b,
1457 * void *vhandle,
1458 * void *ihandle)
1459 *
1460 * Use
1461 * Handles events in a sprite viewer
1462 *
1463 * Parameters
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
1469 */
1470
1471 static void gSprite__viewerHandler(viewer v,
1472 viewer_icon i,
1473 wimp_bbits b,
1474 void *vhandle,
1475 void *ihandle)
1476 {
1477 glass_tfile *t=vhandle;
1478 unused(ihandle);
1479 switch ((int)i)
1480 {
1481 case (int)viewer_CLOSE:
1482 viewer_hide(v);
1483 break;
1484 case (int)viewer_HELP:
1485 help_startHelp();
1486 help_addLine(msgs_lookup("sphMVW"));
1487 help_endHelp();
1488 break;
1489 default:
1490 if (b!=wimp_BMID)
1491 {
1492 gSprite__gainSelection(t);
1493 viewer_clickSelect(v,i,b);
1494 }
1495 switch (b)
1496 {
1497 case wimp_BMID:
1498 if (t==gSprite__selOwner ||
1499 !gSprite__selOwner ||
1500 !viewer_selected(gSprite__selOwner->vs))
1501 {
1502 gSprite__selOwner=t;
1503 viewer_clickSelect(v,i,b);
1504 }
1505 menu_make(gSprite__menuMaker,
1506 gSprite__menuHandler,
1507 gSprite__menuHelp,
1508 t);
1509 break;
1510 case wimp_BLEFT:
1511 case wimp_BRIGHT:
1512 if (i!=viewer_NOICON)
1513 {
1514 gSprite__createWindow(i,viewer_iconHandle(i));
1515 viewer_selectIcon(i,FALSE);
1516 }
1517 break;
1518 case wimp_BDRAGLEFT:
1519 case wimp_BDRAGRIGHT:
1520 if (i!=viewer_NOICON)
1521 {
1522 tfile_dragSelected(i,b,"spackage");
1523 win_add_unknown_event_processor(gSprite__dragUnknowns,t);
1524 }
1525 break;
1526 }
1527 break;
1528 }
1529 }
1530
1531 /*----- External routines -------------------------------------------------*/
1532
1533 /*
1534 * void gSprite_kill(glass_tfile *t)
1535 *
1536 * Use
1537 * Closes the sprite viewer and frees the sprite area
1538 *
1539 * Parameters
1540 * glass_tfile *t == the template file that's closing
1541 */
1542
1543 void gSprite_kill(glass_tfile *t)
1544 {
1545 if (t->vs)
1546 viewer_delete(t->vs,gSprite__closeWindows);
1547 indir_free(t->s);
1548 }
1549
1550 /*
1551 * void gSprite_display(glass_tfile *t)
1552 *
1553 * Use
1554 * Displays the sprite viewer for the specified template file.
1555 *
1556 * glass_tfile *t == the template file whose sprites we want to see
1557 */
1558
1559 void gSprite_display(glass_tfile *t)
1560 {
1561 viewer_selectAll(t->vs,FALSE);
1562 viewer_display(t->vs);
1563 }
1564
1565 /*
1566 * void gSprite_mergeFromMemory(glass_tfile *t,void **p)
1567 *
1568 * Use
1569 * Merges a sprite file which is stored in memory. This is so I can do
1570 * in-memory transfer of sprites.
1571 *
1572 * Parameters
1573 * glass_tfile *t == the template file owner of the sprite area
1574 * void **p == the flex block stroing the sprite file
1575 */
1576
1577 void gSprite_mergeFromMemory(glass_tfile *t,void **p)
1578 {
1579 int sprites=_ptr(sprite_area,*p,-4)->number;
1580 int i;
1581 int h=_ptr(sprite_area,*p,-4)->sproff-4;
1582 int length;
1583 sprite_id sid;
1584 viewer_icon icn;
1585 char buff[15];
1586 gSprite__data *d;
1587 if (!gSprite__getMemory(t,_ptr(sprite_area,*p,-4)->freeoff))
1588 {
1589 werr(FALSE,msgs_lookup("spNEMM"));
1590 return;
1591 }
1592 for (i=1;i<=sprites;i++)
1593 {
1594 length=_ptr(sprite_header,*p,h)->next;
1595 buff[12]=0;
1596 memcpy(buff,_ptr(sprite_header,*p,h)->name,12);
1597 sid.s.name=buff;
1598 sid.tag=0;
1599
1600 /* --- Slight problem --- *
1601 *
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.
1607 *
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
1610 * found the icon.
1611 */
1612
1613 if (icn=viewer_findIcon(t->vs,sid.s.name),
1614 icn && !sprite_delete(t->s,&sid))
1615 {
1616 d=viewer_iconHandle(icn);
1617 if (d->w)
1618 {
1619 win_register_event_handler(d->w,0,0);
1620 wimpt_noerr(wimp_delete_wind(d->w));
1621 d->w=0;
1622 }
1623 mem_free(d);
1624 viewer_removeIcon(icn);
1625 }
1626 mem_useUser(indir_alloc,indir_free);
1627 if (d=mem_alloc(sizeof(gSprite__data)),!d)
1628 {
1629 mem_useMalloc();
1630 werr(FALSE,msgs_lookup("spNEMM"));
1631 return;
1632 }
1633 strcpy(d->name,sid.s.name);
1634 d->t=t;
1635 d->w=0;
1636 d->serial=gSprite__serial++;
1637 if (d->i=viewer_addIcon(t->vs,sid.s.name,sid.s.name,TRUE,d),!d->i)
1638 {
1639 mem_useMalloc();
1640 mem_free(d);
1641 return;
1642 }
1643 mem_useMalloc();
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;
1647 t->s->number++;
1648 h+=length;
1649 }
1650 gSprite__minimise(t);
1651 intMsgs_send(glass_SPRITECHANGE,t);
1652 }
1653
1654 /*
1655 * void gSprite_mergeFromFile(glass_tfile *t,char *name)
1656 *
1657 * Use
1658 * Merges the given file into the sprite area specified.
1659 *
1660 * Parameters
1661 * glass_tfile *t == the template file that we're going to load for
1662 * char *name == the name of the file to load
1663 */
1664
1665 void gSprite_mergeFromFile(glass_tfile *t,char *name)
1666 {
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")))
1672 return;
1673 if (!flex_alloc(&p,f.start))
1674 {
1675 werr(FALSE,msgs_lookup("spNEMM"));
1676 return;
1677 }
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")))
1682 {
1683 flex_free(&p);
1684 return;
1685 }
1686 gSprite_mergeFromMemory(t,&p); /* Now do the merge */
1687 flex_free(&p);
1688 }
1689
1690 /*
1691 * void gSprite_new(glass_tfile *t)
1692 *
1693 * Use
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.
1698 *
1699 * Parameters
1700 * glass_tfile *t == the file to use
1701 */
1702
1703 void gSprite_new(glass_tfile *t)
1704 {
1705 char buff[256];
1706 void *def;
1707 if (t->s=indir_alloc(gSprite__CHUNK),!t->s)
1708 {
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 */
1712 return;
1713 }
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,
1718 gSprite__BOXX,
1719 gSprite__BOXY+48,
1720 resspr_area(),
1721 buff,
1722 msgs_lookup("spBANR"));
1723 mem_useMalloc();
1724 if (!t->vs)
1725 return;
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;
1734 t->s->number=0;
1735 t->s->sproff=16;
1736 t->s->freeoff=16;
1737 if (gPrefs_current()->sLoadDef && gSprite__default)
1738 {
1739 def=&gSprite__default->number;
1740 gSprite_mergeFromMemory(t,&def);
1741 }
1742 }
1743
1744 /*
1745 * sprite_area *gSprite_area(void)
1746 *
1747 * Use
1748 * Returns the address of the Glass default sprite file, or 1 for the
1749 * WIMP sprite area if no default sprites are loaded
1750 */
1751
1752 sprite_area *gSprite_area(void)
1753 {
1754 return (gSprite__default ? gSprite__default : (sprite_area *)1);
1755 }
1756
1757 /*
1758 * void gSprite_init(void)
1759 *
1760 * Use
1761 * Loads the Glass default sprite area into memory.
1762 */
1763
1764 void gSprite_init(void)
1765 {
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")))
1770 return;
1771 if (f.action==0)
1772 return;
1773 if (gSprite__default=mem_alloc(f.start+4),!gSprite__default)
1774 {
1775 werr(FALSE,msgs_lookup("spNEMLD"));
1776 return;
1777 }
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")))
1785 gSprite__default=0;
1786 }