Initial revision
[ssr] / StraySrc / Libraries / Steel / c / fontMenu
1 /*
2 * fontMenu
3 * creates (and handles) a hierarchical font menu
4 *
5 * v. 1.00 (22 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 "fontMenu.h"
31 #include "msgs.h"
32 #include "werr.h"
33 #include "wimpt.h"
34 #include "menuExt.h"
35 #include "buffer.h"
36 #include <stdio.h>
37 #include "font.h"
38 #include "visdelay.h"
39 #include "win.h"
40 #include "utils.h"
41
42 #include <string.h>
43 #include <stdlib.h>
44
45 static BOOL fontMenu__created;
46 static menu fontMenu__menu;
47 static char fontMenu__oldFontPath[256];
48 static BOOL fontMenu__anyFonts;
49 static BOOL fontMenu__includeSystem;
50 static int fontMenu__tick1=-1;
51 static int fontMenu__tick2=-1;
52
53 /*
54 * char *fontMenu__fontFamily(char *fontname)
55 *
56 * Use
57 * Returns the family name of the given font.
58 *
59 * Parameters
60 * char *fontname == the name of the font.
61 *
62 * Returns
63 * The family name of the font (i.e. returns "Trinity" for "Trinity.Medium")
64 * as a pointer to a read-only internal static object.
65 */
66
67 static char *fontMenu__fontFamily(char *fontname)
68 {
69 char *fontFamily=buffer_find();
70 int index=0;
71 char c=fontname[index];
72 while (c!='.' && c>31)
73 {
74 fontFamily[index++]=c;
75 c=fontname[index];
76 }
77 fontFamily[index]='\0';
78 return (fontFamily);
79 }
80
81 /*
82 * char *fontMenu__fontLeaf(char *fontname)
83 *
84 * Use
85 * Returns the leafname of the font (i.e. for "Trinity.Bold.Italic", it
86 * returns "Bold.Italic"). If there is no leafname, it returns
87 * "(Regular)".
88 *
89 * Parameters
90 * char *fontname == the font name
91 *
92 * Returns
93 * A pointer to the leafname (to an internal static object)
94 */
95
96 static char *fontMenu__fontLeaf(char *fontname)
97 {
98 char *fontLeaf=buffer_find();
99 int index=0;
100 int outi=0;
101 char c=fontname[index];
102 BOOL stopHere=FALSE;
103 while (!stopHere)
104 {
105 index++;
106 if (c<32)
107 return (msgs_lookup("fontmRF:(Regular)"));
108 else if (c=='.')
109 stopHere=TRUE;
110 c=fontname[index];
111 }
112 while (c>31)
113 c=fontLeaf[outi++]=fontname[index++];
114 fontLeaf[outi-1]='\0';
115 return (fontLeaf);
116 }
117
118 /*
119 * void fontMenu__handleSubmenu(char *buffer,int *count,menu sub)
120 *
121 * Use
122 * Creates one of those submenus for the font menu.
123 *
124 * Parameters
125 * char *buffer == a buffer to store font names
126 * int *count == pointer to the current font count
127 * menu sub == the submenu handle
128 */
129
130 static void fontMenu__handleSubmenu(char *buffer,int *count,menu sub)
131 {
132 char newbuff[50];
133 char gadbuff[50];
134 strcpy(newbuff,buffer);
135 wimpt_noerr(font_list(buffer,count));
136 while
137 (
138 strcpy(gadbuff,fontMenu__fontFamily(buffer)),
139 *count!=-1 && strcmp(gadbuff,fontMenu__fontFamily(newbuff))==0
140 )
141 {
142 menu_extend(sub,fontMenu__fontLeaf(buffer));
143 strcpy(newbuff,buffer);
144 wimpt_noerr(font_list(buffer,count));
145 }
146 }
147
148 /*
149 * menu fontMenu_createFontMenu(BOOL includeSystem)
150 *
151 * Use
152 * Creates a hierarchical font menu and returns a handle. If the menu is
153 * out-of-date it will be recreated, if not the old handle will be
154 * returned. You must call this before using routines such as
155 * fontMenu_make() (so that the system knows whether you want to use a
156 * menu containing the system font or not). The returned pointer will be
157 * NULL if there are no fonts.
158 *
159 * Parameters
160 * BOOL includeSystem == whether you want to include a 'System font' item
161 *
162 * Returns
163 * A menu handle for the menu.
164 */
165
166 menu fontMenu_createFontMenu(BOOL includeSystem)
167 {
168 char *fontpath=getenv("Font$Path");
169 int fontCount=0;
170 char currentfont[50];
171 char lastTicked[50];
172 int subIndex=1;
173 menu submenu;
174 if (fontMenu__includeSystem!=includeSystem && fontMenu__created==TRUE)
175 {
176 fontMenu__created=FALSE;
177 menu_dispose(&fontMenu__menu,TRUE);
178 fontMenu__menu=0;
179 }
180 fontMenu__includeSystem=includeSystem;
181 if (fontpath)
182 fontMenu__anyFonts=TRUE;
183 else
184 fontMenu__anyFonts=FALSE;
185 if (fontMenu__created==TRUE && strcmp(fontpath,fontMenu__oldFontPath)==0)
186 return (fontMenu__menu);
187 visdelay_begin();
188 if (fontMenu__created==TRUE)
189 {
190 strcpy(lastTicked,fontMenu_fontname(fontMenu__tick1,fontMenu__tick2));
191 menu_dispose(&fontMenu__menu,TRUE);
192 }
193 if (fontMenu__anyFonts==FALSE)
194 {
195 visdelay_end();
196 if (includeSystem==FALSE)
197 {
198 werr(FALSE,msgs_lookup("fontmNF:No fonts available."));
199 fontMenu__created=FALSE;
200 return (0);
201 }
202 else
203 {
204 fontMenu__menu=menu_new
205 (
206 msgs_lookup("fontmFT:Fonts"),msgs_lookup("fontmSF:System font")
207 );
208 fontMenu__created=TRUE;
209 return (fontMenu__menu);
210 }
211 }
212 strcpy(fontMenu__oldFontPath,fontpath);
213 wimpt_noerr(font_list(currentfont,&fontCount));
214 if (includeSystem)
215 {
216 fontMenu__menu=menu_new
217 (
218 msgs_lookup("fontmFT:Fonts"),msgs_lookup("fontmSF:System font")
219 );
220 menu_extend(fontMenu__menu,fontMenu__fontFamily(currentfont));
221 subIndex++;
222 }
223 else if (fontCount==-1)
224 {
225 werr(FALSE,msgs_lookup("fontmNF:No fonts available."));
226 fontMenu__created=FALSE;
227 return (0);
228 }
229 else
230 {
231 fontMenu__menu=menu_new
232 (
233 msgs_lookup("fontmFT:Fonts"),fontMenu__fontFamily(currentfont)
234 );
235 }
236 if (!fontMenu__menu)
237 {
238 werr
239 (
240 FALSE,
241 msgs_lookup("fontmNEM:Not enough memory to create font menu.")
242 );
243 return (0);
244 }
245 while (fontCount!=-1)
246 {
247 submenu=menu_new
248 (
249 fontMenu__fontFamily(currentfont),
250 fontMenu__fontLeaf(currentfont)
251 );
252 if (submenu)
253 {
254 fontMenu__handleSubmenu(currentfont,&fontCount,submenu);
255 menuExt_submenu(fontMenu__menu,subIndex++,submenu);
256 if (fontCount!=-1)
257 menu_extend(fontMenu__menu,fontMenu__fontFamily(currentfont));
258 }
259 }
260 fontMenu__tick1=-1;
261 if (fontMenu__created)
262 fontMenu_tickGivenName(lastTicked);
263 visdelay_end();
264 fontMenu__created=TRUE;
265 return (fontMenu__menu);
266 }
267
268 /*
269 * menu fontMenu(BOOL includeSystem)
270 *
271 * Use
272 * Compatibility. Don't use this function.
273 */
274
275 menu fontMenu(BOOL includeSystem)
276 {
277 menu f=fontMenu_createFontMenu(includeSystem);
278 if (!f)
279 exit(0);
280 return (f);
281 }
282
283 /*
284 * char *fontMenu_fontname(int item1,int item2)
285 *
286 * Use
287 * Returns the font name given by the the menu hit passed. Example code:
288 *
289 * switch (hit[n])
290 * {
291 * ...
292 * case FONTMENU:
293 * {
294 * char *fontname=fontMenu_fontname(hit[n+1],hit[n+2]);
295 * ...
296 * }
297 * break;
298 * ...
299 * }
300 *
301 * Type promotion does the rest! If the hits give a silly result, then a
302 * null string (not a null pointer!) is returned.
303 *
304 * You should check for the system font yourself (hit[n+1]==1).
305 *
306 * Parameters
307 * int item1 == the item number in the main menu
308 * int item2 == the item number in the submenu
309 *
310 * Returns
311 * A pointer to a read-only string.
312 */
313
314 char *fontMenu_fontname(int item1,int item2)
315 {
316 int hits[3];
317 char *buffer=buffer_find();
318 char *reg;
319 if (item1==1 && item2==0 && fontMenu__includeSystem==TRUE)
320 return (msgs_lookup("fontmSF:System font"));
321 if (item1==-1)
322 return ("");
323 hits[0]=item1-1;
324 if (item2==0)
325 hits[1]=0;
326 else
327 hits[1]=item2-1;
328 hits[2]=-1;
329 wimpt_noerr(wimp_decode_menu
330 (
331 (wimp_menustr *)menu_syshandle(fontMenu__menu),
332 hits,
333 buffer
334 ));
335 utils_ctermToNterm(buffer);
336 reg=strstr(buffer,msgs_lookup("fontmRF:(Regular)"));
337 if (reg)
338 *(reg-1)='\0';
339 return (buffer);
340 }
341
342 /*
343 * void fontMenu_submenu(BOOL includeSystem)
344 *
345 * Use
346 * Opens a font menu as the submenu of another menu.
347 *
348 * Parameters
349 * BOOL includeSystem == whether we need to include a system font item.
350 */
351
352 void fontMenu_submenu(BOOL includeSystem)
353 {
354 wimp_eventstr *e=wimpt_last_event();
355 int x=e->data.msg.data.words[1];
356 int y=e->data.msg.data.words[2];
357 if
358 (
359 (e->e!=wimp_ESEND &&
360 e->e!=wimp_ESENDWANTACK) ||
361 e->data.msg.hdr.action!=wimp_MMENUWARN
362 )
363 return;
364 if (win_anyWindows()==FALSE)
365 {
366 werr
367 (
368 FALSE,
369 msgs_lookup("fontmTMWS:Too many windows - "
370 "%s could not create submenu."),
371 wimpt_programname()
372 );
373 }
374 else
375 {
376 visdelay_begin();
377 fontMenu(includeSystem);
378 wimpt_noerr(wimp_create_submenu
379 (
380 (wimp_menustr *)menu_syshandle(fontMenu__menu),
381 x,
382 y
383 ));
384 visdelay_end();
385 }
386 }
387
388 /*
389 * wimp_menuitem *fontMenu__menuItem(wimp_menustr *m,int item)
390 *
391 * Use
392 * Returns a pointer to the menu item given.
393 *
394 * Parameters
395 * wimp_menustr *m == the menu handle
396 * int item == the item number (starting at one)
397 *
398 * Returns
399 * A pointer to the correct menu item structure.
400 */
401
402 static wimp_menuitem *fontMenu__menuItem(wimp_menustr *m,int item)
403 {
404 return ((wimp_menuitem *)(m+1)+item-1);
405 }
406
407 /*
408 * char *fontMenu__menuText(wimp_menustr *m,int item,char *buffer)
409 *
410 * Use
411 * Returns the text of a menu item.
412 *
413 * Parameters
414 * wimp_menustr *m == the menu handle
415 * int item == the item number (1 upwards)
416 * char *buffer == buffer in which to put the string
417 *
418 * Returns
419 * A pointer to the menu item's text (may or may not be in buffer)
420 */
421
422 static char *fontMenu__menuText(wimp_menustr *m,int item,char *buffer)
423 {
424 int i;
425 char c;
426 wimp_menuitem *itm=fontMenu__menuItem(m,item);
427 if (itm->iconflags & wimp_INDIRECT)
428 {
429 c=itm->data.indirecttext.buffer[0];
430 for (i=0;i<254 && c>31;i++)
431 c=buffer[i]=itm->data.indirecttext.buffer[i];
432 buffer[i]='\0';
433 }
434 else
435 {
436 c=itm->data.text[0];
437 for (i=0;i<=11 && c>31;i++)
438 c=buffer[i]=itm->data.text[i];
439 buffer[i]='\0';
440 }
441 return (buffer);
442 }
443
444 /*
445 * wimp_menustr *fontMenu__submenu(wimp_menustr *m,int item)
446 *
447 * Use
448 * Returns the handle of the submenu of a menu item.
449 *
450 * Parameters
451 * wimp_menustr *m == the menu handle
452 * int item == the item number
453 *
454 * Returns
455 * A pointer to the submenu
456 */
457
458 static wimp_menustr *fontMenu__submenu(wimp_menustr *m,int item)
459 {
460 return (fontMenu__menuItem(m,item)->submenu);
461 }
462
463 /*
464 * void fontMenu_findFont(char *name,int *item1,int *item2)
465 *
466 * Use
467 * Finds a font in the font list. Returns the result in two integers,
468 * which are the menu item numbers in the main font menu and the submenu
469 * respectively. -1 is returned as the first item number if the font
470 * wasn't found.
471 *
472 * Parameters
473 * char *name == the (case sensitive) name of the font.
474 * int *item1 == where to store the first item number.
475 * int *item2 == where to store the second item number.
476 */
477
478 void fontMenu_findFont(char *name,int *item1,int *item2)
479 {
480 int i=1;
481 int j;
482 wimp_menustr *m=menu_syshandle(fontMenu__menu);
483 wimp_menustr *s;
484 char *family=fontMenu__fontFamily(name);
485 char *leaf=fontMenu__fontLeaf(name);
486 char buffer[40];
487 if
488 (
489 strcmp(name,msgs_lookup("fontmSF:System font"))==0 &&
490 fontMenu__includeSystem==TRUE
491 )
492 {
493 *item1=1;
494 *item2=-1;
495 return;
496 }
497 do
498 {
499 if (strcmp(fontMenu__menuText(m,i,buffer),family)==0)
500 {
501 s=fontMenu__submenu(m,i);
502 j=1;
503 do
504 {
505 if (strcmp(fontMenu__menuText(s,j,buffer),leaf)==0)
506 {
507 *item1=i;
508 *item2=j;
509 return;
510 }
511 j++;
512 }
513 while ((fontMenu__menuItem(s,j-1)->flags&wimp_MLAST)==0);
514 *item1=-1;
515 return;
516 }
517 i++;
518 }
519 while ((fontMenu__menuItem(m,i-1)->flags&wimp_MLAST)==0);
520 *item1=-1;
521 return;
522 }
523
524 /*
525 * void fontMenu__tickItem(wimp_menustr *m,item i,BOOL onOrOff)
526 *
527 * Use
528 * Ticks a menu item (low-level)
529 *
530 * Parameters
531 * wimp_menustr *m == the menu handle
532 * item i == the menu item
533 * BOOL onOrOff == tick is on or off
534 */
535
536 static void fontMenu__tickItem(wimp_menustr *m,int i,BOOL onOrOff)
537 {
538 if (onOrOff)
539 fontMenu__menuItem(m,i)->flags|=wimp_MTICK;
540 else
541 fontMenu__menuItem(m,i)->flags&=~wimp_MTICK;
542 }
543
544 /*
545 * void fontMenu__doTick(BOOL onOrOff)
546 *
547 * Use
548 * Ticks on or off the current font.
549 *
550 * Parameters
551 * BOOL onOrOff == whether we want to tick or untick the font.
552 */
553
554 static void fontMenu__doTick(BOOL onOrOff)
555 {
556 wimp_menustr *m=menu_syshandle(fontMenu__menu);
557 if (fontMenu__tick1==1 && fontMenu__tick2==-1)
558 {
559 fontMenu__tickItem(m,1,onOrOff);
560 }
561 else if (fontMenu__tick1!=-1)
562 {
563 fontMenu__tickItem(m,fontMenu__tick1,onOrOff);
564 fontMenu__tickItem
565 (
566 fontMenu__submenu(m,fontMenu__tick1),
567 fontMenu__tick2,
568 onOrOff
569 );
570 }
571 }
572
573 /*
574 * void fontMenu_tick(int item1,int item2)
575 *
576 * Use
577 * Ticks the item specified. Only one font may be ticked at a time. If
578 * the menu item specified is silly, no item will be ticked. No range
579 * checking is performed.
580 *
581 * Parameters
582 * int item1 == the item number in the main menu
583 * int item2 == the item number in the submenu
584 */
585
586 void fontMenu_tick(int item1,int item2)
587 {
588 fontMenu__doTick(FALSE);
589 fontMenu__tick1=item1;
590 fontMenu__tick2=item2;
591 fontMenu__doTick(TRUE);
592 }
593
594 /*
595 * void fontMenu_tickGivenName(char *name)
596 *
597 * Use
598 * Ticks the item specified by it's name. If the name is silly, no item
599 * will be ticked.
600 *
601 * Parameters
602 * char *name == the font name to tick
603 */
604
605 void fontMenu_tickGivenName(char *name)
606 {
607 int i1,i2;
608 fontMenu_findFont(name,&i1,&i2);
609 fontMenu_tick(i1,i2);
610 }