Initial revision
[ssr] / StraySrc / Libraries / Steel / c / viewer
1 /*
2 * viewer
3 * Allows creation of Filer-like windows which rearrange themselves.
4 *
5 * v. 1.00 (13 August 1993)
6 *
7 * © 1993-1998 Straylight
8 */
9
10 /*----- Licensing note ----------------------------------------------------*
11 *
12 * This file is part of Straylight's Steel library.
13 *
14 * Steel is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * Steel is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Steel. If not, write to the Free Software Foundation,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 #include "wimp.h"
30 #include "wimpt.h"
31 #include "win.h"
32 #include "viewer.h"
33 #include "msgs.h"
34 #include "bbc.h"
35 #include "werr.h"
36 #include "os.h"
37 #include "xfersend.h"
38 #include "mem.h"
39 #include "coords.h"
40 #include "utils.h"
41 #include "help.h"
42 #include "fileicon.h"
43 #include "buffer.h"
44 #include "swis.h"
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48
49 #include "dll.h"
50
51 #ifndef _dll_NODLL
52 extern void _dllEntry(viewer__events)(wimp_eventstr *e,void *handle);
53 #endif
54
55 /*
56 * A structure of information about a viewer icon.
57 */
58
59 typedef struct viewer__iconstr
60 {
61 viewer_icon next;
62 viewer_icon last;
63 char *text;
64 char sprite[15];
65 void *handle;
66 int filetype;
67 BOOL selected;
68 viewer v;
69 }
70 viewer__iconstr;
71
72 /*
73 * A structure of information about a viewer window.
74 */
75
76 typedef struct viewer__viewerstr
77 {
78 wimp_w wind;
79 int icons;
80 viewer_eventhandler events;
81 void *closeHandle;
82 viewer_raweventhandler rawEvents;
83 void *rawHandle;
84 viewer_redrawhandler rdr;
85 void *rdrHandle;
86 viewer_compare cmp;
87 sprite_area *spr;
88 int width;
89 int height;
90 int across;
91 int down;
92 int selected;
93 char banner[50];
94 char title[256];
95 viewer_icon iconlist;
96 viewer_icon menuSel;
97 wimp_openstr oldSize;
98 }
99 viewer__viewerstr;
100
101 /*
102 * Some constants for the things
103 */
104
105 #define viewer__MINWIDTH 380
106 #define viewer__MINHEIGHT 160
107 #define viewer__GAP 16
108 #define viewer__BANNERHEIGHT 48
109
110 static viewer_saveproc viewer__usersave;
111 static viewer_sendproc viewer__usersend;
112 static viewer_printproc viewer__userprint;
113 static viewer_icon viewer__currentIcon;
114 static viewer viewer__currentViewer;
115 static int viewer__filetype;
116
117 #define max(x,y) ((x)>(y) ? (x) : (y))
118 #define min(x,y) ((x)<(y) ? (x) : (y))
119
120 /*
121 * void viewer__resize(viewer v)
122 *
123 * Use
124 * Resizes the viewer nicely, altering the extent if necessary.
125 *
126 * Parameters
127 * viewer v == the viewer handle
128 */
129
130 static void viewer__resize(viewer v)
131 {
132 wimp_wstate s;
133 int w;
134 int across;
135 int down;
136 int minw;
137 int scw;
138 int maxacc;
139 wimp_redrawstr r;
140 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
141 w=s.o.box.x1-s.o.box.x0;
142 scw=wimpt_scwidth()-40;
143 across=w/(v->width+viewer__GAP);
144 maxacc=scw/(v->width+viewer__GAP);
145 if (across>v->icons)
146 across=v->icons;
147 if (maxacc>v->icons)
148 maxacc=v->icons;
149 if (across>maxacc)
150 across=maxacc;
151 if (across==0)
152 across=1;
153 down=v->icons/across;
154 if (v->icons%across!=0)
155 down++;
156 if (down==0)
157 down=1;
158 if (v->across==across && v->down==down && (s.flags & wimp_WOPEN))
159 return;
160 minw=wimpt_stringWidth(v->title)+164;
161 if (v->banner[0]!='\0')
162 {
163 int l=wimpt_stringWidth(v->banner)+64;
164 if (l>minw)
165 minw=l;
166 }
167 if (minw<viewer__MINWIDTH)
168 minw=viewer__MINWIDTH;
169 r.w=v->wind;
170 r.box.x0=0;
171 r.box.y0=-(v->height+viewer__GAP)*down;
172 if (v->banner[0]!='\0')
173 r.box.y0-=viewer__BANNERHEIGHT;
174 if (r.box.y0>-viewer__MINHEIGHT)
175 r.box.y0=-viewer__MINHEIGHT;
176 r.box.x1=(v->width+viewer__GAP)*maxacc;
177 if (r.box.x1<minw)
178 r.box.x1=minw;
179 r.box.y1=0;
180 wimpt_noerr(wimp_set_extent(&r));
181
182 /* --- Acorn-approved hack --- *
183 *
184 * We have problems with the Wimp fiddling our extent after we've set it,
185 * so we just redraw lots and lots.
186 */
187
188 r.box.x0=r.box.y0=-0xFFFFFF;
189 r.box.x1=r.box.y1=0xFFFFFF;
190 wimpt_noerr(wimp_force_redraw(&r));
191
192 if (s.flags & wimp_WOPEN)
193 wimpt_noerr(wimp_open_wind(&s.o));
194 v->across=across;
195 v->down=down;
196 }
197
198 /*
199 * void viewer__redrawicon(wimp_redrawstr *r,viewer_icon icn,wimp_box *box)
200 *
201 * Use
202 * Redraws an icon in the box specified.
203 *
204 * Parameters
205 * viewer_icon icn == the icon to redraw
206 * wimp_box *box == the box to draw it in
207 */
208
209 static void viewer__redrawicon
210 (
211 wimp_redrawstr *r,
212 viewer_icon icn,
213 wimp_box *box
214 )
215 {
216 wimp_icon i;
217 char valid[256];
218 viewer v=icn->v;
219 if (v->rdr)
220 {
221 (v->rdr)(icn,r,box,icn->text,icn->sprite,icn->selected,v->rdrHandle);
222 return;
223 }
224 i.box=*box;
225 if (icn->text!=0 && icn->sprite[0]!='\0')
226 {
227 i.flags=wimp_ITEXT|wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE;
228 sprintf(valid,"S%s",icn->sprite);
229 i.data.indirecttext.buffer=icn->text;
230 i.data.indirecttext.validstring=valid;
231 i.data.indirecttext.bufflen=1;
232 }
233 else if (icn->text!=0)
234 {
235 i.flags=wimp_ITEXT|wimp_INDIRECT|wimp_IHCENTRE|wimp_IVCENTRE;
236 i.data.indirecttext.buffer=icn->text;
237 i.data.indirecttext.validstring=(char *)-1;
238 i.data.indirecttext.bufflen=1;
239 }
240 else
241 {
242 i.flags=wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE|wimp_IVCENTRE;
243 i.data.indirectsprite.name=icn->sprite;
244 i.data.indirectsprite.spritearea=v->spr;
245 i.data.indirectsprite.nameisname=TRUE;
246 }
247 i.flags|=0x17000000;
248 if (icn->selected)
249 i.flags|=wimp_ISELECTED;
250 wimpt_noerr(wimp_ploticon(&i));
251 }
252
253 /*
254 * void viewer_drawFileIcons
255 * (
256 * viewer_icon icn,
257 * wimp_redrawstr *r,
258 * wimp_box *box,
259 * char *text,
260 * char *sprite,
261 * BOOL selected,
262 * void *handle
263 * )
264 *
265 * Use
266 * Redraw handler which takes into account filetypes of icons. The icons
267 * automatically get new sprites if the sprites for their filetypes change.
268 * For applications, the text is considered to be a filename. Register
269 * this function using viewer_redrawHandler().
270 *
271 * Parameters
272 * viewer_icon icn == the icon to paint
273 * wimp_redrawstr *r == information about this redraw
274 * wimp_box *box == the box to draw the icon in
275 * char *text == the text to display
276 * char *sprite == the sprite to display
277 * BOOL selected == is the icon selected?
278 * void *handle == a caller defined handle (ignored)
279 */
280
281 void viewer_drawFileIcons
282 (
283 viewer_icon icn,
284 wimp_redrawstr *r,
285 wimp_box *box,
286 char *text,
287 char *sprite,
288 BOOL selected,
289 void *handle
290 )
291 {
292 wimp_icon i;
293 char valid[256];
294 handle=handle;
295 r=r;
296 i.box=*box;
297 i.flags=wimp_ITEXT|wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE;
298 if (icn->filetype!=-1)
299 sprintf(valid,"S%s",fileicon_spriteName(icn->filetype,text));
300 else
301 sprintf(valid,"S%s",sprite);
302 i.data.indirecttext.buffer=text;
303 i.data.indirecttext.validstring=valid;
304 i.data.indirecttext.bufflen=1;
305 i.flags|=0x17000000;
306 if (selected)
307 i.flags|=wimp_ISELECTED;
308 wimpt_noerr(wimp_ploticon(&i));
309 }
310
311 /*
312 * viewer__redraw(wimp_redrawstr *r,void *handle)
313 *
314 * Use
315 * Redraws a viewer window
316 *
317 * Parameters
318 * wimp_redrawstr *r == the bit to redraw
319 * void *handle == the viewer
320 */
321
322 static void viewer__redraw(wimp_redrawstr *r,void *handle)
323 {
324 viewer v=(viewer)handle;
325 viewer_icon icn=v->iconlist;
326 int oy=r->box.y1-r->scy;
327 int x=viewer__GAP/2;
328 int y=-viewer__GAP/2;
329 wimp_box box;
330 coords_cvtstr c;
331 wimp_box g;
332 int cnt=0;
333 wimp_icon banicn={28,-48,1000,0,0x037000131};
334 c.box=r->box;
335 c.scx=r->scx;
336 c.scy=r->scy;
337 g=r->g;
338 coords_box_toworkarea(&g,&c);
339 wimp_setcolour(0x81);
340 bbc_clg();
341 if (v->banner[0]!='\0')
342 {
343 if (g.y1>-viewer__BANNERHEIGHT)
344 {
345 wimp_setcolour(3);
346 bbc_rectanglefill
347 (
348 r->g.x0,
349 oy-viewer__BANNERHEIGHT,
350 r->g.x1-r->g.x0,
351 viewer__BANNERHEIGHT
352 );
353 wimp_setcolour(7);
354 banicn.box.x1=100+wimpt_stringWidth(v->banner);
355 banicn.data.indirecttext.buffer=v->banner;
356 banicn.data.indirecttext.validstring=(char *)-1;
357 wimpt_noerr(wimp_ploticon(&banicn));
358 }
359 y-=viewer__BANNERHEIGHT;
360 }
361 while (icn)
362 {
363 box.x0=x;
364 box.x1=x+v->width;
365 box.y1=y;
366 box.y0=y-v->height;
367 if (coords_boxesoverlap(&box,&g))
368 viewer__redrawicon(r,icn,&box);
369 icn=icn->next;
370 if ((++cnt)==v->across)
371 {
372 x=viewer__GAP/2;
373 y-=viewer__GAP+v->height;
374 cnt=0;
375 }
376 else
377 x+=viewer__GAP+v->width;
378 }
379 }
380
381 /*
382 * void viewer__events(wimp_eventstr *e,void *handle)
383 *
384 * Use
385 * Window event handler for the viewer.
386 *
387 * Parameters
388 * wimp_eventstr *e == the wimp event structure
389 * void *handle == my data (i.e. a 'this' pointer to my viewer__viewerstr)
390 */
391
392 _dll_static void viewer__events(wimp_eventstr *e,void *handle)
393 {
394 BOOL handled=FALSE;
395 viewer v=(viewer)handle;
396 wimp_wstate s;
397 if (v->rawEvents)
398 handled=(v->rawEvents)(v,e,v->rawHandle);
399 if (handled)
400 return;
401 switch (e->e)
402 {
403 case wimp_EREDRAW:
404 wimpt_redraw(viewer__redraw,v);
405 break;
406 case wimp_EOPEN:
407 if (wimpt_justChangedMode())
408 viewer_settitle(v,0);
409 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
410 wimpt_noerr(wimp_open_wind(&e->data.o));
411 viewer__resize(v);
412 if (s.flags & wimp_WCLICK_TOGGLE)
413 {
414 if (s.flags & wimp_WFULL)
415 {
416 e->data.o.box=v->oldSize.box;
417 e->data.o.x=v->oldSize.x;
418 e->data.o.y=v->oldSize.y;
419 wimpt_noerr(wimp_open_wind(&e->data.o));
420 }
421 else
422 v->oldSize=s.o;
423 }
424 break;
425 case wimp_ECLOSE:
426 if (v->events)
427 (v->events)(v,viewer_CLOSE,(wimp_bbits)0,v->closeHandle,0);
428 break;
429 case wimp_EBUT:
430 {
431 viewer_icon i=viewer_iconFromCoords
432 (
433 v,
434 e->data.but.m.x,
435 e->data.but.m.y
436 );
437 if (v->events)
438 {
439 (v->events)
440 (
441 v,
442 i,
443 e->data.but.m.bbits,
444 v->closeHandle,
445 (i!=viewer_NOICON) ? i->handle : 0
446 );
447 }
448 }
449 break;
450 case wimp_EKEY:
451 wimpt_noerr(wimp_processkey(e->data.key.chcode));
452 break;
453 case wimp_ESEND:
454 case wimp_ESENDWANTACK:
455 switch (e->data.msg.hdr.action)
456 {
457 case wimp_MHELPREQUEST:
458 {
459 viewer_icon i=viewer_iconFromCoords
460 (
461 v,
462 e->data.msg.data.helprequest.m.x,
463 e->data.msg.data.helprequest.m.y
464 );
465 if (v->events)
466 {
467 (v->events)
468 (
469 v,
470 viewer_HELP,
471 0,
472 v->closeHandle,
473 (i!=viewer_NOICON) ? i->handle : 0
474 );
475 }
476 }
477 break;
478 }
479 break;
480 }
481 }
482
483 /*
484 * viewer viewer_create
485 * (
486 * int x,
487 * int y,
488 * int width,
489 * int height,
490 * sprite_area *spr,
491 * char *title,
492 * char *banner
493 * )
494 *
495 * Use
496 * Creates a viewer window. Note that viewer windows don't need templates,
497 * and don't contain real wimp icons, just yer normal redrawn-by-
498 * application things (which can be handled by a caller-defined function if
499 * necessary). The banner along the top is optional - if a null pointer is
500 * passed, no banner is included. The sprite area passed applies to all
501 * the icons in the window, although if you want to, you can use your own
502 * redraw routine to handle different sprite areas for them.
503 *
504 * Parameters
505 * int x,int y == the coordinates of the top-left corner of the window
506 * (file windows for editors need good positioning here).
507 * int width == the width of an icon
508 * int height == the height of an icon
509 * sprite_area *spr == the sprite area for the window
510 * char *title == the title of the window
511 * char *banner == the banner heading along the top (like 'Sprite file
512 * window' or something)
513 *
514 * Returns
515 * A handle to the viewer window. As usual, a NULL pointer indicates
516 * something went wrong.
517 */
518
519 viewer viewer_create
520 (
521 int x,
522 int y,
523 int width,
524 int height,
525 sprite_area *spr,
526 char *title,
527 char *banner
528 )
529 {
530 viewer v=(viewer)mem_alloc(sizeof(viewer__viewerstr));
531 wimp_wind w=
532 {
533 {0,0,0,0},
534 0,0,
535 -1,
536 (
537 wimp_WMOVEABLE |
538 wimp_WBACK |
539 wimp_WQUIT |
540 wimp_WTITLE |
541 wimp_WTOGGLE |
542 wimp_WVSCR |
543 wimp_WSIZE |
544 wimp_WNEW
545 ),
546 {7,2,7,255,3,1,12,0},
547 {0,0,0,0},
548 wimp_ITEXT|wimp_IHCENTRE|wimp_INDIRECT,
549 wimp_IBTYPE*wimp_BCLICKDRAGDOUBLE,
550 0,
551 1,
552 "Yay",
553 0
554 };
555 w.box.x0=x;
556 w.box.x1=x+900-(900%(width+viewer__GAP));
557 if (w.box.x1==x)
558 w.box.x1=x+width+viewer__GAP;
559 w.box.y0=y-500+(500%(height+viewer__GAP));
560 if (w.box.y0==y)
561 w.box.y0=y-height+viewer__GAP;
562 w.box.y1=y;
563 w.spritearea=(void *)spr;
564 if (!v)
565 {
566 werr(FALSE,msgs_lookup("viewerNEM:Not enough room to create viewer."));
567 return (0);
568 }
569 w.title.indirecttext.buffer=v->title;
570 w.title.indirecttext.validstring=(char *)-1;
571 w.title.indirecttext.bufflen=256;
572 strcpy(v->title,title);
573 if (banner)
574 {
575 strcpy(v->banner,banner);
576 w.box.y0-=viewer__BANNERHEIGHT;
577 }
578 else
579 v->banner[0]='\0';
580 v->icons=0;
581 v->events=0;
582 v->rawEvents=0;
583 v->rdr=0;
584 v->cmp=0;
585 v->iconlist=0;
586 v->width=width;
587 v->height=height;
588 v->spr=spr;
589 v->across=-1;
590 v->selected=0;
591 v->menuSel=viewer_NOICON;
592 v->oldSize.box=w.box;
593 v->oldSize.x=w.scx;
594 v->oldSize.y=w.scy;
595 if (wimp_create_wind(&w,&v->wind))
596 {
597 werr
598 (
599 FALSE,
600 msgs_lookup("viewerTMW:Too many windows - "
601 "%s could not create viewer."),
602 wimpt_programname()
603 );
604 mem_free(v);
605 return (0);
606 }
607 win_register_event_handler(v->wind,_dllEntry(viewer__events),v);
608 win_activeinc();
609 return (v);
610 }
611
612 /*
613 * void viewer_display(viewer v)
614 *
615 * Use
616 * Displays a viewer on the screen.
617 *
618 * Parameters
619 * viewer v == the viewer handle
620 */
621
622 void viewer_display(viewer v)
623 {
624 wimp_wstate state;
625 viewer__resize(v);
626 wimpt_noerr(wimp_get_wind_state(v->wind,&state));
627 state.o.behind=-1;
628 wimpt_noerr(wimp_open_wind(&state.o));
629 }
630
631 /*
632 * void viewer_hide(viewer v)
633 *
634 * Use
635 * Hides an open viewer.
636 *
637 * Parameters
638 * viewer v == the handle
639 */
640
641 void viewer_hide(viewer v)
642 {
643 wimpt_noerr(wimp_close_wind(v->wind));
644 }
645
646 /*
647 * void viewer_delete(viewer v,void (*freeProc)(void *handle))
648 *
649 * Use
650 * Zaps a viewer and everything in it. The function you pass to this
651 * routine is called with every icon handle the viewer has associated with
652 * it, so you don't need to link all the structures together - I've already
653 * done that here!
654 *
655 * Parameters
656 * viewer v == the viewer to destroy
657 * void (*freeProc)(void *handle) == a function to free one of the caller-
658 * defined viewer icon structures.
659 */
660
661 void viewer_delete(viewer v,void (*freeProc)(void *handle))
662 {
663 viewer_icon icn=v->iconlist;
664 viewer_icon i;
665 while (icn)
666 {
667 if (icn->handle && freeProc)
668 freeProc(icn->handle);
669 i=icn;
670 icn=i->next;
671 mem_free(i->text);
672 mem_free(i);
673 }
674 win_register_event_handler(v->wind,0,0);
675 win_activedec();
676 wimpt_noerr(wimp_delete_wind(v->wind));
677 mem_free(v);
678 }
679
680 /*
681 * void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle)
682 *
683 * Use
684 * Attaches an event handler to the viewer. The handle passed to this
685 * function is only used for close events, so you can take appropriate
686 * action at the other end. Otherwise, the handle for the icon concerned
687 * is used. Suggested code:
688 *
689 * void user_viewer(viewer v,viewer_icon i,wimp_bbits b,void *handle)
690 * {
691 * user_fileStructure *file=(user_fileStructure *)handle;
692 * user_itemStructure *item=(user_itemStructure *)handle;
693 * switch ((int)i)
694 * {
695 * case (int)viewer_CLOSE:
696 * ... use 'file' for this bit of code ...
697 * break;
698 * case viewer_NOICON:
699 * ... use 'file' for this bit as well ...
700 * break;
701 * default:
702 * ... use 'item' for this bit of code ...
703 * break;
704 * }
705 * }
706 *
707 * Parameters
708 * viewer v == the viewer to attach the handler to
709 * viewer_eventhandler proc == the event handler
710 * void *handle == the handle
711 */
712
713 void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle)
714 {
715 v->events=proc;
716 v->closeHandle=handle;
717 }
718
719 /*
720 * void viewer_rawEventHandler
721 * (
722 * viewer v,
723 * viewer_raweventhandler proc,
724 * void *handle
725 * )
726 *
727 * Use
728 * Attaches a raw event handler to a viewer. Same as always, this one.
729 *
730 * Parameters
731 * viewer v == the viewer handle
732 * viewer_raweventhandler proc == the handler routine
733 * void *handle == the handle for the user's data
734 */
735
736 void viewer_rawEventHandler
737 (
738 viewer v,
739 viewer_raweventhandler proc,
740 void *handle
741 )
742 {
743 v->rawEvents=proc;
744 v->rawHandle=handle;
745 }
746
747 /*
748 * void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle)
749 *
750 * Use
751 * Adds in a user-defined routine for redrawing icons in the window.
752 *
753 * Parameters
754 * viewer v == the viewer handle
755 * viewer_redrawhandler proc == the routine for doing the redraw
756 * void *handle == a handle to be passed to the routine (a sprite area or
757 * something)
758 */
759
760 void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle)
761 {
762 v->rdr=proc;
763 v->rdrHandle=handle;
764 }
765
766 /*
767 * void viewer_setIconSize(viewer v,int width,int height)
768 *
769 * Use
770 * Sets a new icon size for the viewer. This would normally be
771 * accompanied by a chnge in redraw handler. It would be used e.g. when
772 * using a menu option giving a choice between 'Large icons' and 'Small
773 * icons'.
774 *
775 * Parameters
776 * viewer v == the viewer which is to receive this change
777 * int width == the new width
778 * int height == the new height
779 */
780
781 void viewer_setIconSize(viewer v,int width,int height)
782 {
783 v->width=width;
784 v->height=height;
785 v->across=-1;
786 viewer__resize(v);
787 }
788
789 /*
790 * void viewer_setCompare(viewer v,viewer_compare cmp)
791 *
792 * Use
793 * Registers a compare function for the viewer specified. The function
794 * is passed the caller-defined handles of two icons. The function must
795 * return <0 if a<b, >0 if a>b, or ==0 if a==b (like strcmp does). The
796 * viewer's icons are then resorted. Pass 0 to use the default sorting
797 * system (a caseless compare on the icon text)
798 *
799 * The resorting algorithm is the link mergesort, originally implemented
800 * in the Sapphire linklist manager.
801 *
802 * Parameters
803 * viewer v == the viewer we're going to set the comparer up for
804 * viewer_compare cmp == the function to do comparing
805 */
806
807 void viewer_setCompare(viewer v,viewer_compare cmp)
808 {
809 v->cmp=cmp;
810 if (!v->icons)
811 return;
812 v->across=-1;
813 viewer__resize(v);
814
815 /* --- Now we have to resort the list --- *
816 *
817 * This code is pretty much based on the mergesort code printed in
818 * Sedgewick's Algorithms.
819 */
820
821 #define next(p) ((p) ? (p)->next : (p))
822
823 {
824 viewer_icon a,b,c,t,todo,x,y;
825 int i,n,more;
826
827 n=1;
828 c=v->iconlist;
829
830 do
831 {
832 todo=v->iconlist;
833 more=FALSE;
834 c=(viewer_icon)&v->iconlist;
835 while (todo)
836 {
837 t=todo;
838 a=t;
839 if (a!=v->iconlist)
840 more=TRUE;
841 for (i=1;i<n;i++)
842 t=next(t);
843 b=next(t);
844 x=b;
845 t=b;
846 for (i=1;i<n;i++)
847 t=next(t);
848 t=next(t);
849 y=t;
850 todo=t;
851
852 /* --- Now we have to do the actual merge --- *
853 *
854 * This is made a little bit more difficult since we have null-
855 * terminated lists rather than a weird node which points to itself.
856 */
857
858 while (a!=x || b!=y)
859 {
860 if (a==x)
861 i=1;
862 else if (b==y)
863 i=-1;
864 else if (v->cmp)
865 i=(v->cmp)(a->handle,b->handle);
866 else
867 i=utils_caselessCmp(a->text,b->text);
868
869 if (i<=0)
870 {
871 c->next=a;
872 c=a;
873 a=next(a);
874 }
875 else
876 {
877 c->next=b;
878 c=b;
879 b=next(b);
880 }
881 }
882
883 }
884 c->next=0;
885 n*=2;
886 }
887 while (more);
888 }
889
890 #undef next
891
892 /* --- Now we have to sort out the back links --- */
893
894 {
895 viewer_icon a=v->iconlist;
896
897 a->last=0;
898 while (a->next)
899 {
900 a->next->last=a;
901 a=a->next;
902 }
903 }
904 }
905
906 /*
907 * viewer_icon viewer_addIcon
908 * (
909 * viewer v,
910 * char *text,
911 * char *sprite,
912 * BOOL inOrder,
913 * void *handle
914 * )
915 *
916 * Use
917 * Adds a new icon to a viewer window.
918 *
919 * Parameters
920 * viewer v == the handle of the viewer to use.
921 * char *text == the text to put under the icon (may be null)
922 * char *sprite == the sprite to use (may be null)
923 * BOOL inOrder == whether you want the icons sorted into order according
924 * to the text fields
925 * void *handle == the handle you want to pass to the event handler routine
926 *
927 * Returns
928 * A handle to the icon. If this is NULL, something went majorly wrong
929 * (sorry, John)
930 */
931
932 viewer_icon viewer_addIcon
933 (
934 viewer v,
935 char *text,
936 char *sprite,
937 BOOL inOrder,
938 void *handle
939 )
940 {
941 viewer_icon icn=(viewer_icon)&(v->iconlist);
942 viewer_icon new=(viewer_icon)mem_alloc(sizeof(viewer__iconstr));
943 if (!new)
944 {
945 werr(FALSE,msgs_lookup("viewerCCI:Not enough room to create new icon."));
946 return (0);
947 }
948 if (text)
949 {
950 if (new->text=mem_alloc(strlen(text)+1),!new->text)
951 {
952 mem_free(new);
953 werr
954 (
955 FALSE,
956 msgs_lookup("viewerCCI:Not enough room to create new icon.")
957 );
958 return (0);
959 }
960 strcpy(new->text,text);
961 }
962 else
963 new->text=0;
964 if (sprite)
965 strcpy(new->sprite,sprite);
966 else
967 new->sprite[0]='\0';
968 while (icn->next)
969 {
970 if (v->cmp)
971 {
972 if ((v->cmp)(icn->next->handle,handle)>0 && inOrder==TRUE)
973 break;
974 }
975 else
976 {
977 if (utils_caselessCmp(icn->next->text,text)>0 && inOrder==TRUE)
978 break;
979 }
980 icn=icn->next;
981 }
982 new->next=icn->next;
983 new->last=icn;
984 icn->next=new;
985 if (new->next)
986 new->next->last=new;
987 new->handle=handle;
988 new->v=v;
989 new->selected=FALSE;
990 new->filetype=-1;
991 v->icons++;
992 v->across=-1;
993 viewer__resize(v);
994 return (new);
995 }
996
997 /*
998 * void viewer_setFiletype(viewer_icon i,int type)
999 *
1000 * Use
1001 * Sets the filetype of the icon - useful for bins and things. This
1002 * filetype overrides the setting given to viewer_exportSelected(). It can
1003 * also be used to display the correct icon in the viewer by changing the
1004 * redraw handler to viewer_drawFileIcons().
1005 *
1006 * Parameters
1007 * viewer_icon i == the icon to change
1008 * int type == the filetype to give it (any valid WIMP filetype will do)
1009 */
1010
1011 void viewer_setFiletype(viewer_icon i,int type)
1012 {
1013 i->filetype=type;
1014 }
1015
1016 /*
1017 * int viewer_readFiletype(viewer_icon i)
1018 *
1019 * Use
1020 * Returns the filetype attached to an icon.
1021 *
1022 * Parameters
1023 * viewer_icon i == the icon handle
1024 *
1025 * Returns
1026 * The type attached using viewer_setFiletype(), or -1 if none.
1027 */
1028
1029 int viewer_readFiletype(viewer_icon i)
1030 {
1031 return (i->filetype);
1032 }
1033
1034 /*
1035 * viewer_icon viewer_findIcon(viewer v,char *text)
1036 *
1037 * Use
1038 * Searches through a viewer to find an icon with the same text as 'text'.
1039 * The search is case-insensitive.
1040 *
1041 * Parameters
1042 * viewer v == the viewer handle
1043 * char *text == text to search for
1044 *
1045 * Returns
1046 * The icon handle, or viewer_NOICON if unsuccessful.
1047 */
1048
1049 viewer_icon viewer_findIcon(viewer v,char *text)
1050 {
1051 viewer_icon i=v->iconlist;
1052 while (i)
1053 {
1054 if (utils_caselessCmp(text,i->text)==0)
1055 return (i);
1056 i=i->next;
1057 }
1058 return (viewer_NOICON);
1059 }
1060
1061 /*
1062 * void viewer_removeIcon(viewer_icon i)
1063 *
1064 * Use
1065 * Removes the icon specified. This routine is real easy!
1066 *
1067 * Parameters
1068 * viewer_icon i == the icon to remove (they ALL have unique handles, so
1069 * this is OK)
1070 */
1071
1072 void viewer_removeIcon(viewer_icon i)
1073 {
1074 viewer v=i->v;
1075 if (i->selected)
1076 v->selected--;
1077 if (i->last)
1078 i->last->next=i->next;
1079 else
1080 v->iconlist=i->next;
1081 if (i->next)
1082 i->next->last=i->last;
1083 mem_free(i->text);
1084 mem_free(i);
1085 v->icons--;
1086 v->across=-1;
1087 v->menuSel=viewer_NOICON;
1088 viewer__resize(v);
1089 }
1090
1091 /*
1092 * wimp_w viewer_syshandle(viewer v)
1093 *
1094 * Use
1095 * Returns the WIMP window handle used for the viewer (and much use may it
1096 * do you!)
1097 *
1098 * Parameters
1099 * viewer v == the viewer handle
1100 *
1101 * Returns
1102 * The wimp_w window handle
1103 */
1104
1105 wimp_w viewer_syshandle(viewer v)
1106 {
1107 return (v->wind);
1108 }
1109
1110 /*
1111 * viewer_icon viewer_iconFromCoords(viewer v,int x,int y)
1112 *
1113 * Use
1114 * Given a set of (absolute) coordinates, this returns the icon in the
1115 * viewer specified that the point is on. This is mainly useful for menu
1116 * maker routines, which will want to be able to select items and so on.
1117 *
1118 * Parameters
1119 * viewer v == the viewer handle
1120 * int x == the x-coordinate of the point
1121 * int y == the y-coordinate of the point
1122 *
1123 * Returns
1124 * The icon handle, or viewer__NOICON if there isn't one.
1125 */
1126
1127 viewer_icon viewer_iconFromCoords(viewer v,int x,int y)
1128 {
1129 wimp_wstate s;
1130 int ix,iy;
1131 int i;
1132 int cnt;
1133 viewer_icon icn=v->iconlist;
1134 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
1135 x-=(s.o.box.x0-s.o.x);
1136 y-=(s.o.box.y1-s.o.y);
1137 y=-y;
1138 if (v->banner[0]!='\0')
1139 y-=viewer__BANNERHEIGHT;
1140 ix=x/(v->width+viewer__GAP);
1141 x-=(v->width+viewer__GAP)*ix;
1142 if (x<viewer__GAP/2 || x-viewer__GAP/2>v->width || ix>=v->across)
1143 return (viewer_NOICON);
1144 iy=y/(v->height+viewer__GAP);
1145 y-=(v->height+viewer__GAP)*iy;
1146 if (y<viewer__GAP/2 || y-viewer__GAP/2>v->height || iy>=v->down)
1147 return (viewer_NOICON);
1148 i=ix+iy*v->across;
1149 if (i>=v->icons)
1150 return (viewer_NOICON);
1151 for (cnt=0;cnt<i;cnt++)
1152 {
1153 if (icn==0)
1154 return (viewer_NOICON);
1155 icn=icn->next;
1156 }
1157 return (icn);
1158 }
1159
1160 /*
1161 * void viewer_iconToCoords(viewer_icon i,wimp_box *box)
1162 *
1163 * Use
1164 * Calculates the bounding box of the icon given. If there is an error,
1165 * nothing is written in the block.
1166 *
1167 * Parameters
1168 * viewer_icon i == the icon we're interested in
1169 * wimp_box *box == where to store the coordinates
1170 */
1171
1172 void viewer_iconToCoords(viewer_icon i,wimp_box *box)
1173 {
1174 int x,y;
1175 viewer v=i->v;
1176 BOOL end=FALSE;
1177 viewer_icon icn=v->iconlist;
1178 wimp_wstate s;
1179 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
1180 x=y=0;
1181 while (!end)
1182 {
1183 if (icn==0)
1184 return;
1185 if (icn==i)
1186 end=TRUE;
1187 else
1188 {
1189 if ((++x)==v->across)
1190 {
1191 x=0;
1192 y++;
1193 }
1194 }
1195 icn=icn->next;
1196 }
1197 box->x0=s.o.box.x0-s.o.x+viewer__GAP/2+(viewer__GAP+v->width)*x;
1198 box->x1=box->x0+v->width;
1199 box->y1=s.o.box.y1-s.o.y-viewer__GAP/2-(viewer__GAP+v->height)*y;
1200 if (v->banner[0]!='\0')
1201 box->y1-=viewer__BANNERHEIGHT;
1202 box->y0=box->y1-v->height;
1203 }
1204
1205 /*
1206 * BOOL viewer_isSelected(viewer_icon i)
1207 *
1208 * Use
1209 * Returns whether an icon is selected or not.
1210 *
1211 * Parameters
1212 * viewer_icon i == the icon handle
1213 *
1214 * Returns
1215 * TRUE if the icon is selected, or FALSE otherwise.
1216 */
1217
1218 BOOL viewer_isSelected(viewer_icon i)
1219 {
1220 return (i->selected);
1221 }
1222
1223 /*
1224 * void viewer_selectIcon(viewer_icon i,BOOL onOrOff)
1225 *
1226 * Use
1227 * Selects or deselects the icon specified.
1228 *
1229 * Parameters
1230 * viewer_icon i == the icon handle
1231 * BOOL onOrOff == TRUE to select, FALSE to deselect
1232 */
1233
1234 void viewer_selectIcon(viewer_icon i,BOOL onOrOff)
1235 {
1236 wimp_redrawstr r;
1237 viewer v;
1238 wimp_wstate s;
1239 int ox,oy;
1240 wimp_box box;
1241 BOOL more;
1242 if (i==viewer_NOICON)
1243 return;
1244 v=i->v;
1245 if (i->selected!=onOrOff)
1246 {
1247 if (onOrOff)
1248 v->selected++;
1249 else
1250 v->selected--;
1251 }
1252 else
1253 return;
1254 i->selected=onOrOff;
1255 r.w=v->wind;
1256 viewer_iconToCoords(i,&box);
1257 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
1258 ox=s.o.box.x0-s.o.x;
1259 oy=s.o.box.y1-s.o.y;
1260 box.x0-=ox;
1261 box.y0-=oy;
1262 box.x1-=ox;
1263 box.y1-=oy;
1264 r.box=box;
1265 wimpt_noerr(wimp_update_wind(&r,&more));
1266 while (more)
1267 {
1268 viewer__redrawicon(&r,i,&box);
1269 wimpt_noerr(wimp_get_rectangle(&r,&more));
1270 }
1271 }
1272
1273 /*
1274 * viewer viewer_iconToViewer(viewer_icon i)
1275 *
1276 * Use
1277 * Returns the viewer in which an icon is contained.
1278 *
1279 * Parameters
1280 * viewer_icon i == the icon handle
1281 *
1282 * Returns
1283 * The viewer handle.
1284 */
1285
1286 viewer viewer_iconToViewer(viewer_icon i)
1287 {
1288 return (i->v);
1289 }
1290
1291 /*
1292 * void *viewer_iconHandle(viewer_icon i)
1293 *
1294 * Use
1295 * Returns the handle attached to the icon when it was created
1296 *
1297 * Parameters
1298 * viewer_icon i == the icon in question
1299 *
1300 * Returns
1301 * The handle attached
1302 */
1303
1304 void *viewer_iconHandle(viewer_icon i)
1305 {
1306 return (i->handle);
1307 }
1308
1309 /*
1310 * char *viewer_textOfIcon(viewer_icon i)
1311 *
1312 * Use
1313 * Returns the text of the icon given.
1314 *
1315 * Parameters
1316 * viewer_icon i == the icon
1317 *
1318 * Returns
1319 * Pointer to the string (read only!).
1320 */
1321
1322 char *viewer_textOfIcon(viewer_icon i)
1323 {
1324 return (i->text);
1325 }
1326
1327 /*
1328 * int viewer_selected(viewer v)
1329 *
1330 * Use
1331 * Informs caller how many icons are selected.
1332 *
1333 * Parameters
1334 * viewer v == the viewer handle
1335 *
1336 * Returns
1337 * The number of icons selected.
1338 */
1339
1340 int viewer_selected(viewer v)
1341 {
1342 return (v->selected);
1343 }
1344
1345 /*
1346 * int viewer_icons(viewer v)
1347 *
1348 * Use
1349 * Returns the number of icons in a viewer.
1350 *
1351 * Parameters
1352 * viewer v == the viewer
1353 *
1354 * Returns
1355 * The number of icons.
1356 */
1357
1358 int viewer_icons(viewer v)
1359 {
1360 return (v->icons);
1361 }
1362
1363 /*
1364 * void viewer_doForIcons
1365 * (
1366 * viewer v,
1367 * BOOL onlySelected,
1368 * void (*proc)(viewer_icon i,void *handle)
1369 * )
1370 *
1371 * Use
1372 * Does the same thing for either all the icons in a viewer, or just the
1373 * selected ones.
1374 *
1375 * Parameters
1376 * viewer v == the viewer handle
1377 * BOOL onlySelected == whether you want to handle just the selected ones,
1378 * or the whole lot.
1379 * void (*proc)(viewer_icon i,void *handle) == the routine to do whatever
1380 * it is you want to do.
1381 */
1382
1383 void viewer_doForIcons
1384 (
1385 viewer v,
1386 BOOL onlySelected,
1387 void (*proc)(viewer_icon i,void *handle)
1388 )
1389 {
1390 viewer_icon i=v->iconlist;
1391 viewer_icon next;
1392 while (i)
1393 {
1394 next=i->next;
1395 if (i->selected || !onlySelected)
1396 proc(i,i->handle);
1397 i=next;
1398 }
1399 }
1400
1401 /*
1402 * void viewer__select(viewer_icon i,void *handle)
1403 *
1404 * Use
1405 * Selects an icon.
1406 *
1407 * Parameters
1408 * viewer_icon i == the icon handle
1409 * void *handle == a handle (ignored)
1410 */
1411
1412 static void viewer__select(viewer_icon i,void *handle)
1413 {
1414 handle=handle;
1415 viewer_selectIcon(i,TRUE);
1416 }
1417
1418 /*
1419 * void viewer__deselect(viewer_icon i,void *handle)
1420 *
1421 * Use
1422 * Deselects an icon.
1423 *
1424 * Parameters
1425 * viewer_icon i == the icon handle
1426 * void *handle == a handle (ignored)
1427 */
1428
1429 static void viewer__deselect(viewer_icon i,void *handle)
1430 {
1431 handle=handle;
1432 viewer_selectIcon(i,FALSE);
1433 }
1434
1435 /*
1436 * void viewer_selectAll(viewer v,BOOL onOrOff)
1437 *
1438 * Use
1439 * Selects or deselects all the icons in a viewer.
1440 *
1441 * Parameters
1442 * viewer v == the viewer handle
1443 * BOOL onOrOff == whether you want the icons to be on or off
1444 */
1445
1446 void viewer_selectAll(viewer v,BOOL onOrOff)
1447 {
1448 viewer_doForIcons(v,FALSE,onOrOff ? viewer__select : viewer__deselect);
1449 v->menuSel=viewer_NOICON;
1450 }
1451
1452 /*
1453 * BOOL viewer__selectUnknowns(wimp_eventstr *e,void *handle)
1454 *
1455 * Use
1456 * Selects the icons inside the rubber-band box created, RISC OS 3-like.
1457 *
1458 * Parameters
1459 * wimp_eventstr *e == the event that I might be interested in
1460 * void *handle == a (useless) handle
1461 *
1462 * Returns
1463 * TRUE if the event was interesting.
1464 */
1465
1466 static BOOL viewer__selectUnknowns(wimp_eventstr *e,void *handle)
1467 {
1468 BOOL handled=FALSE;
1469 wimp_box b;
1470 wimp_wstate s;
1471 coords_cvtstr c;
1472 viewer v=viewer__currentViewer;
1473 wimp_box vib;
1474 int i;
1475 int x,y;
1476 viewer_icon icn=v->iconlist;
1477 handle=handle;
1478 switch (e->e)
1479 {
1480 case wimp_EUSERDRAG:
1481 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
1482 c.box=s.o.box;
1483 c.scx=s.o.x;
1484 c.scy=s.o.y;
1485 b.x0=min(e->data.dragbox.x0,e->data.dragbox.x1);
1486 b.y0=min(e->data.dragbox.y0,e->data.dragbox.y1);
1487 b.x1=max(e->data.dragbox.x0,e->data.dragbox.x1);
1488 b.y1=max(e->data.dragbox.y0,e->data.dragbox.y1);
1489 b.x0+=viewer__GAP/2;
1490 b.x1-=viewer__GAP/2;
1491 b.y0+=viewer__GAP/2;
1492 b.y1-=viewer__GAP/2;
1493 coords_box_toworkarea(&b,&c);
1494 if (v->banner[0]!='\0')
1495 coords_offsetbox(&b,0,viewer__BANNERHEIGHT,&b);
1496 vib.x0=b.x0/(v->width+viewer__GAP);
1497 vib.y0=(-b.y1)/(v->height+viewer__GAP);
1498 vib.x1=b.x1/(v->width+viewer__GAP);
1499 vib.y1=(-b.y0)/(v->height+viewer__GAP);
1500 if (b.y1>0)
1501 vib.y0=-1;
1502 if (b.y0>0)
1503 vib.y1=-1;
1504 handled=TRUE;
1505 win_remove_unknown_event_processor(viewer__selectUnknowns,0);
1506 for (i=0;icn!=0;i++,icn=icn->next)
1507 {
1508 x=i%(v->across);
1509 y=i/(v->across);
1510 if (x>=vib.x0 && x<=vib.x1 && y>=vib.y0 && y<=vib.y1)
1511 viewer_selectIcon(icn,TRUE);
1512 }
1513 break;
1514 }
1515 return (handled);
1516 }
1517
1518 /*
1519 * void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b)
1520 *
1521 * Use
1522 * Handles a click on an icon just like clicks in Filer windows.
1523 *
1524 * Parameters
1525 * viewer v == the viewer handle
1526 * viewer_icon i == the icon that was clicked
1527 * wimp_bbits b == the mouse button status
1528 */
1529
1530 void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b)
1531 {
1532 viewer_icon icn=v->iconlist;
1533 switch (b)
1534 {
1535 case wimp_BCLICKRIGHT:
1536 if (i!=viewer_NOICON)
1537 {
1538 viewer_selectIcon(v->menuSel,FALSE);
1539 v->menuSel=viewer_NOICON;
1540 viewer_selectIcon(i,!(i->selected));
1541 }
1542 break;
1543 case wimp_BCLICKLEFT:
1544 v->menuSel=viewer_NOICON;
1545 if (i->selected==FALSE || i==viewer_NOICON)
1546 {
1547 while (icn)
1548 {
1549 if (icn->selected)
1550 viewer_selectIcon(icn,FALSE);
1551 icn=icn->next;
1552 }
1553 viewer_selectIcon(i,TRUE);
1554 }
1555 break;
1556 case wimp_BDRAGLEFT:
1557 case wimp_BDRAGRIGHT:
1558 if (i==viewer_NOICON)
1559 {
1560 wimp_mousestr m;
1561 wimp_wstate s;
1562 wimp_dragstr d;
1563 wimpt_noerr(wimp_get_point_info(&m));
1564 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
1565 d.window=v->wind;
1566 d.type=wimp_USER_RUBBER;
1567 d.box.x0=m.x;
1568 d.box.y0=m.y;
1569 d.box.x1=m.x+wimpt_dx();
1570 d.box.y1=m.y+wimpt_dy();
1571 d.parent=s.o.box;
1572 wimpt_noerr(wimp_drag_box(&d));
1573 viewer__currentViewer=v;
1574 win_add_unknown_event_processor(viewer__selectUnknowns,0);
1575 }
1576 else
1577 {
1578 v->menuSel=viewer_NOICON;
1579 viewer_selectIcon(i,TRUE);
1580 }
1581 break;
1582 case wimp_BMID:
1583 if ((v->menuSel!=viewer_NOICON || v->selected==0) && v->menuSel!=i)
1584 {
1585 viewer_selectIcon(v->menuSel,FALSE);
1586 v->menuSel=i;
1587 viewer_selectIcon(v->menuSel,TRUE);
1588 }
1589 }
1590 }
1591
1592 /*
1593 * char *viewer_menuItem(viewer v,char *header)
1594 *
1595 * Use
1596 * Returns a menu item of the form either "~<header> ''",
1597 * "<header> '<icon name>'", or "Selection", for inclusion in a menu
1598 * string.
1599 *
1600 * Parameters
1601 * viewer v == the viewer handle
1602 * char *header == the header for the menu item
1603 *
1604 * Returns
1605 * A pointer to a read-only string.
1606 */
1607
1608 char *viewer_menuItem(viewer v,char *header)
1609 {
1610 char *buffer=buffer_find();
1611 char *ret;
1612 switch (v->selected)
1613 {
1614 case 0:
1615 sprintf(buffer,"~%s ''",header);
1616 ret=buffer;
1617 break;
1618 case 1:
1619 {
1620 viewer_icon i=v->iconlist;
1621 while (i->selected==FALSE)
1622 {
1623 i=i->next;
1624 }
1625 sprintf(buffer,"%s '%s'",header,i->text);
1626 ret=buffer;
1627 }
1628 break;
1629 default:
1630 strcpy(buffer,msgs_lookup("viewerMIS:Selection"));
1631 ret=buffer;
1632 break;
1633 }
1634 return (ret);
1635 }
1636
1637 /*
1638 * void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff)
1639 *
1640 * Use
1641 * Writes a menu item out as for the previous routine, but implants it
1642 * directly into the menu, so you don't need to fiddle about with things
1643 * like that, and also means that the menu pointer changes. The menu item
1644 * must have been previously set up with menu_redirectItem. This call will
1645 * also set the menu to the correct width. However, ensure that you call
1646 * menu_minWidth(m,0) before fiddling with the width!
1647 *
1648 * Parameters
1649 * viewer v == the viewer handle pertaining to this request
1650 * menu m == the menu to doctor
1651 * int i == the menu item
1652 * char *buff == where the menu item wants the data
1653 */
1654
1655 void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff)
1656 {
1657 char *t=viewer_menuItem(v,header);
1658 if (*t=='~')
1659 {
1660 t++;
1661 menu_setflags(m,i,FALSE,TRUE);
1662 }
1663 else
1664 menu_setflags(m,i,FALSE,FALSE);
1665 strcpy(buff,t);
1666 menu_minWidth(m,strlen(buff));
1667 }
1668
1669 /*
1670 * viewer_icon viewer_firstSelected(viewer v)
1671 *
1672 * Use
1673 * Returns the handle of the first selected icon.
1674 *
1675 * Parameters
1676 * viewer v == the viewer handle
1677 *
1678 * Returns
1679 * A handle to the first one, or viewer_NOICON.
1680 */
1681
1682 viewer_icon viewer_firstSelected(viewer v)
1683 {
1684 viewer_icon i=v->iconlist;
1685 while (i)
1686 {
1687 if (i->selected)
1688 return (i);
1689 i=i->next;
1690 }
1691 return (viewer_NOICON);
1692 }
1693
1694 /*
1695 * void viewer_settitle(viewer v,char *title)
1696 *
1697 * Use
1698 * Changes a viewer's title, so that the extent is updated as well.
1699 *
1700 * Parameters
1701 * viewer v == the viewer handle
1702 * char *title == the new title string
1703 * (internal: may be 0 to indicate just to resize the viewer)
1704 */
1705
1706 void viewer_settitle(viewer v,char *title)
1707 {
1708 wimp_wstate s;
1709 int minw;
1710 int scw;
1711 int maxacc;
1712 wimp_redrawstr r;
1713 if (title)
1714 win_settitle(v->wind,"%s",title);
1715 wimpt_noerr(wimp_get_wind_state(v->wind,&s));
1716 scw=wimpt_scwidth();
1717 maxacc=scw/(v->width+viewer__GAP);
1718 if (maxacc>v->icons)
1719 maxacc=v->icons;
1720 minw=wimpt_stringWidth(v->title)+164;
1721 if (v->banner[0]!='\0') /* Bug fix */
1722 {
1723 int l=wimpt_stringWidth(v->banner)+64;
1724 if (l>minw)
1725 minw=l;
1726 }
1727 if (minw<viewer__MINWIDTH)
1728 minw=viewer__MINWIDTH;
1729 r.w=v->wind;
1730 r.box.x0=0;
1731 r.box.y0=-(v->height+viewer__GAP)*v->down;
1732 if (v->banner[0]!='\0')
1733 r.box.y0-=viewer__BANNERHEIGHT;
1734 if (r.box.y0>-viewer__MINHEIGHT)
1735 r.box.y0=-viewer__MINHEIGHT;
1736 r.box.x1=(v->width+viewer__GAP)*maxacc;
1737 if (r.box.x1<minw)
1738 r.box.x1=minw;
1739 r.box.y1=0;
1740 wimpt_noerr(wimp_set_extent(&r));
1741 if (s.flags & wimp_WOPEN)
1742 wimpt_noerr(wimp_open_wind(&s.o));
1743 }
1744
1745 /*
1746 * void viewer_dragSelected(viewer_icon icn,wimp_bbits b)
1747 *
1748 * Use
1749 * Drags a set of icons around a window.
1750 *
1751 * Parameters
1752 * viewer_icon icn == the viewer icon handle
1753 * wimp_bbits b == the button types that started this lot off
1754 */
1755
1756 void viewer_dragSelected(viewer_icon icn,wimp_bbits b)
1757 {
1758 wimp_box box;
1759 wimp_dragstr d;
1760 wimp_mousestr m;
1761 BOOL started=FALSE;
1762 viewer v;
1763 viewer_icon i;
1764 os_regset r;
1765 int scWidth=wimpt_scwidth();
1766 int scHeight=wimpt_scheight();
1767 sprite_id sid;
1768 if (icn==viewer_NOICON)
1769 return;
1770 if (b!=wimp_BDRAGLEFT && b!=wimp_BDRAGRIGHT)
1771 return;
1772 viewer_selectIcon(icn,TRUE);
1773 v=icn->v;
1774 wimpt_noerr(wimp_get_point_info(&m));
1775 r.r[0]=161;
1776 r.r[1]=28;
1777 wimpt_noerr(os_swix(XOS_Byte,&r)); /* Support DragASprite? */
1778 if (wimpt_getVersion()>=300 && (r.r[2] & 2))
1779 {
1780 r.r[0]=0xC5;
1781 d.box.x0=m.x-50;
1782 d.box.x1=m.x+50;
1783 d.box.y0=m.y-50;
1784 d.box.y1=m.y+50;
1785 if (v->selected==1)
1786 {
1787 if (icn->filetype==-1)
1788 {
1789 r.r[2]=(int)icn->sprite;
1790 r.r[1]=(int)v->spr;
1791 }
1792 else
1793 {
1794 r.r[2]=(int)fileicon_spriteName(icn->filetype,icn->text);
1795 r.r[1]=1;
1796 }
1797 }
1798 else
1799 {
1800 r.r[2]=(int)"package";
1801 r.r[1]=1;
1802 if ((int)v->spr>1)
1803 {
1804 sid.s.name="package";
1805 sid.tag=0;
1806 if (!sprite_select(v->spr,&sid))
1807 r.r[1]=(int)v->spr;
1808 }
1809 }
1810 r.r[3]=(int)&d.box;
1811 wimpt_noerr(os_swix(XDragASprite_Start,&r));
1812 return;
1813 }
1814 i=v->iconlist;
1815 while (i)
1816 {
1817 if (i->selected==TRUE)
1818 {
1819 viewer_iconToCoords(i,&box);
1820 if (started)
1821 {
1822 if (d.box.x0>box.x0)
1823 d.box.x0=box.x0;
1824 if (d.box.y0>box.y0)
1825 d.box.y0=box.y0;
1826 if (d.box.x1<box.x1)
1827 d.box.x1=box.x1;
1828 if (d.box.y1<box.y1)
1829 d.box.y1=box.y1;
1830 }
1831 else
1832 {
1833 d.box=box;
1834 started=TRUE;
1835 }
1836 }
1837 i=i->next;
1838 }
1839 d.box.x0-=viewer__GAP/2;
1840 d.box.y0-=viewer__GAP/2;
1841 d.box.x1+=viewer__GAP/2;
1842 d.box.y1+=viewer__GAP/2;
1843 d.window=0;
1844 d.type=wimp_USER_FIXED;
1845 d.parent.x0=d.box.x0-m.x;
1846 d.parent.y0=d.box.y0-m.y;
1847 d.parent.x1=scWidth-m.x+d.box.x1;
1848 d.parent.y1=scHeight-m.y+d.box.y1;
1849 wimpt_noerr(wimp_drag_box(&d));
1850 }
1851
1852 /*
1853 * The routines for the data transfer.
1854 */
1855
1856 static BOOL viewer__save(char *name,void *handle)
1857 {
1858 handle=handle;
1859 return
1860 (
1861 viewer__usersave(viewer__currentIcon,name,viewer__currentIcon->handle)
1862 );
1863 }
1864
1865 static BOOL viewer__send(void *handle,int *maxbuf)
1866 {
1867 handle=handle;
1868 return
1869 (
1870 viewer__usersend(viewer__currentIcon,viewer__currentIcon->handle,maxbuf)
1871 );
1872 }
1873
1874 static int viewer__print(char *filename,void *handle)
1875 {
1876 handle=handle;
1877 return
1878 (
1879 viewer__userprint
1880 (
1881 viewer__currentIcon,
1882 filename,
1883 viewer__currentIcon->handle
1884 )
1885 );
1886 }
1887
1888 /*
1889 * void viewer__export(viewer_icon i,void *handle)
1890 *
1891 * Use
1892 * Exports each icon in turn.
1893 *
1894 * Parameters
1895 * viewer_icon i == the icon handle
1896 * void *handle == a handle to the user's data (ignored)
1897 */
1898
1899 static void viewer__export(viewer_icon i,void *handle)
1900 {
1901 wimp_eventstr e;
1902 handle=handle;
1903 viewer__currentIcon=i;
1904 e.e=wimp_EUSERDRAG;
1905 wimpt_fake_event(&e);
1906 xfersend
1907 (
1908 i->filetype==-1 ? viewer__filetype : i->filetype,
1909 i->text,
1910 1,
1911 viewer__usersave==0 ? 0 : viewer__save,
1912 viewer__usersend==0 ? 0 : viewer__send,
1913 viewer__userprint==0 ? 0 : viewer__print,
1914 &e,
1915 0
1916 );
1917 }
1918
1919 /*
1920 * BOOL viewer__unknowns(wimp_eventstr *e,void *handle)
1921 *
1922 * Use
1923 * Unknown event processor - handles the end of the drag operation.
1924 *
1925 * Parameters
1926 * wimp_eventstr *e == a pointer to the event.
1927 * void *handle == a handle to some data (ignored).
1928 *
1929 * Returns
1930 * Whether the event was interesting.
1931 */
1932
1933 static BOOL viewer__exportUnknowns(wimp_eventstr *e,void *handle)
1934 {
1935 BOOL handled=FALSE;
1936 wimp_mousestr m;
1937 handle=handle;
1938 switch (e->e)
1939 {
1940 case wimp_EUSERDRAG:
1941 wimpt_noerr(wimp_get_point_info(&m));
1942 if (m.w!=viewer__currentViewer->wind)
1943 viewer_doForIcons(viewer__currentViewer,TRUE,viewer__export);
1944 handled=TRUE;
1945 win_remove_unknown_event_processor(viewer__exportUnknowns,0);
1946 break;
1947 }
1948 return (handled);
1949 }
1950
1951 /*
1952 * void viewer_exportSelected
1953 * (
1954 * viewer_icon icn,
1955 * wimp_bbits b,
1956 * int filetype,
1957 * viewer_saveproc save,
1958 * viewer_sendproc send,
1959 * viewer_printproc print
1960 * )
1961 *
1962 * Use
1963 * Allows you to export the data connected with each selected icon to
1964 * another application. The filename used is the icon's text.
1965 *
1966 * Parameters
1967 * viewer_icon icn == the icon on which the user clicked to start the drag
1968 * operation.
1969 * wimp_bbits b == the mouse buttons which started this up.
1970 * int filetype == the filetype of the data.
1971 * viewer_saveproc save == the save routine (saving and <Wimp$Scrap>
1972 * transfer.
1973 * viewer_sendproc send == the send routine (RAM transfer).
1974 * viewer_printproc print == the print routine (printing etc.)
1975 */
1976
1977 void viewer_exportSelected
1978 (
1979 viewer_icon icn,
1980 wimp_bbits b,
1981 int filetype,
1982 viewer_saveproc save,
1983 viewer_sendproc send,
1984 viewer_printproc print
1985 )
1986 {
1987 if (icn==viewer_NOICON)
1988 return;
1989 if (b!=wimp_BDRAGLEFT && b!=wimp_BDRAGRIGHT)
1990 return;
1991 viewer_dragSelected(icn,b);
1992 viewer__filetype=filetype;
1993 viewer__usersave=save;
1994 viewer__usersend=send;
1995 viewer__userprint=print;
1996 viewer__currentViewer=icn->v;
1997 win_add_unknown_event_processor(viewer__exportUnknowns,0);
1998 }
1999
2000 /*
2001 * viewer_icon viewer_helpIcon(viewer v)
2002 *
2003 * Use
2004 * Informs the caller which icon the Help system is interested in.
2005 *
2006 * Parameters
2007 * viewer v == the viewer handle
2008 *
2009 * Returns
2010 * The icon's handle (or maybe viewer_NOICON)
2011 */
2012
2013 viewer_icon viewer_helpIcon(viewer v)
2014 {
2015 wimp_eventstr *e=wimpt_last_event();
2016 if (help_wasHelp())
2017 return
2018 (
2019 viewer_iconFromCoords
2020 (
2021 v,
2022 e->data.msg.data.helprequest.m.x,
2023 e->data.msg.data.helprequest.m.y
2024 )
2025 );
2026 else
2027 werr(TRUE,msgs_lookup("viewerVIE:(viewer_helpIcon, caller fault): "
2028 "Not called on HELPREQUEST event."));
2029 return (0);
2030 }