home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ucmenu.zip / UCMENUS.PAK / SAMPLES / SAMP3 / SAMP3.C < prev    next >
Text File  |  1995-08-02  |  55KB  |  968 lines

  1. /************************************************************************/
  2. /* Program name: SAMP3.C                                                */
  3. /*                                                                      */
  4. /* OS/2 Developer Magazine, Issue:  Jan '95                             */
  5. /* Author:  Mark McMillan, IBM Corp.                                    */
  6. /*                                                                      */
  7. /* Description: UCMenu sample #3                                        */
  8. /*                                                                      */
  9. /* Program Requirements:  OS/2 2.x                                      */
  10. /*                        IBM C Set/2 (or other OS/2 compiler)          */
  11. /*                        OS/2 Toolkit                                  */
  12. /*                                                                      */
  13. /* Copyright (c)International Business Machines Corp. 1994              */
  14. /*                                                                      */
  15. /************************************************************************/
  16.  
  17. /************************************************************************/
  18. /************************************************************************/
  19. /*                      DISCLAIMER OF WARRANTIES.                       */
  20. /************************************************************************/
  21. /************************************************************************/
  22. /*     The following [enclosed] code is source code created by the      */
  23. /*     author(s).  This source code is provided to you solely           */
  24. /*     for the purpose of assisting you in the development of your      */
  25. /*     applications.  The code is provided "AS IS", without             */
  26. /*     warranty of any kind.  The author(s) shall not be liable         */
  27. /*     for any damages arising out of your use of the source code,      */
  28. /*     even if they have been advised of the possibility of such        */
  29. /*     damages.  It is provided purely for instructional and            */
  30. /*     illustrative purposes.                                           */
  31. /************************************************************************/
  32. /************************************************************************/
  33.  
  34. /*************************************************************************
  35.    Notes for sample #3:
  36.  
  37.    This sample is identical to #2 except that it uses a different 
  38.    method of toolbar customization.  This sample uses the UCMenu API
  39.    UCMenuResourceBuffetDlg() which was not described in the OS/2
  40.    Developers artical.  This API provides a simplified method of 
  41.    toolbar customization whereby the user just drag/drops menu items
  42.    from a "buffet" menu.  The advantage of this method over that used
  43.    in sample #2 is that the user does not have to associate application
  44.    "actions" with bitmaps.  The application pre-defines all possible
  45.    actions and bitmaps and the user just chooses which to place on the
  46.    toolbar.  There is some loss of flexibility (for example, the user
  47.    cannot use their own bitmaps on the toolbar, only those supplied
  48.    by the application).  Howerver, the user interface is much
  49.    simpler and easier to use.
  50.  
  51.    Unless there is a specific need in the application to allow the
  52.    user to specify artibrary action strings and make arbitrary
  53.    associations between actions and bitmaps, this method is
  54.    recomended for toolbar customization.
  55.  
  56.    Too keep this sample shorter, the code for the color menu has been
  57.    removed.  Aside from that, the only code change from sample #2 is:
  58.  
  59.    1. The "Edit" and "Create" items supplied by UCMenus are removed
  60.       from the toolbar context menu via the style flags.
  61.  
  62.    2. New (application-defined) context menu items are added for
  63.       modifying the toolbar and editing the text under a bitmap.
  64.  
  65.    3. When the "Modify toolbar" context item is selected, the application
  66.       calls the UCMenuResourceBuffetDlg() API.  The API takes care of
  67.       updating the toolbar with any changes the user makes.
  68.  
  69.    4. When the "Edit text" context item is selected, the application
  70.       displays a small dialog to allow the user to edit the text
  71.       associated with a toolbar item.
  72.  
  73.    5. Another toolbar menu is defined in the resource file,
  74.       ID_BUFFETBAR.  This toolbar menu defines all the available
  75.       items for the toolbar and is used by the UCMenuResourceBuffetDlg()
  76.       API.
  77.  
  78.    6. We no longer need to respond to the WM_CONTROL notification
  79.       message UCN_QRYRESBMP which is generated by the default
  80.       UCMenu customization notebook.
  81.  
  82. ***************************************************************************/
  83.  
  84. #define  INCL_BASE
  85. #define  INCL_WIN
  86. #define  INCL_DOS
  87. #define  INCL_WINSTDSPIN
  88.  
  89. #include <os2.h>
  90. #include <string.h>
  91. #include <stdio.h>
  92. #include <stdlib.h>
  93. #include <stdarg.h> 
  94.  
  95. #include "DIALOG.H"
  96. #include "samp3.h"
  97. #include "UCMenus.h"     /* UCMenu prototypes and definitions           */
  98. #include "UCMUtils.h"    /* Utility function prototypes and definitions */
  99.  
  100. /* Global Data */
  101. HAB      Hab;                   /* PM anchor block */
  102.  
  103. /* Structure to easily save/restore menu information in INI file */
  104. typedef struct {
  105.                  ULONG CmdStyle;      /* Command menu style bits */
  106.                  ULONG CmdCx;         /* Forced size (x) */
  107.                  ULONG CmdCy;         /* Forced size (y) */
  108.                  ULONG CmdBgColor;    /* Toolbar background */
  109.                  ULONG CmdItemBgColor;/* Item background */
  110.                  char  CmdFont[32];   /* Font name */
  111.                  ULONG CmdSize;       /* Size of menu template */
  112.                  ULONG CmdBblDelay;   /* Bubble delay time */
  113.                  ULONG CmdBblRead;    /* Bubble read  time */
  114.                } IniDataStruct;
  115.  
  116. /* Structure to describe each menu item supported by this application.  Some of */
  117. /* the data here (e.g. action strings) are duplicated in the .RC file.  Only    */
  118. /* selectable items are listed here (e.g. not submenu placeholders).            */
  119.  
  120. typedef struct {
  121.                  USHORT CommandID;   /* Unique ID for each menu item */
  122.                  BOOL   Checkable;   /* Is this item checkable */
  123.                  USHORT CheckStatus; /* Zero (not checked) or MIA_CHECKED */
  124.                  PSZ    Action;      /* Unique 'action' string */
  125.                  PSZ    Desc;        /* Description for this item (used in status bar and customization dlgs) */
  126.                } AppItemStruct;
  127.  
  128. /* Create static table of all supported menu items.  End of list indicated by ID=0.*/
  129. /* We use this list to map action string to IDs when the user selects an action    */
  130. /* on a UC menu.  It is also used to track the check status of checkable items (we */
  131. /* cannot depend on the menu to keep track since the item can be deleted from the  */
  132. /* menu by the user).                                                              */
  133.  
  134. AppItemStruct ItemList[] = {
  135.    /* Item ID              Checkable?  CheckStatus  UCMenu Action String    Description                                 */
  136.    /*--------------------  ----------  -----------  ----------------------  --------------------------------------------*/
  137.    {ID_ACTION_NEW        ,   FALSE,       0,        "Cmd: New"             ,"Start new drawing and discard current file." },
  138.    {ID_ACTION_OPEN       ,   FALSE,       0,        "Cmd: Open"            ,"Open existing drawing file."                 },
  139.    {ID_ACTION_SAVE       ,   FALSE,       0,        "Cmd: Save"            ,"Save drawing to a file."                     },
  140.    {ID_ACTION_CLOSE      ,   FALSE,       0,        "Cmd: Close"           ,"Exit application."                           },
  141.    {ID_ACTION_COPY       ,   FALSE,       0,        "Cmd: Copy"            ,"Copy selected objects to clipboard."         },
  142.    {ID_ACTION_CUT        ,   FALSE,       0,        "Cmd: Cut"             ,"Move selected objects to clipboard."         },
  143.    {ID_ACTION_PASTE      ,   FALSE,       0,        "Cmd: Paste"           ,"Paste objects from clipboard."               },
  144.    {ID_ACTION_UNDO       ,   FALSE,       0,        "Cmd: Undo"            ,"Undo last 'Paste' command."                  },
  145.    {ID_ACTION_LINK       ,   FALSE,       0,        "Cmd: Link"            ,"Link object from another application."       },
  146.    {ID_ACTION_SELECTALL  ,   FALSE,       0,        "Cmd: Select All"      ,"Select all objects in current drawing."      },
  147.    {ID_ACTION_DESELECTALL,   FALSE,       0,        "Cmd: Deselect All"    ,"Unselect all selected objects."              },
  148.    {ID_ACTION_ZOOMIN     ,   FALSE,       0,        "Cmd: Zoom In"         ,"Zoom in around current cursor position."     },
  149.    {ID_ACTION_ZOOMOUT    ,   FALSE,       0,        "Cmd: Zoom Out"        ,"Zoom out from current cursor position."      },
  150.    {ID_ACTION_STYLES     ,   FALSE,       0,        "Styles Submenu"       ,"Style Options (submenu)."                    },
  151.    {ID_ACTION_BOLD       ,   TRUE,        0,        "Style: Bold"          ,"Make text bold."                             },
  152.    {ID_ACTION_ITALIC     ,   TRUE,        0,        "Style: Italic"        ,"Make text italic."                           },
  153.    {ID_ACTION_UNDERLINE  ,   TRUE,        0,        "Style: Underline"     ,"Make text underlined."                       },
  154.    {ID_ACTION_TOOLSLCT   ,   FALSE,       0,        "Tool: Selection"      ,"Tool to select existing objects."            },
  155.    {ID_ACTION_TOOLDRAW   ,   FALSE,       0,        "Tool: Draw"           ,"Freehand drawing tool."                      },
  156.    {ID_ACTION_TOOLBRSH   ,   FALSE,       0,        "Tool: Brush"          ,"Freehand drawing with wide line."            },
  157.    {ID_ACTION_TOOLERAS   ,   FALSE,       0,        "Tool: Eraser"         ,"Erase portions of objects, freehand."        },
  158.    {ID_ACTION_TOOLSPRY   ,   FALSE,       0,        "Tool: Spraycan"       ,"Spray large areas of drawing, freehand."     },
  159.    {ID_ACTION_TOOLFILL   ,   FALSE,       0,        "Tool: Fill"           ,"Fill an object with color or patterns."      },
  160.    {ID_ACTION_TOOLLINE   ,   FALSE,       0,        "Tool: Line"           ,"Draw a straight lines."                      },
  161.    {ID_ACTION_TOOLARC    ,   FALSE,       0,        "Tool: Arc"            ,"Draw arcs."                                  },
  162.    {ID_ACTION_TOOLRECT   ,   FALSE,       0,        "Tool: Rectangle"      ,"Draw rectangles."                            },
  163.    {ID_ACTION_TOOLCIRC   ,   FALSE,       0,        "Tool: Circle"         ,"Draw circles and ovals."                     },
  164.    {ID_ACTION_TOOLTEXT   ,   FALSE,       0,        "Tool: Text"           ,"Place text on the drawing."                  },
  165.    {ID_ACTION_TOOLLSEG   ,   FALSE,       0,        "Tool: Segmented Line" ,"Draw multiple straight-line segments."       },
  166.    {ID_ACTION_TOOLCURV   ,   FALSE,       0,        "Tool: Curve"          ,"Draw arbitrary curves."                      },
  167.    {ID_ACTION_TOOLSHP    ,   FALSE,       0,        "Tool: Shape"          ,"Draw closed shapes with straigt lines."      },
  168.    {ID_ACTION_PALETTE    ,   FALSE,       0,        "Color Palette"        ,"Alter currently selected color."             },
  169.    {ID_ACTION_BLACK      ,   TRUE,        0,        "Color: Black"         ,"Select this color for drawing and filling."  },
  170.    {ID_ACTION_DGRAY      ,   TRUE,        0,        "Color: Dark gray"     ,"Select this color for drawing and filling."  },
  171.    {ID_ACTION_PGRAY      ,   TRUE,        0,        "Color: Pale gray"     ,"Select this color for drawing and filling."  },
  172.    {ID_ACTION_PPINK      ,   TRUE,        0,        "Color: Pale pink"     ,"Select this color for drawing and filling."  },
  173.    {ID_ACTION_DBLUE      ,   TRUE,        0,        "Color: Dark blue"     ,"Select this color for drawing and filling."  },
  174.    {ID_ACTION_BLUE       ,   TRUE,        0,        "Color: Blue"          ,"Select this color for drawing and filling."  },
  175.    {ID_ACTION_MBLUE      ,   TRUE,        0,        "Color: Medium blue"   ,"Select this color for drawing and filling."  },
  176.    {ID_ACTION_DCYAN      ,   TRUE,        0,        "Color: Dark cyan"     ,"Select this color for drawing and filling."  },
  177.    {ID_ACTION_CYAN       ,   TRUE,        0,        "Color: Cyan"          ,"Select this color for drawing and filling."  },
  178.    {ID_ACTION_DGREEN     ,   TRUE,        0,        "Color: Dark green"    ,"Select this color for drawing and filling."  },
  179.    {ID_ACTION_MGREEN     ,   TRUE,        0,        "Color: Medium green"  ,"Select this color for drawing and filling."  },
  180.    {ID_ACTION_GREEN      ,   TRUE,        0,        "Color: Green"         ,"Select this color for drawing and filling."  },
  181.    {ID_ACTION_DRED       ,   TRUE,        0,        "Color: Dark red"      ,"Select this color for drawing and filling."  },
  182.    {ID_ACTION_MRED       ,   TRUE,        0,        "Color: Medium red"    ,"Select this color for drawing and filling."  },
  183.    {ID_ACTION_RED        ,   TRUE,        0,        "Color: Red"           ,"Select this color for drawing and filling."  },
  184.    {ID_ACTION_ORANGE     ,   TRUE,        0,        "Color: Orange"        ,"Select this color for drawing and filling."  },
  185.    {ID_ACTION_DPINK      ,   TRUE,        0,        "Color: Dark pink"     ,"Select this color for drawing and filling."  },
  186.    {ID_ACTION_PINK       ,   TRUE,        0,        "Color: Pink"          ,"Select this color for drawing and filling."  },
  187.    {ID_ACTION_BROWN      ,   TRUE,        0,        "Color: Brown"         ,"Select this color for drawing and filling."  },
  188.    {ID_ACTION_YELLOW     ,   TRUE,        0,        "Color: Yellow"        ,"Select this color for drawing and filling."  },
  189.    {ID_ACTION_WHITE      ,   TRUE,        0,        "Color: White"         ,"Select this color for drawing and filling."  },
  190.    {ID_ACTION_FONTS      ,   FALSE,       0,        "Cmd: Fonts"           ,"Select font for text tool."                  },
  191.    {ID_ACTION_GRID       ,   FALSE,       0,        "Cmd: Grid"            ,"Place grid over drawing area."               },
  192.    {ID_ACTION_RULER      ,   FALSE,       0,        "Cmd: Ruler"           ,"Place ruler over drawing area."              },
  193.    {ID_ACTION_MAG        ,   FALSE,       0,        "Cmd: Magnify"         ,"Magnify area immediatly around cursor."      },
  194.    {ID_ACTION_DISKA      ,   FALSE,       0,        "Cmd: Disk A"          ,"Select disk A."                              },
  195.    {ID_ACTION_DISKB      ,   FALSE,       0,        "Cmd: Disk B"          ,"Select disk B."                              },
  196.    {ID_ACTION_DISKC      ,   FALSE,       0,        "Cmd: Disk C"          ,"Select disk C."                              },
  197.    {ID_ACTION_DISKD      ,   FALSE,       0,        "Cmd: Disk D"          ,"Select disk D."                              },
  198.    {ID_ACTION_HELP       ,   FALSE,       0,        "Cmd: Help"            ,"Show help."                                  },
  199.    {ID_ACTION_VIEWCMD    ,    TRUE,   MIA_CHECKED,  "Show/Hide Command Bar","Toggle top command toolbar on/off."          },
  200.    {ID_ACTION_VIEWCOLOR  ,    TRUE,   MIA_CHECKED,  "Show/Hide Color Bar"  ,"Toggle bottom color toolbar on/off."         },
  201.    {0, FALSE, 0, "", ""}}; /* End of list */
  202.  
  203. CMITEMS CMItem[3] = {{ID_DEFAULTSTYLE, "Reset Style"}, /* Our own context menu items */
  204.                      {ID_MODIFYTOOLBAR,"Modify Toolbar..."},
  205.                      {ID_MODIFYTEXT,   "Edit text..."}};
  206.  
  207. static HWND CommandBar;                /* UC menu window handles */
  208. static HWND TextBar;                   /* Std PM text menu bar   */
  209. static HWND ContextMenu;               /* Toolbar context menu   */
  210. static USHORT DynamIndex;              /* Dynamic info line data */
  211. static int  ColorIndex;                /* Index of curr color    */
  212.  
  213. SWCNTRL Tasklist = {NULLHANDLE, NULLHANDLE, NULLHANDLE, 0, 0,
  214.                     SWL_VISIBLE, SWL_JUMPABLE, "UCMenus Sample"};
  215.  
  216. #define BASIC_STYLES   UCS_CHNGBMPBG |         /* Alter bitmap bkgnd colors to match toolbar */\
  217.                        UCS_PROMPTING |         /* Tell me about mouse movements */             \
  218.                        UCS_NODEFAULTACTION|    /* I will supply all action strings */          \
  219.                        UCS_NO_CM_MENU_IMPORT | /* No 'import' option on context menu */        \
  220.                        UCS_NO_CM_MENU_EXPORT | /* No 'export' option on context menu */        \
  221.                        UCS_NO_CM_ITEM_EDIT   | /* No edit */                                   \
  222.                        UCS_NO_CM_ITEM_CREATE | /* No create */                                 \
  223.                        UCS_CUSTOMHLP           /* We will provide all help */
  224.  
  225. #define MSG_PROCESS_COMMAND (WM_USER+1)  /* Internally used message */
  226. #define APP_NAME "UCMSamp"               /* App key in INI file */
  227. #define INI_NAME "UCMSAMP.INI"           /* INI file name */
  228.  
  229. #define STRSAME(str1,str2) (!strcmpi(str1,str2))
  230. /* Extract a UC menu data item from basic PM menu item structure */
  231. #define UCMITEMDATA(UCitem, UCdata) (((UCMITEM *)(UCitem.hItem))->UCdata)
  232.  
  233. /* Prototypes */
  234. MRESULT EXPENTRY MAINDLG_Proc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  235. MRESULT ProcessUCMenuControlMsg(HWND hwnd, MPARAM mp1, MPARAM mp2);
  236. int FindActionInItemList(PSZ Action);
  237.  
  238. /* General Dialog Helper Macros */
  239. #define MSGBOX(Owner,Title,Msg)  WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OK|MB_INFORMATION)
  240. #define ERRBOX(Owner,Title,Msg)  WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OK|MB_ERROR)
  241. #define WARNBOX(Owner,Title,Msg) WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OKCANCEL|MB_WARNING)
  242. #define SETTEXT(ID,Buff)         WinSetWindowText(WinWindowFromID(hwnd,ID),Buff)
  243. #define QUERYTEXT(ID,Buff,Size) WinQueryWindowText(WinWindowFromID(hwnd,ID),Size,Buff)
  244. #define QUERYTEXTLEN(ID)        WinQueryWindowTextLength(WinWindowFromID(hwnd,ID))
  245.  
  246. /*----------------------------------------------------------------------------*/
  247. MRESULT EXPENTRY MAINDLG_Proc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  248. /*----------------------------------------------------------------------------*/
  249. /*                                                                            */
  250. /*----------------------------------------------------------------------------*/
  251. {
  252. static  HPOINTER DlgIcon;   /* Dialog icon */
  253.  
  254. /* Dynamic dialog data */
  255. UCMINFO UCMInit;            /* Graphic toolbar setup data */
  256. HWND    DummyHwnd;          /* Dummy menu window (unused) */
  257. SWP     MySize;             /* Size of this dialog        */
  258. char    Msg[150];
  259. int     i;
  260.  
  261. VOID   *CmdTemplate;                      /* UC menu templates for INI save/restore */
  262. IniDataStruct IniData;                    /* Data to save/restore in INI file */
  263. HINI   IniHandle;                         /* Handle of INI file */
  264. ULONG  ULValue;                           /* Other INI ULONG values saved/restored */
  265. BOOL   ProfileFound;                      /* Existing INI file */
  266.  
  267.   switch (msg) {
  268.  
  269.     case WM_INITDLG:
  270.       /* Because our main window is a dialog, there are some things we */
  271.       /* have to do manually: load the PM text menu bar, set an icon   */
  272.       /* for the minimized state, and put ourselves in the task list.  */
  273.  
  274.       /* Load and position standard PM text menu bar */
  275.       /* and grow dialog window to fit it in.        */
  276.       WinQueryWindowPos(hwnd, &MySize);
  277.       WinSetWindowPos(hwnd, HWND_TOP, 0,0,
  278.                       MySize.cx, MySize.cy+WinQuerySysValue(HWND_DESKTOP,SV_CYMENU),
  279.                       SWP_SIZE);
  280.       TextBar = WinLoadMenu(hwnd, NULLHANDLE, ID_FRAME_RESOURCE);
  281.       WinSendMsg(hwnd, WM_UPDATEFRAME, MPFROMLONG(FCF_MENU), 0L);
  282.  
  283.       ContextMenu = WinLoadMenu(HWND_OBJECT, NULLHANDLE, ID_CONTEXT);
  284.  
  285.       /* Load icon and make it the default dialog icon */
  286.       DlgIcon = WinLoadPointer (HWND_DESKTOP, NULLHANDLE, ID_FRAME_RESOURCE);
  287.       WinDefDlgProc (hwnd, WM_SETICON, (MPARAM)DlgIcon, (MPARAM)0);
  288.  
  289.       /* Put myself in the task list */
  290.       Tasklist.hwnd = hwnd;
  291.       WinAddSwitchEntry(&Tasklist);
  292.  
  293.       /* If we have saved a previous UC menu configuration in the .INI  */
  294.       /* file, restore its contents and style information.              */
  295.       
  296.       ProfileFound = FALSE;
  297.       IniHandle = PrfOpenProfile(Hab, INI_NAME);
  298.       if (IniHandle != NULLHANDLE) {
  299.         /* If one value is here, they all should be */
  300.         ULValue = sizeof(IniDataStruct);
  301.         if (PrfQueryProfileData(IniHandle, APP_NAME, "IniData", &IniData, &ULValue)) {
  302.           CmdTemplate = malloc(IniData.CmdSize);
  303.           PrfQueryProfileData(IniHandle, APP_NAME, "CmdTemplate", CmdTemplate, &(IniData.CmdSize));
  304.           ProfileFound = TRUE;
  305.         }
  306.         PrfCloseProfile(IniHandle);
  307.       }
  308.  
  309.       /* NOTE: To really do this well, the loading of the toolbar menus */
  310.       /* should really be done with another thread to keep from tying   */
  311.       /* up PM while all the bitmaps and resources are loaded.          */
  312.  
  313.       /* First, set all the basic values into the UCMINFO structure */
  314.     
  315.       memset(&UCMInit, 0x00, sizeof(UCMINFO));    /* Setup initialization data */
  316.       UCMInit.cb = sizeof(UCMINFO);
  317.       UCMInit.hModule = NULLHANDLE;         /* All resources are bound to EXE */
  318.       UCMInit.BgBmp   = 0x00CCCCCC;         /* Light grey is bkgnd color in bitmaps */
  319.       UCMInit.BgColor = 0x00B0B0B0;         /* Darker grey is toolbar background */
  320.       UCMInit.ItemBgColor = WinQuerySysColor(HWND_DESKTOP,SYSCLR_MENU,0L); /* Items are menu color */
  321.       UCMInit.BubbleDelay = 1000L;          /* 1 second startup delay */
  322.       UCMInit.BubbleRead  = 3000L;          /* 1 second read time */
  323.  
  324.       /* If we loaded a previously saved set of UC menus from the INI file, */
  325.       /* use them to create the menus.  Otherwise, use the starter set of   */
  326.       /* menus in the resource file which is bound to this .EXE.            */
  327.  
  328.       if (ProfileFound) { /*------- Create menus from existing templates --------*/
  329.         /* Command menu */
  330.         UCMInit.Style = IniData.CmdStyle;   /* Restore menu style */
  331.         UCMInit.cx    = IniData.CmdCx;      /* Restore forced size (if any) */
  332.         UCMInit.cy    = IniData.CmdCy;      /* Restore forced size (if any) */
  333.         UCMInit.BgColor         = IniData.CmdBgColor;      /* Restore color */
  334.         UCMInit.ItemBgColor     = IniData.CmdItemBgColor;  /* Restore color */ 
  335.         UCMInit.pszFontNameSize = IniData.CmdFont;         /* Restore font  */
  336.         UCMInit.BubbleDelay     = IniData.CmdBblDelay;
  337.         UCMInit.BubbleRead      = IniData.CmdBblRead;
  338.         CommandBar = UCMenuCreateFromTemplate(Hab,
  339.                     hwnd,                   /* Dialog (frame) is parent */
  340.                     hwnd,                   /* Dialog is also owner to get msgs */
  341.                     CMS_HORZ,               /* Horizontal orientation */
  342.                     0,0,0,0,                /* Size/position will be done by frame */
  343.                     HWND_TOP,               /* Put on top of siblings */
  344.                     ID_COMMANDBAR,          /* ID new menu will have */
  345.                     CmdTemplate,            /* Ptr to incore template */
  346.                     &UCMInit,               /* Initialization data structure */
  347.                     &DummyHwnd);            /* Returned text menu handle (not used) */
  348.         free(CmdTemplate);
  349.       }
  350.       else { /*------- Create menus from resource file templates --------*/
  351.         /* Command menu */
  352.         UCMInit.Style   = UCS_FRAMED |        /* Use 3D effects */
  353.                           BASIC_STYLES;       /* Plus my other basic styles */
  354.         CommandBar = UCMenuCreateFromResource(Hab,
  355.                       hwnd,                   /* Dialog (frame) is parent */
  356.                       hwnd,                   /* Dialog is also owner to get msgs */
  357.                       CMS_HORZ,               /* Horizontal orientation */
  358.                       0,0,0,0,                /* Size/position will be done by frame */
  359.                       HWND_TOP,               /* Put on top of siblings */
  360.                       ID_COMMANDBAR,          /* ID new menu will have */
  361.                       NULLHANDLE,             /* Resources come from EXE */
  362.                       ID_COMMANDBAR,          /* ID of menu template in resource file */
  363.                       &UCMInit,               /* Initialization data structure */
  364.                       &DummyHwnd);            /* Returned text menu handle (not used) */
  365.       } /* if profile found */
  366.  
  367.       /* Add my own option to the UCMenu context menus.                  */
  368.       WinSendMsg(CommandBar, UCMENU_ADDITEMSTOCM, MPFROMLONG(3L), MPFROMP(&CMItem));
  369.    // WinSendMsg(CommandBar, UCMENU_SETBUBBLEDELAY, MPFROMLONG(100L), 0L);
  370.     
  371.       /* Now make them frame controls so we will not have to worry about */
  372.       /* size or position of the menus as the window is sized.  The      */
  373.       /* UCMUtils() will also take care of moving the dialog controls.   */
  374.  
  375.       UCMUtilsAddToFrame(hwnd, CommandBar, UCMUTILS_PLACE_TOP);
  376.  
  377.       WinSendMsg(TextBar, MM_SETITEMATTR, MPFROM2SHORT(ID_ACTION_VIEWCMD, TRUE),   MPFROM2SHORT(MIA_CHECKED,MIA_CHECKED));
  378.  
  379.       return (MRESULT)FALSE;  /* End of WM_INITDLG */
  380.  
  381.     case WM_ACTIVATE:
  382.       /* Tell toolbars we are getting/losing focus */
  383.       WinSendMsg(CommandBar, UCMENU_ACTIVECHG, mp1, MPVOID);
  384.       break;
  385.  
  386.     case WM_SAVEAPPLICATION: {
  387.       /* We need to save the current menu configurations in the  application */
  388.       /* .INI file.  We need to save the current menu structure (e.g. the    */
  389.       /* list of items, bitmaps, text, etc), and the current menu style      */
  390.       /* such as text/notext, forced sizing, etc.  The menu structure can be */
  391.       /* saved by creating an in-core template of the menu, and the style    */
  392.       /* information is queried from the UC menu control.                    */
  393.  
  394.       /* A complete application should save more... such as the current      */
  395.       /* window size/position/state, on/off status of toolbars, etc.         */
  396.  
  397.       /* Create incore template representations of the menus */
  398.       CmdTemplate = UCMenuMakeTemplate(CommandBar, &(IniData.CmdSize));
  399.       /* Open INI file and save templates */
  400.       IniHandle = PrfOpenProfile(Hab, INI_NAME);
  401.       if (IniHandle != NULLHANDLE) {
  402.         PrfWriteProfileData(IniHandle, APP_NAME, "CmdTemplate", CmdTemplate, IniData.CmdSize);
  403.         /* We must also save the style bits, size, colors, fonts */
  404.  
  405.         WinSendMsg(CommandBar, UCMENU_QUERYUCMINFO, MPFROMP(&UCMInit), 0L);
  406.         IniData.CmdStyle       = UCMInit.Style;
  407.         IniData.CmdCx          = UCMInit.cx;
  408.         IniData.CmdCy          = UCMInit.cy;
  409.         IniData.CmdBgColor     = UCMInit.BgColor;
  410.         IniData.CmdItemBgColor = UCMInit.ItemBgColor;
  411.         IniData.CmdBblDelay    = UCMInit.BubbleDelay;
  412.         IniData.CmdBblRead     = UCMInit.BubbleRead;
  413.         if (UCMInit.pszFontNameSize != NULL)
  414.           strcpy(IniData.CmdFont, UCMInit.pszFontNameSize);
  415.           else (IniData.CmdFont)[0] = '\0';
  416.         UCMUtilsFreeUCMInfoStrings(&UCMInit);
  417.  
  418.         PrfWriteProfileData(IniHandle, APP_NAME, "IniData", &IniData, sizeof(IniDataStruct));
  419.         PrfCloseProfile(IniHandle);
  420.       }
  421.       UCMenuFree(CmdTemplate);
  422.       break;
  423.       }
  424.  
  425.     case WM_CONTROL:
  426.       switch (SHORT1FROMMP(mp1)) {  /* ID of window sending msg */
  427.         case ID_COMMANDBAR:
  428.           /* To help keep the source code neat, we put all the WM_CONTROL */
  429.           /* processing for the UCMenus in a seperate routine.  There are */
  430.           /* a number of notification codes we must respond to.           */
  431.           return ProcessUCMenuControlMsg(hwnd, mp1, mp2);
  432.       //case ID_XXX: ... any other dialog control WM_CONTROLs processed here...
  433.       }
  434.       break;
  435.  
  436.  
  437.     case WM_NEXTMENU:
  438.       /* When user arrows off the end of a menu, PM wants to know which menu */
  439.       /* should the selection cursor move to.  The default dialog proc would */
  440.       /* normally manage movement between the system menu and action bar,    */
  441.       /* but if we want the UC menus to participate in the menu ring, we must*/
  442.       /* handle this message.  PM hangs can also occure if we don't return   */
  443.       /* some valid menu handle.                                             */
  444.  
  445.       /* Handling this message is complicated by the fact that we must       */
  446.       /* return not the UCMenu window handle, but the underlaying real PM    */
  447.       /* text menu that UCMenu uses internally.  This would normally expose  */
  448.       /* the internals of the UCMenu control to the application... so the    */
  449.       /* handling of this message is encapsulated in the UCMUtils() routines.*/
  450.  
  451.       /* We pass a variable length list of menu window IDs in the order we   */
  452.       /* want them in the selection ring.  E.g. as the user arrows-right the */
  453.       /* selection will move through this list of menus from left to right   */
  454.       /* (with wraparound).  If any menu in the list is not visible it will  */
  455.       /* be skipped and selection will to the next menu.  The list MUST be   */
  456.       /* terminated with an ID of zero.                                      */
  457.  
  458.       /* Boy, this is a lot of comments for one line of code... :-)          */
  459.  
  460.       return UCMUtilsGetNextMenu(hwnd,                     /* Parent of all  */
  461.         HWNDFROMMP(mp1),                                   /* Current menu   */
  462.         SHORT1FROMMP(mp2),                                 /* Direction      */
  463.         FID_SYSMENU, FID_MENU, ID_COMMANDBAR,              /* Ordered list   */
  464.         0);                                                /* List terminator*/
  465.  
  466.     case WM_COMMAND: 
  467.       /* Process selects on the normal PM text menu */
  468.       if (SHORT1FROMMP(mp2) == CMDSRC_MENU) {
  469.         /* Lookup the command in the item list */
  470.         for (i=0; ItemList[i].CommandID != 0; i++) {
  471.           if (ItemList[i].CommandID == SHORT1FROMMP(mp1)) {
  472.             /* Just send ourselves a message to process the command index */
  473.             WinSendMsg(hwnd, MSG_PROCESS_COMMAND, MPFROMSHORT(i), 0L);
  474.             break;
  475.           }
  476.         } /* for */
  477.         return 0;
  478.       } /* if a text menu */
  479.  
  480.       /* Process all WM_COMMAND msgs from dlg controls */
  481.       switch (SHORT1FROMMP(mp1)) {
  482.         case DID_OK:
  483.           /* This occures when user presses EXIT button or CLOSE on the         */
  484.           /* system menu.  Because our main window is a dialog, we must prevent */
  485.           /* WinDismissDlg() from being called or focus is not returned to      */
  486.           /* the correct window.  So instead we save our application state      */
  487.           /* and destory our dialog window (which terminates the dialog         */
  488.           /* without calling WinDismissDlg()).                                  */
  489.           WinSendMsg(hwnd, WM_SAVEAPPLICATION, 0L, 0L);
  490.           WinDestroyWindow(hwnd);
  491.           return 0;
  492.         case DID_CANCEL:
  493.           /* This will occure if ESC key is pressed on dialog.  Since our */
  494.           /* dialog is the main window, we will ignore it.                */
  495.           return 0;
  496.         case PB_HELP:
  497.           MSGBOX(hwnd,"Not implemented yet.","");
  498.           return 0;
  499.       }
  500.       break;  /* End of WM_COMMAND */
  501.  
  502.     case MSG_PROCESS_COMMAND: {
  503.       USHORT CmdIndex;
  504.       USHORT Attr;
  505.       /* A menu command needs to be processed, either from a toolbar  */
  506.       /* or the normal PM text menu.  The index of the command in the */
  507.       /* ItemList[] array is in mp1.  This is where a lot of          */
  508.       /* application specific code would go if this were a real       */
  509.       /* drawing program.                                             */
  510.       CmdIndex = SHORT1FROMMP(mp1);
  511.  
  512.       /* First, see if this command is a checkable type.  If so, we   */
  513.       /* must toggle the check status and update all occurances of    */
  514.       /* this item on all menus (text menus and UC menus).            */
  515.  
  516.       if (ItemList[CmdIndex].Checkable) {
  517.         /* If this is a color action, we want a radio-button like     */
  518.         /* behaviour where one and only one is checked at a time.     */
  519.         if ((ItemList[CmdIndex].CommandID>=ID_ACTION_BLACK) && 
  520.             (ItemList[CmdIndex].CommandID<=ID_ACTION_WHITE)) {
  521.           ItemList[CmdIndex].CheckStatus = MIA_CHECKED;
  522.           if (CmdIndex != ColorIndex) {  /* New color selected, uncheck old color */
  523.             WinSendMsg(TextBar, MM_SETITEMATTR,
  524.                        MPFROM2SHORT(ItemList[ColorIndex].CommandID, TRUE),
  525.                        MPFROM2SHORT(MIA_CHECKED, ~MIA_CHECKED));
  526.             UCMenuSetActionAttr(CommandBar, ItemList[ColorIndex].Action,
  527.                                 MIA_CHECKED, ~MIA_CHECKED);
  528.             ItemList[ColorIndex].CheckStatus = 0;
  529.             ColorIndex = CmdIndex;  /* Save new color index */
  530.             SETTEXT(COLOR, ItemList[ColorIndex].Action);
  531.           }
  532.         }
  533.         else { /* For non-color checkable items, toggle check state */
  534.           ItemList[CmdIndex].CheckStatus = ItemList[CmdIndex].CheckStatus ^ MIA_CHECKED;
  535.         }
  536.         /* Now update checkmarks on all menus */
  537.         WinSendMsg(TextBar, MM_SETITEMATTR,
  538.                    MPFROM2SHORT(ItemList[CmdIndex].CommandID, TRUE),
  539.                    MPFROM2SHORT(MIA_CHECKED, ItemList[CmdIndex].CheckStatus));
  540.         /* Update UC menus.  Use API call to update attributes of all */
  541.         /* items in the menu that have this action on them (may be >1)*/
  542.         UCMenuSetActionAttr(CommandBar, ItemList[CmdIndex].Action,
  543.                             MIA_CHECKED, ItemList[CmdIndex].CheckStatus);
  544.       } /* Item is checkable */
  545.  
  546.       /* Now process the selected command.  If this were a real drawing */
  547.       /* program, we would insert code here to implement the various    */
  548.       /* functions on the menus.  It might look something like:         */
  549.  
  550.       switch (ItemList[CmdIndex].CommandID) {
  551.         case ID_ACTION_SAVE: /* Save drawing...*/
  552.           break;
  553.         case ID_ACTION_NEW:  /* Start new drawing...*/
  554.           break;
  555.         case ID_ACTION_OPEN: /* Open a drawing from disk file */
  556.           break;
  557.         case ID_ACTION_VIEWCMD: /* Toggle command menu on/off (check state already changed) */
  558.           if (ItemList[CmdIndex].CheckStatus & MIA_CHECKED)
  559.             UCMUtilsAddToFrame(hwnd, CommandBar, UCMUTILS_PLACE_TOP);
  560.             else UCMUtilsRemoveFromFrame(hwnd, CommandBar);
  561.           break;
  562.         /* ...etc  <<<=== More application-specific cases here...*/
  563.       }
  564.  
  565.       /* To save code in this example, we just write the command to the */
  566.       /* MLE on the dialog.                                             */
  567.  
  568.       sprintf(Msg,"Item Selected: '%s'\n", ItemList[CmdIndex].Action);
  569.       WinSendMsg(WinWindowFromID(hwnd,CMDLIST), MLM_INSERT, MPFROMP(Msg), 0L);
  570.       return 0;
  571.       } /* end of MSG_PROCESS_COMMAND */
  572.  
  573.     case WM_PAINT: {
  574.       SWP Pos, DlgPos;
  575.       HPS Hps;
  576.       RECTL Rect;
  577.  
  578.       /* First let dialog do normal painting */
  579.       WinDefDlgProc(hwnd, msg, mp1, mp2);
  580.  
  581.       /* Paint recessed frame around the status line */
  582.       Hps = WinGetPS(hwnd);
  583.       WinQueryWindowPos(WinWindowFromID(hwnd, DYNINFO), &Pos);
  584.       WinQueryWindowPos(hwnd, &DlgPos);
  585.       Rect.xLeft = WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME);
  586.       Rect.xRight= DlgPos.cx - Rect.xLeft;
  587.       Rect.yBottom = Pos.y - 1;
  588.       Rect.yTop    = Pos.y + Pos.cy + 1;
  589.       #define DB_RAISED    0x0400  // Undocumented borders
  590.       #define DB_DEPRESSED 0x0800
  591.       WinDrawBorder(Hps, &Rect, 1, 1, 0, 0, DB_DEPRESSED);
  592.       WinReleasePS(Hps);
  593.       return 0;
  594.       }
  595.  
  596.     case WM_ADJUSTWINDOWPOS:
  597.       /* This message occures when the dialog is about to be minimized,     */
  598.       /* maximized, restored, etc.  When a dialog is minimized, any         */
  599.       /* dialog controls in the lower left corner will overlay the icon.    */
  600.       /* So when we minimize we hide these controls, otherwise we make them */
  601.       /* visible.  Note that UCMenu controls do this themselves so we don't */
  602.       /* have to worry about them.                                          */
  603.  
  604.       if (((PSWP)mp1)->fl & SWP_MINIMIZE)
  605.         WinShowWindow(WinWindowFromID(hwnd, DID_OK), FALSE);
  606.       else if (((PSWP)mp1)->fl & SWP_RESTORE)
  607.         WinShowWindow(WinWindowFromID(hwnd, DID_OK), TRUE);
  608.  
  609.       break;  /* Let PM handle the message normally */
  610.  
  611.  
  612.   } /* End of (msg) switch */
  613.                                                                                                   
  614.   return WinDefDlgProc(hwnd, msg, mp1, mp2);
  615.                                                                                                   
  616. } /* End dialog procedure */
  617.  
  618. /*----------------------------------------------------------------------------*/
  619. MRESULT EXPENTRY DLG_TOOLBARTEXT_Proc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  620. /*----------------------------------------------------------------------------*/
  621. /* This dialog proc is called to modify the text of a toolbar item.  Upon     */
  622. /* WM_INITDLG, mp2 is a pointer to a string pointer.  The string will be      */
  623. /* reallocated if the user selected OK.  The return value of the WinDlgBox()  */
  624. /* will be either DID_OK or DID_CANCEL.                                       */
  625. /*----------------------------------------------------------------------------*/
  626. {
  627. static char **StrPtr;
  628. ULONG         Size;
  629. POINTL        MousePos;
  630. SWP           WinPos;
  631.                                                                                  
  632.   switch (msg) {                                                                 
  633.                                                                                  
  634.     case WM_INITDLG:                                                             
  635.       /* MP2 is pointer to string pointer to be edited.  Original string */
  636.       /* ptr will be free'd and reallocated.                             */
  637.       StrPtr = (char **)mp2;
  638.       SETTEXT(TOOLBAR_TEXT, *StrPtr);
  639.  
  640.       /* Position this dialog just below where the mouse   */
  641.       /* pointer was when we fetched the last message.     */
  642.       WinQueryMsgPos(WinQueryAnchorBlock(hwnd), &MousePos);
  643.       WinQueryWindowPos(hwnd, &WinPos);
  644.  
  645.       /* Place just left of mouse, fit into screen edges */
  646.       WinPos.x = min(WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN)-WinPos.cx, MousePos.x);
  647.       /* Place just below mouse, fit into screen edges */
  648.       WinPos.y = min(WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)-WinPos.cy, max(MousePos.y-WinPos.cy, 0));
  649.  
  650.       WinSetWindowPos(hwnd, HWND_TOP, WinPos.x, WinPos.y, 0, 0, SWP_MOVE);
  651.  
  652.       return FALSE;                                                              
  653.                                                                                  
  654.     case WM_COMMAND:                                                             
  655.       switch (SHORT1FROMMP(mp1)) {                                               
  656.         case DID_OK: /*----------~OK (PUSHBUTTON)----------*/                    
  657.           /* Reallocate original string and put new text in it */
  658.           free(*StrPtr);
  659.           Size = QUERYTEXTLEN(TOOLBAR_TEXT)+1;
  660.           *StrPtr = malloc(Size);
  661.           QUERYTEXT(TOOLBAR_TEXT, *StrPtr, Size);
  662.           break;                                                                 
  663.         case DID_CANCEL: /*----------~Cancel (PUSHBUTTON)----------*/            
  664.           break;                                                                 
  665.       }                                                                          
  666.       break;                                                                     
  667.                                                                                  
  668.   } /* End of (msg) switch */                                                    
  669.                                                                                  
  670.   return WinDefDlgProc(hwnd, msg, mp1, mp2);                                     
  671.                                                                                  
  672. } /* End dialog procedure */                                                     
  673.  
  674. /*----------------------------------------------------------------------------*/
  675. MRESULT ProcessUCMenuControlMsg(HWND hwnd, MPARAM mp1, MPARAM mp2)
  676. /*----------------------------------------------------------------------------*/
  677. /* This routine processes all WM_CONTROL messages from all UCMenu toolbar     */
  678. /* controls.  The return value will be the message result.                    */
  679. /*----------------------------------------------------------------------------*/
  680. {
  681. USHORT   MenuID;        /* Window ID of UCMenu           */
  682. UCMITEM  *UCItem;       /* Ptr to UCMenu item data       */
  683. MENUITEM ItemData;      /* Std PM menu item data         */
  684. int      CmdIndex;      /* Index into ActionList[] array */
  685. char     Msg[100];      /* Message formatting buffer     */
  686. int      i;
  687.  
  688.   MenuID = SHORT1FROMMP(mp1);  /* ID of UCMenu sending this message */
  689.  
  690.   switch (SHORT2FROMMP(mp1)) { /* Process each notification code */
  691.  
  692.   case UCN_ITEMSELECTED: /* User made a selection on a toolbar */
  693.  
  694.     UCItem = (UCMITEM *)mp2;
  695.     if (UCItem->pszAction != NULL) { /* Make sure there is an action string */
  696.  
  697.       /* See if we recognize this action.  If so, send ourselves */
  698.       /* a message to process the command index.                 */
  699.  
  700.       CmdIndex = FindActionInItemList(UCItem->pszAction);
  701.       if (CmdIndex >= 0) 
  702.         WinSendMsg(hwnd, MSG_PROCESS_COMMAND, MPFROMSHORT(CmdIndex), 0L);
  703.     }
  704.     return 0;
  705.  
  706.   case UCN_CMITEM: {
  707.     /* One of the items we added to the UCMenu context menu was selected. */
  708.     ULONG MenuColor, ItemColor;
  709.  
  710.     switch (SHORT1FROMMP(mp2)) {  /* What item was selected on context menu? */
  711.  
  712.       case ID_DEFAULTSTYLE:
  713.         /* Reset style flags to default values */
  714.         WinSendMsg(CommandBar, UCMENU_SETSTYLE,
  715.           MPFROMLONG(UCS_FRAMED|BASIC_STYLES),
  716.           MPFROM2SHORT(0,0));
  717.         /* Reset colors and fonts */
  718.         MenuColor = 0x00B0B0B0;         /* Darker grey is toolbar background */
  719.         ItemColor = WinQuerySysColor(HWND_DESKTOP,SYSCLR_MENU,0L); /* Items are menu color */
  720.         WinSendMsg(WinWindowFromID(hwnd, MenuID), UCMENU_SETBGCOLOR,
  721.                    MPFROMLONG(MenuColor), MPFROMLONG(ItemColor));
  722.         WinSendMsg(WinWindowFromID(hwnd, MenuID), UCMENU_SETFONT,
  723.                    MPFROMP("8.Helv"), 0L);
  724.         /* Reset bubble help times */
  725.         WinSendMsg(CommandBar, UCMENU_SETBUBBLETIMERS,
  726.           MPFROMLONG(1000L), MPFROMLONG(3000L));
  727.  
  728.         /* Tell UCMenu to update with new styles */
  729.         WinSendMsg(WinWindowFromID(hwnd, MenuID), UCMENU_UPDATE, 0L, 0L);
  730.         break;
  731.       case ID_MODIFYTOOLBAR:
  732.         /* Call UCMenu API to display buffet menu and update our menu with changes */
  733.         UCMenuResourceBuffetDlg(HWND_DESKTOP,WinWindowFromID(hwnd, MenuID), ID_BUFFETBAR, NULLHANDLE);
  734.         break;
  735.       case ID_MODIFYTEXT: {
  736.         /* Allow user to change menu text.  Note that this selection is enabled even */
  737.         /* when the context menu is invoked with the pointer over blank space in the */
  738.         /* menu.  Therefore, we must check to see that the user was pointing to a    */
  739.         /* menu item.                                                                */
  740.         ULONG Size;
  741.         char  *StrPtr;
  742.         if (SHORT2FROMMP(mp2) != 0) { /* Context menu was over an item... */
  743.           Size = (ULONG)WinSendDlgItemMsg(hwnd, MenuID, MM_QUERYITEMTEXTLENGTH, MPFROMSHORT(SHORT2FROMMP(mp2)), 0L);
  744.           StrPtr = malloc(Size+1);
  745.           WinSendDlgItemMsg(hwnd, MenuID, MM_QUERYITEMTEXT, MPFROM2SHORT(SHORT2FROMMP(mp2), Size+1), MPFROMP(StrPtr));
  746.           if (WinDlgBox(HWND_DESKTOP, hwnd, DLG_TOOLBARTEXT_Proc, NULLHANDLE, DLG_TOOLBARTEXT, &StrPtr)
  747.             == DID_OK)
  748.             WinSendDlgItemMsg(hwnd, MenuID, MM_SETITEMTEXT, MPFROMSHORT(SHORT2FROMMP(mp2)), MPFROMP(StrPtr));
  749.           free(StrPtr);
  750.         }
  751.         else ERRBOX(hwnd,"","Pointer must be over a toolbar item to edit text.");
  752.         return 0;
  753.       }
  754.     } /* switch on item ID */
  755.     return 0;
  756.     }
  757.  
  758.   case UCN_QRYDEFTEMPLATEID:
  759.     /* User has asked to reload the default menu for one of the toolbars. */
  760.     /* Tell the UC menu control the resource ID of the menu template,     */
  761.     /* which is the same as the UCMenu window ID set during UCMenu create.*/
  762.     *(USHORT *)mp2 = MenuID;
  763.     return (MRESULT)TRUE;
  764.  
  765.   case UCN_QRYTEMPLATEMODULE:
  766.     /* Menu needs to know module handle from which to load resources. */
  767.     *(HMODULE *)mp2 = NULLHANDLE;      /* Resources are bound to EXE. */
  768.     return (MRESULT)TRUE;
  769.  
  770.   case UCN_QRYACTIONLIST:
  771.     /* User is customizing a menu item and we need to supply a list of all */
  772.     /* the valid actions the user can put on the item.  We do this by      */
  773.     /* sending the control UCMENU_INSERTACTION messages and then a         */
  774.     /* UCMENU_ACTIONLIST when we are done.                                 */
  775.     for (i=0; ItemList[i].CommandID != 0; i++)
  776.       WinSendMsg(HWNDFROMMP(mp2), UCMENU_INSERTACTION,
  777.                  MPFROMP(ItemList[i].Action),
  778.                  MPFROMP(ItemList[i].Desc));
  779.     /* Tell control we are done */
  780.     WinSendMsg(HWNDFROMMP(mp2), UCMENU_ACTIONSINSERTED, 0L, 0L);
  781.     return 0;
  782.  
  783. // Since we are not using the standard UCMenu customization dialog, we won't
  784. // ever get this message...
  785. //
  786. //case UCN_QRYRESBMP: {
  787. //  ULONG **BmpList, ResSize, ResID;
  788. //  /* The user is customizing a menu item and has asked for a list of all  */
  789. //  /* the built-in bitmaps.  We must supply an array of resource IDs, each */
  790. //  /* of which is a BITMAP resource in the .RC file.  To make this easy,   */
  791. //  /* we have choosen to make all the bitmap resource IDs sequentially     */
  792. //  /* numbered so we can generate the array algorithmicly.  If a specific  */
  793. //  /* ID in the sequence does not exist, we don't put it into the array.   */
  794. //  BmpList = PVOIDFROMMP(mp2);
  795. //  *BmpList = UCMenuAlloc(sizeof(ULONG) * (MAX_BMPID-MIN_BMPID+1));
  796. //  i = 0;
  797. //  for (ResID=MIN_BMPID; ResID<=MAX_BMPID; ResID++ ) {
  798. //    if (DosQueryResourceSize(NULLHANDLE, RT_BITMAP, ResID, &ResSize) == 0) {
  799. //      (*BmpList)[i] = ResID;
  800. //      i++;
  801. //    }
  802. //  } /* endfor */
  803. //  return MRFROMSHORT(i);      /* Tell how many valid entries in the array */
  804. //  }
  805.  
  806.   case UCN_HLP_NB_BMP:
  807.   case UCN_HLP_NB_CREATE:
  808.   case UCN_HLP_NB_ACTION:
  809.   case UCN_HLP_STYLE:
  810.   case UCN_HLP_DM:
  811.     /* User has requested help on a customization dialog.  We only get this */
  812.     /* message if we have the UCS_CUSTOMHLP style on the UCMenu.            */
  813.     MSGBOX(hwnd, "Sorry...","Help not implemented yet.");
  814.     return;
  815.  
  816.   case UCN_QRYBUBBLEHELP:{
  817.      /* Toolbar needs to know what bubble help text to display. */
  818.      /* We keep bubble help in the pszData field of the UCMITEM */
  819.      /* structure, passed to us via mp2.  Note we must return   */
  820.      /* a COPY which UCMenus will free when it is done with it. */
  821.      QBUBBLEDATA *BubbleInfo;
  822.      int        Index;
  823.  
  824.      BubbleInfo = (QBUBBLEDATA *)mp2;
  825.  
  826.      if (UCMFIELD(BubbleInfo->MenuItem, pszAction) != NULL) {
  827.        Index = FindActionInItemList(UCMFIELD(BubbleInfo->MenuItem, pszAction));
  828.        if (Index >= 0)
  829.          BubbleInfo->BubbleText = UCMenuStrdup(ItemList[Index].Desc);
  830.      }
  831.      return 0;
  832.      }
  833.  
  834.   case UCN_MOUSEMOVE: {
  835.     /* The mouse has moved on a toolbar.  As of V2.1 of UCMenus we get only */
  836.     /* one message when the mouse enters an item and one when it leaves the */
  837.     /* toolbar (there is a small delay before we get the notice that the    */
  838.     /* mouse pointer has left the toolbar).  Note that we only get          */
  839.     /* this message if we have the UCS_PROMPTING style on the UCMenu.       */
  840.     /* When the mouse moves over a toolbar, we will update status text with */
  841.     /* description of item under the pointer.  DynamIndex points to the     */
  842.     /* entry in ItemList we last used to update the status text.            */
  843.     POINTL MousePt;
  844.     USHORT MouseItem;
  845.     int    MouseIndex;
  846.  
  847.     MouseItem = SHORT1FROMMP(mp2);
  848.     if (MouseItem == 0)       /* Mouse moved off menu or not on an item */
  849.       SETTEXT(DYNINFO, "");   /* Blank the dynamic info line */
  850.     else {
  851.  
  852.       /* Lookup help text in our command table.                                 */
  853.       /* Query the item to get the MENUITEM -> UCMENU item data.  Note we could */
  854.       /* use some macros from the UCMenu toolkit header to simplify access to   */
  855.       /* the UCMITEM fields, but for this sample we will show the explicit      */
  856.       /* means used to access the data structures.                              */
  857.  
  858.       if (WinSendMsg(WinWindowFromID(hwnd, MenuID), MM_QUERYITEM,
  859.                     MPFROM2SHORT(MouseItem, TRUE), MPFROMP(&ItemData))) {
  860.         if (((UCMITEM *)(ItemData.hItem))!= NULLHANDLE) { /* Make sure there is a UCMITEM structure */
  861.           if (((UCMITEM *)(ItemData.hItem))->pszAction  != NULL) { /* Make sure there is an action string */
  862.             /* See if we recognize this action */
  863.             MouseIndex = FindActionInItemList(((UCMITEM *)(ItemData.hItem))->pszAction);
  864.             if (MouseIndex >= 0)
  865.               SETTEXT(DYNINFO, ItemList[MouseIndex].Desc); /* Update status line */
  866.             else
  867.               SETTEXT(DYNINFO, "??? Unknown toolbar item ???");
  868.           }
  869.         }
  870.       }
  871.     } // search lookup table
  872.  
  873.     return 0;
  874.     }
  875.  
  876.   case UCN_ADDEDITEM:    /* A new item was added to a UCMenu */
  877.   case UCN_ACTION:       /* Action of an existing item was changed */
  878.       /* If an item is added or it's Action is modified, we must check it:        */
  879.       /*  - Is the 'Action' valid?  UC menus allows the user to type in arbitrary */
  880.       /*    action strings.                                                       */
  881.       /*  - Is the selected action a checkable item?  If so, we must set the      */
  882.       /*    check state to our current state for that action.                     */
  883.  
  884.       if (!WinSendMsg(WinWindowFromID(hwnd, MenuID), MM_QUERYITEM,
  885.                       MPFROM2SHORT(SHORT1FROMMP(mp2), TRUE), MPFROMP(&ItemData)))
  886.         return 0;
  887.       if (((UCMITEM *)(ItemData.hItem))== NULLHANDLE)  /* Make sure there is a UCMITEM structure */
  888.         return 0;
  889.       if (((UCMITEM *)(ItemData.hItem))->pszAction  == NULL) /* Make sure there is an action string */
  890.         return 0;
  891.  
  892.       /* Locate the action in our list of valid application actions */
  893.       i = FindActionInItemList(((UCMITEM *)(ItemData.hItem))->pszAction);
  894.  
  895.       if (i>=0) {
  896.         /* If this action is supposed to be checkable, set current check state */
  897.         /* else clear any check mark currently on it.                          */
  898.         if (ItemList[i].Checkable)
  899.           WinSendMsg(WinWindowFromID(hwnd, MenuID), MM_SETITEMATTR,
  900.                      MPFROM2SHORT(SHORT1FROMMP(mp2), TRUE),
  901.                      MPFROM2SHORT(MIA_CHECKED,ItemList[i].CheckStatus));
  902.           else WinSendMsg(WinWindowFromID(hwnd, MenuID), MM_SETITEMATTR,
  903.                      MPFROM2SHORT(SHORT1FROMMP(mp2), TRUE),
  904.                      MPFROM2SHORT(MIA_CHECKED,~MIA_CHECKED));
  905.       } /* if found in list */
  906.       else {
  907.         /* Action specified by user for this menu item is not supported. */
  908.         /* We could notify the user and delete the menu item, or not even*/
  909.         /* tell the user until the item is selected.  For this sample we */
  910.         /* choose to give the user a warning and continue.               */
  911.         sprintf(Msg, "The toolbar item has been assigned an unrecognized action '%s'.\n\n"\
  912.                      "This item will be ignored when selected.",
  913.                      ((UCMITEM *)(ItemData.hItem))->pszAction);
  914.         ERRBOX(hwnd, "Toolbar Update Warning:", Msg);
  915.       }
  916.       return 0;
  917.  
  918.   } /* switch on notification code */
  919.  
  920.   return 0;  /* Did not process notifcation */
  921.  
  922. }
  923.  
  924. /*----------------------------------------------------------------------------*/
  925. int FindActionInItemList(PSZ Action)
  926. /*----------------------------------------------------------------------------*/
  927. /* Look through the list of all the 'actions' this application supports and   */
  928. /* return the index into the ItemList array of the matching entry.  If the    */
  929. /* specified action is not supported, return -1.                              */
  930. /*----------------------------------------------------------------------------*/
  931. {
  932. int i;
  933.   if (Action == NULL)  /* Check for nonexistant action string */
  934.     return -1;
  935.  
  936.   for (i=0; ItemList[i].CommandID != 0; i++) {
  937.     if (STRSAME(ItemList[i].Action, Action)) /* We found the action in the list */
  938.       return i;
  939.   } /* for each item in list */
  940.  
  941.   return -1;  /* Did not find the action in the list */
  942. }
  943. /*----------------------------------------------------------------------------*/
  944. int main(int argc,char **argv, char **envp)
  945. /*----------------------------------------------------------------------------*/
  946. /*  Main routine just runs a dialog box (no main window).                     */
  947. /*----------------------------------------------------------------------------*/
  948. {                                                                                                 
  949. HMQ MyQ;
  950.  
  951.   /* Initialize PM window environment, get a message queue. */
  952.   /* NOTE: We need an extra large queue for UC menus.       */
  953.  
  954.   Hab = WinInitialize(0L);
  955.   MyQ = WinCreateMsgQueue(Hab, 50);
  956.  
  957.   WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, (PFNWP)
  958.             MAINDLG_Proc,
  959.             NULLHANDLE,
  960.             MAINDLG,
  961.             NULL);
  962.  
  963.   /* Cleanup when dialog terminates */
  964.  
  965.   WinDestroyMsgQueue(MyQ);
  966.   WinTerminate(Hab);
  967. }
  968.