home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ucmenu.zip / UCMENUS.PAK / SAMPLES / SAMP2 / SAMP2.C < prev    next >
Text File  |  1995-09-28  |  54KB  |  946 lines

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