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