home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 581a.lha / IntuitionSupLibrary_v2.0 / Menus / source.lzh / menus.c < prev    next >
C/C++ Source or Header  |  1991-09-23  |  11KB  |  370 lines

  1.         /*************************************
  2.          *                                   *
  3.          *             Menus v2.0            *
  4.          *   by Torsten Jürgeleit in 08/91   *
  5.          *                                   *
  6.          *              Routines             *
  7.          *                                   *
  8.          *************************************/
  9.  
  10.     /* Includes */
  11.  
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #include <intuition/intuition.h>
  15. #include <functions.h>
  16. #include <string.h>
  17. #include "/render/render.h"
  18. #include "menus.h"
  19.  
  20.     /* Static prototypes */
  21.  
  22. ULONG get_buffer_size(struct MenuList  *ml);
  23. VOID  get_item_text_pens(struct MenuList  *ml);
  24. BOOL  init_menu(struct MenuList  *ml);
  25. VOID  equal_select_box_width(struct MenuItem  *item);
  26.  
  27.     /* Static pragmas */
  28.  
  29. #pragma regcall(get_buffer_size(a0))
  30. #pragma regcall(get_item_text_pens(a0))
  31. #pragma regcall(init_menu(a0))
  32. #pragma regcall(equal_select_box_width(a0))
  33.  
  34.     /* Create menu list */
  35.  
  36.    struct MenuList *
  37. create_menu(struct RenderInfo  *ri, struct Window  *win,
  38.                  struct MenuData  *md, struct TextAttr  *ta)
  39. {
  40.    struct MenuList  *ml;
  41.  
  42.    if (ri && md) {
  43.       if (ml = AllocMem((LONG)sizeof(struct MenuList), (LONG)MEMF_PUBLIC |
  44.                                   MEMF_CLEAR)) {
  45.      /* init menu list struct */
  46.      ml->ml_RenderInfo = ri;
  47.      ml->ml_Window     = win;   /* needed for colors !!! */
  48.      ml->ml_Data       = md;
  49.      ml->ml_TextAttr   = ta;
  50.      ml->ml_Flags      = 0;
  51.      if (ta) {
  52.         ml->ml_TextFont = OpenFont(ta);
  53.      } else {
  54.         ml->ml_TextFont = ri->ri_TextFont;
  55.      }
  56.      if (ml->ml_TextFont) {
  57.         if (ml->ml_BufferSize = get_buffer_size(ml)) {
  58.            if (ml->ml_Buffer = AllocMem(ml->ml_BufferSize, (LONG)
  59.                         MEMF_PUBLIC | MEMF_CLEAR)) {
  60.           get_item_text_pens(ml);
  61.           if (init_menu(ml) == TRUE) {
  62.              return(ml);
  63.           }
  64.           FreeMem(ml->ml_Buffer, ml->ml_BufferSize);
  65.            }
  66.         }
  67.         if (ta) {
  68.            CloseFont(ml->ml_TextFont);
  69.         }
  70.      }
  71.      FreeMem(ml, (LONG)sizeof(struct MenuList));
  72.       }
  73.    }
  74.    return(NULL);
  75. }
  76.     /* Attach menu list to given window */
  77.  
  78.    VOID
  79. attach_menu(struct Window  *win, struct MenuList  *ml)
  80. {
  81.    if (win && ml) {
  82.       /* remove menu strip from old window if any and attach it to new one */
  83.       if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
  84.      ClearMenuStrip(ml->ml_Window);
  85.       }
  86.       SetMenuStrip(win, (struct Menu *)ml->ml_Buffer);
  87.       ml->ml_Window = win;
  88.       ml->ml_Flags |= MENU_LIST_FLAG_ATTACHED;
  89.    }
  90. }
  91.     /* Return menu item address */
  92.  
  93.    struct MenuItem *
  94. menu_item_address(struct MenuList  *ml, USHORT menu_num)
  95. {
  96.    return(ItemAddress((struct Menu *)ml->ml_Buffer, (LONG)menu_num));
  97. }
  98.     /* Remove menu list from window currently attached to */
  99.  
  100.    VOID
  101. remove_menu(struct MenuList  *ml)
  102. {
  103.    if (ml) {
  104.       if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
  105.      ClearMenuStrip(ml->ml_Window);
  106.      ml->ml_Flags &= ~MENU_LIST_FLAG_ATTACHED;
  107.       }
  108.    }
  109. }
  110.     /* Free menu */
  111.  
  112.    VOID
  113. free_menu(struct MenuList  *ml)
  114. {
  115.    if (ml) {
  116.       if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
  117.      ClearMenuStrip(ml->ml_Window);
  118.       }
  119.       if (ml->ml_TextAttr) {
  120.      CloseFont(ml->ml_TextFont);
  121.       }
  122.       FreeMem(ml->ml_Buffer, ml->ml_BufferSize);
  123.       FreeMem(ml, (LONG)sizeof(struct MenuList));
  124.    }
  125. }
  126.     /* Get buffer size for menus, items and intui texts */
  127.  
  128.    STATIC ULONG
  129. get_buffer_size(struct MenuList  *ml)
  130. {
  131.    struct MenuData   *md = ml->ml_Data;
  132.    USHORT menus = 0, items = 0;
  133.    ULONG  buffer_size = 0;
  134.  
  135.    if (md->md_Type == MENU_DATA_TYPE_TITLE) {
  136.       do {
  137.      switch (md++->md_Type) {
  138.         case MENU_DATA_TYPE_TITLE :
  139.            menus++;
  140.            break;
  141.         case MENU_DATA_TYPE_ITEM :
  142.         case MENU_DATA_TYPE_SUBITEM :
  143.            items++;
  144.            break;
  145.      }
  146.       } while (md->md_Type != INTUISUP_DATA_END &&
  147.                      md->md_Type <= MAX_MENU_DATA_TYPE);
  148.       if (menus && items) {
  149.      buffer_size = menus * sizeof(struct Menu) + items *
  150.                (sizeof(struct MenuItem) + sizeof(struct IntuiText));
  151.       }
  152.    }
  153.    return(buffer_size);
  154. }
  155.     /* Get two different text pens for items */
  156.  
  157.    STATIC VOID
  158. get_item_text_pens(struct MenuList  *ml)
  159. {
  160.    struct RenderInfo  *ri = ml->ml_RenderInfo;
  161.    struct ColorMap    *cmap;
  162.    SHORT i, j, temp, num_colors, back_color, colors[MAX_RENDER_COLORS],
  163.      pens[MAX_RENDER_COLORS];
  164.    
  165.    if ((num_colors = 1 << ri->ri_ScreenDepth) > MAX_RENDER_COLORS) {
  166.       num_colors = MAX_RENDER_COLORS;
  167.    }
  168.    if (num_colors < 3) {
  169.       /* set render pens for monochrome screen */
  170.       if (ml->ml_Window->BlockPen) {
  171.      ml->ml_TextPen1 = 0;
  172.      ml->ml_TextPen2 = 0;
  173.       } else {
  174.      ml->ml_TextPen1 = 1;
  175.      ml->ml_TextPen2 = 1;
  176.       }
  177.    } else {
  178.       /* get current screen colors */
  179.       Forbid();
  180.       cmap = ml->ml_Window->WScreen->ViewPort.ColorMap;
  181.       for (i = 0; i < num_colors; i++) {
  182.      colors[i] = GetRGB4(cmap, (LONG)i);
  183.      pens[i]   = i;
  184.       }
  185.       Permit();
  186.       /* save normal background color */
  187.       back_color = colors[ml->ml_Window->BlockPen];
  188.       /* set pen 1 */
  189.       for (i = 0, j = 0; i < num_colors; i++) {
  190.      if ((temp = calc_color_difference(colors[i], back_color)) > j) {
  191.         j               = temp;
  192.         ml->ml_TextPen1 = pens[i];
  193.      }
  194.       }
  195.       /* set text pen 2 */
  196.       for (i = 0, j = 0; i < num_colors; i++) {
  197.      if ((temp = calc_color_difference(colors[i], back_color)) > j &&
  198.                            pens[i] != ri->ri_TextPen1) {
  199.         j               = temp;
  200.         ml->ml_TextPen2 = pens[i];
  201.      }
  202.       }
  203.    }
  204. }
  205.     /* Initialize menu from menu list */
  206.  
  207.    STATIC BOOL
  208. init_menu(struct MenuList  *ml)
  209. {
  210.    struct RenderInfo  *ri = ml->ml_RenderInfo;
  211.    struct MenuData    *md;
  212.    struct TextFont    *menu_tf = ri->ri_TextFont, *item_tf = ml->ml_TextFont;
  213.    struct Menu        *last_menu, *menu = NULL;
  214.    struct MenuItem    *last_item, *last_subitem, *item = NULL;
  215.    struct IntuiText   *itext, *last_itext;
  216.    SHORT  item_ypos, subitem_xpos, subitem_ypos;
  217.    BYTE   *buffer = ml->ml_Buffer;
  218.    USHORT type, flags;
  219.    BOOL   success = FALSE, error = FALSE, subitem_flag = FALSE;
  220.  
  221.    /* init menus and items */
  222.    for (md = ml->ml_Data; md->md_Type != INTUISUP_DATA_END &&
  223.                   md->md_Type <= MAX_MENU_DATA_TYPE; md++) {
  224.       type  = md->md_Type;
  225.       flags = md->md_Flags;
  226.       switch (type) {
  227.      case MENU_DATA_TYPE_TITLE :
  228.         /* prepare last menu and subitem list */
  229.         if (menu) {
  230.            equal_select_box_width(menu->FirstItem);
  231.         }
  232.         if (subitem_flag == TRUE) {
  233.            equal_select_box_width(last_item->SubItem);
  234.         }
  235.         /* init data for new menu */
  236.         item         = NULL;
  237.         last_item    = NULL;
  238.         last_subitem = NULL;
  239.         item_ypos    = 0;
  240.         subitem_flag = FALSE;
  241.         last_menu    = menu;
  242.         menu         = (struct Menu *)buffer;
  243.         buffer      += sizeof(struct Menu);
  244.         /* init new menu */
  245.         if (last_menu) {
  246.            last_menu->NextMenu = menu;
  247.            menu->LeftEdge      = last_menu->LeftEdge + last_menu->Width
  248.                             + menu_tf->tf_XSize;
  249.         } else {
  250.            menu->LeftEdge = 5;
  251.         }
  252.         menu->Width     = (strlen(md->md_Name) + 1) * menu_tf->tf_XSize;
  253.         menu->Height    = menu_tf->tf_YSize;
  254.         menu->Flags     = MIDRAWN | (flags & MENU_DATA_FLAG_DISABLED ?
  255.                                0 : MENUENABLED);
  256.         menu->MenuName  = md->md_Name;
  257.         menu->FirstItem = (struct MenuItem *)buffer;
  258.         break;
  259.      case MENU_DATA_TYPE_ITEM :
  260.      case MENU_DATA_TYPE_SUBITEM :
  261.         /* init item data */
  262.         if (subitem_flag == TRUE) {
  263.            last_subitem = item;
  264.         } else {
  265.            last_item = item;
  266.         }
  267.         item    = (struct MenuItem *)buffer;
  268.         itext   = (struct IntuiText *)(item + 1);
  269.         buffer += sizeof(struct MenuItem) + sizeof(struct IntuiText);
  270.         /* init intui text */
  271.         itext->LeftEdge  = (flags & MENU_DATA_FLAG_ATTRIBUTE ?
  272.                                 CHECKWIDTH : 0);
  273.         itext->TopEdge   = 1;
  274.         itext->FrontPen  = ml->ml_TextPen1;
  275.         itext->DrawMode  = JAM1;
  276.         itext->ITextFont = ml->ml_TextAttr;
  277.         itext->IText     = (UBYTE *)md->md_Name;
  278.         /* init menu item */
  279.         item->Width         = (strlen(md->md_Name) +
  280.               (md->md_CommandKey ? 2 : 0)) * item_tf->tf_XSize +
  281.                        (md->md_CommandKey ? COMMWIDTH : 0) +
  282.             (flags & MENU_DATA_FLAG_ATTRIBUTE ? CHECKWIDTH : 0);
  283.         item->Height        = item_tf->tf_YSize + 1;
  284.         item->Flags         = ITEMTEXT |
  285.                      (md->md_CommandKey ? COMMSEQ : 0) |
  286.                (flags & MENU_DATA_FLAG_DISABLED ? 0 : ITEMENABLED) |
  287.                   (flags & MENU_DATA_FLAG_HIGH_NONE ? HIGHNONE :
  288.            (flags & MENU_DATA_FLAG_HIGH_BOX ? HIGHBOX : HIGHCOMP)) |
  289.               (flags & MENU_DATA_FLAG_ATTRIBUTE ? CHECKIT : 0) |
  290.                 (flags & MENU_DATA_FLAG_SELECTED ? CHECKED : 0);
  291.         item->MutualExclude = md->md_MutualExclude;
  292.         item->ItemFill      = (APTR)itext;
  293.         item->SelectFill    = (APTR)itext;
  294.         item->Command       = *md->md_CommandKey;
  295.         /* insert empty line before item ? */
  296.         if (flags & MENU_DATA_FLAG_EMPTY_LINE) {
  297.            if (type == MENU_DATA_TYPE_SUBITEM) {
  298.           subitem_ypos += item->Height;
  299.            } else {
  300.           item_ypos += item->Height;
  301.            }
  302.         }
  303.         if (type == MENU_DATA_TYPE_SUBITEM) {
  304.            if (subitem_flag == TRUE) {
  305.           last_subitem->NextItem = item;
  306.            } else {
  307.           if (!last_item) {
  308.              error = TRUE;   /* no menu item to attach subitem */
  309.              break;
  310.           } else {
  311.              last_itext           = (struct IntuiText *)
  312.                             last_item->ItemFill;
  313.              last_itext->FrontPen = ml->ml_TextPen2;
  314.              last_item->SubItem   = item;
  315.              subitem_xpos         = strlen((BYTE *)last_itext->IText)
  316.              * item_tf->tf_XSize + (last_item->Flags & CHECKIT ?
  317.                                 CHECKWIDTH : 0);
  318.              subitem_ypos         = 0;
  319.              subitem_flag         = TRUE;
  320.           }
  321.            }
  322.            item->LeftEdge = subitem_xpos;
  323.            item->TopEdge  = subitem_ypos;
  324.            subitem_ypos  += item->Height;
  325.         } else {
  326.            if (last_item) {
  327.           last_item->NextItem = item;
  328.            }
  329.            item->TopEdge = item_ypos;
  330.            item_ypos    += item->Height;
  331.            if (subitem_flag == TRUE) {
  332.           /* prepare last subitem list */
  333.           equal_select_box_width(last_item->SubItem);
  334.           subitem_flag = FALSE;
  335.            }
  336.         }
  337.         break;
  338.       }
  339.       if (error == FALSE && item) {
  340.      /* prepare current menu and subitem list */
  341.      equal_select_box_width(menu->FirstItem);
  342.      if (subitem_flag == TRUE) {
  343.         equal_select_box_width(last_item->SubItem);
  344.      }
  345.      success = TRUE;
  346.       }
  347.    }
  348.    return(success);
  349. }
  350.     /* Set equal select box width for given menu item list */
  351.  
  352.    STATIC VOID
  353. equal_select_box_width(struct MenuItem  *item)
  354. {
  355.    struct MenuItem  *save_item = item;
  356.    ULONG max_width = 0;
  357.  
  358.    /* search max width */
  359.    do {
  360.       if (item->Width > max_width) {
  361.      max_width = item->Width;
  362.       }
  363.    } while (item = item->NextItem);
  364.    /* set max width */
  365.    item = save_item;
  366.    do {
  367.       item->Width = max_width;
  368.    } while (item = item->NextItem);
  369. }
  370.