chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Steel / c / creator
1 /*
2  * creator.c
3  *
4  * Tearoff menu generating routines
5  *
6  * © 1994-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 #define _CORE
29 #define _STDAPP
30
31 #include <stdlib.h>
32 #include <stdarg.h>
33
34 #include "steel.h"
35 #include "string.h"
36
37 #include "xtearoff.h"
38
39 /*---------------------------------------------------------------------------
40
41   The syntax of menu strings is a subset of the system used by the
42   RISC_OSlib menu segment:
43
44     menu_description ::= <flags> <item> <sep> { <flags> <item> <sep> }
45     flags ::= '!' | '~' | '>' | ' ' | '@'
46     sep ::= ','
47     item ::= <a bunch of other characters>[#<Short-cut string>]
48
49   flags have meanings as follows:
50
51     ' ' has no effect
52     '~' shades the item
53     '>' item has a menu dbox attached
54     '!' item is ticked
55     '@' item is 'radioed'
56
57 ---------------------------------------------------------------------------*/
58
59 static BOOL tearoff__parse(tearoff t,char **p,tearoff__item *item,int *y)
60 {
61   char *ind;
62   int len=0;
63   int hash=0;
64
65   BOOL done=FALSE;
66   tearoff__item *itm;
67   char *eptr;
68   item->sub=(tearoff)-1;
69   item->subMenuWarning = FALSE;
70   item->selType = 0;
71   item->shaded = FALSE;
72   item->subMenu = FALSE;
73   item->subShaded = FALSE;
74   item->dotted = FALSE;
75   item->text = NULL;
76   item->keys = NULL;
77   item->y=*y;
78   while (!done)
79   {
80     switch (**p)
81     {
82       case '!':
83         item->selType=1;
84         (*p)++;
85         break;
86       case '@':
87         item->selType=2;
88         (*p)++;
89         break;
90       case ' ':
91         (*p)++;
92         break;
93       case '>':
94         item->subMenuWarning=TRUE;
95         (*p)++;
96         break;
97       case '~':
98         item->shaded=TRUE;
99         (*p)++;
100         break;
101       default:
102         done=TRUE;
103         break;
104     }
105   }
106   done=FALSE;
107   for (eptr=*p;*eptr!=0 && *eptr!='|' && *eptr!=',';eptr++,len++)
108     if (*eptr=='#') hash=len;
109   if (ind=mem_alloc(len+1),!ind)
110   {
111     werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
112     return (FALSE);
113   }
114   itm=(tearoff__item *)(t+1);
115   item->text=ind;
116   if (hash) item->keys=ind+hash+1;
117   while (**p!=0 && **p!='|' && **p!=',')
118   {
119     *ind=**p;
120     if (*ind=='#') *ind=0;
121     ind++;
122     (*p)++;
123   }
124   if (**p == '|')
125   {
126     item->dotted = TRUE;
127     t->dotted += 24;
128     t->redraw=TRUE;
129     *y-=24;
130   }
131   *(ind++)=0;
132   if (!**p)
133     *p=0;
134   else
135     (*p)++;
136   t->numberOfItems+=1;
137   *y-=44;
138   return (TRUE);
139 }
140
141 static int tearoff__itemCount(char *s)
142 {
143   int count=1;
144   if (*s=='|')
145     s++;
146   while (*s)
147   {
148     switch (*s)
149     {
150       case '|':
151       case ',':
152         count++;
153         break;
154     }
155     s++;
156   }
157   return (count);
158 }
159
160 tearoff tearoff_create(char *title,char *items,BOOL tearable,
161                     tearoff_selectProc proc, int max, void *handle)
162 {
163   int i,y;
164   tearoff__item *itm;
165   tearoff t;
166   int ino=tearoff__itemCount(items);
167
168   if (t=mem_alloc(sizeof(tearoff__str) + ino*sizeof(tearoff__item)),!t)
169   {
170     werr(FALSE,msgs_lookup("Not enough memory to construct menu."));
171     return (0);
172   }
173   t->menuTitle=malloc(strlen(title)+1);
174   if (!t->menuTitle)
175   {
176     werr(FALSE,msgs_lookup("Not enough memory to construct menu."));
177     return (0);
178   }
179   strcpy(t->menuTitle,title);
180   t->numberOfItems=0;
181   t->maxHeight=max;
182   t->selected=0;
183   t->tearoff=tearable;
184   t->tornoff=FALSE;
185   t->warned=FALSE;
186   t->folded=FALSE;
187   t->open=FALSE;
188   t->redraw=FALSE;
189   t->scrollBar=FALSE;
190   t->selectProc=proc;
191   t->userHandle=handle;
192   t->w=NULL;
193   t->sub=NULL;
194   t->prev=NULL;
195   t->dotted=0;
196   t->nextTornoff=NULL;
197   itm=((tearoff__item *)(t+1))-1;
198   y=-44;
199   if (t->tearoff) y-=tearoff__HEIGHT;
200   for (i=0;i<ino;i++)
201   {
202     itm++;
203     if (!items)
204       werr(TRUE,msgs_lookup("(tearoff_create): Menu item undercount."));
205     if (!tearoff__parse(t,&items,itm,&y))
206     {
207       if (t->indirected)
208         mem_free(t->indirected);
209       mem_free(t);
210       return (0);
211     }
212   }
213   if (items)
214     werr(TRUE,msgs_lookup("(tearoff_create): Menu item overcount."));
215   if (ino!=t->numberOfItems)
216     werr(TRUE,msgs_lookup("(tearoff_create): Menu item count mismatch."));
217   return (t);
218 }
219
220 void tearoff_attachSubMenu(tearoff to,int itm,tearoff sub)
221 {
222   tearoff__item *item;
223
224   if (to->numberOfItems < itm)
225   {
226     werr(TRUE,"(tearoff_attachSubMenu): Item does not exist");
227     return;
228   }
229   item = (tearoff__item *)(to+1);
230   item += (itm-1);
231   item->sub = sub;
232   item->subMenu = TRUE;
233 }
234
235 void tearoff_destroy(tearoff t)
236 {
237   tearoff__item *i;
238   int c;
239
240   if (!t) return;
241   i=(tearoff__item *)(t+1);
242   for (c=1;c<=t->numberOfItems;c++,i++)
243     mem_free(i->text);
244   mem_free(t->menuTitle);
245   mem_free(t);
246 }
247
248 void tearoff_selectItem(tearoff t, int item, tearoff_selectType type)
249 {
250   tearoff__item *i;
251   int more;
252   wimp_redrawstr r;
253   wimp_icon icon;
254   BOOL riscos3=(wimpt_getVersion()>=300);
255
256   i = (tearoff__item *)(t + 1);
257   i += (item-1);
258   if (i->selType == type) return;
259   i->selType = type;
260
261   if (t->open && !t->folded)
262   {
263     r.w=t->w;
264     r.box.x0=0;
265     r.box.x1=24;
266     r.box.y0=i->y;
267     r.box.y1=i->y+44;
268     wimp_update_wind(&r,&more);
269     while (more)
270     {
271       icon.box.y1=i->y+44;
272       icon.box.y0=i->y;
273       icon.box.x0=0;
274       icon.box.x1=24;
275
276       icon.flags=wimp_IVCENTRE |
277                  wimp_IHCENTRE |
278                  wimp_IFILLED |
279                  wimp_IBACKCOL * 0 |
280                  wimp_IFORECOL * 7;
281
282       if (i->shaded) icon.flags |= wimp_INOSELECT;
283       if (!riscos3 && i->selType == tearoff_TICKED)
284       {
285         icon.flags |= wimp_ITEXT;
286         strcpy(icon.data.text, "\x80");
287       }
288       if (riscos3 && i->selType == tearoff_TICKED)
289       {
290         icon.flags |= wimp_ISPRITE | wimp_INDIRECT;
291         icon.data.indirectsprite.name = "\x80";
292         icon.data.indirectsprite.spritearea = (sprite_area *)1;
293         icon.data.indirectsprite.nameisname = 4;
294       }
295       if (i->selType == tearoff_RADIOED)
296       {
297         icon.flags |= wimp_ITEXT;
298         strcpy(icon.data.text, "\x8F");
299       }
300       if (i->selType == tearoff_NONE)
301       {
302         icon.flags |= wimp_ITEXT;
303         strcpy(icon.data.text, "");
304       }
305       wimpt_noerr(wimp_ploticon(&icon));
306
307       wimp_get_rectangle(&r,&more);
308     }
309   }
310 }
311
312 void tearoff_shadeItem(tearoff t, int item, BOOL shaded)
313 {
314   tearoff__item *i;
315   wimp_redrawstr r;
316   int more;
317
318   i = (tearoff__item *)(t + 1);
319   i += (item-1);
320   if (i->shaded == shaded) return;
321   i->shaded = shaded;
322
323   if (t->open && !t->folded)
324   {
325     if (t->selected==item)
326     {
327       /* Close menu structure here */
328
329       t->selected=0;
330     }
331     r.w=t->w;
332     r.box.x0=0;
333     r.box.x1=t->width;
334     r.box.y0=i->y;
335     r.box.y1=i->y+44;
336     wimp_update_wind(&r,&more);
337     while (more)
338     {
339       tearoff__doRedraw(t, &r);
340       wimp_get_rectangle(&r,&more);
341     }
342   }
343 }
344
345 void tearoff_changeItemText(tearoff t,int item,char *text)
346 {
347   tearoff__item *i;
348   char *ind,*eptr;
349   int len=0,hash=0,oldWidth;
350
351   i=(tearoff__item *)(t+1);
352   i+=(item-1);
353
354   mem_free(i->text);
355   i->text=i->keys=NULL;
356   for (eptr=text;*eptr!=0;eptr++,len++)
357     if (*eptr=='#') hash=len;
358   if (ind=mem_alloc(len+1),!ind)
359   {
360     werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
361     return;
362   }
363   i->text=ind;
364   if (hash) i->keys=ind+hash+1;
365   while (*text)
366   {
367     *ind=*text;
368     if (*ind=='#') *ind=0;
369     ind++;
370     text++;
371   }
372   *ind=0;
373   if (t->open)
374   {
375     oldWidth=t->width;
376     tearoff_calculateMenuWidth(t);
377     if (oldWidth!=t->width)
378       tearoff_rebuildMenu(t);
379     else
380     {
381       if (t->selected)
382         tearoff_highlightItem(t->selected,t,FALSE);
383       t->selected=item;
384       tearoff_highlightItem(item,t,FALSE);
385       t->selected=0;
386     }
387   }
388 }
389
390 void tearoff_changeTitle(tearoff t,char *title)
391 {
392   int oldWidth;
393   mem_free(t->menuTitle);
394   t->menuTitle=NULL;
395   t->menuTitle=mem_alloc(strlen(title)+1);
396   if (!t->menuTitle)
397     return;
398   strcpy(t->menuTitle,title);
399   if (t->open)
400   {
401     oldWidth=t->width;
402     tearoff_calculateMenuWidth(t);
403     if (t->width!=oldWidth)
404       tearoff_rebuildMenu(t);
405     else
406       win_settitle(t->w,title);
407   }
408 }
409
410 tearoff tearoff_extendMenu(tearoff t,char *items)
411 {
412   tearoff__item *itm;
413   int ino=tearoff__itemCount(items),i,y;
414
415   if (!ino) return t;
416
417   if (t=mem_reAlloc(t, sizeof(tearoff__str) +
418                        (ino+t->numberOfItems)*sizeof(tearoff__item)),!t)
419   {
420     werr(FALSE,msgs_lookup("Not enough memory to construct menu."));
421     return NULL;
422   }
423   itm=((tearoff__item *)(t+1));
424   itm+=(t->numberOfItems-1);
425   y=itm->y-44;
426   if (itm->dotted) y-=24;
427   for (i=0;i<ino;i++)
428   {
429     itm++;
430     if (!items)
431       werr(TRUE,msgs_lookup("(tearoff_create): Menu item undercount."));
432     if (!tearoff__parse(t,&items,itm,&y))
433       return t;
434   }
435   return t;
436 }
437
438 BOOL tearoff_isShaded(tearoff t,int item)
439 {
440   tearoff__item *i;
441
442   i=(tearoff__item *)(t+1);
443   i+=(item-1);
444
445    return i->shaded;
446 }
447
448 tearoff_selectType tearoff_howSelected(tearoff t,int item)
449 {
450   tearoff__item *i;
451
452   i=(tearoff__item *)(t+1);
453   i+=(item-1);
454
455    return i->selType;
456 }