Initial revision
[ssr] / StraySrc / Libraries / Steel / c / ibicon
1 /*
2 * ibicon
3 *
4 * proper icon bar mangement (multiple icons, etc.)
5 *
6 * © 1993-1998 Straylight
7 */
8
9 /*----- Licensing note ----------------------------------------------------*
10 *
11 * This file is part of Straylight's Steel library.
12 *
13 * Steel 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 * Steel 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 Steel. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27
28 #include "wimp.h"
29 #include "wimpt.h"
30 #include "os.h"
31 #include "swis.h"
32 #include "bbc.h"
33 #include "win.h"
34 #include "werr.h"
35 #include "ibicon.h"
36 #include "msgs.h"
37 #include "event.h"
38 #include "mem.h"
39 #include "swiv.h"
40 #include <string.h>
41 #include <stdio.h>
42
43 #include "dll.h"
44
45 #ifndef _dll_NODLL
46 extern void _dllEntry(ibicon__events)(wimp_eventstr *e,void *handle);
47 extern menu _dllEntry(ibicon__menumaker)(void *handle);
48 extern void _dllEntry(ibicon__menuhandler)(int hits[],void *handle);
49 extern void _dllEntry(ibicon__menuhelphandler)(int hits[],void *handle);
50 #endif
51
52 typedef struct ibicon__ibiconstr
53 {
54 struct ibicon__ibiconstr *next;
55 struct ibicon__ibiconstr *prev;
56 wimp_i icon;
57 char *data;
58 char *valid;
59 menu mnu;
60 event_menu_maker maker;
61 menu_selectProc menusel;
62 menu_helpProc menuhelp;
63 void *menuHandle;
64 ibicon_handler handler;
65 void *handle;
66 ibicon_rawHandler raw;
67 void *rawHandle;
68 }
69 ibicon__ibiconstr;
70
71 static ibicon ibicon__anchor;
72 static BOOL ibicon__eventHandler; /* Do we have an event handler? */
73 static ibicon ibicon__menuicon; /* The last icon to open a menu */
74 static int ibicon__priority; /* Icon priorities (RISC OS 3) */
75
76 /*
77 * os_error *ibicon__spriteOp
78 * (
79 * int op,
80 * sprite_area *a,
81 * char *name,
82 * _kernel_swi_regs *r
83 * )
84 *
85 * Use
86 * Does an OS_SpriteOp call. It's designed for calls that return more than
87 * they receive.
88 *
89 * Parameters
90 * int op == the operation number to perform
91 * sprite_area *a == the sprite area to do the op on. May be 1 for the
92 * WIMP area or 0 for the system area
93 * char *name == the name of the sprite
94 * os_regset *r == a regiser set to return inforation in
95 *
96 * Returns
97 * An error block if anything went wrong
98 */
99
100 static os_error *ibicon__spriteOp
101 (
102 int op,
103 sprite_area *a,
104 char *name,
105 os_regset *r
106 )
107 {
108 int swinum;
109 if ((int)a==1)
110 swinum=XWimp_SpriteOp;
111 else
112 {
113 swinum=XOS_SpriteOp;
114 if (a!=0)
115 op+=256;
116 }
117 r->r[0]=op;
118 r->r[1]=(int)a;
119 r->r[2]=(int)name;
120 return (os_swix(swinum,r));
121 }
122
123 /*
124 * void ibicon__spriteSize(char *name,sprite_area *a,wimp_box *b,BOOL centre)
125 *
126 * Use
127 * Returns the size of the sprite specified. If requested, it also
128 * centres the result given within a 68 OS unit vertical area.
129 *
130 * Parameters
131 * char *name == the name of the sprite of which to return the size
132 * sprite_area *a == the sprite area (same conventions as above)
133 * wimp_box *b == a box structure to fill in
134 * BOOL centre == whether to centre the icon vertically
135 */
136
137 static void ibicon__spriteSize
138 (
139 char *name,
140 sprite_area *a,
141 wimp_box *b,
142 BOOL centre
143 )
144 {
145 os_regset r;
146 int height;
147 b->x0=0;
148 wimpt_noerr(ibicon__spriteOp(40,a,name,&r));
149 b->x1=r.r[3]<<bbc_modevar(r.r[6],bbc_XEigFactor);
150 height=r.r[4]<<bbc_modevar(r.r[6],bbc_YEigFactor);
151 if (centre)
152 {
153 b->y0=(68-height)>>1;
154 b->y1=68-b->y0;
155 }
156 else
157 {
158 b->y0=0;
159 b->y1=height;
160 }
161 }
162
163 /*
164 * ibicon ibicon_find(wimp_i icon)
165 *
166 * Use
167 * Return the ibicon handle of an icon.
168 *
169 * Parameters
170 * wimp_i icon == the icon to find
171 */
172
173 ibicon ibicon_find(wimp_i icon)
174 {
175 ibicon i;
176 for (i=ibicon__anchor;i;i=i->next)
177 {
178 if (i->icon==icon)
179 return (i);
180 if (i->icon>icon)
181 return (0);
182 }
183 return (0);
184 }
185
186 /*
187 * wimp_i ibicon_syshandle(ibicon i)
188 *
189 * Use
190 * Returns the low-level WIMP handle for the icon concerned.
191 *
192 * Parameters
193 * ibicon i == the icon whose handle is desired
194 *
195 * Returns
196 * The WIMP icon handle for the icon
197 */
198
199 wimp_i ibicon_syshandle(ibicon i)
200 {
201 return (i->icon);
202 }
203
204 /*
205 * void ibicon__menuhandler(int hit[],void *handle)
206 *
207 * Use
208 * Handles clicks on icon bar menus. It acts an event_menu_proc and passes
209 * the information on the relevant icon.
210 *
211 * Parameters
212 * int hit[] == the hit string to be processed.
213 * void *handle == not worth the effort of worrying about
214 */
215
216 _dll_static void ibicon__menuhandler(int hit[],void *handle)
217 {
218 handle=handle;
219 if (ibicon__menuicon)
220 {
221 if (ibicon__menuicon->menusel)
222 (ibicon__menuicon->menusel)(hit,ibicon__menuicon->menuHandle);
223 }
224 }
225
226 /*
227 * void ibicon__menuhelphandler(int hit[],void *handle)
228 *
229 * Use
230 * Handles help request for icon bar menus. It acts a menu_helpProc or
231 * whatever and passes the information on the relevant icon.
232 *
233 * Parameters
234 * int hit[] == the hit string to be processed.
235 * void *handle == not worth the effort of worrying about
236 */
237
238 _dll_static void ibicon__menuhelphandler(int hit[],void *handle)
239 {
240 handle=handle;
241 if (ibicon__menuicon)
242 {
243 if (ibicon__menuicon->menuhelp)
244 (ibicon__menuicon->menuhelp)(hit,ibicon__menuicon->menuHandle);
245 }
246 }
247
248 /*
249 * menu ibicon__menumaker(void *handle)
250 *
251 * Use
252 * Handles menus and things for the icon bar. Acts as an event_menu_maker
253 * and passes the request on to the icon concerned.
254 *
255 * Parameters
256 * void *handle == nothing worth worrying about
257 *
258 * Returns
259 * The menu to display
260 */
261
262 _dll_static menu ibicon__menumaker(void *handle)
263 {
264 wimp_eventstr *e=wimpt_last_event();
265 handle=handle;
266 if (e->e==wimp_EBUT)
267 ibicon__menuicon=ibicon_find(e->data.but.m.i);
268 if (ibicon__menuicon)
269 {
270 if (ibicon__menuicon->mnu)
271 return (ibicon__menuicon->mnu);
272 else if (ibicon__menuicon->maker)
273 return ((ibicon__menuicon->maker)(ibicon__menuicon->menuHandle));
274 }
275 return (0); /* menu is dead - icon disappeared */
276 }
277
278 /*
279 * void ibicon__events(wimp_eventstr *e,void *handle)
280 *
281 * Purpose
282 * Event handler installed for both win_ICONBAR and win_ICONBARLOAD.
283 *
284 * Parameters
285 * wimp_eventstr *e == the event
286 * void *handle == nothing interesting
287 */
288
289 _dll_static void ibicon__events(wimp_eventstr *e,void *handle)
290 {
291 wimp_i icn=-1;
292 ibicon i;
293 ibicon_eventType type=ibicon_NOTHING;
294 handle=handle;
295 switch (e->e)
296 {
297 case wimp_EBUT:
298 icn=e->data.but.m.i;
299 switch (e->data.but.m.bbits)
300 {
301 case wimp_BLEFT:
302 type=ibicon_LEFTCLICK;
303 break;
304 case wimp_BRIGHT:
305 type=ibicon_RIGHTCLICK;
306 break;
307 }
308 break;
309 case wimp_ESEND:
310 case wimp_ESENDWANTACK:
311 switch (e->data.msg.hdr.action)
312 {
313 case wimp_MDATASAVE:
314 type=ibicon_SAVE;
315 icn=e->data.msg.data.datasave.i;
316 break;
317 case wimp_MDATALOAD:
318 type=ibicon_LOAD;
319 icn=e->data.msg.data.dataload.i;
320 break;
321 case wimp_MHELPREQUEST:
322 type=ibicon_HELP;
323 icn=e->data.msg.data.helprequest.m.i;
324 break;
325 }
326 }
327 if (i=ibicon_find(icn),!i)
328 return;
329 if (i->raw)
330 {
331 if ((i->raw)(i,e,i->rawHandle))
332 type=ibicon_NOTHING;
333 }
334 if (type!=ibicon_NOTHING)
335 {
336 if (i->handler)
337 (i->handler)(i,type,i->handle);
338 }
339 }
340
341 /*
342 * void ibicon_setPriority(int priority)
343 *
344 * Use
345 * Sets the priority with which to create icons under RISC OS 3.
346 *
347 * Parameters
348 * int priority == the new setting
349 */
350
351 void ibicon_setPriority(int priority)
352 {
353 ibicon__priority=priority;
354 }
355
356 /*
357 * ibicon ibicon_create
358 * (
359 * int where,
360 * char *spritename,
361 * sprite_area *sprarea,
362 * char *text,
363 * int maxtext
364 * )
365 *
366 * Use
367 * Creates an icon in the icon bar. Where is up to you. Specify a
368 * sprite-only icon by passing 0 for text. Use the macros to define where
369 * and what area you want the sprite from.
370 *
371 * Parameters
372 * int where == what part of the icon bar you want to put the icon in.
373 * Macros are defined for the RISC OS 2 possibilities. Wait for the
374 * RISC OS 3 macros, or just pass a window handle.
375 * char *spritename == the name of the sprite to display
376 * sprite_area *sprarea == the area from which the sprite area comes. Use
377 * the macros provided for odd things like the WIMP area. If you have
378 * text as well, then this will be ignored anyway.
379 * char *text == the text for the icon. May be a NULL pointer, for no
380 * text.
381 * int maxtext == the max length the text entry can be. If 0 then the
382 * length of the text given will be used.
383 *
384 * Returns
385 * A handle to the icon if successful, or 0 if not.
386 */
387
388 ibicon ibicon_create
389 (
390 int where,
391 char *spritename,
392 sprite_area *sprarea,
393 char *text,
394 int maxtext
395 )
396 {
397 wimp_icreate i;
398 ibicon new=mem_alloc(sizeof(ibicon__ibiconstr));
399 ibicon c;
400 if (!new)
401 {
402 werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
403 return (0);
404 }
405 if (!ibicon__eventHandler)
406 {
407 win_register_event_handler(win_ICONBAR,_dllEntry(ibicon__events),0);
408 win_register_event_handler(win_ICONBARLOAD,_dllEntry(ibicon__events),0);
409 menu_attachMaker
410 (
411 win_ICONBAR,
412 _dllEntry(ibicon__menumaker),
413 _dllEntry(ibicon__menuhandler),
414 _dllEntry(ibicon__menuhelphandler),
415 0
416 );
417 ibicon__eventHandler=TRUE;
418 }
419 if (text)
420 {
421 if (!maxtext)
422 maxtext=strlen(text);
423 if (new->data=mem_alloc(maxtext+1),!new->data)
424 {
425 mem_free(new);
426 werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
427 return (0);
428 }
429 if (new->valid=mem_alloc(15),!new->valid)
430 {
431 mem_free(new);
432 mem_free(new->data);
433 werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
434 return (0);
435 }
436 strcpy(new->data,text);
437 sprintf(new->valid,"S%s",spritename);
438 i.i.data.indirecttext.buffer=new->data;
439 i.i.data.indirecttext.validstring=new->valid;
440 i.i.data.indirecttext.bufflen=maxtext+1;
441 ibicon__spriteSize(spritename,sprarea,&i.i.box,FALSE);
442 i.i.box.y0-=16;
443 i.i.box.y1+=20;
444 if (i.i.box.x1<16*maxtext)
445 i.i.box.x1=16*maxtext;
446 }
447 else
448 {
449 if (new->data=mem_alloc(15),!new->data)
450 {
451 mem_free(new);
452 werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
453 return (0);
454 }
455 strcpy(new->data,spritename);
456 new->valid=0;
457 i.i.data.indirectsprite.name=new->data;
458 i.i.data.indirectsprite.spritearea=(void *)sprarea;
459 i.i.data.indirectsprite.nameisname=TRUE;
460 ibicon__spriteSize(spritename,sprarea,&i.i.box,TRUE);
461 }
462 switch (where)
463 {
464 case ibicon_LEFTSEARCHLEFT:
465 case ibicon_LEFTSEARCHRIGHT:
466 if (wimpt_getVersion()<300)
467 where=ibicon_LEFT;
468 break;
469 case ibicon_RIGHTSEARCHLEFT:
470 case ibicon_RIGHTSEARCHRIGHT:
471 if (wimpt_getVersion()<300)
472 where=ibicon_RIGHT;
473 break;
474 }
475 i.w=where;
476 i.i.flags=
477 (
478 wimp_ISPRITE |
479 (text ? wimp_ITEXT : 0) |
480 wimp_IHCENTRE |
481 (text ? 0 : wimp_IVCENTRE) |
482 wimp_INDIRECT |
483 wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
484 wimp_IFORECOL * 7 |
485 wimp_IBACKCOL * 1
486 );
487 wimpt_noerr(_swix(XWimp_CreateIcon,_inr(0,1)+_out(0),
488 ibicon__priority,(int)&i,
489 &new->icon));
490 win_activeinc();
491 for (c=(ibicon)&ibicon__anchor;c->next;c=c->next)
492 {
493 if (c->next->icon>new->icon)
494 break;
495 }
496 new->next=c->next;
497 if (ibicon__anchor)
498 new->prev=c;
499 else
500 new->prev=0;
501 if (c->next)
502 c->next->prev=new;
503 c->next=new;
504 new->mnu=0;
505 new->maker=0;
506 new->menusel=0;
507 new->menuhelp=0;
508 new->menuHandle=0;
509 new->handler=0;
510 new->handle=0;
511 new->raw=0;
512 new->rawHandle=0;
513 win_activeinc();
514 return (new);
515 }
516
517 /*
518 * void ibicon_changeSprite(ibicon i,char *newsprite)
519 *
520 * Use
521 * Chnage the sprite displayed in an icon
522 *
523 * Parameters
524 * ibicon i == the icon to change
525 * char *newsprite == the new name
526 */
527
528 void ibicon_changeSprite(ibicon i,char *newsprite)
529 {
530 if (i->valid)
531 sprintf(i->valid,"S%s",newsprite);
532 else
533 strcpy(i->data,newsprite);
534 wimpt_noerr(wimp_set_icon_state(-2,i->icon,0,0));
535 }
536
537 /*
538 * void ibicon_changeText(ibicon i,char *newtext)
539 *
540 * Use
541 * Change the text of an icon.
542 *
543 * Parameters
544 * ibicon i == the icon to change
545 * char *text == the new text to display
546 */
547
548 void ibicon_changeText(ibicon i,char *newtext)
549 {
550 if (i->valid)
551 strcpy(i->data,newtext);
552 else
553 werr(TRUE,msgs_lookup("ibicnCCT:(ibicon_changeText, caller fault): "
554 "Attempt to write text to sprite-only ibicon."));
555 wimpt_noerr(wimp_set_icon_state(-2,i->icon,0,0));
556 }
557
558 /*
559 * void ibicon_attachMenu
560 * (
561 * ibicon i,
562 * menu m,
563 * menu_selectProc sel,
564 * menu_helpProc help,
565 * void *handle
566 * )
567 *
568 * Use
569 * Attaches a menu to an icon in the icon bar
570 *
571 * Parameters
572 * ibicon i == the icon to attach to
573 * menu m == the menu to attach
574 * menu_selectProc sel == a handler function for the menu
575 * menu_helpProc help == a help processor for the menu
576 * void *handle == a handle passed to the handler
577 */
578
579 void ibicon_attachMenu
580 (
581 ibicon i,
582 menu m,
583 menu_selectProc sel,
584 menu_helpProc help,
585 void *handle
586 )
587 {
588 i->mnu=m;
589 i->maker=0;
590 i->menusel=sel;
591 i->menuhelp=help;
592 i->menuHandle=handle;
593 }
594
595 /*
596 * void ibicon_attachMenuMaker
597 * (
598 * ibicon i,
599 * event_menu_maker m,
600 * menu_selectProc sel,
601 * menu_helpProc help,
602 * void *handle
603 * )
604 *
605 * Use
606 * Attaches a menu maker to an icon in the icon bar
607 *
608 * Parameters
609 * ibicon i == the icon to attach to
610 * event_menu_maker m == the menu maker to attach
611 * menu_selectProc sel == a handler function for the menu
612 * menu_helpProc help == a help processor for the menu
613 * void *handle == a handle passed to the handler
614 */
615
616 void ibicon_attachMenuMaker
617 (
618 ibicon i,
619 event_menu_maker m,
620 menu_selectProc sel,
621 menu_helpProc help,
622 void *handle
623 )
624 {
625 i->mnu=0;
626 i->maker=m;
627 i->menusel=sel;
628 i->menuhelp=help;
629 i->menuHandle=handle;
630 }
631
632 /*
633 * void ibicon_removeIcon(ibicon i)
634 *
635 * Use
636 * Removes an icon totally from the icon bar.
637 *
638 * Parameters
639 * ibicon i == the icon to vape
640 */
641
642 void ibicon_removeIcon(ibicon i)
643 {
644 wimpt_noerr(wimp_delete_icon(-2,i->icon));
645 if (i->prev)
646 i->prev->next=i->next;
647 else
648 ibicon__anchor=i->next;
649 if (i->next)
650 i->next->prev=i->prev;
651 mem_free(i);
652 win_activedec();
653 }
654
655 /*
656 * void ibicon_eventHandler(ibicon i,ibicon_handler p,void *handle)
657 *
658 * Use
659 * Attaches the handler to an icon.
660 *
661 * Parameters
662 * ibicon i == the icon to attach
663 * ibicon_handler p == the handler
664 * void *handle == a pointer to pass to the handler
665 */
666
667 void ibicon_eventHandler(ibicon i,ibicon_handler p,void *handle)
668 {
669 i->handler=p;
670 i->handle=handle;
671 }
672
673 /*
674 * void ibicon_rawEventHandler(ibicon i,ibicon_rawHandler p,void *handle)
675 *
676 * Use
677 * Attaches a raw event handler. This can 'vet' events before ibicon gets
678 * it mucky mits on them.
679 *
680 * Parameters
681 * ibicon i == the icon to attach
682 * ibicon_rawHandler p == the handler
683 * void *handle == a pointer to pass to the handler
684 */
685
686 void ibicon_rawEventHandler(ibicon i,ibicon_rawHandler p,void *handle)
687 {
688 i->raw=p;
689 i->rawHandle=handle;
690 }