home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 199.lha / GimmeLib / menustuff.c < prev    next >
C/C++ Source or Header  |  1988-12-27  |  11KB  |  402 lines

  1. /*
  2.  *  FILE: menustuff.c
  3.  *  Support routines for dealing with menus and menuitems.
  4.  *
  5.  *  NOTE: these routines should only be used on a menustrip that is
  6.  *  not attached to a window or guaranteed not to be actively used by
  7.  *  Intuition (eg. by using the MENUVERIFY flag).
  8.  *
  9.  *  Public Domain, but keep my name in it as the original author.
  10.  *  31-Oct-88    Jan Sven Trabandt   added to gimme.lib
  11.  */
  12.  
  13.  
  14. #define I_AM_MENUSTUFF
  15. #include "gimmelib/gimmefuncs.h"
  16. #include "gimmelib/menustuff.h"
  17.  
  18.  
  19. /* internal flags: must stay within defined GMI_RESERVED bits */
  20. #define GMI_SUBITEM    (1L << 30)      /* process subitem, not item */
  21. #define GMI_DO_TOP    (1L << 29)      /* modify top edge */
  22. #define GMI_DO_ME    (1L << 28)      /* modify mutual exclude */
  23. #define GMI_SNEAKY    (1L << 27)      /* sneaky -- don't modify too much */
  24.  
  25. #define GMI_ADJUST    (GMI_FIXUP | GMI_SHUFFLE)
  26. #define GMI_ADJUSTME    (GMI_FIXUPME | GMI_SHUFFLEME)
  27.  
  28.  
  29. ULONG addMenuItem( menu, item, positem, possub, numitem, myflags )
  30.     struct Menu     *menu;
  31.     struct MenuItem *item;
  32.     SHORT        positem, possub, numitem;
  33.     ULONG        myflags;
  34. {
  35.     register struct MenuItem    *temp, **old;
  36.     struct MenuItem        *save, *savelast;
  37.     SHORT            pos, sub;
  38.     SHORT            top, topedge;
  39.  
  40.     if( !menu || !item || !numitem ) {
  41.     return( MENUNULL );
  42.     }
  43.     if( myflags & GMI_SUBITEM ) {
  44.     old = &((struct MenuItem *)menu)->SubItem;
  45.     } else {
  46.     old = &menu->FirstItem;
  47.     }
  48.  
  49.     if( myflags & GMI_ADDSUBITEM ) {
  50.     if( !*old ) {                   /* if no items, can't put subitem */
  51.         return( MENUNULL );
  52.     }
  53.     } else {
  54.     /* find last item in list to be added and truncate list appropriately */
  55.     for( temp = item; temp->NextItem; temp = temp->NextItem ) {
  56.         if( --numitem == 0 ) {
  57.         temp->NextItem = NULL;
  58.         break;
  59.         }
  60.     } /* for */
  61.     savelast = temp;        /* save pointer to last item to be added */
  62.  
  63.     if( positem == 0 || !*old ) {       /* add as first (sub)item */
  64.         savelast->NextItem = *old;
  65.         *old = item;
  66.         if( *old && (myflags & (GMI_ADJUST|GMI_ADJUSTME|GMI_APPEAREND)) ) {
  67.         pos = 0;
  68.         save = item;
  69.         myflags |= GMI_SNEAKY;        /* careful handling */
  70.         goto calculate_adjustment_mi;
  71.         }
  72.         adjustMenuItems( item, savelast->NextItem, 0, 0, myflags );
  73.         return( SHIFTITEM(0) | SHIFTSUB(NOSUB) );
  74.     }
  75.     }
  76.  
  77.     /* find the item preceding where to insert, and position# for new item */
  78.     pos = 1;
  79.     for( temp = *old; temp->NextItem; temp = temp->NextItem ) {
  80.     if( --positem == 0 ) {
  81.         break;
  82.     }
  83.     ++pos;
  84.     } /* for */
  85.  
  86.     if( myflags & GMI_ADDSUBITEM ) {
  87.     sub = ITEMNUM( addMenuItem(temp, item, possub, 0, numitem,
  88.                 (myflags | GMI_SUBITEM) & ~GMI_ADDSUBITEM) );
  89.     } else {
  90.     savelast->NextItem = temp->NextItem;
  91.     save = temp;            /* save ptr to item after which to add */
  92.     if( myflags & (GMI_ADJUST | GMI_ADJUSTME) ) {
  93. calculate_adjustment_mi: {}
  94.         /* calculate top edge for new item */
  95.         topedge = 0;
  96.         for( temp = *old; temp; temp = temp->NextItem ) {
  97.         top = temp->TopEdge + temp->Height;
  98.         if( temp == save ) {
  99.             if( !(myflags & GMI_SNEAKY) ) {
  100.             save->NextItem = item;
  101.             if( top > topedge ) {
  102.                 topedge = top;
  103.             }
  104.             }
  105.             if( !(myflags & GMI_APPEAREND) ) {
  106.             break;            /* exit for loop */
  107.             }
  108.             temp = savelast;        /* skip over what we added */
  109.         }
  110.         if( top > topedge ) {
  111.             topedge = top;
  112.         }
  113.         } /* for */
  114.         adjustMenuItems( item, savelast->NextItem, topedge, pos, myflags );
  115.     } else {
  116.         save->NextItem = item;
  117.     }
  118.     sub = NOSUB;
  119.     }
  120.  
  121.     return( SHIFTITEM(pos) | SHIFTSUB(sub) );
  122. } /* addMenuItem */
  123.  
  124.  
  125. ULONG addMenu( menuptr, menu, posmenu, nummenu, myflags )
  126.     struct Menu     **menuptr;
  127.     struct Menu     *menu;
  128.     SHORT        posmenu, nummenu;
  129.     ULONG        myflags;
  130. {
  131.     register struct Menu    *temp, **old;
  132.     struct Menu         *save, *savelast;
  133.     SHORT            pos;
  134.     SHORT            left, leftedge;
  135.  
  136.     if( !nummenu || !menuptr || !menu ) {
  137.     return( MENUNULL );
  138.     }
  139.     old = menuptr;
  140.  
  141.     /* find last menu in list to be added and truncate list appropriately */
  142.     for( temp = menu; temp->NextMenu; temp = temp->NextMenu ) {
  143.     if( --nummenu == 0 ) {
  144.         temp->NextMenu = NULL;
  145.         break;
  146.     }
  147.     } /* for */
  148.     savelast = temp;        /* save pointer to last menu to be added */
  149.  
  150.     if( posmenu == 0 || !*old ) {       /* add to front of menu strip */
  151.     savelast->NextMenu = *old;
  152.     *old = menu;
  153.     if( *old && (myflags & (GMI_ADJUST | GMI_APPEAREND)) ) {
  154.         pos = 0;
  155.         save = menu;
  156.         myflags |= GMI_SNEAKY;        /* careful handling */
  157.         goto calculate_adjustment_m;
  158.     }
  159.     adjustMenuLefts( menu, savelast->NextMenu, 0, myflags );
  160.     return( SHIFTMENU(0) | SHIFTITEM(NOITEM) | SHIFTSUB(NOSUB) );
  161.     }
  162.  
  163.     /* find the menu preceding where to insert, and position# for new menu */
  164.     pos = 1;
  165.     for( temp = *old; temp->NextMenu; temp = temp->NextMenu ) {
  166.     if( --posmenu == 0 ) {
  167.         break;
  168.     }
  169.     ++pos;
  170.     } /* for */
  171.  
  172.     savelast->NextMenu = temp->NextMenu;
  173.     save = temp;        /* save ptr to menu after which to add */
  174.     if( myflags & (GMI_ADJUST | GMI_ADJUSTME) ) {
  175. calculate_adjustment_m: {}
  176.     /* calculate left edge for new menu */
  177.     leftedge = 0;
  178.     for( temp = *old; temp; temp = temp->NextMenu ) {
  179.         left = temp->LeftEdge + temp->Width;
  180.         if( temp == save ) {
  181.         if( !(myflags & GMI_SNEAKY) ) {
  182.             save->NextMenu = menu;
  183.             if( left > leftedge ) {
  184.             leftedge = left;
  185.             }
  186.         }
  187.         if( !(myflags & GMI_APPEAREND) ) {
  188.             break;            /* exit for loop */
  189.         }
  190.         temp = savelast;    /* skip over what we added */
  191.         }
  192.         if( left > leftedge ) {
  193.         leftedge = left;
  194.         }
  195.     } /* for */
  196.     adjustMenuLefts( menu, savelast->NextMenu, leftedge, myflags );
  197.     } else {
  198.     save->NextMenu = menu;
  199.     }
  200.  
  201.     return( SHIFTMENU(pos) | SHIFTITEM(NOITEM) | SHIFTSUB(NOSUB) );
  202. } /* addMenu */
  203.  
  204.  
  205. struct MenuItem *removeMenuItem( menu, item, positem, possub, numitem, myflags )
  206.     struct Menu     *menu;
  207.     struct MenuItem *item;
  208.     SHORT        positem, possub, numitem;
  209.     ULONG        myflags;
  210. {
  211.     register struct MenuItem    *temp, **old;
  212.     struct MenuItem        *save;
  213.     SHORT            pos;        /* position for mutual exclude */
  214.  
  215.     if( !menu ) {
  216.     return( NULL );
  217.     }
  218.     if( myflags & GMI_SUBITEM ) {
  219.     old = &((struct MenuItem *)menu)->SubItem;
  220.     } else {
  221.     old = &menu->FirstItem;
  222.     }
  223.     if( !*old || !numitem ) {           /* if no menu items */
  224.     return( NULL );
  225.     }
  226.     if( myflags & GMI_REMSUBITEM ) {
  227.     save = item;            /* don't want to check item address yet */
  228.     item = NULL;
  229.     } else {
  230.     if( item ) {
  231.         positem = -1;
  232.     }
  233.     }
  234.     pos = 0;
  235.     temp = *old;
  236.     if( temp != item && positem != 0 && temp->NextItem ) {
  237.     /* find the "item" preceding where to remove */
  238.     for( ; temp->NextItem && --positem != 0; ) {
  239.         ++pos;
  240.         if( temp->NextItem == item ) {      /* found the item */
  241.         break;
  242.         }
  243.         temp = temp->NextItem;        /* next in loop */
  244.         if( !temp->NextItem ) {         /* no more to follow so stop */
  245.         break;
  246.         }
  247.     } /* for */
  248.     old = &temp->NextItem;
  249.     }
  250.     /* now old points to a MenuItem pointer to item to be removed */
  251.     if( item && *old != item ) {            /* if its not the right item */
  252.     return( NULL );
  253.     }
  254.  
  255.     if( myflags & GMI_REMSUBITEM ) {
  256.     item = removeMenuItem( temp, save, possub, 0, numitem,
  257.                 (myflags | GMI_SUBITEM) & ~GMI_REMSUBITEM );
  258.     } else {
  259.     if( !item ) {
  260.         item = *old;
  261.     }
  262.     if( myflags & GMI_ADDRONLY ) {
  263.         return( item );
  264.     }
  265.     /* find last one to be removed */
  266.     for( temp = item; temp->NextItem; temp = temp->NextItem ) {
  267.         if( --numitem == 0 ) {
  268.         break;
  269.         }
  270.     } /* for */
  271.     *old = temp->NextItem;
  272.     temp->NextItem = NULL;
  273.     myflags &= ~(GMI_FIXUP | GMI_FIXUPME);
  274.     if( myflags & GMI_SHUFFLE ) {
  275.         myflags |= GMI_FIXUP;
  276.     }
  277.     if( myflags & GMI_SHUFFLEME ) {
  278.         myflags |= GMI_FIXUPME;
  279.     }
  280.     adjustMenuItems( *old, NULL, item->TopEdge, pos, myflags );
  281.     }
  282.  
  283.     return( item );
  284. } /* removeMenuItem */
  285.  
  286.  
  287. struct Menu *removeMenu( menuptr, menu, posmenu, nummenu, myflags )
  288.     struct Menu     **menuptr;
  289.     struct Menu     *menu;
  290.     SHORT        posmenu, nummenu;
  291.     ULONG        myflags;
  292. {
  293.     register struct Menu    *temp, **old;
  294.  
  295.     if( !nummenu || !menuptr || !*menuptr ) {
  296.     return( NULL );
  297.     }
  298.     old = menuptr;
  299.     if( menu ) {
  300.     posmenu = -1;
  301.     }
  302.     temp = *old;
  303.     if( temp != menu && posmenu != 0 && temp->NextMenu ) {
  304.     /* find the menu preceding where to remove */
  305.     for( ; temp->NextMenu && --posmenu != 0; ) {
  306.         if( temp->NextMenu == menu ) {      /* found the menu */
  307.         break;
  308.         }
  309.         temp = temp->NextMenu;        /* next in loop */
  310.         if( !temp->NextMenu ) {         /* no more to follow so stop */
  311.         break;
  312.         }
  313.     } /* for */
  314.     old = &temp->NextMenu;
  315.     }
  316.     /* now old points to a Menu pointer to menu to be removed */
  317.     if( menu && *old != menu ) {            /* if its not the right menu */
  318.     return( NULL );
  319.     }
  320.  
  321.     if( !menu ) {
  322.     menu = *old;
  323.     }
  324.     if( myflags & GMI_ADDRONLY ) {
  325.     return( menu );
  326.     }
  327.     /* find last one to be removed */
  328.     for( temp = menu; temp->NextMenu; temp = temp->NextMenu ) {
  329.     if( --nummenu == 0 ) {
  330.         break;
  331.     }
  332.     } /* for */
  333.     *old = temp->NextMenu;
  334.     temp->NextMenu = NULL;
  335.     adjustMenuLefts( *old, NULL, menu->LeftEdge, myflags );
  336.  
  337.     return( menu );
  338. } /* removeMenu */
  339.  
  340.  
  341. short adjustMenuItems( item, stop, topedge, meposition, myflags )
  342.     struct MenuItem *item, *stop;
  343.     SHORT        topedge, meposition;
  344.     register ULONG  myflags;
  345. {
  346.     register struct MenuItem    *temp;
  347.  
  348.     if( !(myflags & (GMI_ADJUST | GMI_ADJUSTME)) ) {
  349.     return( -1 );
  350.     }
  351.     if( myflags & GMI_FIXUP ) {
  352.     myflags |= GMI_DO_TOP;
  353.     }
  354.     if( myflags & GMI_FIXUPME ) {
  355.     myflags |= GMI_DO_ME;
  356.     }
  357.     for( temp = item; temp; temp = temp->NextItem ) {
  358.     if( temp == stop ) {
  359.         if( !(myflags & (GMI_SHUFFLE | GMI_SHUFFLEME)) ) {
  360.         break;
  361.         }
  362.         myflags &= ~(GMI_DO_TOP | GMI_DO_ME);
  363.         if( (myflags & GMI_SHUFFLE) && !(myflags & GMI_APPEAREND) ) {
  364.         myflags |= GMI_DO_TOP;
  365.         }
  366.         if( myflags & GMI_SHUFFLEME ) {
  367.         myflags |= GMI_DO_ME;
  368.         }
  369.     }
  370.     if( myflags & GMI_DO_TOP ) {
  371.         temp->TopEdge = topedge;
  372.     }
  373.     topedge += temp->Height;
  374.     if( myflags & GMI_DO_ME ) {
  375.         temp->MutualExclude = ~(1L << meposition);
  376.     }
  377.     ++meposition;
  378.     } /* for */
  379.     return( 0 );
  380. } /* adjustMenuItems */
  381.  
  382.  
  383. short adjustMenuLefts( menu, stop, leftedge, myflags )
  384.     struct Menu     *menu, *stop;
  385.     register SHORT  leftedge;
  386.     ULONG        myflags;
  387. {
  388.     register struct Menu    *temp;
  389.  
  390.     if( !(myflags & (GMI_ADJUST)) ) {
  391.     return( -1 );
  392.     }
  393.     for( temp = menu; temp; temp = temp->NextMenu ) {
  394.     if( !(myflags & GMI_SHUFFLE) && temp == stop ) {
  395.         break;
  396.     }
  397.     temp->LeftEdge = leftedge;
  398.     leftedge += temp->Width;
  399.     } /* for */
  400.     return( 0 );
  401. } /* adjustMenuLefts */
  402.