chiark / gitweb /
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 }