home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d180 / browser.lha / Browser / menu.c < prev    next >
C/C++ Source or Header  |  1989-02-25  |  8KB  |  339 lines

  1. /* easy menus: Copyright 1987 Peter da Silva, all rights reserved.
  2.  *
  3.  *    Permission is granted to use this in any application, so long as
  4.  *    this notice is retained in the source. Permission is granted to
  5.  *    modify the code as you like, so long as this notice (between the
  6.  *    first line beginning "easy menus" and the end of this paragraph,
  7.  *    inclusive) is retained intact.
  8.  *
  9.  * Usage:
  10.  *
  11.  *    #include "menu.h"
  12.  *
  13.  *    struct MenuPtr menudata;
  14.  *    struct MenuPtr *menuptr = &menudata;
  15.  *
  16.  *    init_menus(menuptr);    / * Just zero menu pointer out * /
  17.  *
  18.  *    for(each menu item) {
  19.  *        add_menu(menuptr, menu, item, subitem, flags);
  20.  *    }
  21.  *
  22.  *  Flags:
  23.  *    SUBITEM_NOCHECK    -- subitem does not require a checkmark.
  24.  *    SUBITEM_SELECTOR    -- subitem is a 1 of n selector, use mutual-exclude.
  25.  *    SUBITEM_TOGGLE    -- subitem is a toggled flag.
  26.  *    SUBITEM_SELECTED    -- defaults to checked.
  27.  *
  28.  *
  29.  *    SetMenuStrip(yourwindow, menuptr->MenuBar);
  30.  *
  31.  *    ...
  32.  *
  33.  *    ClearMenuStrip(yourwindow);
  34.  *
  35.  *    trash_menus(menuptr);
  36.  *
  37.  * Notes:
  38.  *
  39.  *    if you don't want any subitems, use zero for the subitem value.
  40.  *
  41.  *    subitem is always initialised as a CHECKIT item with all the other
  42.  *    subitems mutually excluded.
  43.  *
  44.  *    it is intended that the menu be set up with all action items in
  45.  *    the first level of the menu, and all toggles in the second level...
  46.  *    this is a piece of blatant authoritarianism on my part. I've seen
  47.  *    too many menus with no rhyme or reason. Look at AmigaTerm (the term
  48.  *    program that comes with the Amiga modem) some time. Baud rate has
  49.  *    an item all by itself, but word size is hidden off in a menu with
  50.  *    things like bell sound.
  51.  *
  52.  *    the appearance of the menus produced by this is (in my humble
  53.  *    opinion) good. I took some care making text centered in menu boxes,
  54.  *    for example.
  55.  */
  56. #include <exec/memory.h>
  57. #include <intuition/intuition.h>
  58. #include "menu.h"
  59. #include "fonts.h"
  60.  
  61. /*
  62. struct MenuPtr {
  63.     struct Menu *MenuBar;
  64.     struct Remember *MenuMemory;
  65. };
  66. */
  67.  
  68. char *AllocRemember();
  69.  
  70. static struct Menu *new_menu();
  71. static struct MenuItem *new_item(), *new_subitem();
  72.  
  73. #define TOMENUNUM(i,j,k) (SHIFTMENU(i)|SHIFTITEM(j)|SHIFTSUB(k))
  74. #define TextLen(s) (strlen(s)*FONTWIDTH)
  75.  
  76. trash_menus(menuptr)
  77. struct MenuPtr *menuptr;
  78. {
  79.     FreeRemember(&menuptr->MenuMemory, 1);
  80.     menuptr->MenuMemory = 0;
  81.     menuptr->MenuBar = 0;
  82. }
  83.  
  84. init_menus(menuptr)
  85. struct MenuPtr *menuptr;
  86. {
  87.     menuptr->MenuMemory = 0;
  88.     menuptr->MenuBar = 0;
  89. }
  90.  
  91. int add_menu(menuptr, menuname, itemname, subitemname, flags)
  92. struct MenuPtr *menuptr;
  93. char *menuname, *itemname, *subitemname;
  94. long flags;
  95. {
  96.     int i, j, k;
  97.     struct Menu *menu;
  98.     struct MenuItem *item;
  99.     struct MenuItem *subitem;
  100.  
  101.     if(menuptr->MenuBar) {
  102.         for(i = 0, menu = menuptr->MenuBar;
  103.             menu;
  104.             menu = menu->NextMenu, i++
  105.            )
  106.             if(strcmp(menuname, menu->MenuName)==0)
  107.                 break;
  108.         if(!menu)
  109.             menu = new_menu(menuptr, menuname);
  110.         if(!menu)
  111.             return MENUNULL;
  112.     } else {
  113.         i = 0;
  114.         menu = new_menu(menuptr, menuname);
  115.         if(!menu)
  116.             return MENUNULL;
  117.     }
  118.     for(j = 0, item = menu->FirstItem;
  119.         item;
  120.         item = item->NextItem, j++
  121.        ) {
  122.         struct IntuiText *text;
  123.         text = (struct IntuiText *)item->ItemFill;
  124.         if(strcmp(itemname, text->IText) == 0)
  125.             break;
  126.     }
  127.     if(subitemname) {
  128.         if(!item)
  129.             item = new_item(menuptr, menu, itemname);
  130.         if(!item)
  131.             return MENUNULL;
  132.         for(k = 0, subitem = item->SubItem;
  133.             subitem;
  134.             subitem = subitem->NextItem, k++
  135.            ) {
  136.             struct IntuiText *text;
  137.             text = (struct IntuiText *)subitem->ItemFill;
  138.             if(strcmp(subitemname, text->IText) == 0)
  139.                 break;
  140.         }
  141.         if(!subitem)
  142.             subitem = new_subitem(menuptr, item, subitemname, flags);
  143.         if(!subitem)
  144.             return MENUNULL;
  145.         return TOMENUNUM(i, j, k);
  146.     } else {
  147.         if(!item)
  148.             item = new_item(menuptr, menu, itemname);
  149.         if(!item)
  150.             return MENUNULL;
  151.         return TOMENUNUM(i, j, NOSUB);
  152.     }
  153. }
  154.  
  155. static struct Menu *
  156. new_menu(menuptr, name)
  157. struct MenuPtr *menuptr;
  158. char *name;
  159. {
  160.     struct Menu *menu;
  161.  
  162.     menu = (struct Menu *)AllocRemember(
  163.         &menuptr->MenuMemory,
  164.         sizeof(struct Menu),
  165.         MEMF_PUBLIC);
  166.     if(!menu)
  167.         return 0;
  168.     menu->NextMenu = NULL;
  169.     menu->LeftEdge = 0;
  170.     menu->TopEdge = 0;
  171.     menu->Width = TextLen(name)+FONTWIDTH;
  172.     menu->Height = 0;
  173.     menu->Flags = MENUENABLED;
  174.     menu->MenuName = name;
  175.     menu->FirstItem = 0;
  176.     if(menuptr->MenuBar) {
  177.         struct Menu *ptr, *prev;
  178.         for(ptr = menuptr->MenuBar; ptr; ptr=ptr->NextMenu) {
  179.             menu->LeftEdge += ptr->Width;
  180.             prev = ptr;
  181.         }
  182.         prev->NextMenu = menu;
  183.     } else {
  184.         menuptr->MenuBar = menu;
  185.     }
  186.  
  187.     return menu;
  188. }
  189.  
  190. static struct item *
  191. new_item(menuptr, menu, name)
  192. struct MenuPtr *menuptr;
  193. char *name;
  194. struct Menu *menu;
  195. {
  196.     struct MenuItem *item;
  197.     struct IntuiText *text;
  198.  
  199.     item = (struct MenuItem *)AllocRemember(
  200.         &menuptr->MenuMemory,
  201.         sizeof(struct MenuItem),
  202.         MEMF_PUBLIC);
  203.     if(!item)
  204.         return 0;
  205.     text = (struct IntuiText *)AllocRemember(
  206.         &menuptr->MenuMemory,
  207.         sizeof(struct IntuiText),
  208.         MEMF_PUBLIC);
  209.     if(!text)
  210.         return 0;
  211.  
  212.     text->FrontPen = AUTOFRONTPEN;
  213.     text->BackPen = AUTOBACKPEN;
  214.     text->DrawMode = JAM2;
  215.     text->LeftEdge = 1;
  216.     text->TopEdge = 1;
  217.     text->ITextFont = NULL;
  218.     text->IText = name;
  219.     text->NextText = NULL;
  220.  
  221.     item->NextItem = NULL;
  222.     item->LeftEdge = 0;
  223.     item->TopEdge = 0;
  224.     item->Width = IntuiTextLength(text)+2;
  225.     if(item->Width <= menu->Width)
  226.         item->Width = menu->Width+1;
  227.     item->Height = FONTHEIGHT+1;
  228.     item->Flags = ITEMTEXT|HIGHCOMP|ITEMENABLED;
  229.     item->MutualExclude = 0;
  230.     item->ItemFill = text;
  231.     item->SelectFill = NULL;
  232.     item->Command = 0;
  233.     item->SubItem = NULL;
  234.     item->NextSelect = NULL;
  235.  
  236.     if(menu->FirstItem) {
  237.         struct MenuItem *ptr, *prev;
  238.         for(ptr = menu->FirstItem; ptr; ptr=ptr->NextItem) {
  239.             if(item->Width > ptr->Width) {
  240.                 if(ptr->SubItem)
  241.                     nudge(ptr->SubItem, item->Width-ptr->Width);
  242.                 ptr->Width = item->Width;
  243.             } else if(ptr->Width>item->Width)
  244.                 item->Width = ptr->Width;
  245.             prev = ptr;
  246.         }
  247.         item->TopEdge = prev->TopEdge + prev->Height;
  248.         prev->NextItem = item;
  249.     } else {
  250.         menu->FirstItem = item;
  251.     }
  252.  
  253.     return item;
  254. }
  255.  
  256. static nudge(item, delta)
  257. struct MenuItem *item;
  258. int delta;
  259. {
  260.     while(item) {
  261.         item->LeftEdge += delta;
  262.         item = item->NextItem;
  263.     }
  264. }
  265.  
  266. static struct item *
  267. new_subitem(menuptr, item, name, flags)
  268. struct MenuPtr *menuptr;
  269. char *name;
  270. struct MenuItem *item;
  271. long flags;
  272. {
  273.     struct MenuItem *subitem;
  274.     struct IntuiText *text;
  275.  
  276.     subitem = (struct MenuItem *)AllocRemember(
  277.         &menuptr->MenuMemory,
  278.         sizeof(struct MenuItem),
  279.         MEMF_PUBLIC);
  280.     if(!subitem)
  281.         return 0;
  282.     text = (struct IntuiText *)AllocRemember(
  283.         &menuptr->MenuMemory,
  284.         sizeof(struct IntuiText),
  285.         MEMF_PUBLIC);
  286.     if(!text)
  287.         return 0;
  288.  
  289.     text->FrontPen = AUTOFRONTPEN;
  290.     text->BackPen = AUTOBACKPEN;
  291.     text->DrawMode = JAM2;
  292.     text->LeftEdge = CHECKWIDTH+1;
  293.     text->TopEdge = 1;
  294.     text->ITextFont = NULL;
  295.     text->IText = name;
  296.     text->NextText = NULL;
  297.  
  298.     subitem->NextItem = NULL;
  299.     subitem->LeftEdge = item->Width;
  300.     subitem->TopEdge = 0;
  301.     subitem->Width = IntuiTextLength(text)+2;
  302.     if(flags != SUBITEM_NOCHECK) subitem->Width += CHECKWIDTH;
  303.     subitem->Height = FONTHEIGHT+1;
  304.     subitem->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
  305.     subitem->MutualExclude = 0;
  306.     if(flags != SUBITEM_NOCHECK) {
  307.         subitem->Flags |= CHECKIT;
  308.         if(flags & SUBITEM_TOGGLE) subitem->Flags |= MENUTOGGLE;
  309.         if(flags & SUBITEM_SELECTED) subitem->Flags |= CHECKED;
  310.     }
  311.     subitem->ItemFill = text;
  312.     subitem->SelectFill = NULL;
  313.     subitem->Command = 0;
  314.     subitem->SubItem = NULL;
  315.     subitem->NextSelect = NULL;
  316.  
  317.     if(item->SubItem) {
  318.         struct MenuItem *ptr, *prev;
  319.         int i;
  320.         for(i=0, ptr = item->SubItem; ptr; i++, ptr=ptr->NextItem) {
  321.             if(subitem->Width > ptr->Width)
  322.                 ptr->Width = subitem->Width;
  323.             else if(ptr->Width>subitem->Width)
  324.                 subitem->Width = ptr->Width;
  325.             prev = ptr;
  326.         }
  327.         subitem->TopEdge = prev->TopEdge + prev->Height;
  328.         if(flags & SUBITEM_SELECTOR)
  329.             subitem->MutualExclude = ~(1<<i);
  330.         prev->NextItem = subitem;
  331.     } else {
  332.         item->SubItem = subitem;
  333.         if(flags & SUBITEM_SELECTOR)
  334.             subitem->MutualExclude = ~1;
  335.     }
  336.  
  337.     return subitem;
  338. }
  339.