home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / andylib_1 / AndyLib / c / fontmenu < prev    next >
Text File  |  1995-03-06  |  10KB  |  440 lines

  1. /* fontmenu.c - Create a menu structure from the fonts on Font$Path.  The
  2.  * returned structure is static; it is only recreated if Font$Path or
  3.  * Font$Prefix changes
  4.  */
  5.  
  6. /*
  7. #define DEBUG
  8. */
  9.  
  10. #include <stdlib.h>
  11. #include <string.h>
  12.  
  13. #include "font.h"
  14. #include "menu.h"
  15. #include "wimpt.h"
  16. #include "werr.h"
  17. #include "visdelay.h"
  18. #include "os.h"
  19. #include "swis.h"
  20. #include "dbox.h"
  21. #include "msgs.h"
  22. #include "tracker.h"
  23.  
  24. #include "fontmenu.h"
  25.  
  26. typedef struct fontname
  27. {  struct fontname *left, *right;   /* Text follows in memory */
  28.    int main, sub;
  29. } fontname;
  30.  
  31. #define TB_LEN 128
  32.  
  33. static menu fontmenu = NULL;
  34. static menu submenu;
  35. static menu *subs;
  36. static char lastroot[40], thisroot[40];
  37. static int item, sub;
  38. static fontname *fonttree;
  39. static int maintick, subtick;
  40. static BOOL hassysfont;
  41. static BOOL needs_submenu;
  42. static char tbuf[TB_LEN];
  43.  
  44. #define VARLEN 512
  45. static char varvals[VARLEN];
  46. #define FONTVARS "<Font$Prefix> and <Font$Path>"
  47.  
  48. #ifdef DEBUG
  49.  
  50. static menu safe_menu_new(char *title, char *text)
  51. {  menu m;
  52.  
  53.    werr(FALSE, "menu_new(\"%s\", \"%s\")", title, text);
  54.    m = menu_new(title, text);
  55.    werr(FALSE, "menu_new() returned %p", m);
  56.    return m;
  57. }
  58.  
  59. static void safe_menu_extend(menu m, char *text)
  60. {  werr(FALSE, "menu_extend(%p, \"%s\")", m, text);
  61.    menu_extend(m, text);
  62.    werr(FALSE, "menu_extend() returned");
  63. }
  64.  
  65. static void safe_menu_submenu(menu m, int i, menu s)
  66. {  werr(FALSE, "menu_submenu(%p, %d, %p)", m, i, s);
  67.    menu_submenu(m, i, s);
  68.    werr(FALSE, "menu_submenu() returned");
  69. }
  70.  
  71. #else
  72.  
  73. #define safe_menu_new(title, text)      menu_new(title, text)
  74. #define safe_menu_extend(m, text)       menu_extend(m, text)
  75. #define safe_menu_submenu(m, i, s)      menu_submenu(m, i, s)
  76.  
  77. #endif
  78.  
  79. static void getfontvars(char *buf, int len)
  80. {  os_regset regs;
  81.  
  82.    regs.r[0] = (int) FONTVARS;
  83.    regs.r[1] = (int) buf;
  84.    regs.r[2] = len-1;
  85.  
  86.    os_swix(OS_GSTrans, ®s);
  87.  
  88.    buf[regs.r[2]] = '\0';
  89. }
  90.  
  91. static void freenames(fontname *node)
  92. {  if (node)
  93.    {  freenames(node->left);
  94.       freenames(node->right);
  95.       free(node);
  96.    }
  97. }
  98.  
  99. static fontname *putname(fontname *node, char *name)
  100. {  if (!node)
  101.    {  if (node = malloc(sizeof(fontname) + strlen(name) + 1), !node)
  102.          werr(TRUE,
  103.      msgs_lookup("fontmenu3:Fatally out of store while reading font names"));
  104.       node->left = node->right = NULL;
  105.       strcpy((char *) (node + 1), name);
  106.       return node;
  107.    }
  108.    else
  109.    {  int cmp = strcmp(name, (char *) (node + 1));
  110.       if (cmp < 0)
  111.          node->left = putname(node->left, name);
  112.       else if (cmp > 0)
  113.          node->right = putname(node->right, name);
  114.    }
  115.  
  116.    return node;
  117. }
  118.  
  119. static fontname *readnames(char *dbname)
  120. {  char fname[41];
  121.    int fnum;
  122.    fontname *tree = NULL;
  123.    dbox db;
  124.    wimp_eventstr ev;
  125.    BOOL open = FALSE;
  126.  
  127.    if (dbname && *dbname)
  128.    {  if (db = dbox_new(dbname), !db)
  129.          werr(FALSE, msgs_lookup("fontmenu4:Can't find template %s"), dbname);
  130.    }
  131.    else
  132.       db = NULL;
  133.  
  134.    for (fnum = 0; fnum >= 0; )
  135.    {  if (wimpt_complain(font_list(fname, &fnum)))
  136.       {  freenames(tree);
  137.          return NULL;
  138.       }
  139.  
  140.       if (fnum >= 0)
  141.       {  if (db)
  142.          {  if (!open)
  143.             {  dbox_showstatic(db);
  144.                wimpt_poll(0, &ev);
  145.                wimpt_fake_event(&ev);
  146.                open = TRUE;
  147.             }
  148.             dbox_setfield(db, 1, fname);
  149.          }
  150.          tree = putname(tree, fname);
  151.       }
  152.    }
  153.  
  154.    if (db)
  155.       dbox_dispose(&db);
  156.  
  157.    return tree;
  158. }
  159.  
  160. static void copyroot(char *buf, char *name)
  161. {  int c;
  162.  
  163.    for (c = 0; c < 39 && name[c] != '.' && name[c] != '\0'; c++)
  164.       buf[c] = name[c];
  165.    buf[c] = '\0';
  166. }
  167.  
  168. static void extendmenu(menu *mp, char *name, char *with)
  169. {  if (!*with) return;
  170.  
  171.    if (*mp)
  172.       safe_menu_extend(*mp, with+1);
  173.    else
  174.       *mp = safe_menu_new(name, with+1);
  175.  
  176.    *with = '\0';
  177. }
  178.  
  179. static void pass1(fontname *node)
  180. {  if (node)
  181.    {  pass1(node->left);
  182.       copyroot(thisroot, (char *) (node + 1));
  183.       if (strcmp(lastroot, thisroot) != 0)
  184.       {  if (*lastroot) item++;
  185.  
  186.          if (strlen(tbuf) + strlen(thisroot) + 2 > TB_LEN)
  187.             extendmenu(&fontmenu, msgs_lookup("fontmenu5:Font"), tbuf);
  188.  
  189.          strcat(tbuf, ",");
  190.          strcat(tbuf, thisroot);
  191.          strcpy(lastroot, thisroot);
  192.       }
  193.       pass1(node->right);
  194.    }
  195. }
  196.  
  197. static void pass2(fontname *node)
  198. {  char *np;
  199.  
  200.    if (node)
  201.    {  pass2(node->left);
  202.       copyroot(thisroot, (char *) (node + 1));
  203.  
  204.       if (strcmp(lastroot, thisroot) != 0)
  205.       {  if (*lastroot)
  206.          {  if (needs_submenu)
  207.             {  extendmenu(&submenu, lastroot, tbuf);
  208.                subs[item++] = submenu;
  209.             }
  210.             else
  211.             {  if (submenu)
  212.                   menu_dispose(&submenu, FALSE);
  213.                subs[item++] = NULL;
  214.             }
  215.  
  216.             *tbuf = '\0';
  217.             submenu = NULL;
  218.             sub = 1;
  219.             needs_submenu = FALSE;
  220.          }
  221.          strcpy(lastroot, thisroot);
  222.       }
  223.  
  224.       for (np = (char *) (node + 1); *np && *np != '.'; np++)
  225.          ;
  226.  
  227.       if (*np == '.')
  228.       {  ++np;
  229.          needs_submenu = TRUE;
  230.       }
  231.       else
  232.          np = msgs_lookup("fontmenu6:(Regular)");
  233.  
  234.       node->main = item;
  235.       node->sub  = sub++;
  236.  
  237.       if (strlen(tbuf) + strlen(np) + 2 > TB_LEN)
  238.          extendmenu(&submenu, thisroot, tbuf);
  239.  
  240.       strcat(tbuf, ",");
  241.       strcat(tbuf, np);
  242.  
  243.       pass2(node->right);
  244.    }
  245. }
  246.  
  247. void fontmenu_init(void)
  248. {  *varvals = '\0';
  249.    fontmenu = NULL;
  250.    subs     = NULL;
  251.    fonttree = NULL;
  252. }
  253.  
  254. BOOL fontmenu_pathchanged(void)
  255. {  char vbuf[VARLEN];
  256.  
  257.    getfontvars(vbuf, VARLEN);
  258.    return !!strcmp(vbuf, varvals);
  259. }
  260.  
  261. /* Build a font menu, and store its address in 'fontmenu'.  It is the callers
  262.  * responsibility to have freed any previous font menu.
  263.  */
  264.  
  265. menu fontmenu_make(BOOL sysfont, char *dbname)
  266. {  int i;
  267.  
  268.    visdelay_begin();
  269.  
  270.    if (fontmenu_pathchanged())
  271.    {  getfontvars(varvals, VARLEN);
  272.       if (fonttree)
  273.       {  freenames(fonttree);
  274.          fonttree = NULL;
  275.       }
  276.    }
  277.  
  278.    if (subs)
  279.       free(subs);
  280.  
  281.    if (!fonttree)
  282.       fonttree = readnames(dbname);
  283.  
  284.    if (sysfont)
  285.       fontmenu = safe_menu_new(msgs_lookup("fontmenu5:Font"),
  286.                                msgs_lookup("fontmenu1:System font"));
  287.    else
  288.       fontmenu = NULL;
  289.  
  290.    *tbuf = '\0';
  291.    item = sysfont ? 2 : 1;
  292.    *lastroot = '\0';
  293.    pass1(fonttree);
  294.  
  295.    /* Flush remaining main menu definition */
  296.  
  297.    extendmenu(&fontmenu, msgs_lookup("fontmenu5:Font"), tbuf);
  298.  
  299.    if (subs = malloc(sizeof(menu) * (item + 1)), !subs)
  300.       werr(TRUE, msgs_lookup("fontmenu2:Fatal memory shortage while building font menu"));
  301.  
  302.    for (i = 0; i <= item; i++)
  303.       subs[i] = NULL;
  304.  
  305.    submenu = NULL;
  306.    *tbuf = '\0';
  307.    item = sysfont ? 2 : 1;
  308.    sub = 1;
  309.    *lastroot = '\0';
  310.    needs_submenu = FALSE;
  311.    pass2(fonttree);
  312.  
  313.    /* Flush remaining submenu definition */
  314.  
  315.    if (needs_submenu)
  316.    {  extendmenu(&submenu, lastroot, tbuf);
  317.       subs[item++] = submenu;
  318.    }
  319.    else
  320.    {  if (submenu)
  321.          menu_dispose(&submenu, FALSE);
  322.       subs[item++] = NULL;
  323.    }
  324.  
  325.    /* Attach submenus to main menu */
  326.  
  327.    for (i = 1; i < item; i++)
  328.       if (subs[i])
  329.          safe_menu_submenu(fontmenu, i, subs[i]);
  330.  
  331.    maintick =
  332.    subtick = -1;
  333.  
  334.    submenu = NULL;
  335.    hassysfont = sysfont;
  336.  
  337.    visdelay_end();
  338.  
  339.    return fontmenu;
  340. }
  341.  
  342. static void settick(int main, int sub, BOOL state)
  343. {  if (main > 0)
  344.    {  menu_setflags(fontmenu, main, state, FALSE);
  345.       if (sub > 0)
  346.          menu_setflags(subs[main], sub, state, FALSE);
  347.    }
  348. }
  349.  
  350. static void findtick(char *name, fontname *node)
  351. {  int cmp;
  352.  
  353.    if (node)
  354.    {  cmp = strcmp(name, (char *) (node + 1));
  355.       if (cmp < 0)
  356.          findtick(name, node->left);
  357.       else if (cmp > 0)
  358.          findtick(name, node->right);
  359.       else
  360.       {  maintick = node->main;
  361.          subtick  = node->sub;
  362.       }
  363.    }
  364. }
  365.  
  366. void fontmenu_tick(char *name)
  367. {  settick(maintick, subtick, FALSE);
  368.    if (hassysfont && strcmp(name, msgs_lookup("fontmenu1:System font")) == 0)
  369.    {  maintick = 1;
  370.       subtick  = 0;
  371.    }
  372.    else
  373.       findtick(name, fonttree);
  374.  
  375.    settick(maintick, subtick, TRUE);
  376. }
  377.  
  378. static char *scan(char *hit, fontname *node, char *ideal)
  379. {  char *np;
  380.  
  381.    if (node)
  382.    {  if (hit[0] == node->main)
  383.       {  if (hit[1] == node->sub)
  384.             return (char *) (node + 1);
  385.  
  386.          if (hit[1] == 0)
  387.          {  if (!ideal && node->sub == 1)
  388.                return (char *) (node + 1);
  389.  
  390.             for (np = (char *) (node + 1); *np && *np != '.'; np++)
  391.                ;
  392.  
  393.             if (*np == '.')
  394.                ++np;
  395.             else
  396.                np = msgs_lookup("fontmenu6:(Regular)");
  397.  
  398.             if (strcmp(ideal, np) == 0)
  399.                return (char *) (node + 1);
  400.          }
  401.       }
  402.  
  403.       if (np = scan(hit, node->left, ideal), np)
  404.          return np;
  405.       if (np = scan(hit, node->right, ideal), np)
  406.          return np;
  407.    }
  408.  
  409.    return NULL;
  410. }
  411.  
  412. char *fontmenu_decode(char *hit)
  413. {  char *ideals = msgs_lookup("fontmenu7:(Regular),Medium,Roman,Book");
  414.    char *result;
  415.    char ideal[32], *ip;
  416.  
  417.    if (hassysfont && hit[0] == 1)
  418.       return msgs_lookup("fontmenu1:System font");
  419.    else
  420.    {  for (ip = ideals; *ip; )
  421.       {  int c;
  422.  
  423.          for (c = 0; c < 31 && *ip && *ip != ','; c++, ip++)
  424.             ideal[c] = *ip;
  425.  
  426.          if (*ip == ',')
  427.             ip++;
  428.  
  429.          ideal[c] = '\0';
  430.  
  431.          result = scan(hit, fonttree, ideal);
  432.  
  433.          if (result)
  434.             return result;
  435.       }
  436.  
  437.       return scan(hit, fonttree, NULL);
  438.    }
  439. }
  440.