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 }