home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ucmenu.zip / UCMENUS.PAK / SOURCE / UCMENUS.C < prev    next >
C/C++ Source or Header  |  1995-09-28  |  554KB  |  13,404 lines

  1. /***************************************************************************/
  2. /***************************************************************************/
  3. /*                        DISCLAIMER OF WARRANTIES.                        */
  4. /***************************************************************************/
  5. /***************************************************************************/
  6. /*                                                                         */
  7. /*  Copyright (C) 1995 IBM Corporation                                     */
  8. /*                                                                         */
  9. /*      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is        */
  10. /*      sample code created by IBM Corporation. This sample code is not    */
  11. /*      part of any standard or IBM product and is provided to you solely  */
  12. /*      for  the purpose of assisting you in the development of your       */
  13. /*      applications.  The code is provided "AS IS", without               */
  14. /*      warranty of any kind.  IBM shall not be liable for any damages     */
  15. /*      arising out of your use of the sample code, even if they have been */
  16. /*      advised of the possibility of such damages.                        */
  17. /***************************************************************************/
  18. #pragma alloc_text ( CODESTARTKEEP, UCMenuDrgDrpMsg               )
  19. #pragma alloc_text ( CODESTARTKEEP, MyMalloc                      )
  20. #pragma alloc_text ( CODESTARTKEEP, MenuWndProc                   )
  21. #pragma alloc_text ( CODESTARTKEEP, UCMenuWndProc                 )
  22. #pragma alloc_text ( CODESTARTKEEP, BubbleWndProc                 )
  23. #pragma alloc_text ( CODESTARTKEEP, UCMenuCalcUnscaledItemSize    )
  24. #pragma alloc_text ( CODESTARTKEEP, UCMenuCalcItemSize            )
  25. #pragma alloc_text ( CODESTARTKEEP, UCMenuCalcTextSize            )
  26. #pragma alloc_text ( CODESTARTKEEP, SubmenuWndProc                )
  27. #pragma alloc_text ( CODESTARTKEEP, CreateUCMenu                  )
  28. #pragma alloc_text ( CODESTARTKEEP, UCMenuCalcBmpPos              )
  29. #pragma alloc_text ( CODESTARTKEEP, MyFree                        )
  30. #pragma alloc_text ( CODESTARTKEEP, UCMenu3DFrame                 )
  31. #pragma alloc_text ( CODESTARTKEEP, HideWndProc                   )
  32. #pragma alloc_text ( CODESTARTKEEP, GetMaxItemSize                )
  33. #pragma alloc_text ( CODESTARTKEEP, UCMenuCheckScrolling          )
  34. #pragma alloc_text ( CODESTARTKEEP, UCMenuSetBmpBgColor           )
  35. // (MAM) Added to KEEP code seg:
  36. #pragma alloc_text ( CODESTARTKEEP, UCAdjacentItemBlank           )
  37.  
  38. #pragma alloc_text ( CODESTARTDROP, UCMenuGetBitmapFullName       )
  39. #pragma alloc_text ( CODESTARTDROP, UCMenuLoadBitmap              )
  40. #pragma alloc_text ( CODESTARTDROP, UCMenuLoadMenuData            )
  41. #pragma alloc_text ( CODESTARTDROP, UCMenuLoadItemBmp             )
  42. #pragma alloc_text ( CODESTARTDROP, UCMenuGetBitmapPath           )
  43. #pragma alloc_text ( CODESTARTDROP, UCMenuSelectColor             )
  44. #pragma alloc_text ( CODESTARTDROP, UCMenuCreateFromTemplate      )
  45. #pragma alloc_text ( CODESTARTDROP, UCMenuCreate                  )
  46.  
  47. //----------------------------------------------------------------------------
  48. //
  49. // UCMENUS.C
  50. //
  51. // User-Customizable Menus utility
  52. //-------------------------------------+--------------------------------------
  53. //                                     |   Advanced Commercial Applications
  54. // Version: 2.01                       |   IBM T.J. Watson Research Center
  55. //                                     |   P.O. Box 218
  56. //                                     |   Yorktown Heights, NY 10598
  57. //-------------------------------------+--------------------------------------
  58. // History:
  59. // --------
  60. //
  61. // created: Feb 10 1993 by Alex BERTRAND
  62. //
  63. // updates: Jun 20 1993 (AB) : Save/Load Menu Template functions
  64. //          Jul 10 1993 (AB) : Pop-up menus (Settings)
  65. //          Aug 04 1993 (AB) : Drag and Drop support
  66. //          Oct 04 1993 (GLS): UCS_ styles
  67. //          Feb 01 1994 (GLS): More Drag and Drop support
  68. //          ===> Build Version 2.01
  69. //          Mar 07 1995 (MAM): Fixed drag/drop of MIS_SPACER items
  70. //          Mar 07 1995 (MAM): Added new bitmap for dragging of spacers (diff from no-bmp items)
  71. //          Mar 07 1995 (MAM): Don't draw edges of adjacent spacer items
  72. //          Mar 15 1995 (MAM): Delete bitmap loaded for drag/drop (plug possible memory leak)
  73. //          Mar 15 1995 (MAM): Fix truncated text on customization dialog
  74. //          Mar 15 1995 (MAM): Added OK/Cancel buttons to customzation dlg, remove confirm box
  75. //          Mar 15 1995 (MAM): Clarified some messages (NLS_xxxx in ucmenus.rc)
  76. //          Mar 21 1995 (MAM): Fixed some missing notify messages when items drag/dropped
  77. //                               -- e.g. only UCN_ADDEDITEM was generated, no UCN_DELETEDITEM
  78. //          Mar 23 1995 (MAM): Fixed many problems with submenus:
  79. //                               -- was unable to drag/drop reoder items in a submenu
  80. //                               -- drag from a submenu left some junk pixels when menu dismissed
  81. //                               -- drag from a submenu did not delete source item (e.g. copied)
  82. //                               -- context menu left dark grey line on main menu
  83. //                               -- missing many UCN_* notify messages when submenus customized
  84. //                               -- mouse-move notify messages gave incorrect item IDs
  85. //                               -- style changes did not change already-opened submenus.  changing
  86. //                                  text of a submenu item did not resize the submenu (autoresize style)
  87. //                               -- SUBMENU placeholders cannot be MIA_NODISMISS, each individual item of
  88. //                                  the submenu to be non-dismissable must have MIA_NODISMISS attribute.
  89. //                                  (This is different than std PM menus, but necessary to prevent
  90. //                                  dismiss of submenus during drag/drop operations).
  91. //          Mar 23 1995 (MAM): UCMenuIdFromCoord() off by one pixel on right/top edges
  92. //          Mar 23 1995 (MAM): Made checkmark (thick brdr) visible on hilited items (3-pel thick bdr)
  93. //          Mar 24 1995 (MAM): Remove ability to use MIS_BREAK on submenus
  94. //                               -- PM bug gives wrong coordinates on MM_QUERYITEMRECT for submenus w/BREAK
  95. //          Mar 24 1995 (MAM): Updated version to "2.02" (ucmenus.h)
  96. //         ----------------------------- Version 2.02 Build (DevCon CD, Volumne 7) ----------------------------------------
  97. //          Mar 27 1995 (MAM): Dismiss submenu before sending WM_CONTROL msg to owner (non-NODISMISS items).
  98. //          Mar 29 1995 (MAM): Dismiss submenu before deleting parent menu item.
  99. //          Mar 29 1995 (MAM): Dismiss submenu before processing WM_DESTROY.
  100. //          Mar 29 1995 (MAM): Remove MIA_NODISMISS attribute when copy/moving parent item of a submenu
  101. //         ----------------------------- Version 2.03 Build (Compuserve) ----------------------------------------
  102. //          Apr 04 1995 (MAM): Improved UCN_MOUSEMOVE control messages:
  103. //                               - Only get message when ID changes instead of every movement
  104. //                               - Always get final msg with ID=0 when mouse leaves menu window
  105. //          Apr 05 1995 (MAM): Replace (HWND)0 with NULLHANDLE for better portability.
  106. //          Apr 05 1995 (MAM): Fix prototype of UCMenuGetVersion() and include <stddef.h>  (Thanks Bill K.)
  107. //          Apr 10 1995 (MAM): Use WinDrawText() to measure space needed for text strings.  GpiQueryTextBox() not always accurate.
  108. //          Apr 12 1995 (MAM): Add support for bubble-help
  109. //                               - UCS_BUBBLEHELP style flag
  110. //                               - UCN_QRYBUBBLEHELP WM_CONTROL message to application
  111. //                                   update passed structure w/string (freed by UCmenus when done --
  112. //                                   app must allocate string with UCMenuAlloc()).
  113. //                               - UCMENU_SETBUBBLETIMERS:
  114. //                                    mp1 = (LONG) new delay in msec, maximum of 65000 (65 seconds)
  115. //                                    mp2 = (LONG) new read-time in msec
  116. //                                    returns 0 (reserved)
  117. //                               App must supply initial delay in UCMINFO data
  118. //          ---NOTE--- Need to recompile apps to get larger UCMINFO structure size
  119. //          Apr 13 1995 (MAM): Remove code to un-hilight current item when context menu invoked
  120. //                               (did not work, no longer needed anyway)
  121. //          Apr 13 1995 (MAM): Add support for application-supplied context menu:
  122. //                               - UCN_QRYCONTEXTHWND message
  123. //                                   mp1 = (UCMenu ID, UCN_QRYCONTEXTHWND)
  124. //                                   mp2 = ptr to MENUITEM structure (usID zero if not over an item)
  125. //                                   return HWND of application popup menu, or NULL if none
  126. //                               - Owner of UCMenu control will get UCN_CMITEM ctrl messages (just like built-in menu)
  127. //          Apr 21 1995 (MAM): Fix: always register UCMenu window class in case DLL is freed
  128. //                             and reloaded by the same process (otherwise class points to window
  129. //                             proc in old freed DLL instance).
  130. //          Apr 21 1995 (MAM): Added UCMINRES.RES to build process to create minimal-resource .RES
  131. //                             file.  For use by apps that don't use the UCMenus built-in context
  132. //                             menu or customization dialogs.
  133. //          Apr 24 1995 (MAM): Fix possible trap in UCMenuSetBmpBgColor() due to uninitialized ptr
  134. //          Apr 24 1995 (MAM): Changed all "(TYPE)0" null pointers to "NULL" or "NULLHANDLE" as appropriate
  135. //          Apr 24 1995 (MAM): Added UCMenuStrdup() to API set (useful during UCN_QRYBUBBLEHELP).
  136. //          Apr 24 1995 (MAM): Changed internal use of UCMenuFree() to MyFree() -- eliminate func call in non-debug mode
  137. //          Apr 25 1995 (MAM): Code cleanup, removed lots of unused vars, etc.
  138. //          Apr 26 1995 (MAM): Don't process MM_DELETEITEM for submenu item in main menu proc.
  139. //          Apr 27 1995 (MAM): Added UCMENU_ACTIVECHG message -- reqd for apps using UCN_BUBBLEHELP style
  140. //                                mp1 = (SHORT1) TRUE -- app is being activated
  141. //                                               FALSE-- app is being deactivated
  142. //                                      (SHORT2) Reserved
  143. //                                mp2 = Reserved
  144. //          Apr 27 1995 (MAM): Dismiss open submenus when app becomes inactive
  145. //          May 01 1995 (MAM): Fixed drawing of overall menu frame when !UCN_FRAMED
  146. //          May 01 1995 (MAM): Chg meaning of UCS_FORCESIZE (just sets size of bitmap, item still sizes to larger of bitmap or text)
  147. //                                (e.g. text is NEVER clipped).  Also FORCESIZE can now scale
  148. //                                the bitmap up or down in size (instead of just down).
  149. //          May 02 1995 (MAM): Added UCMENU_QUERYRECT message to get position of a menu item in UCMenu window
  150. //          May 02 1995 (MAM): Added UCMENU_DISABLEUPDATE to improve performance when app inserts/deletes lots of items
  151. //                                mp1 = (BOOL)  TRUE -- do not update menu
  152. //                                              FALSE-- update when needed
  153. //                                mp2 = reserved
  154. //                             Application should always send UCMENUS_UPDATE after re-enabling update.
  155. //                             Initial state is disabled=FALSE (e.g. update on every insert/delete, etc).
  156. //          May 08 1995 (MAM): Chngd UCMENU_QUERYSIZE to return real size for CMS_MATRIX style (instead of size based in num of row/cols requested)
  157. //          May 09 1995 (MAM): Added UCMenuItemDup() and UCMenuItemFree() functions to copy/free UCMITEM structures
  158. //          May 10 1995 (MAM): Added UCN_CHANGEDITEM msg when MM_SETITEM or MM_SETITEMHANDLE is received (notify of change to item, extent of change is unknown)
  159. //          May 15 1995 (MAM): Fixed memory leak by freeing pszParameters when item is deleted (MM_DELETEITEM processing)
  160. //          May 24 1995 (MAM): Use UCMString2Int() to better distinguish btw bitmap resource numbers and file names (previous code would take "123G.BMP" as resource ID 123).
  161. //          May 24 1995 (MAM): Store binary form of bitmap ID in upper word of ulFlags in UCMITEM structure
  162. //          May 24 1995 (MAM): UCMI_FROMBMPFILE in ulFlags is set if pszBmp[] is a filename (even if the file was not found and a default resource bitmap is being used instead)
  163. //          May 24 1995 (MAM): pszDefaultBitmap in UCMINFO can now be a resource ID (string form) or a file name
  164. //          May 25 1995 (MAM): Fix bug in algorithm for choosing best bitmap when .BMP file contains array of bitmaps
  165. //         June 03 1995 (MAM): Fix test of uninitialized variable in UCMenuNew().
  166. //         June 06 1995 (MAM): Enhanced UCMenuLoadBitmap() to load icons from non-BMP files using WinLoadFileIcon.  Makes it easy to show WPS representation of any file.
  167. //                               -- Commented out because of black-background problem (requires more code to solve).
  168. //         June 06 1995 (MAM): If toolbar is empty set size to size of a normal PM menu.
  169. //         June 13 1995 (MAM): Changed UCMENUS.RCH to UCMLOCAL.H (some build systems need .H extension for all header files)
  170. //         June 13 1995 (MAM): Fixed trap/hang if application had its own drag/drop implementation in addition to the UCMenu control
  171. //                               (dragging over the UCMenu from a same-process, non-UCMenu window would trap/hang due to bad assumption in DM_DRAGOVER processing)
  172. //         July 20 1995 (MAM): Changed background color mapping of bitmaps:
  173. //                              - Added new style "UCS_CHNGBMPBG_AUTO" to use lower-leftmost pixel of bitmap to determine bitmap background color (BgBmp of UCMINFO will be ignored)
  174. //                              - Improved UCMenuSetBmpBgColor() to not assume 256 color bitmaps (less memory allocated and better performance for 2 or 16-color bitmaps)
  175. //                              - Bitmap backgrounds are now mapped (only) when bitmaps are loaded (not at WM_DRAWITEM time)
  176. //                              - All bitmaps are reloaded (and color mapped) when the menu background color is changed (fixes bug where multiple color changes would lose colors in the bitmaps)
  177. //                              - Removed lCurBmpBgColor from UCMITEM structure (no longer needed since colors are mapped only when bitmaps are loaded)
  178. //         July 20 1995 (MAM): Removed use of BitBlt to shift image of items during hilight/unhilight (BltBit method leaves stray pixels in many cases when item is partially obscured by another window).
  179. //                              Now just fully draw the item every time.  Less efficient but more robust.
  180. //         July 21 1995 (MAM): Fixed spurious display of bubble help when pointer passes through toolbar (check for ptr in toolbar window during WM_TIMER (TIMER_BUBBLE) processing)
  181. //         July 21 1995 (MAM): Reduced timer for detecting ptr leaving toolbar to 1/2 second
  182. //         July 21 1995 (MAM): Fixed visual corruption when bubble is removed if underlaying window changed (remove WS_SAVEBITS style)
  183. //         July 21 1995 (MAM): Fixed visual corruption when bubble is quickly hidden/shown (get/dispatch all WM_PAINT messages between HIDE/SHOW so underlaying windows are sure to paint)
  184. //         July 21 1995 (MAM): Added several HWNDs to UCMDATA to elimiate many WinQueryWindow() calls.
  185. //         July 21 1995 (MAM): Added UCMUI #define to create smaller module with no user-customization or context menu functions.
  186. //         ----------------------------- Version 2.1 Build ----------------------------------------
  187. //         Aug  08 1995 (MAM): Activate frame on button 2 down (prevent context menu on inactive frame)
  188. //         Aug  10 1995 (MAM): Fix render of larger fonts by getting new PS in WM_DRAWITEM instead of using PS supplied by PM
  189. //         Aug  16 1995 (MAM): Removed MIS_TEXT bit flag from MIS_SPACER definition -- OS/2 2.1 does not send WM_MEASUREITEM messages if MIS_TEXT flag is set
  190. //         Aug  29 1995 (MAM): Fixed double-painting of toolbar when sized after creationg (changed WM_SIZE from Post to Send)
  191. //         Aug  29 1995 (MAM): Comment-out UCMENUS_DEBUG for memory allocate
  192. //         Aug  30 1995 (MAM): Fix memory leak from unclosed device context (WM_DESTROY processing)
  193. //         Sept  1 1995 (MAM): Fix memory leak from unfreed drag/drop transfer shared memory
  194. //         Sept 14 1995 (MAM): Improved scrolling algorithms (don't reset scroll posn when window size changes)
  195. //         Sept 18 1995 (MAM): Fixed UCN_SIZE notification logic to only send size change notification when dimension of interest changes (e.g. vert dim of a HORZ menu)
  196. //         Sept 21 1995 (MAM): Fixed painting of disabled menu items (render our own half-tone).
  197. //         Sept 28 1995 (MAM): Added CMS_MATRIX_VERT and CMS_MATRIX_HORZ styles for scrollable matrix menus
  198. //         ----------------------------- Version 2.11 Build ----------------------------------------
  199. //----------------------------------------------------------------------------
  200. // Nice to-dos for future versions:
  201. //
  202. // - consolidate bubble-handling of button and context menus to one function
  203. // - fix accelarator handling or remove the capability ("~" in text)
  204. // - Optimize repainting for performance:
  205. //    - On size change, repaint entire bar only if:
  206. //         - vertical size changed, or
  207. //         - scroll bar status (on/off) changed
  208. //         otherwise repaint only items affected by the resizing.
  209. //    - On insert/delete, repaint only toolbar area
  210. //      to the right of the inserted/delete item.  Repaint entire
  211. //      bar only if insert/delete causes change in scrollbar status.
  212. //
  213. // - put mouse capture code into Hide window and modify bubble
  214. //   proc to not change active status when pointer moves into hide window.
  215. //   Have hide window generate dummy ID?
  216. //
  217. // - improve loading of bitmaps from resource file by accessing
  218. //   bitmap resource directly and using same bitmap selection algorithm as
  219. //   UCMenuLoadBitmap() does loading from a file (e.g. select resolution
  220. //   *closest* to screen size instead of exact-match only).
  221. //
  222. //----------------------------------------------------------------------------
  223. // Known problems/limitations:
  224. //
  225. //  - Bug in Warp 3.0 can cause corruption of a random toolbar bitmaps
  226. //    during drag/drop operations.  No known workaround. 
  227. //    This problem does not occure on 2.X versions of OS/2.  Severity 1 APAR
  228. //    submitted to Boca, APAR number PJ17913.  Fixed in fix pack #9.
  229. //
  230. //  - Bug in Warp 3.0 causes 64K byte memory leak on every use of WinFileDlg().
  231. //    APAR number PJ16382.  Fixed in fix pack #9.
  232. //
  233. //  - Cannot support MIS_BREAK on submenus due to PM bug in MM_QUERYITEMRECT
  234. //    which can return wrong coordinates when an OWNERDRAW submenu has breaks.
  235. //    Any MIS_BREAK style flags will be removed when the UCMenu is created.
  236. //    Need to create simple testcase and submit OS/2 defect report.
  237. //
  238. //  - Bubble window on submenus not implemented.
  239. //
  240. //----------------------------------------------------------------------------
  241. // Includes
  242. //----------------------------------------------------------------------------
  243. #define INCL_BASE
  244. #define INCL_PM
  245. #define INCL_WINSTDDRAG
  246. #define MTI_INCLUDED   // PM menu templates
  247. #include <os2.h>
  248. #include <stdio.h>
  249. #include <stdlib.h>
  250. #include <string.h>
  251. #include <ctype.h>
  252. #include <stddef.h>
  253.  
  254. #define OPENREAD(fn)   fopen(fn, "rb")
  255. #define OPENWRITE(fn)  fopen(fn, "wb")
  256. #define FILEHANDLE     FILE *
  257. #define NULLFILE       NULLHANDLE
  258. #define CLOSEFILE(h)   fclose(h)
  259. #define READFILE(Buff,Size,Cnt,h)  fread(Buff, Size, Cnt, h)
  260. #define WRITEFILE(Buff,Size,Cnt,h) fwrite(Buff, Size, Cnt, h)
  261. #define pcslstrchr     strchr
  262. #define SEEKOK(rc)     (rc==0)
  263. #define AnsiUpperBuff(str,len) strupr(str)
  264.  
  265. #include "UCMENUS.H"     // Externalized definitions
  266. #include "UCMLOCAL.H"    // Internal definitions
  267.  
  268. //------------------------------------------------------------------------
  269. // Remove the following to generate a smaller module without
  270. // any user-customization functions.  Application-supplied context
  271. // menu will work, but UCMenu will have no context menu of its own.
  272. // Also the UCMenu...BuffetDlg() functions do nothing.  This is for
  273. // use in applications which supply all context menu and customization
  274. // functions.
  275. //------------------------------------------------------------------------
  276. #define UCMUI
  277.  
  278. //...use 2nd for real build...
  279. //#define DRAGDEBUG (PVOID)0x80000000        // Allow msg dispatching during DrgDrag().
  280. #define DRAGDEBUG NULL                       // Normal drag
  281.  
  282. // ---------------------------------------------------
  283. // -- Memory allocation switches,
  284. // ---------------------------------------------------
  285. #ifdef DEBUGMENUS
  286.     #define UCMENUS_DEBUG
  287. #else
  288.    #undef UCMENUS_DEBUG
  289. #endif
  290. // #define UCMENUS_DEBUG           // -- switches on debug mem allocation
  291. // #define MYMALLOC_RIGHT_BOUNDARY // -- switches the debug mem alloc on right boundary
  292.  
  293. //----------------------------------------------------------------------------
  294. // Debug memory allocations
  295. //----------------------------------------------------------------------------
  296.  
  297. // -------------------------------------------------------------------------------------
  298. // -- The non debug version uses malloc, which does less checkings than DosAllocMem
  299. // -- So when debugging, we use DosAllocMem, which will trap earlier than malloc in case
  300. // -- of access violation. But the granularity of DosAllocMem is 1 page (4096 bytes) so
  301. // -- if we want to check the violations at the right boundary of the memory we allocate
  302. // -- we put the end of the memory on a page boundary.
  303. // -------------------------------------------------------------------------------------
  304.  
  305.  
  306. #ifdef UCMENUS_DEBUG
  307.    VOID  * MyMalloc(size_t size);
  308.    VOID    MyFree(VOID * p);
  309.    char  * MyStrdup(const char * string);
  310.    #define ERRPRT0(a)       fprintf(stderr,a)
  311.    #define ERRPRT1(a,b)     fprintf(stderr,a,b)
  312.    #define ERRPRTKEEP1(a,b) fprintf(stderr,a,b)
  313. #else
  314.    #define MyMalloc malloc
  315.    #define MyFree   free
  316.    char  * MyStrdup(const char * string);
  317.    #define ERRPRT0(a)
  318.    #define ERRPRT1(a,b)
  319.    #define ERRPRTKEEP1(a,b) b
  320. #endif
  321.  
  322.  
  323. //----------------------------------------------------------------------------
  324. // local constants
  325. //----------------------------------------------------------------------------
  326. #define UCAPPNAME   "UCMenus"     //MEK 09/15/94 - for ini file processing
  327. #define UCKEYNAME   "UCKeyName"
  328. #define UCMCLASS    "UCMenu"      // UCMenu window class
  329. #define BUBBLECLASS "UCMBbl"      // Bubble-help window class
  330. #define MAXDESCLEN 256
  331. #define MAX_TMPSIZE 16384
  332. #define MAX_FONTNAMELEN 100       // Max length of a font name
  333. #define MAX_INT         32767     // Max SHORT integer
  334. #define DEFAULT_DELAY   2500      // Default bubble delay time in msec.
  335. #define MIN_BUBBLE_DELAY 150      // Less delay than this treated as zero delay
  336. #define QWL_UCMDATA  4
  337. #define PTR_CHECK_DELAY  500L     // Interval for checking ptr leaving toolbar windows
  338. #define BBLDISMISS_DELAY 4000L    // Auto dismiss of bubble help
  339.  
  340. #define GETTING_FOCUS   WM_USER +  0x1000  // Note UCMENU_* start with 0x2000
  341. #define UCMNBP1_NEWBMP  WM_USER +  0x1001
  342. #define MSG_ITEMCHANGE  WM_USER +  0x1002  // Notice to bubble window ptr moved to diff item
  343. #define MSG_ENABLE_BUBBLE  WM_USER+0x1003  // Enable bubble window
  344. #define MSG_DISABLE_BUBBLE WM_USER+0x1004  // Disable bubble window
  345. #define MSG_UPDATE_BUBBLE  WM_USER+0x1005  // Used internally in bubble window proc
  346.  
  347. #define TIMER_BUBBLE       TID_USERMAX-1   // Timer ID for buble help
  348. #define TIMER_BUBBLE_FAKE  TID_USERMAX-2   // Pseudo timer event ID
  349. #define TIMER_PTRCHECK     TID_USERMAX-3   // Check ptr for in/out of menu window
  350. #define TIMER_BBLAUTODISMISS TID_USERMAX-4 // Auto dismiss of bubble help window
  351. // --
  352. // maximum size of the bitmap drawn while dragging
  353. // --
  354. #define UCM_MAX_DRG_CX 100
  355. #define UCM_MAX_DRG_CY 100
  356. // --
  357. // We leave a 2 pixel frame around the item
  358. // --
  359. #define ITEM_FRAME_THICK_LEFT       2
  360. #define ITEM_FRAME_THICK_RIGHT      2
  361. #define ITEM_FRAME_THICK_BOTTOM     2
  362. #define ITEM_FRAME_THICK_TOP        2
  363. #define SUM_ITEM_FRAME_THICK_HORZ   4
  364. #define SUM_ITEM_FRAME_THICK_VERT   4
  365. // --
  366. // We leave some space right and left of the text
  367. // --
  368. #define TEXT_FRAME_THICK_HORZ       1
  369. #define SUM_TEXT_FRAME_THICK_HORZ   2
  370. // --
  371. // There is a frame around the ucmenu (actually it is the frame
  372. //  of the scrollbar which has the same size as the UCM and is drawn
  373. //  over it)
  374. // --
  375. #define UCM_FRAME_THICK             1
  376. #define SUM_UCM_FRAME_THICK         2
  377. // --
  378. // There is a frame around the menu (it is drawn in the hide window
  379. //  which is drawn inside the ucmenu frame )
  380. // --
  381. #define MENU_FRAME_THICK            1
  382. #define SUM_MENU_FRAME_THICK        2
  383. // --
  384. // (MAM) Added constants
  385. // Constants for UCAdjacentItemBlank() Left/Right parameter
  386. //
  387. #define ADJACENT_LEFT               -1
  388. #define ADJACENT_ABOVE              -1
  389. #define ADJACENT_RIGHT              1
  390. #define ADJACENT_BELOW              1
  391.  
  392. #if defined(_LE_PPC)                                                    
  393. //----------------------------------------------------------------------
  394. // GpiQueryColorData is OK under OS/2 for PowerPC SDK.                  
  395. //----------------------------------------------------------------------
  396. #define GpiQueryColordata GpiQueryColorData                             
  397. #else                                                                   
  398. #endif /* _LE_PPC */                                                    
  399.  
  400. //----------------------------------------------------------------------------
  401. // Macros
  402. //----------------------------------------------------------------------------
  403. #define POST_TO_MENU  (MRESULT)WinPostMsg(UCMData->hwndMenu, msg, mp1, mp2)
  404. #define SEND_TO_MENU  WinSendMsg(UCMData->hwndMenu, msg, mp1, mp2)
  405. #define MSGBOX(Owner,Title,Msg) WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OK|MB_INFORMATION)
  406.  
  407. //----------------------------------------------------------------------------
  408. // local structures
  409. //----------------------------------------------------------------------------
  410.  
  411. typedef struct _UCMDATA {  // Main structure we hang off most window words, has all kinds of useful stuff
  412.    ULONG        size                ;             // Size of this structure
  413.    PFNWP        OldMenuProc         ;             // We subclass the menu & submenu window procedure
  414.    PFNWP        OldSubMenuProc      ;
  415.    HWND         hwndOwner           ;             // Owner of UCMenu
  416.    HWND         hwndUCM             ;             // UCMenu window handle
  417.    HWND         hwndHide            ;             // Hide window handle
  418.    HWND         hwndScroll          ;             // Scrollbar window handle
  419.    HWND         hwndCM              ;             // context menu : loaded once.
  420.    HWND         hwndUserCM          ;             // context menu provided by application, if any
  421.    HWND         hwndMenu            ;             // Handle of the PM menu associated to the ucmenu
  422.    HWND         hwndCMOrig          ;             // Handle of the (sub)menu from which the CM was popped
  423.    HWND         hwndHelpInstance    ;             // Handle of the help instance
  424.    HWND         hwndBubble          ;             // Bubble-help (hover) window
  425. #if defined(UCMUI)
  426.    HWND         hwndTemp            ;             // Temporary window handle
  427.    HWND         hwndSettings        ;             // Window handle of the settings dialog
  428.    HWND         hwndPage1           ;             // Pages of the dialog
  429.    HWND         hwndPage2           ;
  430.    HWND         hwndPage0           ;
  431. #endif
  432.    ULONG        MaxVerticalWidth    ;             // The widest item of vertical UCMENU
  433.    ULONG        MaxHorizontalHeight ;             // The tallest item of horizontal UCMENU
  434.    ULONG        SumItemWidths       ;
  435.    ULONG        SumItemHeights      ;
  436.    ULONG        Style               ;
  437.    ULONG        cx                  ;             // Size to give to all the items if UCS_FORCESIZE
  438.    ULONG        cy                  ;             //
  439.    ULONG        BubbleDelay         ;             // Bubble-help delay (msec)
  440.    ULONG        BubbleRead          ;             // Bubble-help read time (msec)
  441.    ULONG        ulBmpTempId;
  442.    ULONG        MenuPtrTimer        ;             // Timer handle for menu window
  443.    LONG         BgColor             ;             // RGB value of the current background color
  444.    LONG         ItemBgColor         ;             // RGB value of the current item background color
  445.    LONG         BgBmp               ;             // RGB value of the initial bitmap color to be replaced with ItemBgColor
  446.    HMODULE      hModUCM             ;             // Module that we use...
  447.    HMODULE      hModBmp             ;             // Module where we look for the bitmaps
  448.    HBITMAP      hBmpTemp            ;             // Temporary bitmap handle
  449.    HPS          hpsMem              ;             // HPS associated to a mem device context, to perform bitmap manipulations
  450.    PACCELTABLE  AccelTable          ;
  451.    PSZ          pszFontNameSize     ;             // Font of the ucmenu
  452.    USHORT       UCMenuID            ;             // ID of UCMenu window
  453.    USHORT       usItem              ;             // ID of the current submenu
  454.    USHORT       ContextID           ;             // ID of the item over which the context menu is called
  455.    USHORT       TargetID            ;             // ID of the item being target of a drag&drop
  456.    USHORT       HoverID             ;             // ID of item the mouse is hovering over
  457.    USHORT       MinID, MaxID        ;
  458.    USHORT       NbOfRows            ;
  459.    USHORT       NbOfCols            ;
  460.    BOOL         bBmpTempFromFile    ;             // TRUE if hBmpTemp from file, FALSE if from resource
  461.    BOOL         bItemCreation       ;             // TRUE if we are creating an item
  462.    BOOL         bProcessingPP       ;             // TRUE if we are processing a WM_PRESPARAMCHANGED
  463.    BOOL         Active              ;             // Is our app active?  Track UCMENU_ACTIVECHG status.
  464.    BOOL         DisableUpdate       ;             // Update disabled by owner
  465.    TID          tid;                              // Used to store temp thread ids
  466. #if defined(UCMUI)
  467.    CHAR         szTemplatePath[CCHMAXPATH];       // Last path used for the templates
  468.    CHAR         szBitmapPath[CCHMAXPATH];         // Last path used for the bitmaps
  469. #endif
  470.    CHAR         szBitmapSearchPath[MAXPATHL];     // Bitmap search path
  471.    CHAR         szDefaultBitmap[MAXPATHL];
  472. } UCMDATA, *PUCMDATA;
  473.  
  474. typedef struct _UCMINFO {
  475.    ULONG  cb;                   // size of this structure
  476.    HWND    hwndMenu;            // Menu window-handle
  477.    HMODULE hModule;             // Module where the bitmaps are
  478.    USHORT  NbOfCols;            // Number of Columns (used for a matrix UCM)
  479.    USHORT  NbOfRows;            // Number of Rows    (used for a matrix UCM)
  480.    PSZ     pszBitmapSearchPath; // Path(s) to search for bitmap files.
  481.                                 // Environment variables separated by spaces.
  482.    PSZ     pszDefaultBitmap;    // Bitmap to use if bitmap specified for
  483.                                 //  a menu item can't be resolved or loaded.
  484.    ULONG   Style;               // Style of item (combination of UCS_ flags )
  485.    ULONG   cx;                  // Size to give to all the items if UCS_FORCESIZE
  486.    ULONG   cy;                  //
  487.    LONG    BgBmp;               // RGB value of the color of the bmp which has to be replaced with ItemBgColor
  488.    LONG    BgColor;             // RGB color of the UCMenu background
  489.    LONG    ItemBgColor;         // RGB color of the UCMenu items background, used if UCS_CHNGBMPBG is set
  490.    PSZ     pszFontNameSize;     // String describing the font of the UCMenu (such as used
  491.    ULONG   ulTmplVersion;       //  in WinSetPresParam), if NULL, UCM_DEFAULTFONT is used
  492.    ULONG   BubbleDelay;         // Bubble-help delay (msec)
  493.    ULONG   BubbleRead;          // Bubble-help read time (msec)
  494.    HMODULE hModUCM;             // Module that we use...
  495. } UCMINFO2, *PUCMINFO2;
  496.  
  497. typedef struct _MTI {
  498.   USHORT afStyle;
  499.   USHORT afAttribute;
  500.   USHORT idItem;
  501.   CHAR   c[2];
  502. } MTI, *PMTI;
  503.  
  504. typedef struct _MENUTEMPLATE {
  505.   USHORT Length;
  506.   USHORT Version;
  507.   USHORT CodePage;
  508.   USHORT Offset;
  509.   USHORT Count;
  510.   CHAR   c[2];
  511. } MENUTEMPLATE, *PMENUTEMPLATE;
  512.  
  513. typedef struct _UCMDLGINFO {
  514.   ULONG    ulSize;
  515.   HWND     hwndUCMenu;
  516.   HWND     hwndBuffet;
  517.   ULONG    ulBuffetMenuID;
  518.   HMODULE  hmodBuffetMenu;
  519.   PVOID    pTemplate;
  520.   BOOL     bFromTemplate;
  521.   PFNWP    OldShredderWndProc;
  522.   PUCMDATA UCMData;
  523. } UCMDLGINFO, * PUCMDLGINFO;
  524.  
  525. //----------------------------------------------------------------------------
  526. // GpiQueryColorData in pmgpi.h but GpiQueryColordata in os2386.lib
  527. //----------------------------------------------------------------------------
  528. BOOL  APIENTRY GpiQueryColordata(HPS hps, LONG lCount, PLONG alArray);
  529.  
  530.  
  531.  
  532. //----------------------------------------------------------------------------
  533. // local function declarations
  534. //----------------------------------------------------------------------------
  535. MRESULT EXPENTRY          UCMenuWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  536. MRESULT EXPENTRY          ScrollbarProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  537. MRESULT EXPENTRY            HideWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  538. MRESULT EXPENTRY         SubmenuWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  539. MRESULT EXPENTRY            MenuWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  540. MRESULT EXPENTRY          BubbleWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  541. MRESULT EXPENTRY  UCMenuSettingsDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  542. MRESULT EXPENTRY      UCMenuNBP1DlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  543. MRESULT EXPENTRY      UCMenuNBP2DlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  544. MRESULT EXPENTRY      UCMenuNBP0DlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  545. MRESULT EXPENTRY     UCMenuStyleDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  546. MRESULT EXPENTRY      BitmapFileDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  547. MRESULT EXPENTRY UCMenuCreateBmpDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  548. MRESULT EXPENTRY          ResBmpDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  549. MRESULT EXPENTRY             UCMDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  550. MRESULT EXPENTRY        ShredderWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  551. MRESULT _Optlink        UCMenuDrgDrpMsg(PUCMDATA UCMData, HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, PFNWP WindowProc);
  552. VOID _Optlink  UCMenuRemoveDropEmphasis(PUCMDATA UCMdata, HWND hwnd );
  553. BOOL _Optlink     UCMenuCheckScrolling(HWND hwndUCMenu);
  554. BOOL _Optlink               UCMenuSize(HWND hwndMenu, USHORT Style);
  555. VOID _Optlink       UCMenuLoadMenuData(HWND hwndMenu, PUCMDATA UCMData, ULONG ulVersion, HWND hwndUCM );
  556. VOID _Optlink        UCMenuLoadItemBmp(MENUITEM *Item, PUCMDATA UCMData );
  557. VOID _Optlink       UCMenuCalcItemSize(POWNERITEM poi, USHORT Style, HWND hwndUCMenu, ULONG * pCx, ULONG * pCy);
  558. VOID _Optlink UCMenuCalcUnscaledItemSize(PUCMITEM pUCMI, USHORT Style, HWND hwndUCMenu, ULONG * pCx, ULONG * pCy);
  559. VOID _Optlink         UCMenuCalcBmpPos(POWNERITEM poi, HWND hwndUCM, USHORT Style, POINTL aptlPoints[4], PUCMDATA UCMData);
  560. VOID _Optlink       UCMenuCalcTextSize(PUCMITEM pUCMI, HWND hwndUCM, ULONG * pWidth, ULONG * pHeight);
  561. ULONG _Optlink       UCMenuSelectColor(LONG Color, HPS hps);
  562. VOID _Optlink      UCMenuSetBmpBgColor(PUCMITEM pUCMItem, PUCMDATA UCMData, HPS hps);
  563. VOID _Optlink            UCMenu3DFrame(HPS hps, PRECTL rcl, USHORT hilited);
  564. VOID _Optlink        UCMenuContextMenu(HWND hwndUCMenu, HWND hwndMenu, ULONG FromMouse);
  565. VOID   _Optlink           UCMenuNBP1OK(HWND hwnd);
  566. VOID   _Optlink           UCMenuNBP2OK(HWND hwnd);
  567. BOOL   _Optlink           UCMenuNBP0OK(HWND hwndPage);
  568. VOID   _Optlink       UCMenuStyleDlgOK(HWND hwnd);
  569. VOID   _Optlink       UCMenuUpdateMenu(HWND hwndMenu, BOOL UpdateSubmenus);
  570. VOID    _Optlink      UCMenuUnselectAll(HWND hwndMenu);
  571. USHORT  _Optlink         UCMenuGetNewID(HWND hwndMenu, SHORT sID, PUCMDATA UCMData);
  572. VOID    _Optlink      UCMenuReplaceMenu(HWND hwndOldMenu, HWND hwndNewMenu);
  573. BOOL    _Optlink         UCMenuInitDrag(HWND hwnd, SHORT x, SHORT y);
  574. MRESULT _Optlink         UCMenuDragOver(PUCMDATA UCMData, HWND hwnd, PDRAGINFO pDragInfo);
  575. VOID    _Optlink             UCMenuDrop(HWND hwnd, PDRAGINFO pDraginfo);
  576. VOID    _Optlink UCMenuPresParamChanged(PUCMDATA UCMData, HWND hwnd, MPARAM mp1);
  577. PSZ     _Optlink       UCMenuGetExePath(VOID);
  578. USHORT  _Optlink    UCMenuGetBitmapPath(PUCMDATA UCMDATA, PSZ pszBmp, PSZ pszPathName);
  579. USHORT _Optlink UCMenuGetBitmapFullName(PUCMDATA UCMDATA, PSZ pszBmp, PSZ pszFullName);
  580. VOID    _Optlink         GetMaxItemSize(PUCMDATA UCMData, HWND hwndUCMenu, HWND hwndMenu);
  581. VOID    _Optlink   UCMenuNBP0Initialize(PUCMDATA UCMData, HWND hwnd);
  582. VOID    _Optlink   UCMenuNBP1Initialize(PUCMDATA UCMData, HWND hwnd);
  583. VOID    _Optlink   UCMenuNBP2Initialize(PUCMDATA UCMData, HWND hwnd);
  584. VOID    _Optlink      UCMenuEditBmpFile(HWND hwndNBP1, PSZ pszBmpFileName);
  585. VOID    _System     UCMenuEditBmpFileT2(PVOID pArgs);
  586. BOOL    _Optlink    UCMenuCreateBmpFile(PSZ pszBmpFileName, ULONG cx, ULONG cy);
  587. VOID    _Optlink    UCMenuNBP1UpdateBmp(HWND hwnd, PSZ pszFileName);
  588. VOID    _Optlink    UCMenuDisplayHelp(PUCMDATA UCMData, USHORT usPanelID, USHORT usCustomID);
  589. VOID    _Optlink     InitializeStyleDlg(PUCMDATA UCMData, HWND hwnd);
  590. BOOL    _Optlink         TranslateAccel(PUCMDATA UCMData, HWND HwndMenu, USHORT Key, PQMSG QMsg);
  591. VOID    _Optlink           AddAccelItem(PUCMDATA UCMData, USHORT Key, ULONG id);
  592. VOID    _Optlink        RemoveAccelItem(PUCMDATA UCMData, USHORT Key);
  593. PSZ     _Optlink           SubMemStrdup(PVOID pSubMem, PSZ pszSource);
  594. PSZ     _Optlink          nlsgetmessage(HAB Hab, HMODULE HModule, SHORT msg, SHORT buffnum);
  595. PVOID   _Optlink    UCMenuMakeTemplate2(HWND hwndMenu, PVOID pBuf, USHORT MenuAttr);
  596. ULONG   _Optlink      UCMenuTemplateLen(HWND hwndMenu);
  597. HWND    _Optlink           UCMenuCreate(HAB hab, HWND hParent, HWND hOwner, ULONG ulStyle,
  598.                                         LONG x, LONG y, LONG cx, LONG cy, HWND hInsertBehind,
  599.                                         ULONG ulID, PUCMINFO2 pUCMInfo2);
  600. VOID    _System    UCMenuExecuteProgram(PSZ pszName);
  601. SHORT   _Optlink     UCMenuGetActionID2(HWND hwndMenu, PSZ pszAction, BOOL bSubmenus, SHORT sStartID);
  602. VOID    _System        UCMenuLoadResBmp(PVOID pArgs);
  603. VOID    _Optlink         UCMenuNotifAll(PUCMDATA UCMData, HWND hMenu, USHORT usNotif);
  604. BOOL    _Optlink    UCAdjacentItemBlank(HWND MenuHwnd, SHORT ItemID, int LeftRight);
  605. void    _Optlink UCMenuCreateBubbleWindow(HWND UCMenuHwnd, UCMDATA *UCMData);
  606. LONG    _Optlink UCMString2Int(char *lpString, BOOL *lpTranslated);
  607.  
  608. //----------------------------------------------------------------------------
  609. // UCMenuCreateFromResource
  610. //----------------------------------------------------------------------------
  611. // :function res=&IDF_UCMCREATERES. name='UCMenuCreateFromResource' text='Create a ucmenu from a resource menu'.
  612. // This function creates a ucmenu using a menu template stored in the resources.
  613. // :syntax name='UCMenuCreateFromResource' params='hab hParent hOwner ulStyle x y cx cy hInsertBehind ulID hmodResource usMenuID pUCMInfo phTextMenu' return='hUCMenu' .
  614. // :fparams.
  615. // :fparam name='hab' type='HAB' io='input' .
  616. // Handle of the anchor-block.
  617. // :fparam name='hParent' type='HWND' io='input' .
  618. // Handle of the parent window
  619. // :fparam name='hOwner' type='HWND' io='input' .
  620. // Handle of the owner window
  621. // :fparam name='flStyle' type='ULONG' io='input' .
  622. // Style flags of the ucmenu window, combination of WS_ flags and CMS_VERT CMS_HORZ or CMS_MATRIX
  623. // :fparam name='x' type='ULONG' io='input'.
  624. // x coordinate of ucmenu window position
  625. // :fparam name='y' type='ULONG' io='input'.
  626. // y coordinate of ucmenu window position
  627. // :fparam name='cx' type='ULONG' io='input'.
  628. // width of the ucmenu window, ignored if vertical or matrix ucmenu
  629. // :fparam name='cy' type='ULONG' io='input'.
  630. // height of the ucmenu window, ignored if horizontal or matrix ucmenu
  631. // :fparam name='hInsertBehind' type='ULONG' io='input'.
  632. // Sibling window behind which the ucmenu is placed, can also be HWND_TOP or HWND_BOTTOM.
  633. // :fparam name='ulID' type='ULONG' io='input'.
  634. // ID given to the ucmenu.
  635. // :fparam name='hmodResource' type='HMODULE' io='input'.
  636. // Handle of the module where the menu resource is to be found.
  637. // :fparam name='usMenuID' type='USHORT' io='input'.
  638. // ID of the resource menu used as a template to create the ucmenu.
  639. // :fparam name='pUCMInfo' type='PUCMINFO' io='input'.
  640. // Pointer to the ucmenu creation structure
  641. // :fparam name='phTextMenu' type='PHWND' io='output'.
  642. // Handle of the menu loaded from the resource.
  643. // It should normally not be used.
  644. // :freturns.
  645. // :fparam name='hUCMenu' type='PSZ' io='return'.
  646. // Handle of the ucmenu or zero if the creation failed.
  647. // :efparams.
  648. // :remarks.
  649. // :related.
  650. // UCMInfo
  651. // :efunction.
  652. //----------------------------------------------------------------------------
  653. HWND    APIENTRY UCMenuCreateFromResource(HAB hab, HWND hParent, HWND hOwner,
  654.                                           ULONG ulStyle, LONG x, LONG y, LONG cx, LONG cy,
  655.                                           HWND hInsertBehind, ULONG ulID,
  656.                                           HMODULE hmodResource, USHORT usMenuID,
  657.                                           PUCMINFO pUCMInfo, PHWND phTextMenu )
  658. {
  659.    HWND     hMenu;
  660.    ERRORID  err;
  661.  
  662.    hMenu = WinLoadMenu( HWND_OBJECT, hmodResource, usMenuID );
  663.  
  664.    if ( hMenu ){
  665.       UCMINFO2 UCMInfo2;
  666.  
  667.       WinSetWindowUShort( hMenu, QWS_ID, (USHORT)ulID );
  668.  
  669.       UCMInfo2.cb = sizeof( UCMINFO2 );
  670.       UCMInfo2.hwndMenu = hMenu;
  671.       UCMInfo2.hModule              = pUCMInfo->hModule;
  672.       UCMInfo2.NbOfCols             = pUCMInfo->NbOfCols;
  673.       UCMInfo2.NbOfRows             = pUCMInfo->NbOfRows;
  674.       UCMInfo2.pszBitmapSearchPath  = pUCMInfo->pszBitmapSearchPath;
  675.       UCMInfo2.pszDefaultBitmap     = pUCMInfo->pszDefaultBitmap;
  676.       UCMInfo2.Style                = pUCMInfo->Style;
  677.       UCMInfo2.cx                   = pUCMInfo->cx;
  678.       UCMInfo2.cy                   = pUCMInfo->cy;
  679.       UCMInfo2.BgBmp                = pUCMInfo->BgBmp;
  680.       UCMInfo2.BgColor              = pUCMInfo->BgColor;
  681.       UCMInfo2.ItemBgColor          = pUCMInfo->ItemBgColor;
  682.       UCMInfo2.pszFontNameSize      = pUCMInfo->pszFontNameSize;
  683.       UCMInfo2.BubbleDelay          = pUCMInfo->BubbleDelay;  // V2.04 
  684.       UCMInfo2.BubbleRead           = pUCMInfo->BubbleRead;   // V2.04
  685.       UCMInfo2.hModUCM              = pUCMInfo->hModUCM;      // V2.04 
  686.       UCMInfo2.ulTmplVersion        = UCMTMPLVERSION;
  687.  
  688.       *phTextMenu = hMenu;
  689.       return UCMenuCreate( hab, hParent,  hOwner, ulStyle, x, y, cx, cy,
  690.                            hInsertBehind, ulID, &UCMInfo2 );
  691.    } else {
  692.       return NULLHANDLE;
  693.    } // endif
  694.  
  695. }
  696.  
  697. //----------------------------------------------------------------------------
  698. // UCMenuCreateFromHMenu
  699. //----------------------------------------------------------------------------
  700. // :function res=&IDF_UCMCREATEHMENU. name='UCMenuCreateFromHMenu' text='Create a ucmenu from a menu handle'.
  701. // This function creates a ucmenu using an already loaded or created menu.
  702. // :syntax name='UCMenuCreateFromHMenu' params='hab hParent hOwner ulStyle x y cx cy hInsertBehind ulID  hMenu pUCMInfo' return='hUCMenu'.
  703. // :fparams.
  704. // :fparam name='hab' type='HAB' io='input' .
  705. // Handle of the anchor-block.
  706. // :fparam name='hParent' type='HWND' io='input' .
  707. // Handle of the parent window
  708. // :fparam name='hOwner' type='HWND' io='input' .
  709. // Handle of the owner window
  710. // :fparam name='flStyle' type='ULONG' io='input' .
  711. // Style flags of the ucmenu window, combination of WS_ flags and CMS_VERT CMS_HORZ or CMS_MATRIX
  712. // :fparam name='x' type='ULONG' io='input'.
  713. // x coordinate of ucmenu window position
  714. // :fparam name='y' type='ULONG' io='input'.
  715. // y coordinate of ucmenu window position
  716. // :fparam name='cx' type='ULONG' io='input'.
  717. // width of the ucmenu window, ignored if vertical or matrix ucmenu
  718. // :fparam name='cy' type='ULONG' io='input'.
  719. // height of the ucmenu window, ignored if horizontal or matrix ucmenu
  720. // :fparam name='hInsertBehind' type='ULONG' io='input'.
  721. // Sibling window behind which the ucmenu is placed, can also be HWND_TOP or HWND_BOTTOM.
  722. // :fparam name='ulID' type='ULONG' io='input'.
  723. // ID given to the ucmenu.
  724. // :fparam name='hMenu' type='HWND' io='input'.
  725. // Handle of the menu used as a template to create the ucmenu
  726. // :fparam name='pUCMInfo' type='PUCMINFO' io='input'.
  727. // Pointer to the ucmenu creation structure
  728. // :freturns.
  729. // :fparam name='hUCMenu' type='PSZ' io='return'.
  730. // Handle of the ucmenu or zero if the creation failed.
  731. // :efparams.
  732. // :remarks.
  733. // It is useful in case you want to create a void ucmenu and dynamically fill it.
  734. // :related.
  735. // UCMInfo
  736. // :efunction.
  737. //----------------------------------------------------------------------------
  738. HWND    APIENTRY UCMenuCreateFromHMenu( HAB hab, HWND hParent, HWND hOwner,
  739.                                         ULONG ulStyle, LONG x, LONG y, LONG cx, LONG cy,
  740.                                         HWND hInsertBehind, ULONG ulID,
  741.                                         HWND hMenu, PUCMINFO pUCMInfo )
  742. {
  743.    if ( hMenu ){
  744.       UCMINFO2 UCMInfo2;
  745.  
  746.       UCMInfo2.cb = sizeof( UCMINFO2 );
  747.       UCMInfo2.hwndMenu = hMenu;
  748.       UCMInfo2.hModule              = pUCMInfo->hModule;
  749.       UCMInfo2.NbOfCols             = pUCMInfo->NbOfCols;
  750.       UCMInfo2.NbOfRows             = pUCMInfo->NbOfRows;
  751.       UCMInfo2.pszBitmapSearchPath  = pUCMInfo->pszBitmapSearchPath;
  752.       UCMInfo2.pszDefaultBitmap     = pUCMInfo->pszDefaultBitmap;
  753.       UCMInfo2.Style                = pUCMInfo->Style;
  754.       UCMInfo2.cx                   = pUCMInfo->cx;
  755.       UCMInfo2.cy                   = pUCMInfo->cy;
  756.       UCMInfo2.BgBmp                = pUCMInfo->BgBmp;
  757.       UCMInfo2.BgColor              = pUCMInfo->BgColor;
  758.       UCMInfo2.ItemBgColor          = pUCMInfo->ItemBgColor;
  759.       UCMInfo2.pszFontNameSize      = pUCMInfo->pszFontNameSize;
  760.       UCMInfo2.BubbleDelay          = pUCMInfo->BubbleDelay;  // V2.04 
  761.       UCMInfo2.BubbleRead           = pUCMInfo->BubbleRead;   // V2.04
  762.       UCMInfo2.hModUCM              = pUCMInfo->hModUCM;      // V2.04 
  763.       UCMInfo2.ulTmplVersion        = UCMTMPLVERSION;
  764.       return UCMenuCreate( hab, hParent,  hOwner, ulStyle, x, y, cx, cy,
  765.                            hInsertBehind, ulID, &UCMInfo2 );
  766.    } else {
  767.       return NULLHANDLE;
  768.    } // endif
  769.  
  770. }
  771.  
  772.  
  773. //----------------------------------------------------------------------------
  774. // UCMenuCreateFromTemplate
  775. //----------------------------------------------------------------------------
  776. // :function res=&IDF_UCMCREATETMPL. name='UCMenuCreateFromTemplate' text='Create a ucmenu from a menu template'.
  777. // This function creates a ucmenu using a menu template stored in the resources.
  778. // :syntax name='UCMenuCreateFromTemplate' params='hab hParent hOwner ulStyle x y cx cy hInsertBehind ulID pMenuTemplate pUCMInfo phTextMenu' return='hUCMenu' .
  779. // :fparams.
  780. // :fparam name='hab' type='HAB' io='input' .
  781. // Handle of the anchor-block.
  782. // :fparam name='hParent' type='HWND' io='input' .
  783. // Handle of the parent window
  784. // :fparam name='hOwner' type='HWND' io='input' .
  785. // Handle of the owner window
  786. // :fparam name='flStyle' type='ULONG' io='input' .
  787. // Style flags of the ucmenu window, combination of WS_ flags and CMS_VERT CMS_HORZ or CMS_MATRIX
  788. // :fparam name='x' type='ULONG' io='input'.
  789. // x coordinate of ucmenu window position
  790. // :fparam name='y' type='ULONG' io='input'.
  791. // y coordinate of ucmenu window position
  792. // :fparam name='cx' type='ULONG' io='input'.
  793. // width of the ucmenu window, ignored if vertical or matrix ucmenu
  794. // :fparam name='cy' type='ULONG' io='input'.
  795. // height of the ucmenu window, ignored if horizontal or matrix ucmenu
  796. // :fparam name='hInsertBehind' type='ULONG' io='input'.
  797. // Sibling window behind which the ucmenu is placed, can also be HWND_TOP or HWND_BOTTOM.
  798. // :fparam name='ulID' type='ULONG' io='input'.
  799. // ID given to the ucmenu.
  800. // :fparam name='pmtMenuTemplate' type='PVOID' io='input'.
  801. // Pointer to the menu template in binary format
  802. // :fparam name='pUCMInfo' type='PUCMINFO' io='input'.
  803. // Pointer to the ucmenu creation structure
  804. // :fparam name='phTextMenu' type='PHWND' io='output'.
  805. // Handle of the menu loaded from the resource.
  806. // It should normally not be used.
  807. // :freturns.
  808. // :fparam name='hUCMenu' type='PSZ' io='return'.
  809. // Handle of the ucmenu or zero if the creation failed.
  810. // :efparams.
  811. // :remarks.
  812. // :related.
  813. // UCMInfo
  814. // :efunction.
  815. //----------------------------------------------------------------------------
  816. HWND    APIENTRY UCMenuCreateFromTemplate(HAB hab, HWND hParent, HWND hOwner,
  817.                                           ULONG ulStyle, LONG x, LONG y, LONG cx, LONG cy,
  818.                                           HWND hInsertBehind, ULONG ulID,
  819.                                           PVOID pmtMenuTemplate,
  820.                                           PUCMINFO pUCMInfo, PHWND phTextMenu )
  821. {
  822.    HWND     hMenu;
  823.    UCMINFO2 UCMInfo2;
  824.  
  825.  
  826.    if ( *( (PULONG)pmtMenuTemplate ) == UCMTMPLSIG ){
  827.       UCMInfo2.ulTmplVersion = *( (PULONG)( (PBYTE)pmtMenuTemplate + 4 ) );
  828.       hMenu = WinCreateMenu( HWND_OBJECT, (PVOID)((PBYTE)pmtMenuTemplate+8) );
  829.    } else {
  830. //      UCMInfo2.ulTmplVersion = 0;
  831. //      hMenu = WinCreateMenu( HWND_OBJECT, pmtMenuTemplate );
  832.       return NULLHANDLE;
  833.    } // endif
  834.  
  835.    if ( hMenu ){
  836.  
  837.       WinSetWindowUShort( hMenu, QWS_ID, (USHORT)ulID );
  838.  
  839.       UCMInfo2.cb = sizeof( UCMINFO2 );
  840.       UCMInfo2.hwndMenu = hMenu;
  841.       UCMInfo2.hModule              = pUCMInfo->hModule;
  842.       UCMInfo2.NbOfCols             = pUCMInfo->NbOfCols;
  843.       UCMInfo2.NbOfRows             = pUCMInfo->NbOfRows;
  844.       UCMInfo2.pszBitmapSearchPath  = pUCMInfo->pszBitmapSearchPath;
  845.       UCMInfo2.pszDefaultBitmap     = pUCMInfo->pszDefaultBitmap;
  846.       UCMInfo2.Style                = pUCMInfo->Style;
  847.       UCMInfo2.cx                   = pUCMInfo->cx;
  848.       UCMInfo2.cy                   = pUCMInfo->cy;
  849.       UCMInfo2.BgBmp                = pUCMInfo->BgBmp;
  850.       UCMInfo2.BgColor              = pUCMInfo->BgColor;
  851.       UCMInfo2.ItemBgColor          = pUCMInfo->ItemBgColor;
  852.       UCMInfo2.pszFontNameSize      = pUCMInfo->pszFontNameSize;
  853.       UCMInfo2.BubbleDelay          = pUCMInfo->BubbleDelay;  // V2.04 
  854.       UCMInfo2.BubbleRead           = pUCMInfo->BubbleRead;   // V2.04
  855.       UCMInfo2.hModUCM              = pUCMInfo->hModUCM;      // V2.04 
  856.       *phTextMenu = hMenu;
  857.       return UCMenuCreate( hab, hParent,  hOwner, ulStyle, x, y, cx, cy,
  858.                            hInsertBehind, ulID, &UCMInfo2 );
  859.    } else {
  860.       return NULLHANDLE;
  861.    } // endif
  862.  
  863. }
  864.  
  865. //----------------------------------------------------------------------------
  866. // UCMenuCreate
  867. //----------------------------------------------------------------------------
  868. // :pfunction res=&IDF_UCMCREATE. name='UCMenuCreate' text='Create a ucmenu from a menu'.
  869. // This function creates a ucmenu using a menu already loaded.
  870. // :syntax name='UCMenuCreateFromTemplate' params='hab hParent hOwner ulStyle x y cx cy hInsertBehind ulID pUCMInfo2 ' return='hUCMenu' .
  871. // :fparams.
  872. // :fparam name='hab' type='HAB' io='input' .
  873. // Handle of the anchor-block.
  874. // :fparam name='hParent' type='HWND' io='input' .
  875. // Handle of the parent window
  876. // :fparam name='hOwner' type='HWND' io='input' .
  877. // Handle of the owner window
  878. // :fparam name='flStyle' type='ULONG' io='input' .
  879. // Style flags of the ucmenu window, combination of WS_ flags and CMS_VERT CMS_HORZ or CMS_MATRIX
  880. // :fparam name='x' type='ULONG' io='input'.
  881. // x coordinate of ucmenu window position
  882. // :fparam name='y' type='ULONG' io='input'.
  883. // y coordinate of ucmenu window position
  884. // :fparam name='cx' type='ULONG' io='input'.
  885. // width of the ucmenu window, ignored if vertical or matrix ucmenu
  886. // :fparam name='cy' type='ULONG' io='input'.
  887. // height of the ucmenu window, ignored if horizontal or matrix ucmenu
  888. // :fparam name='hInsertBehind' type='ULONG' io='input'.
  889. // Sibling window behind which the ucmenu is placed, can also be HWND_TOP or HWND_BOTTOM.
  890. // :fparam name='ulID' type='ULONG' io='input'.
  891. // ID given to the ucmenu.
  892. // :fparam name='pUCMInfo2' type='PUCMINFO2' io='input'.
  893. // Pointer to the ucmenu creation structure
  894. // :freturns.
  895. // :fparam name='hUCMenu' type='PSZ' io='return'.
  896. // Handle of the ucmenu or zero if the creation failed.
  897. // :efparams.
  898. // :remarks.
  899. // :related.
  900. // :epfunction.
  901. //----------------------------------------------------------------------------
  902. HWND    _Optlink UCMenuCreate( HAB hab, HWND hParent, HWND hOwner,
  903.                                ULONG ulStyle, LONG x, LONG y, LONG cx, LONG cy,
  904.                                HWND hInsertBehind, ULONG ulID,
  905.                                PUCMINFO2 pUCMInfo2 )
  906. {
  907.  
  908.  
  909.  /* Register UCMenu class with storage for 2 pointers */
  910.  
  911.  /* (MAM) Note we must always register the class, even if it already */
  912.  /* exists.  Otherwise an app might free and reload the UCMenus DLL  */
  913.  /* in the same process and the class window proc pointer would be   */
  914.  /* out of date.  Reregistration will replace existing class parms.  */
  915.  
  916.  if ( !WinRegisterClass( hab, UCMCLASS, (PFNWP)UCMenuWndProc, (ULONG)CS_SIZEREDRAW, (ULONG)(2*sizeof(PVOID)) ) ) {
  917.     return NULLHANDLE;
  918.  } // endif
  919.  
  920.  return  WinCreateWindow( hParent,
  921.                           UCMCLASS,
  922.                           "",
  923.                           ulStyle,
  924.                           x,
  925.                           y,
  926.                           cx,
  927.                           cy,
  928.                           hOwner,
  929.                           hInsertBehind,
  930.                           ulID,
  931.                           (PVOID)pUCMInfo2,
  932.                           NULL );
  933.  
  934. }
  935.  
  936. //----------------------------------------------------------------------------
  937. // UCMenuLoadBitmap
  938. //----------------------------------------------------------------------------
  939. // :function res=&IDF_LOADBIT. name='UCMenuLoadBitmap' text='Loads a bitmap'.
  940. // This function loads a bitmap from a file and returns its handle.
  941. // :syntax name='UCMenuLoadBitmap' params='pszFileName' return='hBitmap' .
  942. // :fparams.
  943. // :fparam name='pszFileName' type='PSZ' io='input' .
  944. // Name of the file to load.
  945. // :freturns.
  946. // :fparam name='hBitmap' type='LONG' io='return'.
  947. // Bit-map handle (0 if error)
  948. // :efparams.
  949. // :remarks.
  950. // If there is an array of bitmaps, the bitmap the most appropriate to the
  951. // current display will be chosen.
  952. // :related.
  953. // :efunction.
  954. //----------------------------------------------------------------------------
  955. LONG APIENTRY    UCMenuLoadBitmap(PSZ pszFileName)
  956. {
  957.   HBITMAP                 hBmp = 0;
  958.   FILEHANDLE              File;
  959.   ULONG                   rc;
  960.   USHORT                  usType = 0;           // #@!!! compiler warnings
  961.   PBITMAPARRAYFILEHEADER2 pbafh2 = NULL;        // (MAM) chng init values to NULL instead of ptr to 0
  962.   PBITMAPFILEHEADER2      pbfh2  = NULL;                       
  963.   PBITMAPINFOHEADER2      pbih2  = NULL;                       
  964.   PBITMAPINFO2            pbmi2  = NULL;                       
  965.   PBITMAPARRAYFILEHEADER  pbafh  = NULL;                       
  966.   PBITMAPFILEHEADER       pbfh   = NULL;                       
  967.   PBITMAPINFOHEADER       pbih   = NULL;                       
  968.   BOOL                    f2;        // format 1.x or 2.x
  969.   ULONG                   ulOffset;
  970.   PBYTE                   pData  = NULL;
  971.   ULONG                   ulDataSize;
  972.   SIZEL                   sizel;
  973.   HPS                     hPS = WinGetPS(HWND_DESKTOP);
  974.  
  975.   /* If this is not a .BMP file, let PM try to extract an icon from it */
  976.   //...removed because bitmaps made from icons have black backgrounds
  977.   //...unless you do a lot more work to mask the background bits.
  978. //{
  979. //  char *BmpFn;
  980. //  BmpFn = strdup(pszFileName);
  981. //  AnsiUpperBuff(BmpFn, strlen(BmpFn));
  982. //  if (strstr(BmpFn, ".BMP")==NULL) {
  983. //    HPOINTER Icon;
  984. //    POINTERINFO IconInfo;
  985. //    HBITMAP  IconBmp = 0;
  986. //
  987. //    free(BmpFn);
  988. //    Icon = WinLoadFileIcon(pszFileName, TRUE);
  989. //    if (Icon != 0) {
  990. //      if (WinQueryPointerInfo(Icon, &IconInfo)) {
  991. //        if ((IconInfo.hbmPointer!=0) && (IconInfo.hbmColor!=0)) {
  992. //          IconBmp = IconInfo.hbmColor;
  993. //          //...what we should do here to get a good bitmap from a file, is
  994. //          //...use the hbmPointer bitmap (which is a 2X high monochrome bitmap
  995. //          //...consisting of and AND mask and an XOR mask) and the hbmColor
  996. //          //...bitmap and create a new bitmap that has the background bits set
  997. //          //...to the background color.  The black pixels of the AND mask indicate
  998. //          //...background pixels of the color bitmap.
  999. //          //...Hummm... maybe can use WinDrawPointer() to do all this for us,
  1000. //          //...and draw into a bitmap which is pre-filled w/the background color?
  1001. //        }
  1002. //        WinFreeFileIcon(Icon);
  1003. //      }
  1004. //    }
  1005. //
  1006. //    return IconBmp; // Return file bitmap if we found it
  1007. //  }
  1008. //  free(BmpFn);
  1009. //}
  1010.  
  1011.   //--- open the file
  1012.   File = OPENREAD(pszFileName);
  1013.   if (File == NULLFILE) goto ExitLoadBMP;
  1014.  
  1015.   /* Read image type, and reset the stream...................................*/
  1016.   /* The image type is a USHORT, so we only read that........................*/
  1017.   rc = READFILE(&usType, 1, sizeof(usType), File);
  1018.   if (rc != sizeof(usType)) goto ExitLoadBMP;
  1019.  
  1020.  
  1021.   /* Next read the bitmap info header........................................*/
  1022.   // we allocate enough to hold a complete bitmap array file header
  1023.   pbafh2 = (PBITMAPARRAYFILEHEADER2)MyMalloc(sizeof(*pbafh2)+256*sizeof(RGB2));
  1024.   if (!pbafh2) goto ExitLoadBMP;
  1025.   /* Next we assign pointers to the file header and bitmap info header...*/
  1026.   /* Both the 1.x and 2.x structures are assigned just in case...........*/
  1027.   pbfh2 = &pbafh2->bfh2;
  1028.   pbih2 = &pbfh2->bmp2;
  1029.   pbmi2 = (PBITMAPINFO2)pbih2;
  1030.   pbafh = (PBITMAPARRAYFILEHEADER)pbafh2;
  1031.   pbfh  = &pbafh->bfh;
  1032.   pbih  = &pbfh->bmp;
  1033.   switch (usType) {
  1034.     case BFT_BMAP:
  1035.     case BFT_ICON:
  1036.     case BFT_POINTER:
  1037.     case BFT_COLORICON:
  1038.     case BFT_COLORPOINTER: {
  1039.       /* Now we assume the image is a 2.0 image and so we read a bitmap-file-*/
  1040.       /* Now we reset the stream, next we'll read the bitmap info header. To do .*/
  1041.       /* this we need to reset the stream to 0...................................*/
  1042.       rc = fseek(File, 0, SEEK_SET);
  1043.       if (!SEEKOK(rc)) goto ExitLoadBMP;
  1044.       /*-header-2 structure..................................................*/
  1045.       rc = READFILE(pbfh2, 1, sizeof(*pbfh2), File);
  1046.       if (rc != sizeof(*pbfh2)) goto ExitLoadBMP;
  1047.  
  1048.       f2 = pbih2->cbFix > sizeof(*pbih); // 1.x or 2.x bitmap
  1049.       /* We will need to read the color table. Thus we position the stream...*/
  1050.       /* so that the next read will read IT. This, of course, depends on the.*/
  1051.       /* type of the bitmap (old vs new), note that in the NEW case, we can..*/
  1052.       /* not be certain of the size of the bitmap header.....................*/
  1053.       ulOffset = (f2) ? sizeof(*pbfh2) + pbih->cbFix - sizeof(*pbih2):
  1054.                         sizeof(*pbfh);
  1055.     } break;
  1056.  
  1057.     case BFT_BITMAPARRAY: {
  1058.       /* Now we are dealing with a bitmap array. This is a collection of ....*/
  1059.       /* bitmap files and each has its own file header.......................*/
  1060.       BOOL   bBest = FALSE;
  1061.       ULONG  ulCurOffset, ulOffsetTemp = 0;
  1062.       LONG   lScreenWidth;
  1063.       LONG   lScreenHeight;
  1064.       LONG   lClrsDev, lClrsTemp = 0;
  1065.       LONG   lClrs;
  1066.       ULONG  ulSizeDiff, ulSizeDiffTemp = 0xffffffff;
  1067.       HDC    hdc;
  1068.  
  1069.       // -- We will browse through the array and chose the bitmap best suited
  1070.       // -- for the current display size and color capacities.
  1071.       hdc = GpiQueryDevice( hPS );
  1072.       DevQueryCaps( hdc, CAPS_COLORS, 1, &lClrsDev );
  1073.       DevQueryCaps( hdc, CAPS_WIDTH,  1, &lScreenWidth );
  1074.       DevQueryCaps( hdc, CAPS_HEIGHT, 1, &lScreenHeight );
  1075.       pbafh2->offNext = 0;
  1076.       do {
  1077.          ulCurOffset = pbafh2->offNext;
  1078.          rc = fseek( File, pbafh2->offNext, SEEK_SET );
  1079.          if ( !SEEKOK(rc) ){
  1080.             goto ExitLoadBMP;
  1081.          } // endif
  1082.          rc = READFILE( pbafh2, 1, sizeof(*pbafh2), File );
  1083.          if ( rc != sizeof(*pbafh2) ){
  1084.             goto ExitLoadBMP;
  1085.          } // endif
  1086.          f2 = pbih2->cbFix > sizeof(*pbih);
  1087.          if ( f2 ){
  1088.           lClrs = 1 << ( pbafh2->bfh2.bmp2.cBitCount * pbafh2->bfh2.bmp2.cPlanes);
  1089.          } else {
  1090.           lClrs = 1 << ( pbafh->bfh.bmp.cBitCount * pbafh->bfh.bmp.cPlanes);
  1091.          } //endif
  1092.          if ( ( pbafh2->cxDisplay == 0 ) && ( pbafh2->cyDisplay == 0 ) ) {
  1093.             // This is a device independant bitmap
  1094.             // Process it as a VGA
  1095.             pbafh2->cxDisplay = 640;
  1096.             pbafh2->cyDisplay = 480;
  1097.          } // endif
  1098.          ulSizeDiff = abs( pbafh2->cxDisplay - lScreenWidth ) + abs( pbafh2->cyDisplay - lScreenHeight );
  1099.          if ( ( lClrsDev == lClrs ) &&
  1100.               ( ulSizeDiff == 0 ) ){
  1101.             // We found the perfect match
  1102.             bBest = TRUE;
  1103.             ulOffsetTemp = ulCurOffset;
  1104.          } else {
  1105.             if (    ( ulOffsetTemp == 0 )                                // First time thru
  1106.                  || ( ulSizeDiff < ulSizeDiffTemp )                      // Better fit than any previous
  1107.                  || ( ( lClrs > lClrsTemp ) && ( lClrs < lClrsDev ) )    // More colors than prev & less than device
  1108.                  || ( ( lClrs < lClrsTemp ) && ( lClrs > lClrsDev ) ) ){
  1109.               ulOffsetTemp = ulCurOffset;                                // Make this our current pick
  1110.               lClrsTemp   = lClrs;
  1111.               ulSizeDiffTemp = ulSizeDiff;
  1112.            } // endif
  1113.          } // endif
  1114.       } while ( ( pbafh2->offNext != 0 ) && !bBest ); // enddo
  1115.  
  1116.       // Now retrieve the best bitmap
  1117.       rc = fseek( File, ulOffsetTemp, SEEK_SET );
  1118.       if ( !SEEKOK(rc) ){
  1119.          goto ExitLoadBMP;
  1120.       } // endif
  1121.       rc = READFILE( pbafh2, 1, sizeof(*pbafh2), File );
  1122.       if ( rc != sizeof(*pbafh2) ){
  1123.          goto ExitLoadBMP;
  1124.       } // endif
  1125.  
  1126.       f2 = pbih2->cbFix > sizeof(*pbih);
  1127.       /* as before, we calculate where to position the stream in order to ...*/
  1128.       /* read the color table information....................................*/
  1129.       ulOffset = ulOffsetTemp;
  1130.       ulOffset += (f2) ? sizeof(*pbafh2) + pbih2->cbFix - sizeof(*pbih2):
  1131.                          sizeof(*pbafh);
  1132.     } break;
  1133.  
  1134.    default:
  1135.      goto ExitLoadBMP;
  1136.   } /* endswitch */
  1137.   /* We now position the stream on the color table information...............*/
  1138.   rc = fseek(File, ulOffset, SEEK_SET);
  1139.   if (!SEEKOK(rc)) goto ExitLoadBMP;
  1140.  
  1141.   /* Read the color table....................................................*/
  1142.   if (f2) {
  1143.     /* For a 2.0 bitmap, all we need to do is read the color table...........*/
  1144.     /* The bitmap info structure is just the header + color table............*/
  1145.     // If we have 24 bits per pel, there is usually no color table, unless
  1146.     // pbih2->cclrUsed or pbih2->cclrImportant are non zero, we should
  1147.     // test that !
  1148.     if ( pbih2->cBitCount <24 ) {
  1149.        ULONG ul = (1 << pbih2->cBitCount) * sizeof(RGB2);
  1150.        rc = READFILE(&pbmi2->argbColor[0], 1, ul, File);
  1151.        if (rc != ul) goto ExitLoadBMP;
  1152.     } // endif
  1153.     /* remember the bitmap info we mentioned just above?.....................*/
  1154.     pbmi2 = (PBITMAPINFO2)pbih2;
  1155.   } else {
  1156.     /* This is an old format bitmap. Since the common format is the 2.0......*/
  1157.     /* We have to convert all the RGB entries to RGB2........................*/
  1158.     ULONG ul, cColors;
  1159.     RGB   rgb;
  1160.     if (pbih->cBitCount <24)
  1161.       cColors = 1 << pbih->cBitCount;
  1162.     else
  1163.     // If there are 24 bits per pel, the 24 bits are assumed to be a RGB value
  1164.       cColors = 0;
  1165.     /* Loop over the original table and create the new table, the extra byte.*/
  1166.     /* has to be 0...........................................................*/
  1167.     for (ul = 0; ul < cColors; ul++) {
  1168.       READFILE(&rgb, 1, sizeof(rgb), File);
  1169.       pbmi2->argbColor[ul].bRed      = rgb.bRed;
  1170.       pbmi2->argbColor[ul].bGreen    = rgb.bGreen;
  1171.       pbmi2->argbColor[ul].bBlue     = rgb.bBlue;
  1172.       pbmi2->argbColor[ul].fcOptions = 0;
  1173.     } /* endfor */
  1174.  
  1175.     // we have to convert the old to the new version header
  1176.     pbmi2->cbFix = sizeof(*pbih2);
  1177.     pbmi2->cBitCount = pbih->cBitCount;
  1178.     pbmi2->cPlanes = pbih->cPlanes;
  1179.     pbmi2->cy = pbih->cy;
  1180.     pbmi2->cx = pbih->cx;
  1181.     // set rest to zero
  1182.     memset((PCHAR)pbmi2 +16, 0, sizeof(*pbih2)-16);
  1183.   } /* endif */
  1184.  
  1185.   /* We have the 2.0 bitmap info structure set...............................*/
  1186.   /* move to the stream to the start of the bitmap data......................*/
  1187.   rc = fseek(File, pbfh2->offBits, SEEK_SET);
  1188.   if (!SEEKOK(rc)) goto ExitLoadBMP;
  1189.  
  1190.   /* Read the bitmap data, the read size is derived using the magic formula..*/
  1191.   /* The bitmap scan line is aligned on a doubleword boundary................*/
  1192.   /* The size of the scan line is the number of pels times the bpp...........*/
  1193.   /* After aligning it, we divide by 4 to get the number of bytes, and.......*/
  1194.   /* multiply by the number of scan lines and the number of pel planes.......*/
  1195.   if ( pbmi2->ulCompression ){
  1196.      ulDataSize = pbmi2->cbImage;
  1197.   } else {
  1198.      ulDataSize = (((pbmi2->cBitCount * pbmi2->cx) + 31) / 32) * 4 *
  1199.                    pbmi2->cy * pbmi2->cPlanes;
  1200.   } /* endif */
  1201.   pData = (PBYTE)MyMalloc(ulDataSize);
  1202.   if (!pData) goto ExitLoadBMP;
  1203.   rc = READFILE(pData, 1, ulDataSize, File);
  1204.   if (rc != ulDataSize) goto ExitLoadBMP;
  1205.  
  1206.   /* Now, we create the bitmap...............................................*/
  1207.   sizel.cx = pbmi2->cx;
  1208.   sizel.cy = pbmi2->cy;
  1209.  
  1210.   hBmp= GpiCreateBitmap(hPS, (PBITMAPINFOHEADER2)pbmi2, CBM_INIT, pData, pbmi2);
  1211.  
  1212.   ExitLoadBMP:
  1213.   if (pData) MyFree(pData);
  1214.   if (pbafh2) MyFree(pbafh2);
  1215.   CLOSEFILE(File);
  1216.   WinReleasePS(hPS);
  1217.   return(hBmp);
  1218. }
  1219.  
  1220.  
  1221.  
  1222. //----------------------------------------------------------------------------
  1223. // UCMenuSelectColor : internal function (no entry in the user's doc)
  1224. //----------------------------------------------------------------------------
  1225. // :pfunction res=&IDF_SELCOL. name='UCMenuSelectColor' text='Add a entry in the color palette'.
  1226. // This function add an entry in the color palette
  1227. // :syntax name='UCMenuSelectColor' params='Color, hps' return='colorIndex' .
  1228. // :fparams.
  1229. // :fparam name='Color' type='LONG' io='input' .
  1230. // RGB value of the chosen color
  1231. // :fparam name='hps' type='HPS' io='input' .
  1232. // HPS in which indexed color palette we add an entry
  1233. // :freturns.
  1234. // :fparam name='colorIndex' type='ULONG' io='return'.
  1235. // Index of the added color
  1236. // :efparams.
  1237. // :remarks.
  1238. // :related.
  1239. // :epfunction.
  1240. //----------------------------------------------------------------------------
  1241. ULONG _Optlink       UCMenuSelectColor(LONG Color, HPS hps)
  1242. {
  1243.    LONG  alArray[4];
  1244.  
  1245.    // ------------------------------------------------------------------------------------------
  1246.    // -- Toolkit 2.1 bug "GpiQueryColorData" in pmgpi.h and "GpiQueryColordata" in os2386.lib !!
  1247.    // -- -> prototype added in ucmenus.c
  1248.    // ------------------------------------------------------------------------------------------
  1249.    GpiQueryColordata(hps, 3L, alArray);
  1250.    GpiCreateLogColorTable( hps,
  1251.                            0L,
  1252.                            LCOLF_CONSECRGB,
  1253.                            alArray[QCD_LCT_HIINDEX] + 1,
  1254.                            1L,
  1255.                            &Color );
  1256.  
  1257.    return (alArray[QCD_LCT_HIINDEX]+1);
  1258.  
  1259. }
  1260.  
  1261. //----------------------------------------------------------------------------
  1262. // UCMenuSetBmpBgColor : internal function (no entry in the user's doc)
  1263. //----------------------------------------------------------------------------
  1264. // This function is called when the background color of a bitmap needs to be
  1265. // changed to match the current background face color of the toolbar.  This
  1266. // is done by reading the bitmap color table and changing the entry that
  1267. // corresponds to the bitmap background.  The bitmap is then updated with the
  1268. // new color table.
  1269. //----------------------------------------------------------------------------
  1270. VOID _Optlink UCMenuSetBmpBgColor( PUCMITEM pUCMItem, PUCMDATA UCMData, HPS hps )
  1271. {
  1272.  
  1273.   BITMAPINFOHEADER2 BmpHeader;            // Bitmap header
  1274.   PBYTE        pbBits = NULL;             // Ptr to bitmap pixel values
  1275.   PBITMAPINFO2 BmpInfo = NULL;            // Bitmap header + color table
  1276.   ULONG        BitsLen;                   // Length of bitmap pixel buffer
  1277.   ULONG        BmpInfoLen;                // Length of bitmap header + color table
  1278.   ULONG        ulMaxPaletteIndex;
  1279.  
  1280.   BmpHeader.cbFix = sizeof( BITMAPINFOHEADER2 );
  1281.   GpiQueryBitmapInfoHeader( pUCMItem->hBmp, &BmpHeader );
  1282.  
  1283.   // We can only background color map standard format bitmaps (2,16,256 color). 
  1284.   // With more work we could do 24-bit (true color) bitmaps, but it would be
  1285.   // very slow since we would have to walk the bitmap and change every pixel
  1286.   // that was in the background color.
  1287.  
  1288.   switch (BmpHeader.cBitCount) {
  1289.     case 1:
  1290.     case 4:
  1291.     case 8:
  1292.       break;    // continue and process
  1293.     default:
  1294.       return;   // no can do, just return
  1295.   }
  1296.  
  1297.   // Number of bytes in bitmap is width x bits/pel x planes x height
  1298.   // with rounding up of each line to a 4 byte boundry
  1299.   BitsLen = (((BmpHeader.cBitCount * BmpHeader.cx)+31)/32)*4  // one row on 4-byte boundry
  1300.              * BmpHeader.cPlanes                           // number of planes
  1301.              * BmpHeader.cy;                               // bitmap height
  1302.  
  1303.   // Size of BITMAPINFO2 structure we need is basic structure size plus
  1304.   // room for bitmap color table.  Color table is either the exact
  1305.   // size given in the bitmap header, or large enough to hold
  1306.   // the bigest pel index value (which depends on bits/pel). 
  1307.  
  1308.   if (BmpHeader.cclrUsed == 0)              // All index values are used
  1309.     ulMaxPaletteIndex = 1 << BmpHeader.cBitCount;
  1310.   else
  1311.     ulMaxPaletteIndex = BmpHeader.cclrUsed; // Only this many used
  1312.  
  1313.  
  1314.   BmpInfoLen = sizeof( BITMAPINFO2 ) + (sizeof( RGB2 ) * ulMaxPaletteIndex);
  1315.  
  1316.   if (   ( pbBits = (PBYTE)MyMalloc( BitsLen ) )
  1317.       && ( BmpInfo = (PBITMAPINFO2)MyMalloc( BmpInfoLen ) ) ) {
  1318.      LONG lScanRead;
  1319.      HBITMAP  hbmpOld;
  1320.  
  1321.      // Must have bitmap in memory device context to change it
  1322.      hbmpOld = GpiSetBitmap( UCMData->hpsMem, pUCMItem->hBmp );
  1323.  
  1324.      /* Copy header info to new structure with room for color table */
  1325.      *((BITMAPINFOHEADER2 *)BmpInfo) = BmpHeader;
  1326.      BmpInfo->cbFix = sizeof( BITMAPINFOHEADER2 );
  1327.  
  1328.      /* Read bitmap and fill in the color table */
  1329.      lScanRead = GpiQueryBitmapBits( UCMData->hpsMem, 0, BmpHeader.cy, pbBits, BmpInfo );
  1330.  
  1331.      if ( lScanRead == BmpHeader.cy ) {
  1332.         if (UCMData->Style & UCS_CHNGBMPBG) {  // Use app-supplied background color
  1333.           int i;
  1334.           RGB2 rgbOldBg;
  1335.  
  1336.           rgbOldBg.bRed      = (BYTE)( (UCMData->BgBmp & 0x00FF0000L)>>16 );
  1337.           rgbOldBg.bGreen    = (BYTE)( (UCMData->BgBmp & 0x0000FF00L)>>8 );
  1338.           rgbOldBg.bBlue     = (BYTE)  (UCMData->BgBmp & 0x000000FFL);
  1339.           /* Locate all color table entries for the background bitmap color */
  1340.           /* and change them to the toolbar background color.               */
  1341.           for (i=0;i<ulMaxPaletteIndex ;i++ ) {
  1342.              if (  ( BmpInfo->argbColor[i].bRed   == rgbOldBg.bRed   )
  1343.                  &&( BmpInfo->argbColor[i].bGreen == rgbOldBg.bGreen )
  1344.                  &&( BmpInfo->argbColor[i].bBlue  == rgbOldBg.bBlue  ) ) {
  1345.                 BmpInfo->argbColor[i].bRed      = (BYTE)( (UCMData->ItemBgColor & 0x00FF0000L)>>16 );
  1346.                 BmpInfo->argbColor[i].bGreen    = (BYTE)( (UCMData->ItemBgColor & 0x0000FF00L)>>8 );
  1347.                 BmpInfo->argbColor[i].bBlue     = (BYTE)  (UCMData->ItemBgColor & 0x000000FFL);
  1348.                 BmpInfo->argbColor[i].fcOptions = 0;
  1349.              } // endif
  1350.           } // endfor
  1351.  
  1352.         } // if UCS_CHNGBMPBG style
  1353.  
  1354.         else { // Must be AUTO color mapping style
  1355.           ULONG BgColorIndex;
  1356.  
  1357.           // Get first pixel value which will point to the color entry for the background
  1358.           switch (BmpHeader.cBitCount) {
  1359.             case 1:  // Monochrome (1-bit color index, MSB of 1st byte is 1st pixel)
  1360.               BgColorIndex = *pbBits >> 7;
  1361.               break;
  1362.             case 4:  // 16-color (1/2 byte color index, upper nibble is 1st pixel)
  1363.               BgColorIndex = *pbBits >> 4;
  1364.               break;
  1365.             case 8:  // 256-color (1 byte color index)
  1366.               BgColorIndex = *pbBits;
  1367.               break;
  1368.           }
  1369.           // Modify the color table with toolbar background color
  1370.           BmpInfo->argbColor[BgColorIndex].bRed      = (BYTE)( (UCMData->ItemBgColor & 0x00FF0000L)>>16 );
  1371.           BmpInfo->argbColor[BgColorIndex].bGreen    = (BYTE)( (UCMData->ItemBgColor & 0x0000FF00L)>>8 );
  1372.           BmpInfo->argbColor[BgColorIndex].bBlue     = (BYTE)  (UCMData->ItemBgColor & 0x000000FFL);
  1373.           BmpInfo->argbColor[BgColorIndex].fcOptions = 0;
  1374.         } // AUTO style
  1375.  
  1376.         /* Update the bitmap with new color table */
  1377.         GpiSetBitmapBits( UCMData->hpsMem, 0, lScanRead, pbBits, BmpInfo );
  1378.  
  1379.      } // endif
  1380.  
  1381.      GpiSetBitmap( UCMData->hpsMem, hbmpOld ); // Deselect from memory device
  1382.  
  1383.   } // endif
  1384.  
  1385.   if ( pbBits )       { MyFree( pbBits ); }
  1386.   if ( BmpInfo ) { MyFree( BmpInfo );  }
  1387.  
  1388.   return;
  1389. }
  1390.  
  1391. //----------------------------------------------------------------------------
  1392. // UCMenu3DFrame : internal function (no entry in the user's doc)
  1393. //----------------------------------------------------------------------------
  1394. // :pfunction res=&IDF_3DFRAM. name='UCMenu3DFrame' text='Draw a 3D frame'.
  1395. // This function draws a 3D frame
  1396. // :syntax name='UCMenu3DFrame' params='hps, rcl, hilited' return='-' .
  1397. // :fparams.
  1398. // :fparam name='hps' type='HPS' io='input' .
  1399. // HPS where we draw
  1400. // :fparam name='rcl' type='PRECTL' io='input' .
  1401. // Upper right exclusive rectangle of the frame
  1402. // :fparam name='hilited' type='USHORT' io='input'.
  1403. // Type of the frame&colon.
  1404. // :dl compact.
  1405. // :dt.<>0
  1406. // :dd.Hilited item
  1407. // :dt.0
  1408. // :dd.Non hilited item
  1409. // :edl.
  1410. // :freturns.
  1411. // :fparam name='-' type='VOID' io='-'.
  1412. // Nothing
  1413. // :efparams.
  1414. // :remarks.
  1415. // :related.
  1416. // :epfunction.
  1417. //----------------------------------------------------------------------------
  1418. VOID _Optlink UCMenu3DFrame(HPS hps, PRECTL rcl, USHORT hilited)
  1419. {
  1420. #if 0
  1421.    POINTL pt;
  1422.  
  1423.    pt.x = rcl->xLeft;
  1424.    pt.y = rcl->yBottom ;
  1425.    GpiMove(hps, &pt);
  1426.    pt.x  = rcl->xRight - 1;
  1427.    GpiSetColor(hps, hilited?SYSCLR_BUTTONLIGHT:SYSCLR_BUTTONDARK);
  1428.    GpiLine(hps, &pt);
  1429.    pt.y  = rcl->yTop - 1;
  1430.    GpiLine(hps, &pt);
  1431.    pt.x = rcl->xLeft;
  1432.    GpiSetColor(hps,  hilited?SYSCLR_BUTTONDARK:SYSCLR_BUTTONLIGHT);
  1433.    GpiLine(hps, &pt);
  1434.    pt.y = rcl->yBottom;
  1435.    GpiLine(hps, &pt);
  1436. #endif
  1437.    //Simpler, but undocumented PM way to draw 3D borders...
  1438.    #define DB_RAISED    0x0400
  1439.    #define DB_DEPRESSED 0x0800
  1440.    WinDrawBorder( hps, rcl, 1, 1, 0, 0, ( hilited ? DB_DEPRESSED : DB_RAISED ) );
  1441. }
  1442.  
  1443. //----------------------------------------------------------------------------
  1444. // UCMenuMakeTemplate :
  1445. //----------------------------------------------------------------------------
  1446. // :function res=&IDF_MAKETMP. name='UCMenuMakeTemplate' text='Builds a menu template'.
  1447. // This function builds the menu template associated with a specified ucmenu.
  1448. // :syntax name='UCMenuMakeTemplate' params='hwndUCMenu, pBufLen' return='pBuffer' .
  1449. // :fparams.
  1450. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  1451. // UCMenu window handle.
  1452. // :fparam name='pBufLen' type='PULONG' io='output' .
  1453. // Pointer to the ucmenu template buffer length.
  1454. // :freturns.
  1455. // :fparam name='pBuffer' type='PVOID' io='return'.
  1456. // Pointer to the template (NULL if error), has to be freed by the caller with UCMenuFree.
  1457. // :efparams.
  1458. // :remarks.
  1459. // :related.
  1460. // :efunction.
  1461. //----------------------------------------------------------------------------
  1462. PVOID APIENTRY  UCMenuMakeTemplate(HWND hwndUCMenu, PULONG pBufLen)
  1463. {
  1464.    PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwndUCMenu, QWL_UCMDATA );
  1465.    if ( UCMData && UCMData->hwndMenu ) {
  1466.       HWND hwndMenu = UCMData->hwndMenu;
  1467.       ULONG ulLen   = UCMenuTemplateLen( hwndMenu ) + 8;
  1468.       PVOID pBuf    = MyMalloc( ulLen ); // 8 is the size of the signature and version number
  1469.  
  1470.       if ( pBuf ) {
  1471.          *( (PULONG)pBuf ) = UCMTMPLSIG;
  1472.          *( (PULONG)( (PBYTE)pBuf + sizeof( ULONG ) ) ) = UCMTMPLVERSION;
  1473.  
  1474.          UCMenuMakeTemplate2( hwndMenu, (PVOID)( (PBYTE)pBuf + 8 ), 0 );
  1475.       } else {
  1476.          ulLen = 0;
  1477.       } // endif
  1478.  
  1479.       *pBufLen = ulLen;
  1480.       return pBuf;
  1481.    } else {
  1482.       *pBufLen = 0;
  1483.       return NULL;
  1484.    } // endif
  1485. }
  1486.  
  1487. //----------------------------------------------------------------------------
  1488. // UCMenuTemplateLen :
  1489. //----------------------------------------------------------------------------
  1490. // :pfunction res=&IDF_TMPLEN. name='UCMenuTemplateLen' text='Calculates the length of a template'.
  1491. // This function returns the length needed for the template associated to a ucmenu.
  1492. // :syntax name='UCMenuTemplateLen' params='hwndMenu' return='ulLen' .
  1493. // :fparams.
  1494. // :fparam name='hwndMenu' type='HWND' io='input' .
  1495. // Menu window handle.
  1496. // :freturns.
  1497. // :fparam name='BufLen' type='ULONG' io='return'.
  1498. // Length neededfor the template
  1499. // :efparams.
  1500. // :remarks.
  1501. // :related.
  1502. // :epfunction.
  1503. //----------------------------------------------------------------------------
  1504. ULONG  _Optlink UCMenuTemplateLen( HWND hwndMenu )
  1505. {
  1506.   MENUTEMPLATE  Mt;
  1507.   PMENUTEMPLATE pMt = &Mt;
  1508.   PMTI          pMti;
  1509.   MENUITEM      Mi;
  1510.   USHORT        NbOfItems = (SHORT)WinSendMsg(hwndMenu, MM_QUERYITEMCOUNT, NULL, NULL);
  1511.   USHORT        i, itemID;
  1512.   SHORT         sLen = 0;
  1513.  
  1514.   pMti = (PMTI)&(pMt->c);
  1515.  
  1516.   for (i=0 ; i<NbOfItems ; i++ ) {
  1517.     itemID = (USHORT)WinSendMsg(hwndMenu,
  1518.                                 MM_ITEMIDFROMPOSITION,
  1519.                                 MPFROMSHORT(i),
  1520.                                 NULL);
  1521.     WinSendMsg(hwndMenu,
  1522.                MM_QUERYITEM,
  1523.                MPFROM2SHORT(itemID, FALSE),
  1524.                MPFROMP(&Mi));
  1525.  
  1526.  
  1527.     if (Mi.afStyle & MIS_TEXT || Mi.afStyle & MIS_BITMAP) {
  1528.       sLen = (SHORT)WinSendMsg(hwndMenu,
  1529.                                MM_QUERYITEMTEXTLENGTH,
  1530.                                MPFROMSHORT(Mi.id),
  1531.                                NULL);
  1532.       sLen++;
  1533.     } else {
  1534.       if (Mi.afStyle & MIS_OWNERDRAW) {
  1535.         sLen = 5; // we have the 5 delimiters no matter what
  1536.         if (ITEM(&Mi, pszText)) {
  1537.           sLen += strlen(ITEM(&Mi, pszText));
  1538.         } /* endif */
  1539.  
  1540.         if (ITEM(&Mi, pszBmp)) {
  1541.           sLen += strlen(ITEM(&Mi, pszBmp));
  1542.         } /* endif */
  1543.  
  1544.         if (ITEM(&Mi, pszAction)) {
  1545.           sLen += strlen((PSZ)ITEM(&Mi, pszAction));
  1546.         } /* endif */
  1547.  
  1548.         if (ITEM(&Mi, pszParameters)) {
  1549.           sLen += strlen((PSZ)ITEM(&Mi, pszParameters));
  1550.         } /* endif */
  1551.  
  1552.         if (ITEM(&Mi, pszData)) {
  1553.           sLen += strlen((PSZ)ITEM(&Mi, pszData));
  1554.         } /* endif */
  1555.  
  1556.         sLen++;
  1557.       } else {
  1558.         sLen = 0;
  1559.       } /* endif */
  1560.     } /* endif */
  1561.  
  1562.     pMti = (PMTI)((ULONG)pMti->c + sLen);
  1563.     if (Mi.afStyle & MIS_SUBMENU) {
  1564.       pMti = (PMTI)( (ULONG)pMti + UCMenuTemplateLen( Mi.hwndSubMenu ) );
  1565.     } /* endif */
  1566.   } /* endfor */
  1567.  
  1568.   return (ULONG)pMti - (ULONG)pMt;
  1569. }
  1570.  
  1571. //----------------------------------------------------------------------------
  1572. // UCMenuMakeTemplate2 :
  1573. //----------------------------------------------------------------------------
  1574. // :pfunction res=&IDF_MAKETMP2. name='UCMenuMakeTemplate2' text='Builds a menu template'.
  1575. // This function builds the menu template associated with a specified menu.
  1576. // :syntax name='UCMenuMakeTemplate2' params='hwndMenu, pBuffer' return='pEndBuffer' .
  1577. // :fparams.
  1578. // :fparam name='hwndMenu' type='HWND' io='input' .
  1579. // Menu window handle.
  1580. // :fparam name='pBuffer' type='PVOID' io='input' .
  1581. // Pointer to the menu template buffer
  1582. // :fparam name='MenuAttr' type='SHORT' io='input'.
  1583. // MIA_SUBMENU if processing a submenu, else 0.
  1584. // :freturns.
  1585. // :fparam name='pEndBuffer' type='PVOID' io='return'.
  1586. // Pointer to the end of the template, plus one.
  1587. // :efparams.
  1588. // :remarks.
  1589. // pBuffer has to be allocated before, and freed after this call
  1590. // :related.
  1591. // :epfunction.
  1592. //----------------------------------------------------------------------------
  1593. //(MAM) Added MenuAttr parameter to detect recursive submenu processing.
  1594. PVOID _Optlink  UCMenuMakeTemplate2(HWND hwndMenu, PVOID pBuf, USHORT MenuAttr)
  1595. {
  1596.   PMENUTEMPLATE pMt = (PMENUTEMPLATE)pBuf;
  1597.   PMTI          pMti;
  1598.   MENUITEM      Mi;
  1599.   USHORT        NbOfItems = (SHORT)WinSendMsg(hwndMenu, MM_QUERYITEMCOUNT, NULL, NULL);
  1600.   USHORT        i, itemID;
  1601.   SHORT         sLen = 0, pszLen;
  1602.   UCHAR ucDelim = '\t';
  1603.  
  1604.   pMt->Version=0;
  1605.   pMt->CodePage=0x01B5;
  1606.   pMt->Offset=4;
  1607.   pMt->Count=NbOfItems;
  1608.   pMti = (PMTI)&(pMt->c);
  1609.  
  1610.   for (i=0 ; i<NbOfItems ; i++ ) {
  1611.     itemID = (USHORT)WinSendMsg(hwndMenu,
  1612.                                 MM_ITEMIDFROMPOSITION,
  1613.                                 MPFROMSHORT(i),
  1614.                                 NULL);
  1615.     WinSendMsg(hwndMenu,
  1616.                MM_QUERYITEM,
  1617.                MPFROM2SHORT(itemID, FALSE),
  1618.                MPFROMP(&Mi));
  1619.  
  1620.     pMti->afStyle     = Mi.afStyle & (USHORT)~MIS_OWNERDRAW;
  1621.     if (Mi.afStyle & MIS_OWNERDRAW) { // transform MIS_OWNERDRAW into MIS_TEXT !!
  1622.       pMti->afStyle  |= MIS_TEXT;
  1623.     } /* endif */
  1624.  
  1625.     /* Remove most attributes since app will need to reset them when menu is loaded */
  1626.     /* according to (then current) application state.                               */
  1627.     pMti->afAttribute = Mi.afAttribute & (USHORT)~MIA_CHECKED;
  1628.     pMti->afAttribute = Mi.afAttribute & (USHORT)~MIA_DISABLED;
  1629.     pMti->afAttribute = Mi.afAttribute & (USHORT)~MIA_HILITED;
  1630.  
  1631.     pMti->idItem      = Mi.id;
  1632.  
  1633.     if (Mi.afStyle & MIS_TEXT || Mi.afStyle & MIS_BITMAP) {
  1634.       sLen = (SHORT)WinSendMsg(hwndMenu,
  1635.                                MM_QUERYITEMTEXTLENGTH,
  1636.                                MPFROMSHORT(Mi.id),
  1637.                                NULL);
  1638.       WinSendMsg(hwndMenu,
  1639.                  MM_QUERYITEMTEXT,
  1640.                  MPFROM2SHORT(Mi.id, ++sLen),
  1641.                  MPFROMP(pMti->c));
  1642.     } else {
  1643.       if (Mi.afStyle & MIS_OWNERDRAW) {
  1644.         sLen = 0;
  1645.         pMti->c[0]='\0';
  1646.  
  1647. #if 0
  1648.         if (ITEM(&Mi, pszText)) {
  1649.           sLen = strlen(ITEM(&Mi, pszText));
  1650.           memcpy(pMti->c, ITEM(&Mi, pszText), sLen);
  1651.         } /* endif */
  1652. #endif
  1653.  
  1654.         if (ITEM(&Mi, pszText)) {
  1655.           pszLen = strlen(ITEM(&Mi, pszText));
  1656.           pMti->c[sLen]=ucDelim;
  1657.           memcpy(&pMti->c[++sLen], ITEM(&Mi, pszText), pszLen);
  1658.           sLen += pszLen;
  1659.         } else {
  1660.           pMti->c[sLen]=ucDelim;
  1661.           sLen++;
  1662.         } /* endif */
  1663.  
  1664.         if (ITEM(&Mi, pszBmp)) {
  1665.           pszLen = strlen(ITEM(&Mi, pszBmp));
  1666.           pMti->c[sLen]=ucDelim;
  1667.           memcpy(&pMti->c[++sLen], ITEM(&Mi, pszBmp), pszLen);
  1668.           sLen += pszLen;
  1669.         } else {
  1670.           pMti->c[sLen]=ucDelim;
  1671.           sLen++;
  1672.         } /* endif */
  1673.  
  1674.         if (ITEM(&Mi, pszAction)) {
  1675.           pszLen = strlen((PSZ)ITEM(&Mi, pszAction));
  1676.           pMti->c[sLen]=ucDelim;
  1677.           memcpy(&pMti->c[++sLen], ITEM(&Mi, pszAction), pszLen);
  1678.           sLen += pszLen;
  1679.         } else {
  1680.           pMti->c[sLen]=ucDelim;
  1681.           sLen++;
  1682.         } /* endif */
  1683.  
  1684.         if (ITEM(&Mi, pszParameters)) {
  1685.           pszLen = strlen((PSZ)ITEM(&Mi, pszParameters));
  1686.           pMti->c[sLen]=ucDelim;
  1687.           memcpy(&pMti->c[++sLen], ITEM(&Mi, pszParameters), pszLen);
  1688.           sLen += pszLen;
  1689.         } else {
  1690.           pMti->c[sLen]=ucDelim;
  1691.           sLen++;
  1692.         } /* endif */
  1693.  
  1694.         if (ITEM(&Mi, pszData)) {
  1695.           pszLen = strlen((PSZ)ITEM(&Mi, pszData));
  1696.           pMti->c[sLen]=ucDelim;
  1697.           memcpy(&pMti->c[++sLen], ITEM(&Mi, pszData), pszLen);
  1698.           sLen += pszLen;
  1699.         } else {
  1700.           pMti->c[sLen]=ucDelim;
  1701.           sLen++;
  1702.         } /* endif */
  1703.  
  1704.         pMti->c[sLen]='\0';
  1705.         sLen++;
  1706.       } else {
  1707.         pMti->c[0] = '\0';
  1708.         sLen       = 0;
  1709.       } /* endif */
  1710.     } /* endif */
  1711.  
  1712.     pMti = (PMTI)((ULONG)pMti->c + sLen);
  1713.     if (Mi.afStyle & MIS_SUBMENU) {
  1714.       pMti = (PMTI)UCMenuMakeTemplate2(Mi.hwndSubMenu, (PVOID)pMti, MIS_SUBMENU);
  1715.     } /* endif */
  1716.   } /* endfor */
  1717.  
  1718.   pMt->Length = (ULONG)pMti - (ULONG)pMt;
  1719.   return (PVOID)pMti;
  1720. }
  1721. //----------------------------------------------------------------------------
  1722. // UCMenuSaveTemplate :
  1723. //----------------------------------------------------------------------------
  1724. // :function res=&IDF_SAVETMP. name='UCMenuSaveTemplate' text='Saves a menu template'.
  1725. // This function builds and saves a ucmenu template.
  1726. // :syntax name='UCMenuSaveTemplate' params='hwndUCMenu, pszFileName' return='bRc' .
  1727. // :fparams.
  1728. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  1729. // UCMenu window handle.
  1730. // :fparam name='pszFileName' type='PSZ' io='input' .
  1731. // File name (NULL-terminated string)
  1732. // :freturns.
  1733. // :fparam name='bRc' type='BOOL' io='return'.
  1734. // FALSE if an error occured.
  1735. // :efparams.
  1736. // :remarks.
  1737. // :related.
  1738. // UCMenuMakeTemplate
  1739. // :efunction.
  1740. //----------------------------------------------------------------------------
  1741. BOOL APIENTRY  UCMenuSaveTemplate(HWND hwndUCMenu, PSZ pszFileName)
  1742. {
  1743.   PVOID  pBuffer;
  1744.   USHORT size;
  1745.   BOOL   bRc = FALSE;
  1746.   ULONG  ulBufLen;
  1747.  
  1748.  
  1749.   pBuffer = UCMenuMakeTemplate(hwndUCMenu, &ulBufLen);
  1750.   if (pBuffer) {
  1751.     size = (USHORT)ulBufLen;
  1752.     if (size) {
  1753.       ULONG ulAction, ulWritten=0;
  1754.       HFILE hFile = NULLHANDLE;
  1755.  
  1756.       if (DosOpen(pszFileName,
  1757.                   &hFile,
  1758.                   &ulAction,
  1759.                   0,
  1760.                   FILE_NORMAL,
  1761.                   OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
  1762.                   OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE|
  1763.                   OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NO_CACHE ,
  1764.                   0L) == 0 ) {
  1765.         DosWrite(hFile, pBuffer, size, &ulWritten);
  1766.         DosClose(hFile);
  1767.         if (ulWritten == size)
  1768.           bRc = TRUE;
  1769.       } /* endif */
  1770.     } /* endif */
  1771.     MyFree(pBuffer);
  1772.   } /* endif */
  1773.  
  1774.   return (bRc);
  1775. }
  1776.  
  1777.  
  1778. //----------------------------------------------------------------------------
  1779. // UCMenuLoadTemplate :
  1780. //----------------------------------------------------------------------------
  1781. // :function res=&IDF_LOADTMP. name='UCMenuLoadTemplate' text='Loads a menu template'.
  1782. // This function loads a menu template from a file.
  1783. // :syntax name='UCMenuLoadTemplate' params='pszFileName, pBufLen' return='pBuffer' .
  1784. // :fparams.
  1785. // :fparam name='pszFileName' type='PSZ' io='input' .
  1786. // File name (NULL-terminated string)
  1787. // :fparam name='pBufLen' type='PULONG' io='output' .
  1788. // Pointer to the length of the allocated buffer.
  1789. // :freturns.
  1790. // :fparam name='pBuffer' type='PVOID' io='input' .
  1791. // Pointer to a buffer (NULL if error).
  1792. // :hp2.Note&colon.:ehp2. The buffer must be freed by the caller using the UCMenuFree() function:enote.
  1793. // :efparams.
  1794. // :remarks.
  1795. // :related.
  1796. // :efunction.
  1797. //----------------------------------------------------------------------------
  1798. PVOID APIENTRY  UCMenuLoadTemplate(PSZ pszFileName, PULONG pBufLen)
  1799. {
  1800.   PVOID       pBuffer;
  1801.   ULONG       ulAction=0, ulRead;
  1802.   FILESTATUS3 flstInfo;
  1803.   HFILE       hFile= NULLHANDLE;
  1804.   APIRET      Error;
  1805.  
  1806.   Error = DosOpen(pszFileName,
  1807.                   &hFile,
  1808.                   &ulAction,
  1809.                   0,
  1810.                   FILE_NORMAL,
  1811.                   OPEN_ACTION_OPEN_IF_EXISTS,
  1812.                   OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE,
  1813.                   0L);
  1814.   if (Error) {
  1815.     pBuffer = NULL;
  1816.   } else {
  1817.     if (DosQueryFileInfo(hFile,
  1818.                          1,
  1819.                          (PBYTE)&flstInfo,
  1820.                          sizeof(flstInfo))) {
  1821.       DosClose(hFile);
  1822.       pBuffer = NULL;
  1823.     } else {
  1824.       pBuffer = MyMalloc(flstInfo.cbFile);
  1825.       if (!pBuffer) {
  1826.         DosClose(hFile);
  1827.         *pBufLen = 0;
  1828.       } else {
  1829.         *pBufLen = flstInfo.cbFile;
  1830.         DosRead(hFile,
  1831.                 pBuffer,
  1832.                 flstInfo.cbFile,
  1833.                 &ulRead);
  1834.         DosClose(hFile);
  1835.       } /* endif */
  1836.     } /* endif */
  1837.   } /* endif */
  1838.  
  1839.   return (pBuffer);
  1840. }
  1841.  
  1842. //----------------------------------------------------------------------------
  1843. // UCMenuSaveTemplateIni :
  1844. //----------------------------------------------------------------------------
  1845. // :function res=&IDF_SAVETMPINI. name='UCMenuSaveTemplateIni' text='Saves a menu template'.
  1846. // This function builds and saves a ucmenu template in an ini file.
  1847. // :syntax name='UCMenuSaveTemplateIni' params='hwndUCMenu, pszFileName, pszKeyName' return='bRc' .
  1848. // :fparams.
  1849. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  1850. // UCMenu window handle.
  1851. // :fparam name='pszFileName' type='PSZ' io='input' .
  1852. // File name (NULL-terminated string)
  1853. // :fparam name='pszKeyName' type='PSZ' io='input' .
  1854. // Template name (NULL-terminated string)
  1855. // :freturns.
  1856. // :fparam name='bRc' type='BOOL' io='return'.
  1857. // FALSE if an error occured.
  1858. // :efparams.
  1859. // :remarks.
  1860. // :related.
  1861. // UCMenuMakeTemplate
  1862. // :efunction.
  1863. //----------------------------------------------------------------------------
  1864. BOOL APIENTRY  UCMenuSaveTemplateIni(HWND hwndUCMenu, PSZ pszFileName,
  1865.                                   PSZ pszKeyName)
  1866. {
  1867.   PVOID  pBuffer;
  1868.   BOOL   bRc = FALSE;
  1869.   ULONG  ulBufLen;
  1870.   HINI   hIni;
  1871.   //HWND   hwndMenu = ((PUCMDATA)WinQueryWindowULong(hwndUCMenu,QWL_UCMDATA))->hwndMenu;
  1872.  
  1873.   pBuffer = UCMenuMakeTemplate(hwndUCMenu, &ulBufLen);
  1874.   if (pBuffer) {
  1875.     if (ulBufLen) {
  1876.       hIni = PrfOpenProfile(WinQueryAnchorBlock(HWND_DESKTOP), pszFileName);
  1877.       if (hIni) {
  1878.          PrfWriteProfileData(hIni, UCAPPNAME, pszKeyName, pBuffer, ulBufLen);
  1879.          PrfCloseProfile(hIni);
  1880.          bRc = TRUE;
  1881.       }
  1882.     } /* endif */
  1883.     MyFree(pBuffer);
  1884.   } /* endif */
  1885.  
  1886.   return (bRc);
  1887. }
  1888.  
  1889. //----------------------------------------------------------------------------
  1890. // UCMenuLoadTemplateIni :
  1891. //----------------------------------------------------------------------------
  1892. // :function res=&IDF_LOADTMPINI. name='UCMenuLoadTemplateIni' text='Loads a menu template'.
  1893. // This function loads a menu template from an ini file.
  1894. // :syntax name='UCMenuLoadTemplateIni' params='pszFileName, pszKeyName, pBufLen' return='pBuffer' .
  1895. // :fparams.
  1896. // :fparam name='pszFileName' type='PSZ' io='input' .
  1897. // Ini File name (NULL-terminated string)
  1898. // :fparam name='pszKeyName' type='PSZ' io='input' .
  1899. // Template name (NULL-terminated string)
  1900. // :fparam name='pBufLen' type='PULONG' io='output' .
  1901. // Pointer to the length of the allocated buffer.
  1902. // :freturns.
  1903. // :fparam name='pBuffer' type='PVOID' io='input' .
  1904. // Pointer to a buffer (NULL if error).
  1905. // :hp2.Note&colon.:ehp2. The buffer must be freed by the caller using the UCMenuFree() function:enote.
  1906. // :efparams.
  1907. // :remarks.
  1908. // :related.
  1909. // :efunction.
  1910. //----------------------------------------------------------------------------
  1911. PVOID APIENTRY  UCMenuLoadTemplateIni(PSZ pszFileName, PSZ pszKeyName,
  1912.                                    PULONG pBufLen)
  1913. {
  1914.   PVOID       pBuffer=(PVOID)NULL;
  1915.   HINI        hIni;
  1916.   ULONG       ulSize;
  1917.  
  1918.   hIni = PrfOpenProfile(WinQueryAnchorBlock(HWND_DESKTOP), pszFileName);
  1919.   if (hIni) {
  1920.      PrfQueryProfileSize(hIni, UCAPPNAME, pszKeyName, &ulSize);
  1921.      if (ulSize) {
  1922.         pBuffer = MyMalloc(ulSize);
  1923.      }
  1924.      if (pBuffer) {
  1925.         PrfQueryProfileData(hIni, UCAPPNAME, pszKeyName, pBuffer, &ulSize);
  1926.      }
  1927.      PrfCloseProfile(hIni);
  1928.   }
  1929.   return(pBuffer);
  1930. }
  1931.  
  1932. //----------------------------------------------------------------------------
  1933. // UCMenuSaveStyle :
  1934. //----------------------------------------------------------------------------
  1935. // :function res=&IDF_SAVESTL. name='UCMenuSaveStyle' text='Saves a menu style'.
  1936. // This function saves the informations relative to the style of a ucmenu.
  1937. // :syntax name='UCMenuSaveStyle' params='hwndMenu, pszFileName' return='bRC' .
  1938. // :fparams.
  1939. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  1940. // UCMenu window handle.
  1941. // :fparam name='pszFileName' type='PSZ' io='input' .
  1942. // File name (NULL-terminated string)
  1943. // :freturns.
  1944. // :fparam name='bRC' type='BOOL' io='return'.
  1945. // FALSE if an error occured.
  1946. // :efparams.
  1947. // :remarks.
  1948. // :related.
  1949. // :efunction.
  1950. //----------------------------------------------------------------------------
  1951. BOOL APIENTRY  UCMenuSaveStyle(HWND hwndUCMenu, PSZ pszFileName)
  1952. {
  1953.   PVOID  pBuffer;
  1954.   USHORT size;
  1955.   BOOL   bRC = FALSE;
  1956.   PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwndUCMenu, QWL_UCMDATA );
  1957.  
  1958.   pBuffer = MyMalloc(MAX_TMPSIZE);
  1959.   if (pBuffer) {
  1960.     PVOID pBufIndex = pBuffer;
  1961.     size = 0;
  1962.     *((PULONG)pBufIndex)   = UCMData->Style;
  1963.     pBufIndex = ((PULONG)pBufIndex)+1;
  1964.     size += sizeof( ULONG );
  1965.     *((PULONG)pBufIndex) = UCMData->cx;
  1966.     pBufIndex = ((PULONG)pBufIndex)+1;
  1967.     size += sizeof( ULONG );
  1968.     *((PULONG)pBufIndex) = UCMData->cy;
  1969.     pBufIndex = ((PULONG)pBufIndex)+1;
  1970.     size += sizeof( ULONG );
  1971.     *((LONG*)pBufIndex) = UCMData->BgColor;
  1972.     pBufIndex = ((LONG*)pBufIndex)+1;
  1973.     size += sizeof( LONG );
  1974.     *((LONG*)pBufIndex) = UCMData->ItemBgColor;
  1975.     pBufIndex = ((LONG*)pBufIndex)+1;
  1976.     size += sizeof( LONG );
  1977.     if (UCMData->pszFontNameSize) {
  1978.        strcpy( pBufIndex, UCMData->pszFontNameSize );
  1979.        size += 1 + strlen( UCMData->pszFontNameSize );
  1980.     } // endif
  1981.     if (size) {
  1982.       ULONG ulAction, ulWritten=0;
  1983.       HFILE hFile = NULLHANDLE;
  1984.  
  1985.       if (DosOpen(pszFileName,
  1986.                   &hFile,
  1987.                   &ulAction,
  1988.                   0,
  1989.                   FILE_NORMAL,
  1990.                   OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
  1991.                   OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE|
  1992.                   OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NO_CACHE ,
  1993.                   0L) == 0 ) {
  1994.         DosWrite(hFile, pBuffer, size, &ulWritten);
  1995.         DosClose(hFile);
  1996.         if (ulWritten == size)
  1997.           bRC = TRUE;
  1998.       } /* endif */
  1999.     } /* endif */
  2000.     MyFree(pBuffer);
  2001.   } /* endif */
  2002.   return (bRC);
  2003. }
  2004.  
  2005.  
  2006. //----------------------------------------------------------------------------
  2007. // UCMenuLoadStyle :
  2008. //----------------------------------------------------------------------------
  2009. // :function res=&IDF_LOADSTL. name='UCMenuLoadStyle' text='Loads a menu style'.
  2010. // This function loads a menu style from a file into a UCMInfo ucmenu
  2011. // creation structure.
  2012. // :syntax name='UCMenuLoadStyle' params='pszFileName, pUCMInfo' return='bSuccess'.
  2013. // :fparams.
  2014. // :fparam name='pszFileName' type='PSZ' io='input' .
  2015. // File name (NULL-terminated string)
  2016. // :fparam name='pUCMInfo' type='UCMINFO *' io='output' .
  2017. // Pointer to the UCMInfo structure in which to load the style
  2018. // :freturns.
  2019. // :fparam name='bSuccess' type='BOOL' io='return' .
  2020. // FALSE if an error occured.
  2021. // :efparams.
  2022. // :remarks.
  2023. // :related.
  2024. // :efunction.
  2025. //----------------------------------------------------------------------------
  2026. BOOL APIENTRY  UCMenuLoadStyle(PSZ pszFileName, PUCMINFO pUCMInfo)
  2027. {
  2028.   BOOL        bSuccess;
  2029.   PVOID       pBuffer;
  2030.   ULONG       ulAction=0, ulRead;
  2031.   FILESTATUS3 flstInfo;
  2032.   HFILE       hFile= NULLHANDLE;
  2033.   APIRET      Error;
  2034.  
  2035.   Error = DosOpen(pszFileName,
  2036.                   &hFile,
  2037.                   &ulAction,
  2038.                   0,
  2039.                   FILE_NORMAL,
  2040.                   OPEN_ACTION_OPEN_IF_EXISTS,
  2041.                   OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE,
  2042.                   0L);
  2043.   if (Error) {
  2044.     bSuccess = FALSE;
  2045.   } else {
  2046.     if (DosQueryFileInfo(hFile,
  2047.                          1,
  2048.                          (PBYTE)&flstInfo,
  2049.                          sizeof(flstInfo))) {
  2050.       DosClose(hFile);
  2051.       bSuccess = FALSE;
  2052.     } else {
  2053.       pBuffer = MyMalloc(flstInfo.cbFile);
  2054.       if (!pBuffer) {
  2055.         DosClose(hFile);
  2056.         bSuccess = FALSE;
  2057.       } else {
  2058.         DosRead(hFile,
  2059.                 pBuffer,
  2060.                 flstInfo.cbFile,
  2061.                 &ulRead);
  2062.         DosClose(hFile);
  2063.         if ( ulRead >= ( 3*sizeof(ULONG) + 2*sizeof(LONG) ) ) {
  2064.            PVOID pBufIndex;
  2065.            pBufIndex = pBuffer;
  2066.            pUCMInfo->Style = *(PULONG)pBufIndex;
  2067.            pBufIndex = ((PULONG)pBufIndex)+1;
  2068.            pUCMInfo->cx = *(PULONG)pBufIndex;
  2069.            pBufIndex = ((PULONG)pBufIndex)+1;
  2070.            pUCMInfo->cy = *(PULONG)pBufIndex;
  2071.            pBufIndex = ((PULONG)pBufIndex)+1;
  2072.            pUCMInfo->BgColor = *(LONG*)pBufIndex;
  2073.            pBufIndex = ((LONG*)pBufIndex)+1;
  2074.            pUCMInfo->ItemBgColor = *(LONG*)pBufIndex;
  2075.            pBufIndex = ((LONG*)pBufIndex)+1;
  2076.            if (((PBYTE)pBufIndex-(PBYTE)pBuffer)>ulRead) {
  2077.               *((PBYTE)pBuffer+ulRead-1) = 0;
  2078.               pUCMInfo->pszFontNameSize = MyStrdup( (PSZ)pBufIndex );
  2079.            } else {
  2080.               pUCMInfo->pszFontNameSize = 0;
  2081.            } // endif
  2082.            bSuccess = TRUE;
  2083.         } else {
  2084.            bSuccess = FALSE;
  2085.         } // endif
  2086.       MyFree( pBuffer );
  2087.       } // endif
  2088.     } // endif
  2089.   } // endif
  2090.  
  2091.   return (bSuccess);
  2092. }
  2093.  
  2094. //----------------------------------------------------------------------------
  2095. // UCMenuSaveStyleIni :
  2096. //----------------------------------------------------------------------------
  2097. // :function res=&IDF_SAVESTLINI. name='UCMenuSaveStyleIni' text='Saves a menu style'.
  2098. // This function saves the informations relative to the style of a ucmenu in an ini file.
  2099. // :syntax name='UCMenuSaveStyleIni' params='hwndMenu, pszFileName, pszKeyName' return='bRC' .
  2100. // :fparams.
  2101. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  2102. // UCMenu window handle.
  2103. // :fparam name='pszFileName' type='PSZ' io='input' .
  2104. // File name (NULL-terminated string)
  2105. // :fparam name='pszKeyName' type='PSZ' io='input' .
  2106. // Style name (NULL-terminated string)
  2107. // :freturns.
  2108. // :fparam name='bRC' type='BOOL' io='return'.
  2109. // FALSE if an error occured.
  2110. // :efparams.
  2111. // :remarks.
  2112. // :related.
  2113. // :efunction.
  2114. //----------------------------------------------------------------------------
  2115. BOOL APIENTRY  UCMenuSaveStyleIni(HWND hwndUCMenu, PSZ pszFileName,
  2116.                                PSZ pszKeyName)
  2117. {
  2118.   PVOID  pBuffer;
  2119.   USHORT size;
  2120.   BOOL   bRC = FALSE;
  2121.   PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwndUCMenu, QWL_UCMDATA );
  2122.  
  2123.   pBuffer = MyMalloc(MAX_TMPSIZE);
  2124.   if (pBuffer) {
  2125.     PVOID pBufIndex = pBuffer;
  2126.     size = 0;
  2127.     *((PULONG)pBufIndex)   = UCMData->Style;
  2128.     pBufIndex = ((PULONG)pBufIndex)+1;
  2129.     size += sizeof( ULONG );
  2130.     *((PULONG)pBufIndex) = UCMData->cx;
  2131.     pBufIndex = ((PULONG)pBufIndex)+1;
  2132.     size += sizeof( ULONG );
  2133.     *((PULONG)pBufIndex) = UCMData->cy;
  2134.     pBufIndex = ((PULONG)pBufIndex)+1;
  2135.     size += sizeof( ULONG );
  2136.     *((LONG*)pBufIndex) = UCMData->BgColor;
  2137.     pBufIndex = ((LONG*)pBufIndex)+1;
  2138.     size += sizeof( LONG );
  2139.     *((LONG*)pBufIndex) = UCMData->ItemBgColor;
  2140.     pBufIndex = ((LONG*)pBufIndex)+1;
  2141.     size += sizeof( LONG );
  2142.     if (UCMData->pszFontNameSize) {
  2143.        strcpy( pBufIndex, UCMData->pszFontNameSize );
  2144.        size += 1 + strlen( UCMData->pszFontNameSize );
  2145.     } // endif
  2146.  
  2147.     if (size) {
  2148.        HINI    hIni;
  2149.        hIni = PrfOpenProfile(WinQueryAnchorBlock(HWND_DESKTOP), pszFileName);
  2150.        if (hIni) {
  2151.           PrfWriteProfileData(hIni, UCAPPNAME, pszKeyName, pBuffer, size);
  2152.           PrfCloseProfile(hIni);
  2153.        }
  2154.     }
  2155.     MyFree(pBuffer);
  2156.   } /* endif */
  2157.   return (bRC);
  2158. }
  2159.  
  2160.  
  2161. //----------------------------------------------------------------------------
  2162. // UCMenuLoadStyleIni :
  2163. //----------------------------------------------------------------------------
  2164. // :function res=&IDF_LOADSTLINI. name='UCMenuLoadStyleIni' text='Loads a menu style'.
  2165. // This function loads a menu style from an ini file into a UCMInfo ucmenu
  2166. // creation structure.
  2167. // :syntax name='UCMenuLoadStyleIni' params='pszFileName, pszKeyName, pUCMInfo' return='bSuccess'.
  2168. // :fparams.
  2169. // :fparam name='pszFileName' type='PSZ' io='input' .
  2170. // File name (NULL-terminated string)
  2171. // :fparam name='pszKeyName' type='PSZ' io='input' .
  2172. // Style name (NULL-terminated string)
  2173. // :fparam name='pUCMInfo' type='UCMINFO *' io='output' .
  2174. // Pointer to the UCMInfo structure in which to load the style
  2175. // :freturns.
  2176. // :fparam name='bSuccess' type='BOOL' io='return' .
  2177. // FALSE if an error occured.
  2178. // :efparams.
  2179. // :remarks.
  2180. // :related.
  2181. // :efunction.
  2182. //----------------------------------------------------------------------------
  2183. BOOL APIENTRY  UCMenuLoadStyleIni(PSZ pszFileName, PSZ pszKeyName,
  2184.                                  PUCMINFO pUCMInfo)
  2185. {
  2186.   BOOL        bSuccess=FALSE;
  2187.   PVOID       pBuffer;
  2188.   HINI        hIni;
  2189.   ULONG       ulSize;
  2190.  
  2191.   hIni = PrfOpenProfile(WinQueryAnchorBlock(HWND_DESKTOP), pszFileName);
  2192.   if (hIni) {
  2193.      PrfQueryProfileSize(hIni, UCAPPNAME, pszKeyName, &ulSize);
  2194.      if (ulSize) {
  2195.        pBuffer = MyMalloc(ulSize);
  2196.        if (pBuffer) {
  2197.          PrfQueryProfileData(hIni, UCAPPNAME, pszKeyName, pBuffer, &ulSize);
  2198.          if ( ulSize >= ( 3*sizeof(ULONG) + 2*sizeof(LONG) ) ) {
  2199.             PVOID pBufIndex;
  2200.             pBufIndex = pBuffer;
  2201.             pUCMInfo->Style = *(PULONG)pBufIndex;
  2202.             pBufIndex = ((PULONG)pBufIndex)+1;
  2203.             pUCMInfo->cx = *(PULONG)pBufIndex;
  2204.             pBufIndex = ((PULONG)pBufIndex)+1;
  2205.             pUCMInfo->cy = *(PULONG)pBufIndex;
  2206.             pBufIndex = ((PULONG)pBufIndex)+1;
  2207.             pUCMInfo->BgColor = *(LONG*)pBufIndex;
  2208.             pBufIndex = ((LONG*)pBufIndex)+1;
  2209.             pUCMInfo->ItemBgColor = *(LONG*)pBufIndex;
  2210.             pBufIndex = ((LONG*)pBufIndex)+1;
  2211.             if (((PBYTE)pBufIndex-(PBYTE)pBuffer)>ulSize) {
  2212.                *((PBYTE)pBuffer+ulSize-1) = 0;
  2213.                pUCMInfo->pszFontNameSize = MyStrdup( (PSZ)pBufIndex );
  2214.             } else {
  2215.                pUCMInfo->pszFontNameSize = 0;
  2216.             } // endif
  2217.             bSuccess = TRUE;
  2218.          } // endif
  2219.          MyFree( pBuffer );
  2220.        } //endif
  2221.      } //endif
  2222.      PrfCloseProfile(hIni);
  2223.   } //endif
  2224.   return(bSuccess);
  2225.  
  2226. }
  2227.  
  2228. //----------------------------------------------------------------------------
  2229. // UCMenuLoadMenuData
  2230. //----------------------------------------------------------------------------
  2231. // :pfunction res=&IDF_LOADMENU. name='UCMenuLoadMenuData' text='Loads the menu data'.
  2232. // This function loads the data associated with the OWNERDRAW items of a menu.
  2233. // :syntax name='UCMenuLoadMenuData' params='hwndMenu, hModule, UCMData, ulVersion, hwndUCM ' return='-' .
  2234. // :fparams.
  2235. // :fparam name='hwndMenu' type='HWND' io='input' .
  2236. // Menu window handle.
  2237. // :fparam name='UCMData' type='PUCMDATA' io='input'
  2238. // Pointer to the UCMDATA structure
  2239. // :fparam name='ulVersion' type='ULONG' io='input'
  2240. // template version
  2241. // :fparam name='hwndUCM' type='HWND' io='input' .
  2242. // UCMenu window handle.
  2243. // :freturns.
  2244. // :fparam name='-' type='VOID' io='-'.
  2245. // Nothing.
  2246. // :efparams.
  2247. // :remarks.
  2248. // This function parses the whole menu (including submenus). It creates ownerdrawn
  2249. // items from special text items.
  2250. // :p.
  2251. // The text field of such items must have the following format &colon.
  2252. // "&lbrk.Text&rbrk.#BitmapID&lbrk.#Action&rbrk.&lbrk.#Data&rbrk.".
  2253. // :dl compact.
  2254. // :dt.:hp2.Text:ehp2.
  2255. // :dd.The text displayed in the bitmap
  2256. // :dt.:hp2.BitmapID:ehp2.
  2257. // :dd.Bitmap identifier or file name
  2258. // :dt.:hp2.Action:ehp2.
  2259. // :dd.Some text associated with the item , for example the name of a macro.
  2260. // :dt.:hp2.Data:ehp2.
  2261. // :dd.Information about the action associated with the item , for example the name of a macro.
  2262. // :edl.
  2263. // :p.
  2264. // The style of these items is replaced by MIS_OWNERDRAW. The item handle contains
  2265. // a pointer to an :link reftype=hd res=&IDT_ITEMD..UCMITEM data structure:elink.
  2266. // :p.
  2267. // Any MIS_BREAK style not for a submenu item is removed.
  2268. // :hp2.Note&colon.:ehp2. This function is automatically called during the creation of a UCMenu.
  2269. // :enote.
  2270. // :xamples.
  2271. // Definition of the menu in a resource file &colon.
  2272. // :xmp.
  2273. // BITMAP 2000 BITMAP1.BMP
  2274. //  ...
  2275. // MENUITEM    "#Item 1#2000#Macro 1",        IDM_MAC1,     MIS_TEXT
  2276. // MENUITEM    "#Item 2#bitmap2.bmp#Macro 2", IDM_MAC2,     MIS_TEXT
  2277. //  ...
  2278. // :exmp.
  2279. // :related.
  2280. // :epfunction.
  2281. //----------------------------------------------------------------------------
  2282. VOID _Optlink  UCMenuLoadMenuData(HWND hwndMenu, PUCMDATA UCMData, ULONG ulVersion, HWND hwndUCM )
  2283. {
  2284.   MENUITEM mi;
  2285.   SHORT    sIndex, sIndexBis, sOtherIndex, ItemID, NewID, NbOfItems, sItemTextLen;
  2286.   PSZ      ItemText, ItemText2;
  2287.   PSZ      pszBmpHandle=0, pszText=0, pszAction=0, pszParameters=0, pszBmp=0, pszAct = 0;
  2288.   PSZ      pszData=0, pszD = 0, pszPar = 0;
  2289.   LONG     pszLen;
  2290.   UCHAR    ucDelim = '\t';
  2291.  
  2292.   WinSetWindowULong( hwndMenu, QWL_USER, (ULONG) UCMData );
  2293.  
  2294.  
  2295.   /*┌────────────────────────────────┐
  2296.     │ Query the Number of menu items │
  2297.     └────────────────────────────────┘*/
  2298.   NbOfItems = (SHORT)WinSendMsg(hwndMenu,
  2299.                                 MM_QUERYITEMCOUNT,
  2300.                                 (MPARAM)0,
  2301.                                 (MPARAM)0);
  2302.  
  2303.   for (sIndex=0 ; sIndex<NbOfItems ; sIndex++) {
  2304.  
  2305.     /*┌─────────────────────────────────┐
  2306.       │ Query the item ID and structure │
  2307.       └─────────────────────────────────┘*/
  2308.     ItemID = (SHORT)WinSendMsg(hwndMenu,
  2309.                                MM_ITEMIDFROMPOSITION,
  2310.                                MPFROMSHORT(sIndex),
  2311.                                (MPARAM)0);
  2312.  
  2313.     sOtherIndex = sIndex;
  2314.     for ( sIndexBis = sIndex + 1; sIndexBis < NbOfItems; sIndexBis++ ) {
  2315.        NewID = (SHORT)WinSendMsg( hwndMenu,
  2316.                                   MM_ITEMIDFROMPOSITION,
  2317.                                   MPFROMSHORT(sIndexBis),
  2318.                                   (MPARAM)0);
  2319.        if ( NewID == ItemID ) {
  2320.           sOtherIndex = sIndexBis;
  2321.        } /* endif */
  2322.     } /* endfor */
  2323.     if ( sOtherIndex != sIndex ) {
  2324.        // Another item has the same ID, so get an unused one
  2325.        // We assume here that when 2 items have the same ID,
  2326.        // MM_QUERYITEM  amd MM_REMOVEITEM use the one
  2327.        // in the first position
  2328.        memset( &mi, 0, sizeof( MENUITEM ) );
  2329.        WinSendMsg(hwndMenu,
  2330.                   MM_QUERYITEM,
  2331.                   MPFROM2SHORT(ItemID,FALSE),
  2332.                   MPFROMP(&mi));
  2333.        NewID = UCMenuGetNewID( hwndMenu, MIT_NONE, UCMData );
  2334.        ItemText2 = 0;
  2335.        sItemTextLen = (SHORT) WinSendMsg( hwndMenu,
  2336.                                           MM_QUERYITEMTEXTLENGTH,
  2337.                                           MPFROMSHORT(ItemID ),
  2338.                                           (MPARAM)0 );
  2339.        if ( sItemTextLen ){
  2340.           ItemText2 = MyMalloc( ++sItemTextLen );
  2341.           if ( ItemText2 ) {
  2342.              WinSendMsg( hwndMenu,
  2343.                          MM_QUERYITEMTEXT,
  2344.                          MPFROM2SHORT( ItemID, sItemTextLen ),
  2345.                          MPFROMP( ItemText2 ) );
  2346.           } /* endif */
  2347.        } /* endif */
  2348.        if ( ItemText2 ) {
  2349.           ItemText = ItemText2;
  2350.        } else {
  2351.           ItemText = "";
  2352.        } /* endif */
  2353.        WinSendMsg(hwndMenu,
  2354.                   MM_REMOVEITEM,
  2355.                   MPFROM2SHORT(ItemID,FALSE),
  2356.                   (MPARAM)0 );
  2357.        mi.id = NewID;
  2358.        if ( mi.hItem ){
  2359.           ITEM( &mi, usId ) = NewID;
  2360.        } /* endif */
  2361.        ItemID = NewID;
  2362.        WinSendMsg( hwndMenu,
  2363.                    MM_INSERTITEM,
  2364.                    MPFROMP( &mi ),
  2365.                    MPFROMP( ItemText ) );
  2366.        if ( ItemText2 ){
  2367.           MyFree( ItemText2 );
  2368.        } /* endif */
  2369.     } /* endif */
  2370.  
  2371.     memset( &mi, 0, sizeof( MENUITEM ) );
  2372.     WinSendMsg(hwndMenu,
  2373.                MM_QUERYITEM,
  2374.                MPFROM2SHORT(ItemID,FALSE),
  2375.                MPFROMP(&mi));
  2376.  
  2377.     /*┌─────────────────────────────────────────────────────────┐
  2378.       │ If it's a Submenu, do a recursive call with hwndSubMenu │
  2379.       └─────────────────────────────────────────────────────────┘*/
  2380.     if (mi.hwndSubMenu){
  2381.        PFNWP pFnwp;
  2382.        UCMenuLoadMenuData(mi.hwndSubMenu, UCMData, ulVersion, hwndUCM );
  2383.        if ( ( pFnwp =(PFNWP)WinQueryWindowPtr( mi.hwndSubMenu, QWP_PFNWP ) ) != SubmenuWndProc ){
  2384.           UCMData->OldSubMenuProc = pFnwp;
  2385.           UCMData->OldSubMenuProc = (PFNWP)WinSubclassWindow( mi.hwndSubMenu, SubmenuWndProc );
  2386.        } // endif
  2387.     }
  2388.  
  2389.     // (MAM) same for SPACER and non-SPACER, so moved here to save code.
  2390.     // If both MIS_SPACER and MIS_TEXT specified, SPACER is used.
  2391.  
  2392.     mi.afStyle |= (USHORT)  MIS_OWNERDRAW ;
  2393.     mi.afStyle &= (USHORT) ~MIS_TEXT;
  2394.     mi.afStyle &= (USHORT) ~MIS_BREAK;  //(MAM) Don't allow BREAK on any item
  2395.  
  2396.     if (mi.afStyle & MIS_SPACER) {
  2397.     /*┌─────────────────────────────────────────────────────────┐
  2398.       │ It's a SPACER item                                      │
  2399.       └─────────────────────────────────────────────────────────┘*/
  2400.  
  2401.        mi.hItem = (LONG)MyMalloc(sizeof(UCMITEM));
  2402.  
  2403.        if (mi.hItem) {
  2404.           memset( (VOID *) mi.hItem, '\0', sizeof(UCMITEM) );
  2405.        } // endif mi.hItem != 0
  2406.  
  2407.  
  2408.       WinSendMsg(hwndMenu,
  2409.                  MM_SETITEM,
  2410.                  MPFROM2SHORT(0,FALSE),
  2411.                  MPFROMP(&mi));
  2412.  
  2413.     } else {
  2414.  
  2415.     /*┌─────────────────────────────────────────────────────────┐
  2416.       │ Assume it is a MIS_TEXT item                            │
  2417.       └─────────────────────────────────────────────────────────┘*/
  2418.       ItemText2 = 0;
  2419.       sItemTextLen = (SHORT) WinSendMsg( hwndMenu,
  2420.                                          MM_QUERYITEMTEXTLENGTH,
  2421.                                          MPFROMSHORT(ItemID ),
  2422.                                          (MPARAM)0 );
  2423.       if ( sItemTextLen ){
  2424.          ItemText2 = MyMalloc( ++sItemTextLen );
  2425.          if ( ItemText2 ) {
  2426.             WinSendMsg( hwndMenu,
  2427.                         MM_QUERYITEMTEXT,
  2428.                         MPFROM2SHORT( ItemID, sItemTextLen ),
  2429.                         MPFROMP( ItemText2 ) );
  2430.          } /* endif */
  2431.       } /* endif */
  2432.       if ( ItemText2 ){
  2433.          ItemText = ItemText2;
  2434.       } else {
  2435.          ItemText = "";
  2436.       } /* endif */
  2437.  
  2438.       /*┌────────────────────────────────────────────────────────────────────┐
  2439.         │ The format is the following : "#Text#Bitmap#Action#Parameters#Data"│
  2440.         │ Text is optional, Bitmap is either a number (bitmap ID) or a       │
  2441.         │ string (file name), Action, Parameters and Data are string         │
  2442.         │ The delimiter (here # is given by the first character of the string│
  2443.         └────────────────────────────────────────────────────────────────────┘*/
  2444.  
  2445.       if ( ulVersion == UCMTMPLVERSION ){
  2446.          ucDelim = ItemText[0];
  2447.          pszBmpHandle = strchr(&ItemText[1], ucDelim);
  2448.       } else {
  2449.          ucDelim = '#';
  2450.          pszBmpHandle = strchr(&ItemText[0], ucDelim);
  2451.       } // endif
  2452.  
  2453.  
  2454.       if (pszBmpHandle) {
  2455.  
  2456.         pszAction = strchr(&pszBmpHandle[1], ucDelim);
  2457.  
  2458.         if(pszAction) {
  2459.           if ( ulVersion == UCMTMPLVERSION ){
  2460.               pszParameters   = (PSZ) strchr((PSZ)(pszAction+1), ucDelim);
  2461.               if ( pszParameters ){
  2462.                  pszData   = (PSZ) strchr((PSZ)(pszParameters+1), ucDelim);
  2463.               } // endif
  2464.            } else {
  2465.               pszParameters = NULL;
  2466.               pszData   = (PSZ) strchr((PSZ)(pszAction+1), ucDelim);
  2467.            } // endif
  2468.         }
  2469.  
  2470.         /*┌───────────────────────┐
  2471.           │ Get the text (if any) │
  2472.           └───────────────────────┘*/
  2473.         if ( ulVersion == UCMTMPLVERSION ){
  2474.            pszLen = (LONG)pszBmpHandle - (LONG)(&ItemText[1]);
  2475.         } else {
  2476.            pszLen = (LONG)pszBmpHandle - (LONG)(&ItemText[0]);
  2477.         } // endif
  2478.         if (pszLen>0) {
  2479.           PSZ StrPtr;
  2480.           pszText = (PSZ)MyMalloc(pszLen + 1);
  2481.           if ( ulVersion == UCMTMPLVERSION ){
  2482.              strncpy(pszText, &ItemText[1], pszLen);
  2483.           } else {
  2484.              strncpy(pszText, &ItemText[0], pszLen);
  2485.           } // endif
  2486.           pszText[pszLen] = '\0';
  2487.           if(StrPtr = strstr(pszText, "~")) {
  2488.              ULONG Index = UCMData->AccelTable->cAccel;
  2489.              //??? should following be using "Index" instead of "sIndex" which is otherwise unused?
  2490.              ULONG cmd = (ULONG) WinSendMsg(hwndMenu, MM_ITEMIDFROMPOSITION, (MPARAM)sIndex, 0L);
  2491.              AddAccelItem(UCMData, StrPtr[1], cmd);
  2492.           }
  2493.         } else {
  2494.           pszText = 0;
  2495.         } /* endif */
  2496.         /*┌──────────────────────────────────────────┐
  2497.           │ Replace '#' with '\0' and get the data   │
  2498.           └──────────────────────────────────────────┘*/
  2499.         if (pszData) {
  2500.           pszData[0] = '\0';
  2501.           pszData++;
  2502.           pszD = (PSZ)MyMalloc(strlen(pszData)+1);
  2503.           strcpy(pszD, pszData);
  2504.         } else {
  2505.           pszD = NULL;
  2506.         } /* endif */
  2507.  
  2508.         /*┌──────────────────────────────────────────┐
  2509.           │ Replace '#' with '\0' and get the params │
  2510.           └──────────────────────────────────────────┘*/
  2511.         if (pszParameters) {
  2512.           pszParameters[0] = '\0';
  2513.           pszParameters++;
  2514.           pszPar = (PSZ)MyMalloc(strlen(pszParameters)+1);
  2515.           strcpy(pszPar, pszParameters);
  2516.         } else {
  2517.           pszPar = NULL;
  2518.         } /* endif */
  2519.  
  2520.         /*┌──────────────────────────────────────────┐
  2521.           │ Replace '#' with '\0' and get the action │
  2522.           └──────────────────────────────────────────┘*/
  2523.         if (pszAction) {
  2524.           pszAction[0] = '\0';
  2525.           pszAction++;
  2526.           if ( ulVersion != UCMTMPLVERSION ){
  2527.              pszParameters = strchr( pszAction, ' ' );
  2528.              if ( pszParameters ) {
  2529.                 *pszParameters = '\0';
  2530.                 pszParameters++;
  2531.                 pszPar = (PSZ)MyMalloc(strlen(pszParameters)+1);
  2532.                 strcpy(pszPar, pszParameters);
  2533.              } // endif
  2534.           } // endif
  2535.           pszAct = (PSZ)MyMalloc(strlen(pszAction)+1);
  2536.           strcpy(pszAct, pszAction);
  2537.         } else {
  2538.           pszAct = NULL;
  2539.         } /* endif */
  2540.  
  2541.         /*┌───────────────────────────────────────┐
  2542.           │ Get the Bitmap text (ID or File name) │
  2543.           └───────────────────────────────────────┘*/
  2544.         if (strlen(&pszBmpHandle[1])>0) {
  2545.            pszBmp = MyMalloc(strlen(&pszBmpHandle[1])+1);
  2546.            strcpy(pszBmp, &pszBmpHandle[1]);
  2547.         } else {
  2548.            pszBmp = 0;
  2549.         } // endif pszBmpHandle<>""
  2550.       } else {
  2551.          pszBmp = 0;
  2552.          pszAct =0;
  2553.          pszPar = 0;
  2554.          pszD = 0;
  2555.          pszText = MyMalloc( strlen(ItemText) + 1);
  2556.          strcpy( pszText, ItemText );
  2557.       } // endif pszBmpHandle
  2558.  
  2559.       /*┌──────────────────────────────────────────┐
  2560.         │Create and fill the item handle structure │
  2561.         └──────────────────────────────────────────┘*/
  2562.       mi.hItem = (LONG)MyMalloc(sizeof(UCMITEM));
  2563.  
  2564.       if (mi.hItem) {
  2565.         memset((PVOID)mi.hItem, 0x00, sizeof(UCMITEM));
  2566.       //ITEM(&mi, hBmp)    = 0;
  2567.         ITEM(&mi, pszBmp)  = pszBmp;
  2568.         ITEM(&mi, pszText) = pszText;
  2569.         ITEM(&mi, pszAction) = pszAct;
  2570.         ITEM(&mi, pszParameters) = pszPar;
  2571.         ITEM(&mi, pszData) = pszD;
  2572.         } // endif mi.hItem != 0
  2573.  
  2574.       // -- The menu is not subclassed yet so it won't load the bitmap
  2575.       UCMenuLoadItemBmp(&mi, UCMData );
  2576.  
  2577.       WinSendMsg(hwndMenu,
  2578.                  MM_SETITEM,
  2579.                  MPFROM2SHORT(0,FALSE),
  2580.                  MPFROMP(&mi));
  2581.        if ( ItemText2 ){
  2582.           MyFree( ItemText2 );
  2583.        } // endif
  2584.     } // endif MIS_TEXT
  2585.  
  2586.   } /* endfor */
  2587.  
  2588. }
  2589.  
  2590. //----------------------------------------------------------------------------
  2591. // UCMenuNotifAll
  2592. //----------------------------------------------------------------------------
  2593. // :pfunction res=&IDF_NOTIFALL. name='UCMenuNotifAll' text='Sends notifications about each item'.
  2594. // This function sends UCN_ADDEDITEM or UCN_DELETEDITEM about all the items in the menu
  2595. // :syntax name='UCMenuNotifAll' params='hwndUCMenu, hwndMenu, usNotif ' return='-' .
  2596. // :fparams.
  2597. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  2598. // UCMenu window handle.
  2599. // :fparam name='hwndMenu' type='HWND' io='input' .
  2600. // Menu window handle.
  2601. // :fparam name='usNotification' type='USHORT' io='input'
  2602. // Notification code, UCN_ADDEDITEM or UCN_DELETEDITEM
  2603. // :freturns.
  2604. // :fparam name='-' type='VOID' io='-'.
  2605. // Nothing.
  2606. // :efparams.
  2607. // :remarks.
  2608. // :related.
  2609. // :epfunction.
  2610. //----------------------------------------------------------------------------
  2611.  
  2612. VOID  _Optlink UCMenuNotifAll(PUCMDATA UCMData, HWND hwndMenu, USHORT usNotif)
  2613. {
  2614.   MENUITEM mi;
  2615.   SHORT    sIndex, ItemID, NbOfItems;
  2616.  
  2617.  
  2618.   NbOfItems = (SHORT)WinSendMsg(hwndMenu,
  2619.                                 MM_QUERYITEMCOUNT,
  2620.                                 (MPARAM)0,
  2621.                                 (MPARAM)0);
  2622.  
  2623.   for (sIndex=0 ; sIndex<NbOfItems ; sIndex++) {
  2624.  
  2625.     ItemID = (SHORT)WinSendMsg(hwndMenu,
  2626.                                MM_ITEMIDFROMPOSITION,
  2627.                                MPFROMSHORT(sIndex),
  2628.                                (MPARAM)0);
  2629.  
  2630.  
  2631.     memset( &mi, 0, sizeof( MENUITEM ) );
  2632.     WinSendMsg(hwndMenu,
  2633.                MM_QUERYITEM,
  2634.                MPFROM2SHORT(ItemID,FALSE),
  2635.                MPFROMP(&mi));
  2636.  
  2637.     if (mi.hwndSubMenu){
  2638.        UCMenuNotifAll(UCMData, mi.hwndSubMenu, usNotif );
  2639.     } // endif
  2640.  
  2641.     WinSendMsg( UCMData->hwndOwner,
  2642.                 WM_CONTROL,
  2643.                 MPFROM2SHORT( UCMData->UCMenuID, usNotif ),
  2644.                 MPFROMSHORT( ItemID ) );
  2645.  
  2646.   } /* endfor */
  2647.  
  2648. }
  2649.  
  2650. //----------------------------------------------------------------------------
  2651. // UCMenuCalcItemSize : internal function (no entry in the user's doc)
  2652. //----------------------------------------------------------------------------
  2653. // :pfunction res=&IDF_CLCITSZ. name='UCMenuCalcItemSize' text='Calculates the scaled size of an item'.
  2654. // This function calculates the size of an item, according to the others so that they are even.
  2655. // :syntax name='UCMenuCalcItemSize' params='poi, style, hwndUCMenu, pCx, pCy' return='-' .
  2656. // :fparams.
  2657. // :fparam name='poi' type='POWNERITEM' io='input' .
  2658. // Pointer to the OWNERITEM structure of the item
  2659. // :fparam name='style' type='USHORT' io='input' .
  2660. // Style of the ucmenu
  2661. // :fparam name='hwndUCMenu' type='HWND' io='input'.
  2662. // Handle of the ucmenu
  2663. // :fparam name='pCx' type='PULONG' input='output' .
  2664. // Width of the item
  2665. // :fparam name='pCy' type='PULONG' input='output' .
  2666. // Height of the item
  2667. // :freturns.
  2668. // :fparam name='-' type='VOID' io='-' .
  2669. // Nothing
  2670. // :efparams.
  2671. // :remarks.
  2672. // :related.
  2673. // :epfunction.
  2674. //----------------------------------------------------------------------------
  2675.  
  2676. VOID _Optlink  UCMenuCalcItemSize( POWNERITEM poi, USHORT Style, HWND hwndUCMenu, ULONG * pCx, ULONG * pCy)
  2677. {
  2678.    PUCMITEM pUCMI = (PUCMITEM) poi->hItem;
  2679.    ULONG MenuStyle = WinQueryWindowULong(hwndUCMenu, QWL_STYLE);
  2680.    PUCMDATA UCMData = (PUCMDATA) WinQueryWindowULong( hwndUCMenu, QWL_UCMDATA );
  2681.  
  2682.    UCMenuCalcUnscaledItemSize( pUCMI, Style, hwndUCMenu, pCx, pCy);
  2683.  
  2684.    if ( poi->fsState & MIS_SPACER ) {
  2685.       *pCx = 8;
  2686.       *pCy = 8;
  2687.    } // endif
  2688.  
  2689.    if (WinQueryWindow(poi->hwnd, QW_OWNER)==hwndUCMenu) {
  2690.       // First level ucmenu item
  2691.       // Submenu ucmenu items are not scaled, since it makes no sense
  2692.       // to scale them according to the items of their parent
  2693.       if  (MenuStyle & CMS_VERT) {
  2694.          *pCx = UCMData->MaxVerticalWidth;
  2695.       } // endif CMS_VERTICAL
  2696.  
  2697.       if  (MenuStyle & CMS_HORZ) {
  2698.          *pCy = UCMData->MaxHorizontalHeight;
  2699.       } // endif CMS_HORIZONTAL
  2700.  
  2701.       if  (MenuStyle & CMS_MATRIX) {
  2702.          *pCx = UCMData->MaxVerticalWidth;
  2703.          *pCy = UCMData->MaxHorizontalHeight;
  2704.       } // endif CMS_MATRIX
  2705.    } // endif
  2706.  
  2707. }
  2708.  
  2709. //----------------------------------------------------------------------------
  2710. // UCMenuCalcUnscaledItemSize : internal function (no entry in the user's doc)
  2711. //----------------------------------------------------------------------------
  2712. // :pfunction res=&IDF_CLCUNSCITSZ. name='UCMenuCalcUnscaledItemSize' text='Calculates the unscaled size of an item'.
  2713. // This function calculates the size of an item
  2714. // :syntax name='UCMenuCalcUnscaledItemSize' params='pUCMI, Style, hwndUCMenu, pCx, pCy' return='-' .
  2715. // :fparams.
  2716. // :fparam name='pUCMI' type='PUCMITEM' io='input' .
  2717. // Pointer to the UCMITEM structure of the ucmenu item
  2718. // :fparam name='Style' type='USHORT' io='input' .
  2719. // Style of the ucmenu
  2720. // :fparam name='hwndUCMenu' type='HWND' io='input'.
  2721. // Handle of the ucmenu
  2722. // :fparam name='pCx' type='PULONG' input='output' .
  2723. // Width of the item
  2724. // :fparam name='pCy' type='PULONG' input='output' .
  2725. // Height of the item
  2726. // :freturns.
  2727. // :fparam name='-' type='VOID' io='-' .
  2728. // Nothing
  2729. // :efparams.
  2730. // :remarks.
  2731. // :related.
  2732. // :epfunction.
  2733. //----------------------------------------------------------------------------
  2734.  
  2735. VOID _Optlink  UCMenuCalcUnscaledItemSize( PUCMITEM pUCMI, USHORT Style, HWND hwndUCMenu,
  2736.                                            ULONG * pCx, ULONG * pCy)
  2737. {
  2738.    PUCMDATA UCMData = (PUCMDATA) WinQueryWindowULong( hwndUCMenu, QWL_UCMDATA );
  2739.  
  2740.    if ( Style & UCS_FORCESIZE ) {
  2741.       *pCx = UCMData->cx;
  2742.       *pCy = UCMData->cy;
  2743.    }
  2744.    else if ( pUCMI ){
  2745.       BITMAPINFOHEADER2 BmpInfo;
  2746.     //ULONG MenuStyle = WinQueryWindowULong(hwndUCMenu, QWL_STYLE);
  2747.  
  2748.       // By default, size the item to its bitmap
  2749.       BmpInfo.cbFix = sizeof(BITMAPINFOHEADER2);
  2750.       if (!GpiQueryBitmapInfoHeader( pUCMI->hBmp, &BmpInfo)){
  2751.          BmpInfo.cx = 0;
  2752.          BmpInfo.cy = 0;
  2753.       }
  2754.       //(MAM) Add one (all sides) for thicker checkable items.
  2755.       *pCx = SUM_ITEM_FRAME_THICK_HORZ + BmpInfo.cx +2;
  2756.       *pCy = SUM_ITEM_FRAME_THICK_VERT + BmpInfo.cy +2;
  2757.    }
  2758.  
  2759.    /* If text is wider, size to text (even in FORCESIZE mode) */
  2760.  
  2761.    if (pUCMI) {
  2762.       if ( pUCMI->pszText && !(Style & UCS_NOTEXT)) {
  2763.          ULONG TextWidth, TextHeight;
  2764.  
  2765.          UCMenuCalcTextSize(pUCMI, hwndUCMenu, &TextWidth, &TextHeight );
  2766.          TextWidth += SUM_ITEM_FRAME_THICK_HORZ;
  2767.          // set width to TextWidth if text larger than bmp
  2768.          if ( TextWidth > *pCx ) {
  2769.             *pCx = TextWidth;
  2770.          }
  2771.          // add the height of the text
  2772.          *pCy += TextHeight;
  2773.  
  2774.       } // endif pszText!=0  && !UCS_NOTEXT
  2775.    } //
  2776. }
  2777.  
  2778. //----------------------------------------------------------------------------
  2779. // UCMenuCalcBmpPos : internal function (no entry in the user's doc)
  2780. //----------------------------------------------------------------------------
  2781. // :pfunction res=&IDF_CLCBMPPOS. name='UCMenuCalcBmpPos' text='Calculates the position of the bitmap in the item'.
  2782. // This function calculates the position of the bitmap inside a ucmenu item
  2783. // :syntax name='UCMenuCalcBmpPos' params='poi, Style, pDestRect' return='-' .
  2784. // :fparams.
  2785. // :fparam name='poi' type='POWNERITEM' io='input' .
  2786. // Pointer to the OWNERITEM structure of the ucmenu item
  2787. // :fparam name='Style' type='USHORT' io='input' .
  2788. // Style of the ucmenu
  2789. // :fparam name='aptlPoints' type='POINTL[4]' io='output'.
  2790. // Destination and source rectangles of the bitmap (upper right exclusive )
  2791. // :freturns.
  2792. // :fparam name='-' type='VOID' io='-' .
  2793. // Nothing
  2794. // :efparams.
  2795. // :remarks.
  2796. // :related.
  2797. // :epfunction.
  2798. //----------------------------------------------------------------------------
  2799. VOID _Optlink  UCMenuCalcBmpPos( POWNERITEM poi, HWND hwndUCMenu, USHORT Style, POINTL aptlPoints[4], PUCMDATA UCMData)
  2800. {
  2801.    LONG    ItemCxForBmp ;
  2802.    LONG    ItemCyForBmp ;
  2803.    ULONG   TextWidth    = 0;
  2804.    ULONG   TextHeight   = 0;
  2805.    PUCMITEM pUCMI = (PUCMITEM) poi->hItem;
  2806.  
  2807.    BITMAPINFOHEADER2 BmpInfo;
  2808.    POINTL  ImageSize;
  2809.  
  2810.    if ( !pUCMI ){
  2811.       return;
  2812.    } // endif
  2813.  
  2814.    /* Get natural bitmap size */
  2815.  
  2816.    BmpInfo.cbFix = sizeof(BITMAPINFOHEADER2);
  2817.    if (!GpiQueryBitmapInfoHeader( ITEM( poi, hBmp ), &BmpInfo)){
  2818.       BmpInfo.cx = 0;
  2819.       BmpInfo.cy = 0;
  2820.    }
  2821.  
  2822.    /* Determine image size to be viewed */
  2823.  
  2824.    if (Style & UCS_FORCESIZE) {  // Size of bitmap image is fixed
  2825.      ImageSize.x = UCMData->cx;
  2826.      ImageSize.y = UCMData->cy;
  2827.    }
  2828.    else {                        // Use natural bitmap size
  2829.      ImageSize.x = BmpInfo.cx;
  2830.      ImageSize.y = BmpInfo.cy;
  2831.    }
  2832.  
  2833.    /* Query the size of the text */
  2834.  
  2835.    if ( ITEM( poi, pszText ) && !(Style&UCS_NOTEXT)) {
  2836.       UCMenuCalcTextSize( pUCMI, hwndUCMenu, &TextWidth, &TextHeight );
  2837.    }
  2838.  
  2839.    ItemCxForBmp =  poi->rclItem.xRight - poi->rclItem.xLeft;
  2840.    ItemCxForBmp -= SUM_ITEM_FRAME_THICK_HORZ;
  2841.    ItemCyForBmp =  poi->rclItem.yTop - poi->rclItem.yBottom;
  2842.    ItemCyForBmp -= SUM_ITEM_FRAME_THICK_VERT;
  2843.  
  2844.    // We won't have the full item to draw the bmp
  2845.    ItemCyForBmp -= TextHeight;
  2846.  
  2847.    if ( ItemCxForBmp < 0 ) { ItemCxForBmp = 0; }
  2848.    if ( ItemCyForBmp < 0 ) { ItemCyForBmp = 0; }
  2849.  
  2850.    aptlPoints[0].x  = poi->rclItem.xLeft;
  2851.    aptlPoints[0].x  += ITEM_FRAME_THICK_LEFT; // do not draw over the frame
  2852.  
  2853.    /* If image is smaller than available space then center it */
  2854.    /* by setting target rectangle points in [0],[1].          */
  2855.  
  2856.    if ( ImageSize.x <= ItemCxForBmp ) {
  2857.       aptlPoints[0].x += (ItemCxForBmp - ImageSize.x)/2;
  2858.       aptlPoints[1].x = aptlPoints[0].x  + ImageSize.x - 1;
  2859.    } else {
  2860.       aptlPoints[1].x  = poi->rclItem.xRight - ITEM_FRAME_THICK_RIGHT - 1;
  2861.    } // endif
  2862.  
  2863.    aptlPoints[0].y = poi->rclItem.yBottom;
  2864.    aptlPoints[0].y += ITEM_FRAME_THICK_BOTTOM ;
  2865.    aptlPoints[0].y+=TextHeight;
  2866.  
  2867.    if ( ImageSize.y <= ItemCyForBmp ) {
  2868.       aptlPoints[0].y += (ItemCyForBmp - ImageSize.y)/2;
  2869.       aptlPoints[1].y = aptlPoints[0].y + ImageSize.y - 1;
  2870.    } else {
  2871.       aptlPoints[1].y = poi->rclItem.yTop - ITEM_FRAME_THICK_TOP - 1;
  2872.    } // endif
  2873.  
  2874.    /* Source rectangle is just the original bitmap */
  2875.  
  2876.    aptlPoints[2].x = 0;
  2877.    aptlPoints[2].y = 0;
  2878.    aptlPoints[3].x = BmpInfo.cx;
  2879.    aptlPoints[3].y = BmpInfo.cy;
  2880.  
  2881. }
  2882.  
  2883.  
  2884. //----------------------------------------------------------------------------
  2885. // UCMenuCalcTextSize : internal function (no entry in the user's doc)
  2886. //----------------------------------------------------------------------------
  2887. // :pfunction res=&IDF_CLCTXTSZ. name='UCMenuCalcTextSize' text='Calculates the size of the item text'.
  2888. // This function calculates the text size of a ucmenu item, according to its font
  2889. // :syntax name='UCMenuCalcTextSize' params='pUCMI, hwndUCMenu, pWidth, pHeight' return='-' .
  2890. // :fparams.
  2891. // :fparam name='pUCMI' type='PUCMITEM' io='input' .
  2892. // Pointer to the UCMITEM structure of the ucmenu item
  2893. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  2894. // Handle of the ucmenu
  2895. // :fparam name='pWidth' type='PULONG' io='output'.
  2896. // Width of the text
  2897. // :fparam name='pHeight' type='PULONG' io='output'.
  2898. // Height of the text
  2899. // :freturns.
  2900. // :fparam name='-' type='VOID' io='-' .
  2901. // Nothing
  2902. // :efparams.
  2903. // :remarks.
  2904. // :related.
  2905. // :epfunction.
  2906. //----------------------------------------------------------------------------
  2907. VOID _Optlink  UCMenuCalcTextSize(PUCMITEM pUCMI, HWND hwndUCMenu, ULONG * pWidth, ULONG * pHeight)
  2908. {
  2909.    PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong(hwndUCMenu, QWL_UCMDATA);
  2910.  
  2911.    if ( !pUCMI ){
  2912.       return;
  2913.    } // endif
  2914.  
  2915.    if (pUCMI->pszText) {
  2916.    // POINTL aptl[TXTBOX_COUNT];
  2917.       RECTL  Rect;
  2918.       HPS hps = WinGetPS(UCMData->hwndMenu);
  2919.  
  2920.       //(MAM) Use WinDrawText() to calculate required text size, since this
  2921.       // is the API used in the actual drawing.  QueryTextBox() does not always
  2922.       // return correct box size when italic fonts are used.
  2923.       memset(&Rect, 0x00, sizeof(RECTL));
  2924.       Rect.yTop = MAX_INT;
  2925.       Rect.xRight = MAX_INT;
  2926.       WinDrawText(hps, -1, pUCMI->pszText, &Rect, 0L, 0L, DT_QUERYEXTENT|DT_CENTER|DT_VCENTER|DT_TEXTATTRS|DT_MNEMONIC);
  2927.       *pHeight = Rect.yTop - Rect.yBottom;
  2928.       *pWidth  = (Rect.xRight - Rect.xLeft) + SUM_TEXT_FRAME_THICK_HORZ;
  2929.  
  2930.    // GpiQueryTextBox( hps,
  2931.    //                  strlen( pUCMI->pszText ),
  2932.    //                  pUCMI->pszText,
  2933.    //                  TXTBOX_COUNT,
  2934.    //                  aptl );
  2935.       WinReleasePS(hps);
  2936.    // *pHeight = aptl[TXTBOX_TOPLEFT].y  - aptl[TXTBOX_BOTTOMLEFT].y;
  2937.    // *pWidth  = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_TOPLEFT].x;
  2938.    // *pWidth += SUM_TEXT_FRAME_THICK_HORZ;  // we leave some space around the text
  2939.    } else {
  2940.       *pHeight = 0;
  2941.       *pWidth  = 0;
  2942.    } // endif
  2943. }
  2944.  
  2945. //----------------------------------------------------------------------------
  2946. // UCMenuFreeMenuData
  2947. //----------------------------------------------------------------------------
  2948. // :function res=&IDF_FREEMENU. name='UCMenuFreeMenuData' text='Frees the menu data'.
  2949. // This function frees the data associated with the OWNERDRAW items of a menu.
  2950. // :syntax name='UCMenuFreeMenuData' params='hwndMenu' return='-' .
  2951. // :fparams.
  2952. // :fparam name='hwndMenu' type='HWND' io='input' .
  2953. // Menu window handle.
  2954. // :freturns.
  2955. // :fparam name='-' type='VOID' io='-'.
  2956. // Nothing.
  2957. // :efparams.
  2958. // :remarks.
  2959. // This function parses the whole menu (including submenus). It frees the
  2960. // data structure associated with every OWNERDRAW item.
  2961. // :p.This function requires the owner of the menu to be the ucmenu.
  2962. // :hp2.Note&colon.:ehp2. This function is automatically executed when a UCMenu receives a WM_DESTROY message.
  2963. // :enote.
  2964. // :related.
  2965. // :efunction.
  2966. //----------------------------------------------------------------------------
  2967. VOID APIENTRY  UCMenuFreeMenuData(HWND hwndMenu)
  2968. {
  2969.   MENUITEM mi;
  2970.   SHORT    sIndex, ItemID, NbOfItems;
  2971.   PUCMDATA UCMData = (PUCMDATA) WinQueryWindowULong( hwndMenu, QWL_USER );
  2972.   HWND     hwndUCM;
  2973.  
  2974.   if ( UCMData ) {
  2975.      hwndUCM = WinQueryWindow( UCMData->hwndMenu, QW_OWNER );
  2976.   } else {
  2977.      hwndUCM = WinQueryWindow( hwndMenu, QW_OWNER );
  2978.   } /* endif */
  2979.  
  2980.   /*┌────────────────────────────────┐
  2981.     │ Query the Number of menu items │
  2982.     └────────────────────────────────┘*/
  2983.   NbOfItems = (SHORT)WinSendMsg(hwndMenu,
  2984.                                 MM_QUERYITEMCOUNT,
  2985.                                 (MPARAM)0,
  2986.                                 (MPARAM)0);
  2987.  
  2988.   for (sIndex=0 ; sIndex<NbOfItems ; sIndex++) {
  2989.  
  2990.     /*┌─────────────────────────────────────┐
  2991.       │ Query the item handle and structure │
  2992.       └─────────────────────────────────────┘*/
  2993.     ItemID = (SHORT)WinSendMsg(hwndMenu,
  2994.                                MM_ITEMIDFROMPOSITION,
  2995.                                MPFROMSHORT(sIndex),
  2996.                                (MPARAM)0);
  2997.     WinSendMsg( WinQueryWindow( hwndUCM, QW_OWNER ),
  2998.                 WM_CONTROL,
  2999.                 MPFROM2SHORT( WinQueryWindowUShort( hwndUCM, QWS_ID ), UCN_DELETEDITEM ),
  3000.                 MPFROMSHORT( ItemID ) );
  3001.     WinSendMsg(hwndMenu,
  3002.                MM_QUERYITEM,
  3003.                MPFROM2SHORT(ItemID,FALSE),
  3004.                MPFROMP(&mi));
  3005.  
  3006.     /*┌─────────────────────────────────────────────────────────┐
  3007.       │ If it's a Submenu, do a recursive call with hwndSubMenu │
  3008.       └─────────────────────────────────────────────────────────┘*/
  3009.     if (mi.hwndSubMenu){
  3010.        PFNWP pFnwp;
  3011.        UCMenuFreeMenuData(mi.hwndSubMenu);
  3012.        pFnwp = (PFNWP)WinQueryWindowPtr( mi.hwndSubMenu, QWP_PFNWP );
  3013.        if ( ( pFnwp == SubmenuWndProc ) && UCMData && UCMData->OldSubMenuProc ){
  3014.           WinSubclassWindow( mi.hwndSubMenu, (PFNWP)UCMData->OldSubMenuProc );
  3015.        } // endif
  3016.     } // endif
  3017.  
  3018.     /*┌─────────────────────────────────────┐
  3019.       │ Free the handle of ownerdrawn items │
  3020.       └─────────────────────────────────────┘*/
  3021.     if ((mi.afStyle & MIS_OWNERDRAW) && mi.hItem) {
  3022.       if ( ITEM( &mi, pszBmp ) ){
  3023.         MyFree( ITEM( &mi, pszBmp ) );
  3024.         ITEM( &mi, pszBmp ) = 0;
  3025.       }
  3026.       if ( ITEM( &mi, pszText ) ){
  3027.         MyFree( ITEM( &mi, pszText ) );
  3028.         ITEM( &mi, pszText ) = 0;
  3029.       }
  3030.       if ( ITEM( &mi, pszAction ) ){
  3031.         MyFree( ITEM( &mi, pszAction ) );
  3032.         ITEM( &mi, pszAction ) = 0;
  3033.       }
  3034.       if ( ITEM( &mi, pszData ) ){
  3035.         MyFree( ITEM( &mi, pszData ) );
  3036.         ITEM( &mi, pszData ) = 0;
  3037.       }
  3038.       if ( ITEM( &mi, pszParameters ) ){
  3039.         MyFree( ITEM( &mi, pszParameters ) );
  3040.         ITEM( &mi, pszParameters ) = 0;
  3041.       }
  3042.       if ( ITEM( &mi, hBmp ) ){
  3043.         GpiDeleteBitmap( ITEM( &mi, hBmp ) );
  3044.         ITEM( &mi, hBmp ) = 0;
  3045.       }
  3046.       MyFree( (PVOID)mi.hItem );
  3047.       mi.hItem = 0;
  3048.       WinSendMsg( hwndMenu,
  3049.                   MM_SETITEM,
  3050.                   MPFROM2SHORT( 0, TRUE ),
  3051.                   MPFROMP( &mi ) );
  3052.     } /* endif */
  3053.  
  3054.   } /* endfor */
  3055.  
  3056. }
  3057.  
  3058. //----------------------------------------------------------------------------
  3059. // CreateUCMenu : Internal function
  3060. //----------------------------------------------------------------------------
  3061. // :pfunction res=&IDF_CREATUCM. name='CreateUCMenu' text='Creates a User-customizable Menu'.
  3062. // This function creates a User-customizable Menu of the specified style in a given rectangle.
  3063. // :syntax name='CreateUCMenu' params='hwndUCMenu, hwndParent, hwndOwner, hwndMenu, hModule, MenuID, pRcl, Style, NbOfCols, NbOfRows' return='-'.
  3064. // :fparams.
  3065. // :fparam name='hwndUCMenu' type='HWND' io='input'.
  3066. // Handle of the UCMenu.
  3067. // :fparam name='hwndParent' type='HWND' io='input'.
  3068. // Handle of the UCMenu's parent window.
  3069. // :fparam name='hwndOwner' type='HWND' io='input'.
  3070. // Handle of the UCMenu's owner window.
  3071. // :fparam name='hwndMenu' type='HWND' io='input'.
  3072. // Handle of the menu window associated with the UCMenu.
  3073. // :fparam name='MenuID' type='USHORT' io='input'.
  3074. // ID of the menu in the resource
  3075. // :fparam name='pRcl' type='PRECTL' io='input'.
  3076. // UCMenu rectangle.
  3077. // p.The height of a horizontal ucmenu is the height of the tallest item
  3078. // p.The width of a vertical ucmenu is the width of the widest item
  3079. // p.The size of a matrix ucmenu is calculated according to NbOfCols, NbOfRows, the widest and tallest items
  3080. // :fparam name='Style' type='USHORT' io='input'.
  3081. // :dl compact.
  3082. // :dt.:hp2.CMS_VERT:ehp2.
  3083. // :dd.Vertical UCMenu
  3084. // :dt.:hp2.CMS_HORZ:ehp2.
  3085. // :dd.Horizontal UCMenu
  3086. // :dt.:hp2.CMS_MATRIX:ehp2.
  3087. // :dd.Matrix UCMenu
  3088. // :edl.
  3089. // :fparam name='NbOfCols' type='USHORT io='input'.
  3090. // Number of columns if matrix ucmenu
  3091. // :fparam name='NbOfRows' type='USHORT io='input'.
  3092. // Number of rows if matrix ucmenu
  3093. // :fparam name='ulVersion' type='ULONG io='input'.
  3094. // Template version used to build the menu
  3095. // :freturns.
  3096. // :fparam name='-' type='-' io='-'.
  3097. // Nothing.
  3098. // :efparams.
  3099. // :remarks.
  3100. // The UCMenu is the owner of the menu window and therefore receives all the messages.
  3101. // However, it forwards the following messages to its owner. They are
  3102. // described in PM Reference Guide (Menu Control Notification Messages).
  3103. // :dl compact.
  3104. // :dt.:hp2.WM_COMMAND:ehp2.
  3105. // :dd.:hp2.SHORT2FROMMP(mp1) = UCMenuID, SHORT1FROMMP(mp2) = CMDSRC_UCMENU:ehp2.
  3106. // :dt.:hp2.WM_HELP:ehp2.
  3107. // :dd.:hp2.SHORT2FROMMP(mp1) = UCMenuID, SHORT1FROMMP(mp2) = CMDSRC_UCMENU:ehp2.
  3108. // :dt.:hp2.WM_INITMENU:ehp2.
  3109. // :dd.
  3110. // :dt.:hp2.WM_MENUEND:ehp2.
  3111. // :dd.:hp2.mp2 = hwndUCMenu:ehp2.
  3112. // :dt.:hp2.WM_MENUSELECT:ehp2.
  3113. // :dd.:hp2.mp2 = hwndUCMenu:ehp2.
  3114. // :dt.:hp2.WM_NEXTMENU:ehp2.
  3115. // :dd.
  3116. // :edl.
  3117. // :p.
  3118. // The items for which a bitmap can not be found are processed like regular menu items. This
  3119. // means that the parameters associated to the previous messages are not changed for them.
  3120. // :p.
  3121. // The following messages are processed by the UCMenu and not forwarded &colon.
  3122. // :dl compact.
  3123. // :dt.:hp2.WM_DRAWITEM:ehp2.
  3124. // :dd.
  3125. // :dt.:hp2.WM_MEASUREITEM:ehp2.
  3126. // :dd.
  3127. // :edl.
  3128. // :p.
  3129. // The Menu Control Window Messages (MM_*) sent to the UCMenu are forwarded to
  3130. // the menu window. :hp2.MM_QUERYITEMTEXT:ehp2., :hp2.MM_QUERYITEMTEXTLENGTH:ehp2.
  3131. // and :hp2.MM_SETITEMTEXT:ehp2., which usually only work for items with a MIS_TEXT style, can
  3132. // be used with the MIS_OWNERDRAW items to query and set the text displayed in the bitmap.
  3133. // :xamples.
  3134. // :related.
  3135. // :epfunction.
  3136. //----------------------------------------------------------------------------
  3137. VOID _Optlink  CreateUCMenu(HWND hwndUCMenu, HWND hwndParent, HWND hwndOwner,
  3138.                            HWND hwndMenu, USHORT MenuID,
  3139.                            PRECTL prcl, USHORT Style, USHORT NbOfCols, USHORT NbOfRows, ULONG ulVersion)
  3140. {
  3141.   LONG      Arrow;
  3142.   RECTL     rcl, rclM;
  3143.   BOOL      Scrollable;
  3144.   PUCMDATA  UCMData;
  3145.   ULONG     ScrollStyle;
  3146.  
  3147.  
  3148.   UCMData = (PUCMDATA)WinQueryWindowULong(hwndUCMenu, QWL_UCMDATA);
  3149.  
  3150.   /*┌───────────────────────────┐
  3151.     │ Load the OWNERDRAWN items │
  3152.     └───────────────────────────┘*/
  3153.   UCMData->AccelTable->cAccel = 0;
  3154.  
  3155.   UCMenuLoadMenuData(hwndMenu, UCMData, ulVersion, hwndUCMenu );
  3156.  
  3157.   WinSetOwner (hwndMenu, hwndUCMenu);
  3158.  
  3159.   UCMenuNotifAll( UCMData, hwndMenu, UCN_ADDEDITEM );
  3160.  
  3161.   /*┌─────────────────────────────────────────────────────────────┐
  3162.     │ Autosize : take the size of the biggest item as a reference │
  3163.     └─────────────────────────────────────────────────────────────┘*/
  3164.  
  3165.     GetMaxItemSize(UCMData, hwndUCMenu, hwndMenu);
  3166.  
  3167.     if (Style & CMS_MATRIX) {
  3168.         prcl->yTop  = prcl->yBottom + (UCMData->MaxHorizontalHeight) * NbOfRows;
  3169.         prcl->yTop += SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  3170.         prcl->xRight  = prcl->xLeft + (UCMData->MaxVerticalWidth) * NbOfCols;
  3171.         prcl->xRight += SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  3172.     } // endif
  3173.  
  3174.     if ( Style & CMS_VERT ) {
  3175.       prcl->xRight = prcl->xLeft + UCMData->MaxVerticalWidth;
  3176.       prcl->xRight += SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  3177.     } // endif
  3178.  
  3179.     if ( Style & CMS_HORZ ) {
  3180.       prcl->yTop  = prcl->yBottom + UCMData->MaxHorizontalHeight;
  3181.       prcl->yTop += SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  3182.     } // endif
  3183.  
  3184.  
  3185.   /*┌──────────────────┐
  3186.     │ Size the UC Menu │
  3187.     └──────────────────┘*/
  3188.   WinSetWindowPos(hwndUCMenu,
  3189.                   HWND_TOP,
  3190.                   prcl->xLeft,
  3191.                   prcl->yBottom,
  3192.                   prcl->xRight - prcl->xLeft,
  3193.                   prcl->yTop - prcl->yBottom,
  3194.                   SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER);
  3195.  
  3196.   /*┌───────────────────┐
  3197.     │ Create Scroll Bar │
  3198.     └───────────────────┘*/
  3199.   ScrollStyle = SBS_HORZ;
  3200.   if ((Style & CMS_VERT) || ((Style & CMS_MATRIX_VERT) == CMS_MATRIX_VERT))
  3201.     ScrollStyle = SBS_VERT;
  3202.   UCMData->hwndScroll = WinCreateWindow(hwndUCMenu,
  3203.                                WC_SCROLLBAR,
  3204.                                "",
  3205.                                WS_VISIBLE | WS_CLIPCHILDREN | ScrollStyle,
  3206.                                0,
  3207.                                0,
  3208.                                prcl->xRight - prcl->xLeft,
  3209.                                prcl->yTop - prcl->yBottom,
  3210.                                hwndUCMenu,
  3211.                                HWND_TOP,
  3212.                                0,
  3213.                                NULL,
  3214.                                NULL);
  3215.  
  3216.   /*┌─────────────────────────────────────────────────┐
  3217.     │ Register and create a window to hide the slider │
  3218.     └─────────────────────────────────────────────────┘*/
  3219.   WinRegisterClass((HAB)NULLHANDLE, "Hide", (PFNWP)HideWndProc, (ULONG)CS_SIZEREDRAW, 4);
  3220.  
  3221.   UCMData->hwndHide = WinCreateWindow(UCMData->hwndScroll,
  3222.                              "Hide",
  3223.                              "",
  3224.                              WS_VISIBLE,
  3225.                              0,0,0,0,
  3226.                              hwndUCMenu,
  3227.                              HWND_TOP,
  3228.                              0,
  3229.                              (PVOID)WinQueryWindowULong(hwndUCMenu, QWL_UCMDATA),
  3230.                              (PVOID)NULL);
  3231.  
  3232.   WinSetParent(hwndMenu, UCMData->hwndHide, FALSE);
  3233.  
  3234.   switch (Style & 0x7) {
  3235.  
  3236.     case CMS_VERT:
  3237.       /*┌────────────────────────────────────────────────────────────────┐
  3238.         │ Get the menu height to know if we have to hide the buttons too:│
  3239.         │  - Set the width of the menu window and query its height       │
  3240.         └────────────────────────────────────────────────────────────────┘*/
  3241.       WinSetWindowPos(hwndMenu,
  3242.                       HWND_TOP,
  3243.                       0,
  3244.                       0,
  3245.                       UCMData->MaxVerticalWidth,
  3246.                       10000,
  3247.                       SWP_SIZE);
  3248.       WinQueryWindowRect(hwndMenu, &rclM);
  3249.       // The height returned is the sum  of all the items heights + 1
  3250.       //  ( don't ask me why ... )
  3251.       rclM.yTop --;
  3252.       WinSetWindowPos(hwndMenu,
  3253.                       HWND_TOP,
  3254.                       0,
  3255.                       0,
  3256.                       rclM.xRight,
  3257.                       rclM.yTop,
  3258.                       SWP_SIZE);
  3259.  
  3260.  
  3261.       /*┌──────────────────────┐
  3262.         │ Size the Hide Window │
  3263.         └──────────────────────┘*/
  3264.       Arrow = WinQuerySysValue(HWND_DESKTOP, SV_CYVSCROLLARROW);
  3265.       Scrollable = (rclM.yTop > (prcl->yTop - prcl->yBottom - SUM_UCM_FRAME_THICK - SUM_MENU_FRAME_THICK));
  3266.       WinSetWindowPos(UCMData->hwndHide,
  3267.                       HWND_TOP,
  3268.                       UCM_FRAME_THICK,
  3269.                       UCM_FRAME_THICK + Arrow * Scrollable,
  3270.                       prcl->xRight - prcl->xLeft   - SUM_UCM_FRAME_THICK,
  3271.                       prcl->yTop   - prcl->yBottom - SUM_UCM_FRAME_THICK - 2 * Arrow * Scrollable,
  3272.                       SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER);
  3273.  
  3274.       /*┌─────────────────────────────────────────────────────┐
  3275.         │Set the scrollbar parameters : slider size and range │
  3276.         └─────────────────────────────────────────────────────┘*/
  3277.       WinQueryWindowRect(UCMData->hwndHide, &rcl);
  3278.       WinSendMsg(UCMData->hwndScroll,
  3279.                  SBM_SETSCROLLBAR,
  3280.                  MPFROMSHORT(0),
  3281.                  MPFROM2SHORT(0, rclM.yTop - (rcl.yTop - rcl.yBottom - SUM_MENU_FRAME_THICK)));
  3282.       WinSendMsg(UCMData->hwndScroll,
  3283.                  SBM_SETTHUMBSIZE,
  3284.                  MPFROM2SHORT(rcl.yTop - rcl.yBottom - SUM_MENU_FRAME_THICK, rclM.yTop),
  3285.                  (MPARAM)0);
  3286.  
  3287.       /*┌────────────────────────────┐
  3288.         │ Position and show the menu │
  3289.         └────────────────────────────┘*/
  3290.       WinSetWindowPos(hwndMenu,
  3291.                       HWND_TOP,
  3292.                       MENU_FRAME_THICK,
  3293.                       (rcl.yTop - rcl.yBottom - SUM_MENU_FRAME_THICK) - rclM.yTop  + MENU_FRAME_THICK,
  3294.                       0,
  3295.                       0,
  3296.                       SWP_MOVE | SWP_SHOW);
  3297.       break;
  3298.  
  3299.     case CMS_HORZ:
  3300.       /*┌────────────────────────────────────────────────────────────────┐
  3301.         │ Get the menu  width to know if we have to hide the buttons too:│
  3302.         │  - Query all items ...                                         │
  3303.         └────────────────────────────────────────────────────────────────┘*/
  3304.       { SHORT sIndex, NbOfItems, ItemID2, MenuWidth=0;
  3305.         RECTL rclItem;
  3306.  
  3307.         /*┌────────────────────────────────┐
  3308.           │ Query the Number of menu items │
  3309.           └────────────────────────────────┘*/
  3310.         NbOfItems = (SHORT)WinSendMsg(hwndMenu,
  3311.                                       MM_QUERYITEMCOUNT,
  3312.                                       (MPARAM)0,
  3313.                                       (MPARAM)0);
  3314.  
  3315.         for (sIndex=0 ; sIndex<NbOfItems ; sIndex++) {
  3316.           /*┌─────────────────────────────────────────────────────────┐
  3317.             │ Query the item rectangle and add the width to MenuWidth │
  3318.             └─────────────────────────────────────────────────────────┘*/
  3319.           ItemID2 = (SHORT)WinSendMsg(hwndMenu,
  3320.                                       MM_ITEMIDFROMPOSITION,
  3321.                                       MPFROMSHORT(sIndex),
  3322.                                       (MPARAM)0);
  3323.           WinSendMsg(hwndMenu,
  3324.                      MM_QUERYITEMRECT,
  3325.                      MPFROM2SHORT(ItemID2,FALSE),
  3326.                      MPFROMP(&rclItem));
  3327.  
  3328.           MenuWidth += rclItem.xRight - rclItem.xLeft;
  3329.         } /* endfor */
  3330.  
  3331.         /*┌──────────────────────┐
  3332.           │ Size the menu window │
  3333.           └──────────────────────┘*/
  3334.         WinSetWindowPos(hwndMenu,
  3335.                         HWND_TOP,
  3336.                         0,
  3337.                         0,
  3338.                         MenuWidth,
  3339.                         UCMData->MaxHorizontalHeight,
  3340.                         SWP_SIZE);
  3341.       }
  3342.  
  3343.       WinQueryWindowRect(hwndMenu, &rclM);
  3344.  
  3345.       /*┌──────────────────────┐
  3346.         │ Size the Hide Window │
  3347.         └──────────────────────┘*/
  3348.       Arrow = WinQuerySysValue(HWND_DESKTOP, SV_CXHSCROLLARROW);
  3349.       Scrollable = (rclM.xRight > (prcl->xRight - prcl->xLeft - SUM_UCM_FRAME_THICK - SUM_MENU_FRAME_THICK));
  3350.       WinSetWindowPos(UCMData->hwndHide,
  3351.                       HWND_TOP,
  3352.                       UCM_FRAME_THICK + Arrow * Scrollable,
  3353.                       UCM_FRAME_THICK,
  3354.                       prcl->xRight - prcl->xLeft - SUM_UCM_FRAME_THICK - 2 * Arrow * Scrollable,
  3355.                       prcl->yTop - prcl->yBottom - SUM_UCM_FRAME_THICK,
  3356.                       SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER);
  3357.  
  3358.       /*┌─────────────────────────────────────────────────────┐
  3359.         │Set the scrollbar parameters : slider size and range │
  3360.         └─────────────────────────────────────────────────────┘*/
  3361.       WinQueryWindowRect(UCMData->hwndHide, &rcl);
  3362.       WinSendMsg(UCMData->hwndScroll,
  3363.                  SBM_SETSCROLLBAR,
  3364.                  MPFROMSHORT(0),
  3365.                  MPFROM2SHORT(0, rclM.xRight - (rcl.xRight - rcl.xLeft - SUM_MENU_FRAME_THICK)));
  3366.       WinSendMsg(UCMData->hwndScroll,
  3367.                  SBM_SETTHUMBSIZE,
  3368.                  MPFROM2SHORT(rcl.xRight - rcl.xLeft - SUM_MENU_FRAME_THICK, rclM.xRight),
  3369.                  (MPARAM)0);
  3370.  
  3371.       /*┌────────────────────────────┐
  3372.         │ Position and show the menu │
  3373.         └────────────────────────────┘*/
  3374.       WinSetWindowPos(hwndMenu,
  3375.                       HWND_TOP,
  3376.                       MENU_FRAME_THICK,
  3377.                       MENU_FRAME_THICK,
  3378.                       0,
  3379.                       0,
  3380.                       SWP_MOVE | SWP_SHOW);
  3381.       break;
  3382.  
  3383.     case CMS_MATRIX:
  3384.       WinSetWindowPos(hwndMenu,
  3385.                       HWND_TOP,
  3386.                       0,
  3387.                       0,
  3388.                       prcl->xRight - prcl->xLeft - SUM_MENU_FRAME_THICK - SUM_UCM_FRAME_THICK,
  3389.                       10000,
  3390.                       SWP_SIZE);
  3391.       WinQueryWindowRect(hwndMenu, &rclM);
  3392.  
  3393.       WinSetWindowPos(UCMData->hwndHide,
  3394.                       HWND_TOP,
  3395.                       UCM_FRAME_THICK,
  3396.                       UCM_FRAME_THICK,
  3397.                       prcl->xRight - prcl->xLeft - SUM_UCM_FRAME_THICK,
  3398.                       prcl->yTop - prcl->yBottom - SUM_UCM_FRAME_THICK,
  3399.                       SWP_MOVE | SWP_SIZE | SWP_SHOW );
  3400.  
  3401.       WinSetWindowPos(hwndMenu,
  3402.                       HWND_TOP,
  3403.                       MENU_FRAME_THICK,
  3404.                       prcl->yTop - prcl->yBottom - SUM_MENU_FRAME_THICK - SUM_UCM_FRAME_THICK - rclM.yTop + MENU_FRAME_THICK,
  3405.                       0,
  3406.                       0,
  3407.                       SWP_MOVE | SWP_ZORDER | SWP_SHOW);
  3408.  
  3409.       break;
  3410.   } /* endswitch */
  3411. }
  3412.  
  3413. //----------------------------------------------------------------------------
  3414. // UCMenuSize : Not for the user's doc
  3415. //----------------------------------------------------------------------------
  3416. // :pfunction res=&IDF_UCMenuSize. name='UCMenuSize' text='Resizes a menu window'.
  3417. // This function resizes the menu window of horizontal and vertical UCMenus.
  3418. // It is basically used when a user adds, removes or changes a bitmap.
  3419. // :syntax name='UCMenuSize' params='hwndMenu, Style' return='rc'.
  3420. // :fparams.
  3421. // :fparam name='hwndMenu' type='HWND' io='input'.
  3422. // Window handle of the menu.
  3423. // :fparam name='Style' type='LONG' io='input'.
  3424. // Style of the menu (CMS_HORZ or CMS_VERT).
  3425. // :freturns.
  3426. // :fparam name='rc' type='BOOL' io='output'.
  3427. // Returns :hp2.TRUE:ehp2. if the menu window is resized.
  3428. // :efparams.
  3429. // :remarks.
  3430. // This function recalculates the width of horizontal menus and the height of
  3431. // vertical menus by adding the bitmap sizes.
  3432. // :hp2.Note&colon.:ehp2. This function is automatically called by the UCMenu when it receives
  3433. // a MM_DELETEITEM, MM_REMOVEITEM, MM_INSERTITEM, MM_SETITEM, MM_SETITEMATTR
  3434. // or MM_SETITEMHANDLE message.
  3435. // :enote.
  3436. // :xamples.
  3437. // :related.
  3438. // :epfunction.
  3439. //----------------------------------------------------------------------------
  3440. BOOL _Optlink  UCMenuSize(HWND hwndMenu, USHORT Style)
  3441. {
  3442.   RECTL rcl;
  3443.   SHORT Size=0;
  3444.   SHORT NbOfItems, ItemID, sIndex;
  3445.   HWND  hwndHide;
  3446.   PUCMDATA UCMData ;
  3447.  
  3448.   UCMData = (PUCMDATA)WinQueryWindowULong(hwndMenu , QWL_USER);
  3449.  
  3450.   /*┌────────────────────────────────┐
  3451.     │ Query the Number of menu items │
  3452.     └────────────────────────────────┘*/
  3453.   NbOfItems = (SHORT)WinSendMsg(hwndMenu,
  3454.                                 MM_QUERYITEMCOUNT,
  3455.                                 (MPARAM)0,
  3456.                                 (MPARAM)0);
  3457.  
  3458.   for (sIndex=0 ; sIndex<NbOfItems ; sIndex++) {
  3459.     /*┌───────────────────────────────────────────────────┐
  3460.       │ Query the item rectangle and add its size to Size │
  3461.       └───────────────────────────────────────────────────┘*/
  3462.     ItemID = (SHORT)WinSendMsg(hwndMenu,
  3463.                                MM_ITEMIDFROMPOSITION,
  3464.                                MPFROMSHORT(sIndex),
  3465.                                (MPARAM)0);
  3466.     WinSendMsg(hwndMenu,
  3467.                MM_QUERYITEMRECT,
  3468.                MPFROM2SHORT(ItemID,FALSE),
  3469.                MPFROMP(&rcl));
  3470.  
  3471.     if (Style & CMS_HORZ)
  3472.       Size += rcl.xRight - rcl.xLeft;
  3473.     else
  3474.       Size += rcl.yTop - rcl.yBottom;
  3475.  
  3476.   }
  3477.  
  3478.   /*┌───────────────────────┐
  3479.     │ Invalidate the parent │
  3480.     └───────────────────────┘*/
  3481.   hwndHide = WinQueryWindow(hwndMenu, QW_PARENT);
  3482.   WinQueryWindowRect(hwndHide, &rcl);
  3483.   WinInvalidateRect(hwndHide, &rcl, TRUE);
  3484.  
  3485.   /*┌──────────────────────┐
  3486.     │ Size the menu window │
  3487.     └──────────────────────┘*/
  3488.   if (!(Style & CMS_MATRIX))
  3489.     WinSetWindowPos(hwndMenu,
  3490.                     HWND_TOP,
  3491.                     MENU_FRAME_THICK,
  3492.                     MENU_FRAME_THICK,
  3493.                     (Style & CMS_HORZ ? Size : UCMData->MaxVerticalWidth ),
  3494.                     (Style & CMS_VERT ? Size : UCMData->MaxHorizontalHeight),
  3495.                     SWP_SIZE);
  3496.   else
  3497.     WinSetWindowPos(hwndMenu,
  3498.                     HWND_TOP,
  3499.                     MENU_FRAME_THICK,
  3500.                     MENU_FRAME_THICK,
  3501.                     UCMData->MaxVerticalWidth    * UCMData->NbOfCols,
  3502.                     UCMData->MaxHorizontalHeight * UCMData->NbOfRows,
  3503.                     SWP_SIZE);
  3504.  
  3505.   return TRUE;
  3506. }
  3507.  
  3508. //----------------------------------------------------------------------------
  3509. // UCMenuCheckScrolling : Not for the user's doc
  3510. //----------------------------------------------------------------------------
  3511. // :pfunction res=&IDF_CHKSCROL. name='UCMenuCheckScrolling' text='Checks the scrolling status'.
  3512. // This function compares the menu size with the UCMenu size and enables or disables
  3513. // the scrolling.
  3514. // :syntax name='UCMenuCheckScrolling' params='hwndUCMenu' return='rc'.
  3515. // :fparams.
  3516. // :fparam name='hwndUCMenu' type='HWND' io='input'.
  3517. // Window handle of the UCMenu (as returned by CreateUCMenu).
  3518. // :freturns.
  3519. // :fparam name='rc' type='BOOL' io='output'.
  3520. // Returns :hp1.TRUE:ehp1. if the scrolling status changed.
  3521. // :efparams.
  3522. // :remarks.
  3523. // The parameters are reset in two cases &colon.
  3524. // :ol compact.
  3525. // :li.The menu is larger than the UCMenu and the scrolling disabled
  3526. // :li.The menu is shorter than the UCMenu and the scrolling enabled
  3527. // :eol.
  3528. // :note.This function is called every time the UCMenu receives a WM_SIZE
  3529. // message.
  3530. // :enote.
  3531. // :xamples.
  3532. // :related.
  3533. // :epfunction.
  3534. //----------------------------------------------------------------------------
  3535. BOOL _Optlink  UCMenuCheckScrolling(HWND hwndUCMenu)
  3536. {
  3537.   HWND      hwndScroll = WinQueryWindow(hwndUCMenu, QW_TOP);
  3538.   HWND      hwndHide   = WinQueryWindow(hwndScroll, QW_TOP);
  3539.   HWND      hwndMenu   = WinQueryWindow(hwndHide,   QW_TOP);
  3540.   LONG      Arrow      = WinQuerySysValue(HWND_DESKTOP, SV_CYVSCROLLARROW);
  3541.   ULONG     Style      = WinQueryWindowULong(hwndUCMenu, QWL_STYLE);
  3542.   SWP       swpMenu, swpHide, swpScroll;
  3543.  
  3544.   if (!Style)
  3545.     return FALSE;
  3546.  
  3547.   WinQueryWindowPos(hwndMenu,   &swpMenu);
  3548.   WinQueryWindowPos(hwndHide,   &swpHide);
  3549.   WinQueryWindowPos(hwndScroll, &swpScroll);
  3550.  
  3551.   if (((Style & CMS_VERT) || ((Style & CMS_MATRIX_VERT) == CMS_MATRIX_VERT)) &&
  3552.       swpMenu.cy >  swpScroll.cy - SUM_UCM_FRAME_THICK - SUM_MENU_FRAME_THICK
  3553.       ) {
  3554.     SHORT     CurrPos;    //@XXXa
  3555.     CurrPos = (SHORT)WinSendMsg(hwndScroll, SBM_QUERYPOS, MPVOID, MPVOID);  //@XXXa
  3556.     /*┌──────────────────────────────────────────────────────────────────┐
  3557.       │ Menu larger than scrollbar. We reset the                         │
  3558.       │ whole thing : Resize the hiding window, reposition the menu      │
  3559.       │ window, reset the scrolling parameters                           │
  3560.       └──────────────────────────────────────────────────────────────────┘*/
  3561.  
  3562.     /* Adjust hide window to uncover scroll bar arrows */
  3563.     swpHide.y    += Arrow;
  3564.     swpHide.cy   -= 2 * Arrow;
  3565.  
  3566.     /* Adjust menu to current scroll position */
  3567.     swpMenu.y = (swpHide.cy - MENU_FRAME_THICK) - swpMenu.cy + CurrPos;
  3568.  
  3569.     // Adjust position of the menu window relative to the scrollbar window.  Position the
  3570.     // X coordinate to align the left edge of the menu into the scrollbar.  Leave the Y
  3571.     // coordinate where it is, or flush-top align it if it does not extend to the bottom.
  3572.  
  3573.     swpMenu.x = MENU_FRAME_THICK;
  3574. //  if (swpMenu.y + swpMenu.cy < swpHide.y + swpHide.cy - MENU_FRAME_THICK)  // Does not reach top?
  3575. //    swpMenu.y = (swpHide.y + swpHide.cy - MENU_FRAME_THICK) - swpMenu.cy;  // Align to top
  3576. //  else
  3577.       swpMenu.y = min(swpMenu.y, MENU_FRAME_THICK);         // Dont allow to lift off bottom
  3578.     WinSetWindowPos(hwndMenu,
  3579.                       HWND_TOP, swpMenu.x, swpMenu.y, 0, 0,
  3580.                       SWP_MOVE | SWP_SHOW | SWP_ZORDER);
  3581.  
  3582.     WinSetWindowPos(hwndHide,
  3583.                     HWND_TOP,
  3584.                     swpHide.x,
  3585.                     swpHide.y,
  3586.                     swpHide.cx,
  3587.                     swpHide.cy,
  3588.                     SWP_MOVE | SWP_SIZE | SWP_SHOW);
  3589.  
  3590.     /*┌──────────────────────────────┐
  3591.       │ Set the scrolling parameters │
  3592.       └──────────────────────────────┘*/
  3593.     WinSendMsg(hwndScroll,
  3594.                SBM_SETSCROLLBAR,
  3595.                MPFROMSHORT((swpMenu.y+swpMenu.cy)-(swpHide.cy-MENU_FRAME_THICK)),
  3596.                MPFROM2SHORT(0, swpMenu.cy - (swpHide.cy-SUM_MENU_FRAME_THICK)));
  3597.     WinSendMsg(hwndScroll,
  3598.                SBM_SETTHUMBSIZE,
  3599.                MPFROM2SHORT(swpHide.cy-SUM_MENU_FRAME_THICK, swpMenu.cy),
  3600.                (MPARAM)0);
  3601.   
  3602.     /*┌───────────────────────────────┐
  3603.       │ Window resized : return TRUE  │
  3604.       └───────────────────────────────┘*/
  3605.     return TRUE;
  3606.   } /* endif */
  3607.  
  3608.   if (((Style & CMS_VERT) || ((Style & CMS_MATRIX_VERT) == CMS_MATRIX_VERT)) &&
  3609.       swpMenu.cy <= swpScroll.cy - SUM_UCM_FRAME_THICK - SUM_MENU_FRAME_THICK
  3610.       ) {
  3611.     /*┌──────────────────────────────────────────────────────────────────┐
  3612.       │ Menu smaller than scrollbar. We reset the                        │
  3613.       │ whole thing : Resize the hiding window, reposition the menu      │
  3614.       │ window, reset the scrolling parameters                           │
  3615.       └──────────────────────────────────────────────────────────────────┘*/
  3616.  
  3617.       // Reset menu to left/top flush edge
  3618.       WinSetWindowPos(hwndMenu,
  3619.                       HWND_TOP,
  3620.                       MENU_FRAME_THICK,
  3621.                       (swpHide.cy - MENU_FRAME_THICK) - swpMenu.cy,
  3622.                       0,
  3623.                       0,
  3624.                       SWP_MOVE | SWP_SHOW | SWP_ZORDER);
  3625.  
  3626.  
  3627.     /*┌──────────────────────────────┐
  3628.       │ Set the scrolling parameters │
  3629.       └──────────────────────────────┘*/
  3630.     WinSendMsg(hwndScroll,
  3631.                SBM_SETSCROLLBAR,
  3632.                MPFROMSHORT(0),
  3633.                MPFROM2SHORT(0, swpMenu.cy - (swpHide.cy-SUM_MENU_FRAME_THICK)));
  3634.     WinSendMsg(hwndScroll,
  3635.                SBM_SETTHUMBSIZE,
  3636.                MPFROM2SHORT(swpHide.cy-SUM_MENU_FRAME_THICK, swpMenu.cy),
  3637.                (MPARAM)0);
  3638.  
  3639.     return TRUE;
  3640.   } /* endif */
  3641.  
  3642.   if ((Style & CMS_HORZ) &&
  3643.       swpMenu.cx >  swpScroll.cx - SUM_UCM_FRAME_THICK - SUM_MENU_FRAME_THICK
  3644.       ) {
  3645.  
  3646.     /*┌──────────────────────────────────────────────────────────────────┐
  3647.       │ Menu larger than scrollbar. We reset the                         │
  3648.       │ whole thing : Resize the hiding window, reposition the menu      │
  3649.       │ window, reset the scrolling parameters                           │
  3650.       └──────────────────────────────────────────────────────────────────┘*/
  3651.  
  3652.     /*┌───────────────────────────────────┐
  3653.       │ Resize Hide : width   -= 2 Arrows │
  3654.       │ Repos  Hide : xLeft   += Arrow    │
  3655.       └───────────────────────────────────┘*/
  3656.     swpHide.x  +=     Arrow;
  3657.     swpHide.cx -= 2 * Arrow;
  3658.  
  3659.     // Adjust position of the menu window relative to the scrollbar window.  Position the
  3660.     // Y coordinate to align the top edge of the menu into the scrollbar.  Leave the X
  3661.     // coordinate where it is, or flush-right align it if it does not extend to the edge.
  3662.  
  3663.     swpMenu.y = swpScroll.cy - (2*SUM_UCM_FRAME_THICK) - swpMenu.cy + MENU_FRAME_THICK;                         //@P5a
  3664.     swpMenu.x = max(swpMenu.x, swpScroll.x + swpScroll.cx - (2*Arrow) - swpMenu.cx - (2*SUM_MENU_FRAME_THICK)); //@P5a
  3665.     WinSetWindowPos(hwndMenu,                                                                                   //@P5m
  3666.                       HWND_TOP, swpMenu.x, swpMenu.y, 0, 0,                                                     //@P5m
  3667.                       SWP_MOVE | SWP_SHOW | SWP_ZORDER);                                                        //@P5m
  3668.  
  3669.     WinSetWindowPos(hwndHide,
  3670.                     HWND_TOP,
  3671.                     swpHide.x,
  3672.                     swpHide.y,
  3673.                     swpHide.cx,
  3674.                     swpHide.cy,
  3675.                     SWP_MOVE | SWP_SIZE | SWP_SHOW);
  3676.  
  3677.     /*┌──────────────────────────────┐
  3678.       │ Set the scrolling parameters │
  3679.       └──────────────────────────────┘*/
  3680.     WinSendMsg(hwndScroll,
  3681.                SBM_SETSCROLLBAR,
  3682.                MPFROMSHORT(swpScroll.x - swpMenu.x),  // Posn may have changed by move of menu above //@P5c
  3683.                MPFROM2SHORT(0, swpMenu.cx - (swpHide.cx-SUM_MENU_FRAME_THICK)));
  3684.     WinSendMsg(hwndScroll,
  3685.                SBM_SETTHUMBSIZE,
  3686.                MPFROM2SHORT(swpHide.cx-SUM_MENU_FRAME_THICK, swpMenu.cx),
  3687.                (MPARAM)0);
  3688.  
  3689.     /*┌───────────────────────────────┐
  3690.       │ Window resized : return TRUE  │
  3691.       └───────────────────────────────┘*/
  3692.     return TRUE;
  3693.   } /* endif */
  3694.  
  3695.   if ((Style & CMS_HORZ) &&
  3696.       swpMenu.cx <= swpScroll.cx - SUM_UCM_FRAME_THICK - SUM_MENU_FRAME_THICK
  3697.       ) {
  3698.     /*┌──────────────────────────────────────────────────────────────────┐
  3699.       │ Menu smaller than scrollbar. We reset the                        │
  3700.       │ whole thing : Resize the hiding window, reposition the menu      │
  3701.       │ window, reset the scrolling parameters                           │
  3702.       └──────────────────────────────────────────────────────────────────┘*/
  3703.  
  3704.       // Reset menu to left/top flush edge
  3705.       WinSetWindowPos(hwndMenu,                                                                 //@P5a
  3706.                       HWND_TOP,                                                                 //@P5a 
  3707.                       MENU_FRAME_THICK,                                                         //@P5a 
  3708.                       swpScroll.cy - (2*SUM_UCM_FRAME_THICK) - swpMenu.cy + MENU_FRAME_THICK,   //@P5a 
  3709.                       0, 0, SWP_MOVE | SWP_SHOW | SWP_ZORDER);                                  //@P5a 
  3710.  
  3711.     /*┌──────────────────────────────┐
  3712.       │ Set the scrolling parameters │
  3713.       └──────────────────────────────┘*/
  3714.     WinSendMsg(hwndScroll,
  3715.                SBM_SETSCROLLBAR,
  3716.                MPFROMSHORT(0),        // Scroll position is now zero (flush left)
  3717.                MPFROM2SHORT(0, swpMenu.cx - (swpHide.cx-SUM_MENU_FRAME_THICK)));
  3718.     WinSendMsg(hwndScroll,
  3719.                SBM_SETTHUMBSIZE,
  3720.                MPFROM2SHORT(swpHide.cx-SUM_MENU_FRAME_THICK, swpMenu.cx),
  3721.                (MPARAM)0);
  3722.  
  3723.     return TRUE;
  3724.   } else {
  3725.     /*┌─────────────────────┐
  3726.       │ Matrix, no scrolling│
  3727.       └─────────────────────┘*/
  3728.  
  3729.       // Reset menu to flush left/top
  3730.       WinSetWindowPos(hwndMenu, HWND_TOP,                                                       //@P5a
  3731.                       MENU_FRAME_THICK,                                                         //@P5a 
  3732.                       (swpHide.cy - MENU_FRAME_THICK) - swpMenu.cy,                             //@P5a
  3733.                       0, 0, SWP_MOVE | SWP_SHOW | SWP_ZORDER);                                  //@P5a 
  3734.  
  3735. //  WinSendMsg(hwndScroll,
  3736. //             SBM_SETSCROLLBAR,
  3737. //             MPFROMSHORT(0),
  3738. //             MPFROM2SHORT(0,0));
  3739. //  WinSendMsg(hwndScroll,
  3740. //             SBM_SETTHUMBSIZE,
  3741. //             MPFROM2SHORT(swpHide.cx-SUM_MENU_FRAME_THICK, swpMenu.cx),
  3742. //             (MPARAM)0);
  3743.     return TRUE;
  3744.   } /* endif */
  3745. }
  3746.  
  3747. //----------------------------------------------------------------------------
  3748. // UCMenuIdFromCoord :
  3749. //----------------------------------------------------------------------------
  3750. // :function res=&IDF_IDFROMP. name='UCMenuIdFromCoord' text='Get the ID of a specified menu item' .
  3751. // This function returns the id of the menu item that is at a specified position.
  3752. // :syntax name='UCMenuIdFromCoord' params='hwndMenu, pptrPos' return='ItemID' .
  3753. // :fparams.
  3754. // :fparam name='hwndMenu' type='HWND' io='input' .
  3755. // Menu window handle.
  3756. // :fparam name='pptrPos' type='PPOINTL' io='input' .
  3757. // Position
  3758. // :freturns.
  3759. // :fparam name='ItemID' type='USHORT' io='return'.
  3760. // The item Identifier. 0 if not found.
  3761. // :efparams.
  3762. // :remarks.
  3763. // This function doesn't check the submenus. However, you can identify an item in a submenu
  3764. // if you pass the hwnd of the submenu...
  3765. // :related.
  3766. // :efunction.
  3767. //----------------------------------------------------------------------------
  3768. USHORT APIENTRY  UCMenuIdFromCoord(HWND hwndMenu, PPOINTL pptrPos)
  3769. {
  3770.   USHORT    NbOfItems, ItemID, usIndex;
  3771.   RECTL    rcl;
  3772.  
  3773.   /*┌────────────────────────────────┐
  3774.     │ Query the Number of menu items │
  3775.     └────────────────────────────────┘*/
  3776.   NbOfItems = (USHORT)WinSendMsg(hwndMenu,
  3777.                                  MM_QUERYITEMCOUNT,
  3778.                                  (MPARAM)0,
  3779.                                  (MPARAM)0);
  3780.  
  3781.   for (usIndex=0 ; usIndex<NbOfItems ; usIndex++) {
  3782.     /*┌───────────────────┐
  3783.       │ Query the item id │
  3784.       └───────────────────┘*/
  3785.     ItemID = (USHORT)WinSendMsg(hwndMenu,
  3786.                                MM_ITEMIDFROMPOSITION,
  3787.                                MPFROMSHORT(usIndex),
  3788.                                (MPARAM)0);
  3789.  
  3790.     /*┌─────────────────────────┐
  3791.       │ Query the item rectangle│
  3792.       └─────────────────────────┘*/
  3793.     WinSendMsg(hwndMenu,
  3794.                MM_QUERYITEMRECT,
  3795.                MPFROM2SHORT(ItemID,TRUE),
  3796.                MPFROMP(&rcl));
  3797.  
  3798.     //(MAM) fixed following to include xRight and yTop pixels
  3799.     if (    pptrPos->x >= rcl.xLeft
  3800.          && pptrPos->x <= rcl.xRight
  3801.          && pptrPos->y >= rcl.yBottom
  3802.          && pptrPos->y <= rcl.yTop     ) {
  3803.       /*┌─────────────┐
  3804.         │ We got it ! │
  3805.         └─────────────┘*/
  3806.       return ItemID;
  3807.      } // endif;
  3808.   } // endfor
  3809.   return 0;
  3810. }
  3811.  
  3812. //----------------------------------------------------------------------------
  3813. // UCMenuGetActionID
  3814. //----------------------------------------------------------------------------
  3815. // :function res=&IDF_IDFROMACTION. name='UCMenuGetActionID' text='Get the IDs corresponding to an action' .
  3816. // This function returns the ID of the item with a pszAction action, starting at the item sStart.
  3817. // :syntax name='UCMenuGetActionID' params='hwndUCM, pszAction, , bSubmenus, sStart ' return='FoundID' .
  3818. // :fparams.
  3819. // :fparam name='hwndUCM' type='HWND' io='input' .
  3820. // UCMenu window handle.
  3821. // :fparam name='pszAction' type='PSZ' io='input' .
  3822. // Action string to look for
  3823. // :fparam name='bSubmenus' type='BOOL' io='input' .
  3824. // Look in submenus or not.
  3825. // :fparam name='Start' type='SHORT' io='input' .
  3826. // Item ID to start with, MIT_FIRST for the beginning.
  3827. // :freturns.
  3828. // :fparam name='FoundID' type='SHORT' io='return'.
  3829. // Item ID found, or MIT_NONE
  3830. // :efparams.
  3831. // :remarks.
  3832. // :related.
  3833. // :efunction.
  3834. //----------------------------------------------------------------------------
  3835. SHORT APIENTRY UCMenuGetActionID(HWND hwndUCM, PSZ pszAction, BOOL bSubmenus, SHORT sStartID)
  3836. {
  3837.    SHORT    sFound;
  3838.    PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwndUCM, QWL_UCMDATA );
  3839.  
  3840.    if ( UCMData ) {
  3841.       sFound =  UCMenuGetActionID2( UCMData->hwndMenu, pszAction, bSubmenus, sStartID );
  3842.       if ( sFound == -2 ){
  3843.          return MIT_NONE;
  3844.       } else {
  3845.          return sFound;
  3846.       } // endif
  3847.    } else {
  3848.       return MIT_NONE;
  3849.    } /* endif */
  3850. }
  3851.  
  3852.  
  3853. //----------------------------------------------------------------------------
  3854. // UCMenuGetActionID2
  3855. //----------------------------------------------------------------------------
  3856. // :pfunction res=&IDF_IDFROMACTION2. name='UCMenuGetActionID2' text='Get the IDs corresponding to an action'.
  3857. // This function returns the ID of the item with a pszAction action, starting at the item sStart.
  3858. // :syntax name='UCMenuGetActionID2' params='hwndUCM, pszAction, , bSubmenus, sStart ' return='FoundID' .
  3859. // :fparams.
  3860. // :fparam name='hwndMenu' type='HWND' io='input' .
  3861. // Menu window handle.
  3862. // :fparam name='pszAction' type='PSZ' io='input' .
  3863. // Action string to look for
  3864. // :fparam name='bSubmenus' type='BOOL' io='input' .
  3865. // Look in submenus or not.
  3866. // :fparam name='Start' type='SHORT' io='input' .
  3867. // Item ID to start with, MIT_FIRST for the beginning.
  3868. // :freturns.
  3869. // :fparam name='FoundID' type='SHORT' io='return'.
  3870. // Item ID found, or MIT_NONE if none, -2 if sStart has been found
  3871. // :efparams.
  3872. // :remarks.
  3873. // :related.
  3874. // :epfunction.
  3875. //----------------------------------------------------------------------------
  3876.  
  3877. SHORT _Optlink UCMenuGetActionID2(HWND hwndMenu, PSZ pszAction, BOOL bSubmenus, SHORT sStartID)
  3878. {
  3879.   USHORT    NbOfItems, ItemID, usIndex;
  3880.   BOOL      bStartIDPassed;
  3881.   MENUITEM  mi;
  3882.  
  3883.   if ( sStartID == MIT_FIRST ){
  3884.      bStartIDPassed = TRUE;
  3885.   } else {
  3886.      bStartIDPassed = FALSE;
  3887.   } // endif
  3888.  
  3889.   /*┌────────────────────────────────┐
  3890.     │ Query the Number of menu items │
  3891.     └────────────────────────────────┘*/
  3892.   NbOfItems = (USHORT)WinSendMsg(hwndMenu,
  3893.                                  MM_QUERYITEMCOUNT,
  3894.                                  (MPARAM)0,
  3895.                                  (MPARAM)0);
  3896.  
  3897.   for (usIndex=0 ; usIndex<NbOfItems ; usIndex++) {
  3898.     /*┌───────────────────┐
  3899.       │ Query the item id │
  3900.       └───────────────────┘*/
  3901.     memset( &mi, '\0', sizeof mi );
  3902.     ItemID = (USHORT)WinSendMsg(hwndMenu,
  3903.                                MM_ITEMIDFROMPOSITION,
  3904.                                MPFROMSHORT(usIndex),
  3905.                                (MPARAM)0);
  3906.  
  3907.     /*┌────────────────┐
  3908.       │ Query the item │
  3909.       └────────────────┘*/
  3910.     WinSendMsg(hwndMenu,
  3911.                MM_QUERYITEM,
  3912.                MPFROM2SHORT(ItemID,FALSE),
  3913.                MPFROMP(&mi));
  3914.     if ( bStartIDPassed ){
  3915.        if ( mi.hItem && ITEM( &mi, pszAction ) ){
  3916.           if ( !strcmp( pszAction, ITEM( &mi, pszAction ) ) ){
  3917.              return ItemID;
  3918.           } // endif
  3919.        } // endif
  3920.     } // endif
  3921.  
  3922.     if ( bSubmenus && mi.hwndSubMenu ){
  3923.        SHORT sFoundID =
  3924.           UCMenuGetActionID2( mi.hwndSubMenu, pszAction, FALSE, bStartIDPassed?MIT_FIRST:sStartID);
  3925.        if ( sFoundID != MIT_NONE  && sFoundID != -2){
  3926.           return sFoundID;
  3927.        } else if ( sFoundID == -2 ){
  3928.           bStartIDPassed = TRUE;
  3929.        } // endif
  3930.     } // endif
  3931.  
  3932.     if ( ItemID == sStartID ){
  3933.        bStartIDPassed = TRUE;
  3934.     } // endif
  3935.  
  3936.   } // endfor
  3937.  
  3938.   if ( bStartIDPassed ){
  3939.      return -2;
  3940.   } else {
  3941.      return MIT_NONE;
  3942.   } // endif
  3943. }
  3944.  
  3945. //----------------------------------------------------------------------------
  3946. // UCMenuSetActionAttr
  3947. //----------------------------------------------------------------------------
  3948. // :function res=&IDF_SETACTIONATTR. name='UCMenuSetActionAttr' text='Get the IDs corresponding to an action' .
  3949. // This function sets the attributes of the items with the given action.
  3950. // :syntax name='UCMenuSetActionAttr' params='hwndUCM, pszAction, usAttrMask, usAttrValue' return='nothing' .
  3951. // :fparams.
  3952. // :fparam name='hwndUCM' type='HWND' io='input' .
  3953. // UCMenu window handle.
  3954. // :fparam name='pszAction' type='PSZ' io='input' .
  3955. // Action string to look for
  3956. // :fparam name='usAttrMask' type='USHORT' io='input' .
  3957. // Attribute mask to use
  3958. // :fparam name='usAttrValue' type='USHORT' io='input' .
  3959. // Attribute value to set
  3960. // :freturns.
  3961. // :fparam name='-' type='VOID' io='return'.
  3962. // Nothing
  3963. // :efparams.
  3964. // :remarks.
  3965. // :related.
  3966. // MM_SETITEMATTR
  3967. // :efunction.
  3968. //----------------------------------------------------------------------------
  3969. VOID APIENTRY UCMenuSetActionAttr(HWND hwndUCM, PSZ pszAction, USHORT usAttrMask, USHORT usAttrValue )
  3970. {
  3971.    SHORT sIndex = MIT_FIRST;
  3972.    sIndex =  UCMenuGetActionID( hwndUCM, pszAction, TRUE, sIndex );
  3973.    while ( sIndex != MIT_NONE ){
  3974.       WinSendMsg( hwndUCM, MM_SETITEMATTR, MPFROM2SHORT( sIndex, TRUE ), MPFROM2SHORT( usAttrMask, usAttrValue ) );
  3975.       sIndex =  UCMenuGetActionID( hwndUCM, pszAction, TRUE, sIndex );
  3976.    } // endwhile
  3977. }
  3978.  
  3979.  
  3980. //----------------------------------------------------------------------------
  3981. // UCMenuContextMenu : Not for the user's doc
  3982. //----------------------------------------------------------------------------
  3983. // :pfunction res=&IDF_CTXTMENU. name='UCMenuContextMenu' text='Popups the context menu' .
  3984. // This function popups the appropriate context menu accroding to the mouse location
  3985. // :syntax name='UCMenuContextMenu' params='hwndUCMenu, hwndMenu, FromMouse' return='-' .
  3986. // :fparams.
  3987. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  3988. // UCMenu window handle.
  3989. // :fparam name='hwndMenu' type='HWND' io='input' .
  3990. // Menu window handle.
  3991. // :fparam name='FromMouse' type='BOOL' io='input' .
  3992. // Tells wether the CM was initiated from the mouse or not
  3993. // :freturns.
  3994. // :fparam name='-' type='VOID' io='-'.
  3995. // Nothing
  3996. // :efparams.
  3997. // :remarks.
  3998. // :related.
  3999. // :epfunction.
  4000. //----------------------------------------------------------------------------
  4001. VOID _Optlink UCMenuContextMenu(HWND hwndUCMenu, HWND hwndMenu, BOOL FromMouse)
  4002. { POINTL   ptl;
  4003.   MENUITEM mi;
  4004.   HWND     PopupHwnd;
  4005.   PUCMDATA UCMData    = (PUCMDATA)WinQueryWindowULong(hwndUCMenu, QWL_UCMDATA);
  4006.  
  4007.  
  4008.   // --------------------------------------
  4009.   // -- First check if context menu allowed
  4010.   // --------------------------------------
  4011.   if ( UCMData->Style & UCS_NO_CM ) {
  4012.      return;
  4013.   } // endif
  4014.  
  4015.   // -------------------------------------------------------------
  4016.   // -- UCMData->hwndCMOrig will be used to send the MM_INSERTITEM
  4017.   // -- If we add an item in the menu, send it to hwndUCMenu
  4018.   // --  If we add an item in a submenu, send it to the submenu
  4019.   // -------------------------------------------------------------
  4020.   if (UCMData->hwndMenu==hwndMenu) {
  4021.      UCMData->hwndCMOrig = hwndUCMenu;
  4022.   } else {
  4023.      UCMData->hwndCMOrig = hwndMenu;
  4024.   } // endif
  4025.  
  4026.   // ----------------------------------------------------------------
  4027.   // -- Query the id of the item under the mouse & get menu item info
  4028.   // ----------------------------------------------------------------
  4029.   if (FromMouse) {
  4030.      WinQueryPointerPos(HWND_DESKTOP, &ptl);
  4031.      WinMapWindowPoints(HWND_DESKTOP, hwndMenu, &ptl, 1);
  4032.      UCMData->ContextID = UCMenuIdFromCoord(hwndMenu, &ptl);
  4033.      WinMapWindowPoints(hwndMenu, HWND_DESKTOP, &ptl, 1);
  4034.   } else {
  4035.      RECTL Rectl;
  4036.      ULONG SelectedItem = (ULONG)
  4037.               WinSendMsg(hwndMenu, MM_QUERYSELITEMID, 0L, 0L);
  4038.      WinSendMsg( hwndMenu, MM_QUERYITEMRECT, (MPARAM)SelectedItem, MPFROMP(&Rectl));
  4039.      ptl.x = Rectl.xLeft   + (Rectl.xRight - Rectl.xLeft)/2;
  4040.      ptl.y = Rectl.yBottom + (Rectl.yTop - Rectl.yBottom)/2;
  4041.      UCMData->ContextID = UCMenuIdFromCoord(hwndMenu, &ptl);
  4042.      WinMapWindowPoints(hwndMenu, HWND_DESKTOP, &ptl, 1);
  4043.   }
  4044.  
  4045.   memset(&mi, 0x00, sizeof(MENUITEM));  // set to all zeros if not over an item
  4046.   if (UCMData->ContextID != 0)
  4047.     WinSendMsg( hwndMenu, MM_QUERYITEM, MPFROM2SHORT( UCMData->ContextID, FALSE ), MPFROMP( &mi ));
  4048.  
  4049.   /* See if the application has a context menu for us to use. */
  4050.   UCMData->hwndUserCM = (HWND)WinSendMsg(UCMData->hwndOwner, WM_CONTROL,
  4051.                               MPFROM2SHORT(UCMData->UCMenuID, UCN_QRYCONTEXTHWND),
  4052.                               MPFROMP(&mi));
  4053.  
  4054.   if (UCMData->hwndUserCM == NULLHANDLE) {  // Use our built-in menu
  4055.     #if !defined(UCMUI)
  4056.     return;           // No app context menu, and we don't support it
  4057.     #else
  4058.     PopupHwnd = UCMData->hwndCM;
  4059.     // ---------------------------------------------------------------------------
  4060.     // -- But if we were  on a MIS_SPACER item we won't be able to edit anyway
  4061.     // ---------------------------------------------------------------------------
  4062.     if ( mi.afStyle & MIS_SPACER ) {
  4063.       WinEnableMenuItem( UCMData->hwndCM, IDM_UCM_EDIT,   FALSE );
  4064.     } else {
  4065.       WinEnableMenuItem( UCMData->hwndCM, IDM_UCM_EDIT,   TRUE );
  4066.     } // endif
  4067.     // ---------------------------------------------------------------------------
  4068.     // -- But if we were not on an item we won't be able to edit and delete anyway
  4069.     // ---------------------------------------------------------------------------
  4070.     if ( UCMData->ContextID == 0 ) {
  4071.       WinEnableMenuItem( UCMData->hwndCM, IDM_UCM_DELETE, FALSE );
  4072.       WinEnableMenuItem( UCMData->hwndCM, IDM_UCM_EDIT,   FALSE );
  4073.     } else {
  4074.       WinEnableMenuItem( UCMData->hwndCM, IDM_UCM_DELETE, TRUE );
  4075.     } // endif
  4076.     #endif // UCMUI
  4077.   }
  4078.   else PopupHwnd = UCMData->hwndUserCM;    // Use application menu
  4079.  
  4080.   // Disable bubble help until popup is dismissed (WM_MENUEND message
  4081.   // processed in HideWndProc).  Otherwise bubble can overlay
  4082.   // and will be corrupted by poup repainting.
  4083.   WinSendMsg(UCMData->hwndBubble, MSG_DISABLE_BUBBLE, 0L, 0L);
  4084.  
  4085.   // --------------------------------------------------------------
  4086.   // -- At last pop up the  context menu.  Messages from this menu
  4087.   // -- will be processed by the HideWndProc() procedure.
  4088.   // --------------------------------------------------------------
  4089.   WinPopupMenu(HWND_DESKTOP,
  4090.                WinQueryWindow(UCMData->hwndMenu, QW_PARENT), // Hide window is owner
  4091.                PopupHwnd,
  4092.                ptl.x,
  4093.                ptl.y,
  4094.                0,
  4095.                PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_KEYBOARD |
  4096.                PU_HCONSTRAIN | PU_VCONSTRAIN);
  4097. } // endif
  4098.  
  4099. // (MAM) Added following routine
  4100. //----------------------------------------------------------------------------
  4101. // UCAdjacentItemBlank : Not for users doc
  4102. //----------------------------------------------------------------------------
  4103. // This function will take a menu item and see if the adjacent (left/right)
  4104. // item has the MIS_SPACER attribute, or if the given item is at the start/end
  4105. // of the menu.  A TRUE/FALSE is returned (TRUE if the adjacent item is
  4106. // a spacer or there is no adjacent item).  Last parm (LeftRight) is -1 for
  4107. // left/above check, +1 for right/below check.  The given ID is assumed to
  4108. // exist in the given menu.
  4109. //----------------------------------------------------------------------------
  4110.  
  4111. BOOL _Optlink UCAdjacentItemBlank(HWND MenuHwnd, SHORT ItemID, int LeftRight)
  4112. {
  4113.   SHORT ItemPos;      /* Position of this item in the menu */
  4114.   SHORT AdjItemID;    /* ID of adjacent menu item (if one) */
  4115.   MENUITEM MenuItem;  /* Adjacent item data                */
  4116.  
  4117.   ItemPos = (SHORT)WinSendMsg(MenuHwnd, MM_ITEMPOSITIONFROMID, MPFROM2SHORT(ItemID, FALSE), 0L);
  4118.   AdjItemID = (SHORT)WinSendMsg(MenuHwnd, MM_ITEMIDFROMPOSITION, MPFROMSHORT(ItemPos+LeftRight), 0L);
  4119.   if (AdjItemID != MIT_ERROR) {
  4120.     /* Get info about adjacent menu item and examine style flags */
  4121.     WinSendMsg(MenuHwnd, MM_QUERYITEM, MPFROM2SHORT(AdjItemID, FALSE), MPFROMP(&MenuItem));
  4122.     if (!(MIS_SPACER & MenuItem.afStyle))
  4123.       return FALSE;   /* There is a non-blank adjacent item */
  4124.   }
  4125.   return TRUE;        /* No adjacent item, or adjacent item is MIS_SPACER */
  4126. }
  4127.  
  4128. //----------------------------------------------------------------------------
  4129. // UCMenuWndProc
  4130. //----------------------------------------------------------------------------
  4131. // :pfunction res=&IDF_UCMWNDPROC. name='UCMenuWndProc' text='UCMenu window procedure'.
  4132. // Window procedure of the UCMenu class
  4133. // :syntax name='UCMenuWndProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  4134. // :fparams.
  4135. // :fparam name='hwnd' type='HWND' io='input' .
  4136. // UCMenu window handle
  4137. // :fparam name='msg' type='ULONG' io='input' .
  4138. // Message
  4139. // :fparam name='mp1' type='MPARAM' io='input'.
  4140. // First parameter
  4141. // :fparam name='mp2' type='MPARAM' io='input'.
  4142. // Second parameter
  4143. // :freturns.
  4144. // :fparam name='mresult' type='MRESULT' io='return'.
  4145. // Return code of a PM message.
  4146. // :efparams.
  4147. // :remarks.
  4148. // :dl compact.
  4149. // :dt.:hp2.WM_INITMENU:ehp2.
  4150. // :dd.:hp2.A submenu is about to be shown : we subclass it :ehp2.
  4151. // :dt.:hp2.WM_MENUEND:ehp2.
  4152. // :dd.:hp2.A submenu is about to be destroyed : we un-subclass it :ehp2.
  4153. // :dt.:hp2.WM_VSCROLL:ehp2.
  4154. // :dd.:hp2.Vertical scrolling event :ehp2.
  4155. // :dt.:hp2.WM_HSCROLL:ehp2.
  4156. // :dd.:hp2.Horizontal scrolling event :ehp2.
  4157. // :dt.:hp2.WM_DRAWITEM:ehp2.
  4158. // :dd.:hp2.Draws any OWNERDRAW menu item :ehp2.
  4159. // :dt.:hp2.WM_MEASUREITEM:ehp2.
  4160. // :dd.:hp2.Returns the height of an OWNERDRAW item :ehp2.
  4161. // :edl.
  4162. // :epfunction.
  4163. //----------------------------------------------------------------------------
  4164. MRESULT EXPENTRY UCMenuWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  4165. {
  4166.   ULONG Style      = WinQueryWindowULong(hwnd, QWL_STYLE);
  4167.   PUCMDATA UCMData = (PUCMDATA) WinQueryWindowULong( hwnd, QWL_UCMDATA );
  4168.  
  4169.   switch (msg) {
  4170.      case WM_TRANSLATEACCEL:
  4171.           {
  4172.            //??? does this code work?
  4173.            //PACCELTABLE AccelTable;
  4174.              HWND        hwndMenu = UCMData->hwndMenu;
  4175.              PQMSG       QMsg = (PQMSG)mp1;
  4176.            //USHORT      VK  = SHORT2FROMMP(mp2);
  4177.  
  4178.              if(QMsg->msg == WM_CHAR) {
  4179.                 USHORT flags = SHORT1FROMMP(QMsg->mp1);
  4180.                 if(((flags & KC_CHAR)||!(flags & KC_VIRTUALKEY)) && (flags & KC_ALT) && !(flags & KC_PREVDOWN)) {
  4181.                    return (MRESULT) TranslateAccel(UCMData, hwndMenu, SHORT1FROMMP(QMsg->mp2), QMsg);
  4182.                 }
  4183.              }
  4184.              return (MRESULT)0;
  4185.           }
  4186.      case WM_UPDATEFRAME:
  4187.           {
  4188.              if ( ( (ULONG)mp1 == FCF_MENU ) && UCMData->bProcessingPP ){
  4189.                 // sent by the menu original wndproc after the processing of WM_PRESPARAMCHANGED
  4190.                 UCMenuUpdateMenu( UCMData->hwndMenu, FALSE );
  4191.                 UCMData->bProcessingPP = FALSE;
  4192.                 return (MRESULT) TRUE;
  4193.              } else {
  4194.                 return (MRESULT) FALSE;
  4195.              }
  4196.           }
  4197.      case UCMENU_ADDITEMSTOCM:
  4198.           {
  4199.             ULONG    i;
  4200.             MENUITEM MenuItem;
  4201.             ULONG    NbOfAdditionalCMItems = (ULONG)mp1;
  4202.             PCMITEMS CMItems = (PCMITEMS)mp2;
  4203.             memset(&MenuItem, 0, sizeof(MENUITEM));
  4204.             for(i=0; i<NbOfAdditionalCMItems; i++) {
  4205.                MenuItem.iPosition = MIT_END;
  4206.                MenuItem.id = (CMItems+i)->ID;
  4207.                MenuItem.afStyle = MIS_TEXT;
  4208.                WinSendMsg(UCMData->hwndCM, MM_INSERTITEM, MPFROMP(&MenuItem),
  4209.                           MPFROMP( (CMItems+i)->pszItemText ) );
  4210.             }
  4211.             return((MRESULT)0);
  4212.           }
  4213.  
  4214.      case UCMENU_DELETECMITEM:
  4215.           {
  4216.             ULONG    i;
  4217.             ULONG    NbOfItems = (ULONG)mp1;
  4218.             PULONG   ItemArray = (PULONG)mp2;
  4219.             for(i=0; i<NbOfItems; i++) {
  4220.                WinSendMsg(UCMData->hwndCM, MM_DELETEITEM, (MPARAM)ItemArray[i], 0L);
  4221.             }
  4222.             return (MRESULT)0;
  4223.           }
  4224.     case WM_PRESPARAMCHANGED:
  4225.           {
  4226.              UCMenuPresParamChanged(UCMData, hwnd, mp1 );
  4227.              return((MRESULT)0);
  4228.           }
  4229.      case UCMENU_QUERYSIZE:
  4230.          {
  4231.             if ( UCMData && mp1 && mp2 ){
  4232.                if (Style & CMS_MATRIX) {
  4233.                   //(MAM) changed to return real size based on actual number of
  4234.                   // rows and columns in use.
  4235.                   USHORT Count, Rows;
  4236.                   Count = (USHORT)WinSendMsg(hwnd, MM_QUERYITEMCOUNT, MPVOID, MPVOID);
  4237.                   * (ULONG*)mp1 = min(Count,UCMData->NbOfCols) * UCMData->MaxVerticalWidth    + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  4238.                   Rows = Count / max(1,UCMData->NbOfCols);  // Full rows (don't div by zero!)
  4239.                   if ((Rows * UCMData->NbOfCols) < Count)   // Partial row?
  4240.                     Rows++;
  4241.                   * (ULONG*)mp2 = Rows * UCMData->MaxHorizontalHeight + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  4242.                } // endif
  4243.                if ( Style & CMS_VERT ) {
  4244.                   * (ULONG*)mp1 = UCMData->MaxVerticalWidth + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  4245.                   * (ULONG*)mp2 = UCMData->SumItemHeights   + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  4246.                } // endif
  4247.                if ( Style & CMS_HORZ ) {
  4248.                   * (ULONG*)mp1 = UCMData->SumItemWidths       + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  4249.                   * (ULONG*)mp2 = UCMData->MaxHorizontalHeight + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  4250.                } // endif
  4251.                return (MRESULT)TRUE;
  4252.             } else {
  4253.                return (MRESULT)FALSE;
  4254.             } // endif
  4255.          }
  4256.  
  4257.     case UCMENU_QUERYCOLOR:
  4258.        {
  4259.           if ( UCMData && mp1 && mp2 ) {
  4260.              * (LONG*)mp1 = UCMData->BgColor;
  4261.              * (LONG*)mp2 = UCMData->ItemBgColor;
  4262.              return (MRESULT)TRUE;
  4263.           } else {
  4264.              return (MRESULT)FALSE;
  4265.           } // endif
  4266.        }
  4267.  
  4268.     case UCMENU_QUERYSTYLE:
  4269.        {
  4270.           if ( UCMData && mp1) {
  4271.              * (ULONG*)mp1 = UCMData->Style;
  4272.              return (MRESULT) TRUE;
  4273.           } else {
  4274.              return (MRESULT) FALSE;
  4275.           } // endif
  4276.       }
  4277.  
  4278.     case UCMENU_SETSTYLE:
  4279.        {
  4280.           if ( UCMData ) {
  4281.              /* If removing bubble-help, destroy bubble window */
  4282.              if ((UCMData->hwndBubble != NULLHANDLE) && !((ULONG)mp1 & UCS_BUBBLEHELP)) {
  4283.                WinDestroyWindow(UCMData->hwndBubble);
  4284.                UCMData->hwndBubble = NULLHANDLE;
  4285.             // UCMData->HoverCapture = FALSE;
  4286.                UCMData->HoverID = 0;
  4287.              }
  4288.  
  4289.              /* If adding bubble-help, create bubble window */
  4290.              if ((UCMData->hwndBubble == NULLHANDLE) && ((ULONG)mp1 & UCS_BUBBLEHELP))
  4291.                UCMenuCreateBubbleWindow(hwnd, UCMData);
  4292.  
  4293.              UCMData->Style = (ULONG)mp1;
  4294.              UCMData->cx    = SHORT1FROMMP(mp2);
  4295.              UCMData->cy    = SHORT2FROMMP(mp2);
  4296.              return (MRESULT) TRUE;
  4297.           } else {
  4298.              return (MRESULT) FALSE;
  4299.           } // endif
  4300.       }
  4301.  
  4302.     case UCMENU_SETBGCOLOR:
  4303.        {
  4304.           if ( UCMData ) {
  4305.              UCMData->BgColor      = (ULONG)mp1;
  4306.              UCMData->ItemBgColor  = (ULONG)mp2;
  4307.              WinSetPresParam( UCMData->hwndMenu,
  4308.                               PP_MENUBACKGROUNDCOLOR,
  4309.                               sizeof UCMData->ItemBgColor,
  4310.                               &(UCMData->ItemBgColor) );
  4311.              return (MRESULT) TRUE;
  4312.           } else {
  4313.              return (MRESULT) FALSE;
  4314.           } // endif
  4315.       }
  4316.     case UCMENU_SETFONT :
  4317.       {
  4318.          if ( mp1 && UCMData ){
  4319.             if ( WinSetPresParam( UCMData->hwndMenu, PP_FONTNAMESIZE, strlen( mp1 ) + 1, mp1 ) ){
  4320.                if ( UCMData->pszFontNameSize ) {
  4321.                   MyFree( UCMData->pszFontNameSize );
  4322.                } /* endif */
  4323.                UCMData->pszFontNameSize = MyMalloc( strlen( mp1 ) + 1 );
  4324.                if ( UCMData->pszFontNameSize ){
  4325.                   strcpy( UCMData->pszFontNameSize, mp1 );
  4326.                } /* endif */
  4327.                return (MRESULT)TRUE;
  4328.             } else {
  4329.                return (MRESULT)FALSE;
  4330.             } /* endif */
  4331.          } else {
  4332.             return (MRESULT)FALSE;
  4333.          } /* endif */
  4334.       }
  4335.  
  4336.     case UCMENU_SETBUBBLETIMERS: // Added V2.04
  4337.        {
  4338.           UCMData->BubbleDelay = LONGFROMMP(mp1);
  4339.           UCMData->BubbleRead  = LONGFROMMP(mp2);
  4340.           return 0;
  4341.        }
  4342.  
  4343.     case UCMENU_ACTIVECHG:  // Added V2.04
  4344.        {
  4345.           if (!(BOOL)SHORT1FROMMP(mp1)) {  // Becoming inactive
  4346.             /* When owning app becomes inactive we will close any open */
  4347.             /* submenu and deactivate the bubble help, if any.         */
  4348.             UCMData->Active = FALSE;
  4349.             if (UCMData->usItem != 0) {   // There is an open submenu, close it
  4350.                MENUITEM OpenItem;
  4351.                if ((BOOL)WinSendMsg(UCMData->hwndMenu,
  4352.                           MM_QUERYITEM,
  4353.                           MPFROM2SHORT(UCMData->usItem,TRUE),
  4354.                           MPFROMP(&OpenItem)))
  4355.                  WinSendMsg(OpenItem.hwndSubMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0L);
  4356.             }
  4357.             if (UCMData->Style & UCS_BUBBLEHELP) {
  4358.           //  if (UCMData->HoverCapture)
  4359.           //    WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  4360.           //  UCMData->HoverCapture = FALSE;
  4361.               UCMData->HoverID = 0;
  4362.               WinSendMsg(UCMData->hwndBubble,  // Deactivate bubble if showing
  4363.                           MSG_ITEMCHANGE, MPFROM2SHORT(0, TRUE), MPFROMHWND(hwnd));
  4364.             }
  4365.           }
  4366.           else {  // Becoming active
  4367.             /* When owning app becomes active, we fake a mouse message if the */
  4368.             /* pointer is over toolbar window to reactivate the bubble help.  */
  4369.             UCMData->Active = TRUE;
  4370.             if (UCMData->Style & UCS_BUBBLEHELP) {
  4371.               POINTL MousePos;
  4372.               WinQueryPointerPos((HAB)NULLHANDLE, &MousePos);
  4373.               WinMapWindowPoints(HWND_DESKTOP,UCMData->hwndMenu,&MousePos, 1);
  4374.               WinSendMsg(UCMData->hwndMenu, WM_MOUSEMOVE, MPFROM2SHORT((SHORT)MousePos.x,(SHORT)MousePos.y), MPFROM2SHORT(0,KC_NONE));
  4375.             }
  4376.           }
  4377.        } // end UCMENU_ACTIVECHG
  4378.        return 0;
  4379.  
  4380.     case UCMENU_UPDATE:
  4381.        {
  4382.           if ( UCMData ) {
  4383.              UCMenuUpdateMenu( UCMData->hwndMenu, TRUE );
  4384.              return (MRESULT) TRUE;
  4385.           } else {
  4386.              return (MRESULT) FALSE;
  4387.           } // endif
  4388.       }
  4389.  
  4390.     case UCMENU_DISABLEUPDATE:
  4391.       /* Set update disable status */
  4392.       UCMData->DisableUpdate = (BOOL)SHORT1FROMMP(mp1);
  4393.       return 0;
  4394.  
  4395.     case UCMENU_QUERYFORCEDSIZE:
  4396.        {
  4397.           if ( UCMData && mp1 && mp2 ) {
  4398.              * (ULONG*)mp1 = UCMData->cx;
  4399.              * (ULONG*)mp2 = UCMData->cy;
  4400.              return (MRESULT)TRUE;
  4401.           } else {
  4402.              return (MRESULT)FALSE;
  4403.           } // endif
  4404.       }
  4405.  
  4406.     case UCMENU_QUERYFONT:
  4407.        {
  4408.           if ( UCMData && UCMData->pszFontNameSize && mp1 ) {
  4409.              if ( (ULONG)mp2 > strlen( UCMData->pszFontNameSize) ) {
  4410.                 strcpy( (CHAR *)mp1, UCMData->pszFontNameSize );
  4411.                 return (MRESULT)TRUE;
  4412.              } else {
  4413.                 return (MRESULT)FALSE;
  4414.              } // endif
  4415.           } else {
  4416.              return (MRESULT)FALSE;
  4417.           } // endif
  4418.        }
  4419.  
  4420.     case UCMENU_QUERYRECT:
  4421.        /* Return the bounding rectangle of the specified menu item, */
  4422.        /* relative to the UCMenu toolbar window.  mp1(short1) is    */
  4423.        /* the item ID, mp2 is ptr to RECTL.  Return TRUE if OK.     */
  4424.  
  4425.        /* See if item is on main menu */
  4426.        if ((BOOL) WinSendMsg(UCMData->hwndMenu, MM_QUERYITEMRECT, MPFROM2SHORT(SHORT1FROMMP(mp1), FALSE), MPFROMP((PRECTL)PVOIDFROMMP(mp2)))) {
  4427.          WinMapWindowPoints(UCMData->hwndMenu, hwnd, (POINTL *)PVOIDFROMMP(mp2), 2);
  4428.          return (MRESULT)TRUE;
  4429.        }
  4430.        /* If a submenu is currently open, try there */
  4431.        else if (UCMData->usItem != 0) {
  4432.          MENUITEM Item;
  4433.          if ((BOOL) WinSendMsg(hwnd, MM_QUERYITEM, MPFROM2SHORT(UCMData->usItem, TRUE), MPFROMP(&Item))) {
  4434.             if ((BOOL) WinSendMsg(Item.hwndSubMenu, MM_QUERYITEMRECT, MPFROM2SHORT(SHORT1FROMMP(mp1), FALSE), MPFROMP((PRECTL)PVOIDFROMMP(mp2)))) {
  4435.                WinMapWindowPoints(Item.hwndSubMenu, hwnd, (POINTL *)PVOIDFROMMP(mp2), 2);
  4436.                return (MRESULT)TRUE;
  4437.             }
  4438.          }
  4439.        }
  4440.        return (MRESULT)FALSE; // Not found.
  4441.  
  4442.     case UCMENU_QUERYUCMINFO:
  4443.        {
  4444.           if ( UCMData && mp1 ){
  4445.              PUCMINFO UCMInfo  = (PUCMINFO)mp1;
  4446.  
  4447.              UCMInfo->cb           = sizeof(UCMINFO);
  4448.              UCMInfo->hModule      = UCMData->hModBmp;
  4449.              UCMInfo->NbOfCols     = UCMData->NbOfCols;
  4450.              UCMInfo->NbOfRows     = UCMData->NbOfRows;
  4451.              UCMInfo->Style        = UCMData->Style;
  4452.              UCMInfo->cx           = UCMData->cx;
  4453.              UCMInfo->cy           = UCMData->cy;
  4454.              UCMInfo->BgBmp        = UCMData->BgBmp;
  4455.              UCMInfo->BgColor      = UCMData->BgColor;
  4456.              UCMInfo->ItemBgColor  = UCMData->ItemBgColor;
  4457.              UCMInfo->hModUCM      = UCMData->hModUCM;        // added V2.04
  4458.              UCMInfo->BubbleDelay  = UCMData->BubbleDelay;    // added V2.04 
  4459.              UCMInfo->BubbleRead   = UCMData->BubbleRead;     // added V2.04
  4460.  
  4461.              if ( *(UCMData->szBitmapSearchPath) &&
  4462.                   (UCMInfo->pszBitmapSearchPath = MyMalloc(strlen( UCMData->szBitmapSearchPath )+1)) ){
  4463.                 strcpy( UCMInfo->pszBitmapSearchPath, UCMData->szBitmapSearchPath );
  4464.              } else {
  4465.                 UCMInfo->pszBitmapSearchPath = NULL;
  4466.              } // endif
  4467.  
  4468.              if ( *(UCMData->szDefaultBitmap) &&
  4469.                   (UCMInfo->pszDefaultBitmap = MyMalloc(strlen( UCMData->szDefaultBitmap )+1)) ){
  4470.                 strcpy( UCMInfo->pszDefaultBitmap, UCMData->szDefaultBitmap );
  4471.              } else {
  4472.                 UCMInfo->pszDefaultBitmap = NULL;
  4473.              } // endif
  4474.  
  4475.              if ( UCMData->pszFontNameSize &&
  4476.                   (UCMInfo->pszFontNameSize = MyMalloc(strlen( UCMData->pszFontNameSize )+1)) ){
  4477.                 strcpy( UCMInfo->pszFontNameSize, UCMData->pszFontNameSize );
  4478.              } else {
  4479.                 UCMInfo->pszFontNameSize = NULL;
  4480.              } // endif
  4481.  
  4482.              return (MRESULT)TRUE;
  4483.           } else {
  4484.              return (MRESULT)FALSE;
  4485.           } // endif
  4486.        }
  4487.  
  4488.     case UCMENU_QUERYVERSION:
  4489.        {
  4490.           return (MRESULT)(ULONG)UCMENUS_VERSION;  // constant defined in ucmenus.h
  4491.        }
  4492.  
  4493.     case UCMENU_ACTIONSINSERTED:
  4494.       //-- This message is posted by the owner to let me know that
  4495.       //-- the list of actions was filled. What I have to do is hilite the
  4496.       //-- current action in the list or, if it's not in it, add it to the
  4497.       //-- list and highlight it.
  4498.       #if !defined(UCMUI)
  4499.         return 0;
  4500.       #else
  4501.         if (UCMData->hwndPage2)
  4502.           WinPostMsg(UCMData->hwndPage2,
  4503.                      UCMENU_ACTIONSINSERTED,
  4504.                      (MPARAM)0,
  4505.                      (MPARAM)0);
  4506.         return 0;
  4507.       #endif
  4508.  
  4509.     case UCMENU_INSERTACTION:
  4510.       #if !defined(UCMUI)
  4511.         return 0;
  4512.       #else
  4513.         WinSendDlgItemMsg(UCMData->hwndPage2,
  4514.                           IDC_UCMNBP2FLIST,
  4515.                           LM_INSERTITEM,
  4516.                           (MPARAM)LIT_END,
  4517.                           mp1);
  4518.         WinSendDlgItemMsg(UCMData->hwndPage2,
  4519.                           IDC_UCMNBP2DLIST,
  4520.                           LM_INSERTITEM,
  4521.                           (MPARAM)LIT_END,
  4522.                           mp2);
  4523.         return (MRESULT)0;
  4524.       #endif
  4525.  
  4526.     case WM_CONTEXTMENU:
  4527.       {
  4528.  
  4529.        UCMenuContextMenu(hwnd, UCMData->hwndMenu, (ULONG)mp1);
  4530.        return (MRESULT) TRUE;
  4531.       }
  4532.  
  4533.     case WM_CREATE:
  4534.       /*---------------------------------------------*/
  4535.       /*        Create code                          */
  4536.       /*---------------------------------------------*/
  4537.      { PCREATESTRUCT CreateParms = (PCREATESTRUCT)mp2;
  4538.        PUCMINFO2      UCMInfo     = (PUCMINFO2)mp1;
  4539.        RECTL         rcl;
  4540.        HPS           hps;
  4541.        HDC           hdcMem;
  4542.  
  4543.  
  4544.        // Test if the menu handle is valid
  4545.        if ( !WinIsWindow( WinQueryAnchorBlock( hwnd ), UCMInfo->hwndMenu ) ) {
  4546.           return (MRESULT)FALSE;
  4547.        } // endif
  4548.  
  4549.        // Allocate memory for UCMenu internal Data
  4550.        if(!(UCMData = MyMalloc(sizeof(UCMDATA)))) {
  4551.           return((MRESULT)1);
  4552.        }
  4553.  
  4554.        // Zero out memory
  4555.        memset(UCMData, 0, sizeof(UCMDATA));
  4556.  
  4557.        UCMData->size = sizeof( UCMDATA );
  4558.  
  4559.        WinSetWindowULong(hwnd, QWL_UCMDATA, (ULONG)UCMData);
  4560.  
  4561.        /* These are new in UCMDATA for V2.04 */
  4562.        UCMData->hwndUCM = hwnd;
  4563.        UCMData->hwndOwner = WinQueryWindow(hwnd, QW_OWNER);
  4564.        UCMData->UCMenuID = WinQueryWindowUShort(hwnd, QWS_ID);
  4565.  
  4566.        // -----------------------------------------------------------------------
  4567.        // -- Eventually create a memory device context to manipulate the bitmaps
  4568.        // -- We need that if we want to change their background color
  4569.        // -----------------------------------------------------------------------
  4570.        if (UCMInfo->Style & (UCS_CHNGBMPBG|UCS_CHNGBMPBG_AUTO))   {
  4571.          hdcMem = DevOpenDC( WinQueryAnchorBlock( hwnd ),
  4572.                              OD_MEMORY,
  4573.                              "*",
  4574.                              0L,
  4575.                              NULL,       // -- compatible with screen device
  4576.                              (ULONG)0 );
  4577.          if ( hdcMem ) {
  4578.             SIZEL sizlPS;
  4579.  
  4580.             sizlPS.cx = 0;
  4581.             sizlPS.cy = 0;
  4582.             UCMData->hpsMem = GpiCreatePS( WinQueryAnchorBlock( hwnd ),
  4583.                                            hdcMem,
  4584.                                            &sizlPS,
  4585.                                            PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  4586.  
  4587.          } // endif
  4588.        } // endif
  4589.  
  4590.        // Allocate memory for the accelerator table
  4591.        UCMData->AccelTable = (PACCELTABLE)MyMalloc(sizeof(ACCELTABLE)+(100*sizeof(ACCEL)));
  4592.        UCMData->AccelTable->codepage = 850;
  4593.        UCMData->AccelTable->cAccel   = 0;
  4594.  
  4595.        rcl.xLeft   = CreateParms->x;
  4596.        rcl.xRight  = CreateParms->x + CreateParms->cx;
  4597.        rcl.yTop    = CreateParms->y + CreateParms->cy;
  4598.        rcl.yBottom = CreateParms->y;
  4599.  
  4600.        if(UCMInfo->pszBitmapSearchPath) {
  4601.           strcpy(UCMData->szBitmapSearchPath, UCMInfo->pszBitmapSearchPath);
  4602.        }
  4603.  
  4604.        if(UCMInfo->pszDefaultBitmap) {
  4605.           strcpy(UCMData->szDefaultBitmap, UCMInfo->pszDefaultBitmap);
  4606.        }
  4607.  
  4608.        UCMData->NbOfRows = UCMInfo->NbOfRows;
  4609.        UCMData->NbOfCols = UCMInfo->NbOfCols;
  4610.        UCMData->Style    = UCMInfo->Style;
  4611.        UCMData->cx       = UCMInfo->cx;
  4612.        UCMData->cy       = UCMInfo->cy;
  4613.        // -----------------------------------------------------------------------
  4614.        // -- We want only solid colors, because the bitmap background can only be
  4615.        // -- solid, and we want it to match with everything we paint
  4616.        // -----------------------------------------------------------------------
  4617.        hps = WinGetPS( UCMInfo->hwndMenu );
  4618.        UCMData->BgBmp = UCMInfo->BgBmp;  // Background color in real bitmap can be anything
  4619.      //UCMData->BgBmp        = GpiQueryNearestColor( hps, (ULONG)0, UCMInfo->BgBmp );
  4620.        UCMData->BgColor      = GpiQueryNearestColor( hps, (ULONG)0, UCMInfo->BgColor );
  4621.        UCMData->ItemBgColor  = GpiQueryNearestColor( hps, (ULONG)0, UCMInfo->ItemBgColor );
  4622.        WinReleasePS( hps );
  4623.  
  4624.        UCMData->hwndMenu = UCMInfo->hwndMenu;
  4625.  
  4626.        // -----------------------------------------------------------------------
  4627.        // -- The WinSetPresParam causes a WM_UPDATEFRAME to be sent to the owner,
  4628.        // -- this will cause trouble if the owner is a WC_FRAME or if it is already
  4629.        // -- the ucmenu, -> set the owner temporarily to the desktop object window
  4630.        // -----------------------------------------------------------------------
  4631.        WinSetOwner (UCMInfo->hwndMenu, HWND_OBJECT);
  4632.  
  4633.        // -------------------------------------------------------------------------------------------
  4634.        // -- The presparam change has to be done before subclassing the menu, else it fails
  4635.        // -- (Here, we want to have PRESPARAMCHANGED processed by the default routines only,
  4636.        // -- since everything is not set up yet, especially the UCMData * in QWL_USER or QWL_UCMDATA)
  4637.        // -------------------------------------------------------------------------------------------
  4638.        if ( ! UCMInfo->pszFontNameSize ){
  4639.           UCMInfo->pszFontNameSize = MyMalloc( strlen( UCM_DEFAULTFONT ) + 1 );
  4640.           strcpy( UCMInfo->pszFontNameSize, UCM_DEFAULTFONT );
  4641.        }
  4642.        WinSetPresParam( UCMInfo->hwndMenu, PP_FONTNAMESIZE,
  4643.                         strlen(UCMInfo->pszFontNameSize) + 1,
  4644.                         UCMInfo->pszFontNameSize);
  4645.  
  4646.  
  4647.        if ( UCMData->pszFontNameSize = MyMalloc( strlen( UCMInfo->pszFontNameSize ) + 1 ) ){
  4648.           strcpy( UCMData->pszFontNameSize, UCMInfo->pszFontNameSize );
  4649.        }
  4650.  
  4651.        WinSetPresParam( UCMInfo->hwndMenu, PP_MENUBACKGROUNDCOLOR, sizeof UCMData->ItemBgColor, &(UCMData->ItemBgColor) );
  4652.  
  4653.        WinSetOwner (UCMInfo->hwndMenu, hwnd);
  4654.  
  4655.        UCMData->OldMenuProc = (PFNWP)WinSubclassWindow(UCMInfo->hwndMenu, (PFNWP)MenuWndProc);
  4656.  
  4657.        /* As of UCMenus V2.04, app must supply our module handle if we are  */
  4658.        /* in a DLL.  Otherwise we do our best to get it ourselves, but may  */
  4659.        /* not work if we are in a DLL loaded by full path name.             */
  4660.  
  4661.        UCMData->hModUCM = UCMInfo->hModUCM;
  4662.        if (UCMData->hModUCM == NULLHANDLE) {
  4663.          //--- Here we have to get the module name to load the resource
  4664.          PSZ pszModuleName = "UCMENUS";
  4665.          // ----------------------------------------------------------------
  4666.          // -- If we can not find ucmenus.dll then we use 0, this will work
  4667.          // -- if we are statically linked to an exe
  4668.          // ----------------------------------------------------------------
  4669.          if ( DosQueryModuleHandle(pszModuleName, &(UCMData->hModUCM)) ){
  4670.                UCMData->hModUCM = NULLHANDLE;
  4671.          } // endif
  4672.        } // endif
  4673.  
  4674.        UCMData->hModBmp = UCMInfo->hModule; // Application resources from this module
  4675.        UCMData->BubbleDelay = UCMInfo->BubbleDelay;
  4676.        UCMData->BubbleRead  = UCMInfo->BubbleRead;
  4677.  
  4678.        CreateUCMenu(hwnd,
  4679.                     CreateParms->hwndParent,
  4680.                     CreateParms->hwndOwner,
  4681.                     UCMInfo->hwndMenu,
  4682.                     CreateParms->id,
  4683.                     &rcl,
  4684.                     CreateParms->flStyle,
  4685.                     UCMInfo->NbOfCols,
  4686.                     UCMInfo->NbOfRows,
  4687.                     UCMInfo->ulTmplVersion);
  4688.  
  4689.  
  4690.        //-- Load the context menu
  4691.        UCMData->hwndCM = WinLoadMenu(HWND_OBJECT,   // was hwnd
  4692.                               UCMData->hModUCM,
  4693.                               IDD_UCMCTXT);
  4694.       WinGetLastError( WinQueryAnchorBlock( hwnd ) );
  4695.  
  4696.   // ------------------------------------------------------------
  4697.   // -- Set the context menu items according to the UCS_ flags
  4698.   // ------------------------------------------------------------
  4699.   if ( UCMData->Style & UCS_NO_CM_SEPARATOR ){
  4700.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_SEPARATOR, TRUE ), (MPARAM)0 );
  4701.   } // endif
  4702.   if ( UCMData->Style & UCS_NO_CM_ITEM_CREATE ){
  4703.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_CREATE, TRUE ), (MPARAM)0 );
  4704.   } // endif
  4705.   if ( UCMData->Style & UCS_NO_CM_ITEM_DELETE ){
  4706.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_DELETE, TRUE ), (MPARAM)0 );
  4707.   } // endif
  4708.   if ( UCMData->Style & UCS_NO_CM_ITEM_EDIT ){
  4709.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_EDIT, TRUE ), (MPARAM)0 );
  4710.   } // endif
  4711.   if ( UCMData->Style & UCS_NO_CM_MENU_STYLE ){
  4712.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_STYLE, TRUE ), (MPARAM)0 );
  4713.   } // endif
  4714.   if ( UCMData->Style & UCS_NO_CM_MENU_DEFAULT ){
  4715.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_DEFAULT, TRUE ), (MPARAM)0 );
  4716.   } // endif
  4717.   if ( UCMData->Style & UCS_NO_CM_MENU_IMPORT ){
  4718.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_LOAD, TRUE ), (MPARAM)0 );
  4719.   } // endif
  4720.   if ( UCMData->Style & UCS_NO_CM_MENU_EXPORT ){
  4721.      WinSendMsg( UCMData->hwndCM, MM_DELETEITEM, MPFROM2SHORT( IDM_UCM_SAVEAS, TRUE ), (MPARAM)0 );
  4722.   } // endif
  4723.  
  4724.   /* Create bubble help window if required by style */
  4725.  
  4726.   if (UCMData->Style & UCS_BUBBLEHELP)
  4727.     UCMenuCreateBubbleWindow(hwnd, UCMData);
  4728.  
  4729.   /* Try to determine if our app is currently the active window so */
  4730.   /* we can set our initial Active state correctly.  If the        */
  4731.   /* parent of the UCMenu is a child of the active window then     */
  4732.   /* our app is active.                                            */
  4733.  
  4734.   if (WinIsChild(WinQueryWindow(hwnd, QW_PARENT), WinQueryActiveWindow(HWND_DESKTOP)))
  4735.     UCMData->Active = TRUE;
  4736.  
  4737.   } break;  // end of WM_CREATE
  4738.  
  4739.     /*┌───────────────┐
  4740.       │ Menu messages │
  4741.       └───────────────┘*/
  4742.     case WM_INITMENU:
  4743.       {
  4744.          /*┌──────────────────────────────────────────────────────────────────┐
  4745.            │ A submenu is about to be shown : we save the item Identifier of  │
  4746.            │ the currently open submenu.                                      │
  4747.            └──────────────────────────────────────────────────────────────────┘*/
  4748.  
  4749.          UCMData->usItem = (USHORT)mp1;
  4750.          WinPostMsg(UCMData->hwndOwner, msg, mp1, mp2);
  4751.       }
  4752.       break;
  4753.  
  4754.     case WM_MENUEND:
  4755.       {
  4756.          /*┌──────────────────────────────────────────────────────────────────┐
  4757.            │ A submenu is about to end : zero the submenu ID                  │
  4758.            └──────────────────────────────────────────────────────────────────┘*/
  4759.          mp2 = MPFROMHWND(hwnd);
  4760.          WinPostMsg(UCMData->hwndOwner, msg, mp1, mp2);
  4761.          UCMData->usItem = 0;
  4762.       }
  4763.       break;
  4764.  
  4765.     case WM_MEASUREITEM:
  4766.       /*┌────────────────────────────────────────────────────────────────────────┐
  4767.         │ We receive this message the first time an item with the OWNERDRAW      │
  4768.         │ style is about to be drawn. We have to set the item's height and width │
  4769.         │ In submenus, we have to decrease xRight by DELTA because of the space  │
  4770.         │ left by PM for the arrow and check item.  PM docs (2.1) indicate only  │
  4771.         │ the height is required, but we set both width and height in the item   │
  4772.         │ rectangle structure and return the height in the message result.       │
  4773.         └────────────────────────────────────────────────────────────────────────┘*/
  4774.       { POWNERITEM        pitem;
  4775.         BITMAPINFOHEADER2 BmpInfo;
  4776.         SHORT             delta=0;
  4777.         ULONG             cx, cy;
  4778.  
  4779.         pitem = (POWNERITEM)mp2;
  4780.         BmpInfo.cbFix = sizeof(BITMAPINFOHEADER2);
  4781.         UCMenuCalcItemSize( pitem, UCMData->Style, hwnd, &cx, &cy );
  4782.  
  4783.         if ( WinQueryWindow(pitem->hwnd, QW_OWNER) != hwnd ) {
  4784.           // -- This is a submenu item and not a menu item
  4785.           HBITMAP hbm;
  4786.  
  4787.           hbm = WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUCHECK);
  4788.           GpiQueryBitmapInfoHeader(hbm, &BmpInfo);
  4789.           delta += BmpInfo.cx;
  4790.           GpiDeleteBitmap(hbm);
  4791.  
  4792.           hbm = WinGetSysBitmap(HWND_DESKTOP, SBMP_MENUATTACHED);
  4793.           GpiQueryBitmapInfoHeader(hbm, &BmpInfo);
  4794.           delta += BmpInfo.cx;
  4795.           GpiDeleteBitmap(hbm);
  4796.         } // endif
  4797.  
  4798.         // In the submenus, PM will add some space for the checkmark&arrow : - delta
  4799.         //  (We don't want unnecessary space around the non checkable items)
  4800.         pitem->rclItem.xLeft   = 0;
  4801.         pitem->rclItem.yBottom = 0;
  4802.         pitem->rclItem.xRight  = cx  - delta ;
  4803.         pitem->rclItem.yTop    = cy  ;
  4804.  
  4805.         return MRFROMSHORT((SHORT)cy); // Return height of menu item
  4806.       } 
  4807.  
  4808.     case WM_DRAWITEM:
  4809.       /*┌───────────────────────────────────────────────────────────┐
  4810.         │ We receive this message when we have to draw an item with │
  4811.         │ the OWNERDRAW style                                       │
  4812.         └───────────────────────────────────────────────────────────┘*/
  4813.        {
  4814.         POWNERITEM        poi;
  4815.         PSZ               pszText;
  4816.         POINTL            aptlPoints[4];
  4817.         ULONG             TextHeight, TextWidth;
  4818.         ULONG             ItemBgColorIndex;
  4819.         ULONG             BgColorIndex;
  4820.         ULONG flOptions;
  4821.         HPS hps;
  4822.  
  4823.         poi = (POWNERITEM)mp2;
  4824.  
  4825.         /* Presentation space given in owner-draw structure does not */
  4826.         /* render larger fonts correctly (not sure why).  So we get  */
  4827.         /* our own pres space instead to use for the drawing.        */
  4828.  
  4829.         hps = WinGetPS(poi->hwnd);       //@P1a
  4830.  
  4831.         ItemBgColorIndex = UCMenuSelectColor( UCMData->ItemBgColor, hps ); //@P1m
  4832.         BgColorIndex = UCMenuSelectColor( UCMData->BgColor, hps );         //@P1m
  4833.  
  4834.         if (poi->fsState & MIS_SPACER) {
  4835.            /*------------- Draw spacer items -----------------------*/
  4836.  
  4837.            WinFillRect(hps, &poi->rclItem, BgColorIndex);
  4838.            if ( UCMData->Style & UCS_FRAMED ){
  4839.               POINTL pt;
  4840.               if ( Style & CMS_HORZ ){
  4841.                  // (MAM) Don't draw edges adjacent to other MIS_SPACER items
  4842.                  if (!UCAdjacentItemBlank(hwnd, poi->idItem, ADJACENT_LEFT)) {
  4843.                    pt.x = poi->rclItem.xLeft;
  4844.                    pt.y = poi->rclItem.yBottom ;
  4845.                    GpiMove( hps, &pt );
  4846.                    pt.y  = poi->rclItem.yTop - 1;
  4847.                    GpiSetColor( hps, SYSCLR_BUTTONDARK );
  4848.                    GpiLine( hps, &pt );
  4849.                  }
  4850.                  if (!UCAdjacentItemBlank(hwnd, poi->idItem, ADJACENT_RIGHT)) {
  4851.                    pt.x = poi->rclItem.xRight - 1;
  4852.                    pt.y = poi->rclItem.yBottom;
  4853.                    GpiMove( hps, &pt );
  4854.                    pt.y  = poi->rclItem.yTop - 1;
  4855.                    GpiSetColor( hps, SYSCLR_BUTTONLIGHT );
  4856.                    GpiLine( hps, &pt );
  4857.                  }
  4858.               } else if ( Style & CMS_VERT ){
  4859.                  // (MAM) Don't draw edges adjacent to other MIS_SPACER items
  4860.                  if (!UCAdjacentItemBlank(hwnd, poi->idItem, ADJACENT_ABOVE)) {
  4861.                    pt.x = poi->rclItem.xLeft;
  4862.                    pt.y = poi->rclItem.yBottom ;
  4863.                    GpiMove( hps, &pt );
  4864.                    pt.x  = poi->rclItem.xRight - 1;
  4865.                    GpiSetColor( hps, SYSCLR_BUTTONLIGHT );
  4866.                    GpiLine( hps, &pt );
  4867.                  }
  4868.                  if (!UCAdjacentItemBlank(hwnd, poi->idItem, ADJACENT_BELOW)) {
  4869.                    pt.x = poi->rclItem.xLeft;
  4870.                    pt.y = poi->rclItem.yTop - 1 ;
  4871.                    GpiMove( hps, &pt );
  4872.                    pt.x  = poi->rclItem.xRight - 1;
  4873.                    GpiSetColor( hps, SYSCLR_BUTTONDARK );
  4874.                    GpiLine( hps, &pt );
  4875.                  }
  4876.               } else if (Style & CMS_MATRIX ){
  4877.                  UCMenu3DFrame( hps, &poi->rclItem, 1);
  4878.               } // endif
  4879.            } // endif
  4880.            if (poi->fsAttribute != poi->fsAttributeOld) {
  4881.               poi->fsAttributeOld = (poi->fsAttribute &= (USHORT)~MIA_HILITED);
  4882.            } // endif
  4883.            WinReleasePS(hps);
  4884.            return (MRESULT)TRUE;
  4885.         } // endif
  4886.  
  4887.         if ( !poi->hItem ){
  4888.            WinReleasePS(hps);
  4889.            return (MRESULT)FALSE;
  4890.         } // endif
  4891.  
  4892.         /*---------------- Non-SPACER item to be drawn ------------------*/
  4893.  
  4894.         /* Note we completely redraw the item on all WM_DRAWITEM messages */
  4895.         /* even if only a state change.  Our state drawings require       */
  4896.         /* repainting to change states.                                   */
  4897.  
  4898.         WinFillRect(hps, &poi->rclItem, ItemBgColorIndex);
  4899.  
  4900.         /* Draw the bitmap into the drawing rectangle.  For hilight state */
  4901.         /* we draw it 1 pixel down and right of the usual position.       */
  4902.  
  4903.         UCMenuCalcBmpPos( poi, hwnd, UCMData->Style, aptlPoints, UCMData );
  4904.  
  4905.         if (poi->fsAttribute & MIA_HILITED) {
  4906.           aptlPoints[0].x++;
  4907.           aptlPoints[1].x++;
  4908.           aptlPoints[0].y--;
  4909.           aptlPoints[1].y--;
  4910.         }
  4911.  
  4912.         if ( !(UCMData->Style&UCS_SHRINK_BLEND)) {
  4913.            flOptions = BBO_IGNORE;
  4914.         } else {
  4915.            flOptions = UCMData->Style&UCS_SHRINK_OR ? BBO_OR : BBO_AND;
  4916.         } // endif
  4917.  
  4918.         GpiWCBitBlt( hps,
  4919.                      ITEM(poi, hBmp),
  4920.                      4,
  4921.                      aptlPoints,
  4922.                      ROP_SRCCOPY,
  4923.                      flOptions );
  4924.  
  4925.         /* Now draw the text, also down/right in hilight state */
  4926.  
  4927.         UCMenuCalcTextSize( (PUCMITEM) poi->hItem, hwnd, &TextWidth, &TextHeight);
  4928.  
  4929.         pszText = ITEM(poi, pszText);
  4930.         if (pszText && !(UCMData->Style & UCS_NOTEXT)) {
  4931.            RECTL rect;
  4932.            GpiSetColor(hps, SYSCLR_MENUTEXT);
  4933.  
  4934.            rect.xLeft   = poi->rclItem.xLeft   + ITEM_FRAME_THICK_LEFT;
  4935.            rect.xRight  = poi->rclItem.xRight  - ITEM_FRAME_THICK_RIGHT;
  4936.            rect.yBottom = poi->rclItem.yBottom + ITEM_FRAME_THICK_BOTTOM;
  4937.            rect.yTop    = rect.yBottom + TextHeight;
  4938.            if (poi->fsAttribute & MIA_HILITED) {
  4939.              rect.xLeft++;   // adjust target of text
  4940.              rect.xRight++;
  4941.              rect.yBottom--;
  4942.              rect.yTop--;
  4943.            }
  4944.            WinDrawText(hps, -1, pszText, &rect, 0, 0,
  4945.                        DT_CENTER | DT_VCENTER | DT_TEXTATTRS | DT_MNEMONIC);
  4946.         } // endif
  4947.  
  4948.         /* For checked state, draw thick border */
  4949.  
  4950.         if (  ( poi->fsAttribute & MIA_CHECKED ) ) {
  4951.            // Make it 1 pel thicker than frame to keep visible when HILITED
  4952.            WinDrawBorder( hps,
  4953.                           &(poi->rclItem),
  4954.                           ITEM_FRAME_THICK_LEFT+1,
  4955.                           ITEM_FRAME_THICK_TOP+1,
  4956.                           CLR_BLACK, CLR_BLACK,
  4957.                           DB_PATCOPY);
  4958.         } // endif
  4959.  
  4960.         /* Draw a frame  around the item or erase any hilight frame if the */
  4961.         /* style bits indicate items are not to be framed.                 */
  4962.  
  4963.         if (UCMData->Style & UCS_FRAMED)
  4964.            UCMenu3DFrame( hps,& poi->rclItem, poi->fsAttribute & MIA_HILITED);
  4965.         else {
  4966.            if (poi->fsAttribute & MIA_HILITED)  // Always draw depressed hilite frame
  4967.              UCMenu3DFrame(hps, &poi->rclItem, TRUE);
  4968.            else
  4969.              WinDrawBorder( hps,                // Erase any frame
  4970.                           &(poi->rclItem),
  4971.                           1L, 1L,
  4972.                           ItemBgColorIndex, ItemBgColorIndex,
  4973.                           DB_PATCOPY);
  4974.              }
  4975.  
  4976.         /* If item is disabled, shade the area with a half-tone background    */
  4977.         /* color pattern.  Note that PM also does this under some conditions, */
  4978.         /* but not when we redraw the item due to a state change.  PM does    */
  4979.         /* not seem to honor our clearing of the MIA_DISABLED bits (PM bug?)  */
  4980.         /* In general we cannot predict when PM will or will not provide the  */
  4981.         /* disable half-tone, so we always do it ourselves.                   */
  4982.  
  4983.         if (poi->fsAttribute & MIA_DISABLED) {
  4984.           POINTL BoxCorner;
  4985.           GpiSetPattern(hps, PATSYM_HALFTONE);  // Setup background halftone pattern
  4986.           GpiSetColor(hps, ItemBgColorIndex);
  4987.           GpiBeginArea(hps, BA_NOBOUNDARY);
  4988.           BoxCorner.x = poi->rclItem.xLeft+1;   // Don't halftone the frame
  4989.           BoxCorner.y = poi->rclItem.yBottom+1;
  4990.           GpiMove(hps, &BoxCorner);
  4991.           BoxCorner.x = poi->rclItem.xRight-2;  // Border pixel included, and 1 for frame
  4992.           BoxCorner.y = poi->rclItem.yTop-2;
  4993.           GpiBox(hps, DRO_OUTLINE, &BoxCorner, 0L, 0L);
  4994.           GpiEndArea(hps);
  4995.         }
  4996.   
  4997.          /* Clear all attribute bits since we do all rendering of attributes */
  4998.          /* and we don't want PM do modify our drawing.  PM seems to not     */
  4999.          /* honor this for MIA_DISABLED (see above).                         */
  5000.  
  5001.          poi->fsAttribute    = poi->fsAttribute    & ~(MIA_CHECKED|MIA_HILITED|MIA_FRAMED|MIA_DISABLED);
  5002.          poi->fsAttributeOld = poi->fsAttributeOld & ~(MIA_CHECKED|MIA_HILITED|MIA_FRAMED|MIA_DISABLED);
  5003.  
  5004.          WinReleasePS(hps);
  5005.          return (MRESULT)TRUE; /* TRUE means the item is drawn. */
  5006.  
  5007.       } // end of WM_DRAWITEM
  5008.  
  5009.     case WM_COMMAND:
  5010.       switch (SHORT1FROMMP(mp1)) {
  5011.         default:
  5012.           if ( SHORT1FROMMP( mp2 ) == CMDSRC_MENU ){
  5013.             MENUITEM mi;
  5014.             BOOL bButton2Down=0;
  5015.             LONG ButtonState;
  5016.    
  5017.             WinSendMsg(UCMData->hwndMenu,
  5018.                        MM_QUERYITEM,
  5019.                        MPFROM2SHORT(SHORT1FROMMP(mp1), TRUE),
  5020.                        MPFROMP(&mi));
  5021.    
  5022.             ButtonState = WinGetPhysKeyState(HWND_DESKTOP, VK_BUTTON2);
  5023.             if(ButtonState & 0x8000) {
  5024.               bButton2Down = 1;
  5025.             }
  5026.    
  5027.             /* (MAM)Dismiss any open submenu unless this item has MIA_NODISMISS attribute */
  5028.             /* since we force all submenus to be globally NODISMISS.                      */
  5029.             if ((!(mi.afAttribute & MIA_NODISMISS)) && (!bButton2Down))
  5030.               WinSendMsg(UCMData->hwndMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0L);
  5031.    
  5032.             if ( !( UCMData->Style & UCS_NODEFAULTACTION ) &&
  5033.                  !bButton2Down &&
  5034.                  mi.hItem &&
  5035.                  ITEM( &mi, pszAction ) &&
  5036.                  strstr( ITEM( &mi, pszAction ), UCM_ACTION_EXEC ) == ITEM( &mi, pszAction ) ){
  5037.               PSZ pszParams = ITEM( &mi, pszParameters );
  5038.               PSZ pszParams2;
  5039.               if ( pszParams ){
  5040.                  PSZ const pszCmd = "CMD.EXE /K ";
  5041.                  TID tid;
  5042.                  pszParams += strspn( pszParams, " \t" );
  5043.                  pszParams2 = MyMalloc( strlen( pszParams ) + strlen( pszCmd ) + 1 );
  5044.                  if ( pszParams2 ) {
  5045.                     char * cmdext;
  5046.                     char * firstspace;
  5047.                     strcpy( pszParams2, pszParams );
  5048.                     strupr( pszParams2 );
  5049.                     cmdext = strstr( pszParams2, ".CMD" );
  5050.                     firstspace = strpbrk( pszParams2, " \t" );
  5051.                     if ( cmdext && ( !firstspace || ( firstspace > cmdext ) ) ){
  5052.                        strcpy( pszParams2, pszCmd );
  5053.                     } else {
  5054.                        *pszParams2 = '\0';
  5055.                     } // endif
  5056.                     strcat( pszParams2, pszParams );
  5057.                  } // endif
  5058.                  // pszParams2 will be freed by UCMenuExecuteProgram
  5059.                  DosCreateThread(&tid, (PFNTHREAD)UCMenuExecuteProgram, (ULONG)pszParams2, 0, 4096) ;
  5060.               } // endif
  5061.             } else {
  5062.               if (!bButton2Down) {
  5063.                  UCMITEM ucmi;
  5064.     
  5065.                  memset( &ucmi, '\0', sizeof( UCMITEM ) );
  5066.                  ucmi = *((PUCMITEM)( mi.hItem ) );
  5067.                  if ( ITEM( &mi, pszBmp ) ){
  5068.                     ucmi.pszBmp = MyStrdup( ITEM( &mi, pszBmp ) );
  5069.                  } // endif
  5070.                  if ( ITEM( &mi, pszText ) ){
  5071.                     ucmi.pszText = MyStrdup( ITEM( &mi, pszText ) );
  5072.                  } // endif
  5073.                  if ( ITEM( &mi, pszAction ) ){
  5074.                     ucmi.pszAction = MyStrdup( ITEM( &mi, pszAction ) );
  5075.                  } // endif
  5076.                  if ( ITEM( &mi, pszParameters ) ){
  5077.                     ucmi.pszParameters = MyStrdup( ITEM( &mi, pszParameters ) );
  5078.                  } // endif
  5079.                  if ( ITEM( &mi, pszData ) ){
  5080.                     ucmi.pszData = MyStrdup( ITEM( &mi, pszData ) );
  5081.                  } // endif
  5082.     
  5083.                  ucmi.usId = (USHORT)mp1;
  5084.     
  5085.                  WinSendMsg( UCMData->hwndOwner, WM_CONTROL,
  5086.                              MPFROM2SHORT(UCMData->UCMenuID, UCN_ITEMSELECTED ),
  5087.                              MPFROMP( &ucmi ) );
  5088.                  if ( ucmi.pszBmp ){
  5089.                     MyFree( ucmi.pszBmp );
  5090.                  } // endif
  5091.                  if ( ucmi.pszText ){
  5092.                     MyFree( ucmi.pszText );
  5093.                  } // endif
  5094.                  if ( ucmi.pszAction ){
  5095.                     MyFree( ucmi.pszAction );
  5096.                  } // endif
  5097.                  if ( ucmi.pszParameters ){
  5098.                     MyFree( ucmi.pszParameters );
  5099.                  } // endif
  5100.                  if ( ucmi.pszData ){
  5101.                     MyFree( ucmi.pszData );
  5102.                  } // endif
  5103.               } // endif
  5104.             } /* endif */
  5105.    
  5106.           } /* endif */
  5107.           break;
  5108.       } /* endswitch */
  5109.       break;
  5110.  
  5111.     case WM_HELP:
  5112.       mp1 = MPFROM2SHORT( SHORT1FROMMP(mp1), (USHORT)(UCMData->UCMenuID) );
  5113.       mp2 = MPFROM2SHORT( CMDSRC_UCMENU, SHORT2FROMMP(mp2) );
  5114.       WinPostMsg(UCMData->hwndOwner, msg, mp1, mp2);
  5115.       break;
  5116.  
  5117.     case WM_NEXTMENU:
  5118.       return WinSendMsg(UCMData->hwndOwner, msg, mp1, mp2);
  5119.  
  5120.     case WM_MENUSELECT:
  5121.       mp2 = MPFROMHWND(hwnd);
  5122.       WinPostMsg(UCMData->hwndOwner, msg, mp1, mp2);
  5123.       return (MRESULT)TRUE;
  5124.  
  5125.     case MM_INSERTITEM:
  5126.     case MM_SETITEM:
  5127.        {
  5128.           PMENUITEM pMi;
  5129.           MRESULT rc;
  5130.           USHORT  NotifyMsg;
  5131.  
  5132.           if ( msg == MM_INSERTITEM ) {
  5133.              pMi = (PMENUITEM)mp1;
  5134.           } else {
  5135.              pMi = (PMENUITEM)mp2;
  5136.           } // endif
  5137.  
  5138.           if ( pMi->hwndSubMenu ){
  5139.  
  5140.              // -- When we insert a submenu, we have to make sure that the submenu window
  5141.              // --  is associated with the right id and UCMData (in case it comes from another
  5142.              // --  UCMenu)
  5143.              PUCMDATA UCMDataSub = (PUCMDATA)WinQueryWindowULong( pMi->hwndSubMenu, QWL_USER );
  5144.  
  5145.              if ( !UCMDataSub || ( UCMDataSub != UCMData ) ){
  5146.                 PFNWP pFnwp;
  5147.                 pFnwp = (PFNWP)WinQueryWindowPtr( pMi->hwndSubMenu, QWP_PFNWP );
  5148.                 if ( pFnwp != SubmenuWndProc ){
  5149.                    UCMData->OldSubMenuProc = pFnwp;
  5150.                 } else if ( UCMDataSub ){
  5151.                    UCMData->OldSubMenuProc = UCMDataSub->OldSubMenuProc;
  5152.                 } // endif
  5153.                 WinSetWindowULong(  pMi->hwndSubMenu, QWL_USER, (ULONG)UCMData);
  5154.                 WinSetWindowUShort( pMi->hwndSubMenu, QWS_ID,   pMi->id);
  5155.                 WinSetOwner( pMi->hwndSubMenu, UCMData->hwndMenu );
  5156.                 // PRESPARAMCHANGED has to be processed by the original wnd proc
  5157.                 WinSubclassWindow( pMi->hwndSubMenu, UCMData->OldSubMenuProc );
  5158.                 WinSetPresParam( pMi->hwndSubMenu, PP_MENUBACKGROUNDCOLOR, sizeof UCMData->ItemBgColor, &(UCMData->ItemBgColor) );
  5159.                 WinSetPresParam( pMi->hwndSubMenu, PP_FONTNAMESIZE,
  5160.                                  strlen( UCMData->pszFontNameSize ) + 1, UCMData->pszFontNameSize );
  5161.                 WinSubclassWindow( pMi->hwndSubMenu, SubmenuWndProc );
  5162.                 // The parent is the desktop, so it doesn't change
  5163.              } // endif
  5164.           } // endif
  5165.  
  5166.           if (UCMData->usItem != 0) {   //(MAM) There is an open submenu, close it
  5167.              MENUITEM OpenItem;
  5168.              if ((BOOL)WinSendMsg(UCMData->hwndMenu,
  5169.                         MM_QUERYITEM,
  5170.                         MPFROM2SHORT(UCMData->usItem,TRUE),
  5171.                         MPFROMP(&OpenItem)))
  5172.                WinSendMsg(OpenItem.hwndSubMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0L);
  5173.           }
  5174.        
  5175.           rc = SEND_TO_MENU;
  5176.  
  5177.           UCMenuUpdateMenu( UCMData->hwndMenu, FALSE );
  5178.  
  5179.           /* Tell owner of change */
  5180.           if ( msg == MM_INSERTITEM )
  5181.             NotifyMsg = UCN_ADDEDITEM;
  5182.           else
  5183.             NotifyMsg = UCN_CHANGEDITEM;
  5184.           WinSendMsg( UCMData->hwndOwner,
  5185.                       WM_CONTROL,
  5186.                       MPFROM2SHORT(UCMData->UCMenuID, NotifyMsg ),
  5187.                       MPFROMSHORT(pMi->id));
  5188.  
  5189.           return rc;
  5190.        }
  5191.  
  5192.     //(MAM) Removed fall-through of case from above.
  5193.  
  5194.     case MM_DELETEITEM:
  5195.     case MM_REMOVEITEM:
  5196.     case MM_SETITEMHANDLE:
  5197.       { MRESULT rc;
  5198.         MENUITEM mi;
  5199.         USHORT  NotifyMsg;
  5200.  
  5201.         if (UCMData->usItem != 0) {   //(MAM) There is an open submenu, close it
  5202.            MENUITEM OpenItem;
  5203.            if ((BOOL)WinSendMsg(UCMData->hwndMenu,
  5204.                       MM_QUERYITEM,
  5205.                       MPFROM2SHORT(UCMData->usItem,TRUE),
  5206.                       MPFROMP(&OpenItem)))
  5207.              WinSendMsg(OpenItem.hwndSubMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0L);
  5208.         }
  5209.  
  5210.         //(MAM) Don't process delete on submenus here -- submenu window proc will do it.
  5211.         if (!(BOOL)WinSendMsg(UCMData->hwndMenu, MM_QUERYITEM, MPFROM2SHORT(SHORT1FROMMP(mp1),FALSE), MPFROMP(&mi)))
  5212.           return SEND_TO_MENU;
  5213.  
  5214.         if ( msg == MM_DELETEITEM ) {
  5215.            if ( mi.hItem ){
  5216.               if ( ITEM( &mi, pszBmp ) ){
  5217.                 MyFree( ITEM( &mi, pszBmp ) );
  5218.               }
  5219.               if ( ITEM( &mi, pszText ) ){
  5220.                 MyFree( ITEM( &mi, pszText ) );
  5221.               }
  5222.               if ( ITEM( &mi, pszAction ) ){
  5223.                 MyFree( ITEM( &mi, pszAction ) );
  5224.               }
  5225.               if ( ITEM( &mi, pszData ) ){
  5226.                 MyFree( ITEM( &mi, pszData ) );
  5227.               }
  5228.               if ( ITEM( &mi, pszParameters ) ){
  5229.                 MyFree( ITEM( &mi, pszParameters ) );
  5230.               }
  5231.               if ( ITEM( &mi, hBmp ) ){
  5232.                 GpiDeleteBitmap( ITEM( &mi, hBmp ) );
  5233.               }
  5234.               MyFree( (PVOID)mi.hItem );
  5235.               if ( mi.hwndSubMenu ){
  5236.                  UCMenuFreeMenuData( mi.hwndSubMenu );
  5237.               } // endif
  5238.            } // endif
  5239.         } // endif
  5240.  
  5241.         //(MAM) Moved outside above IF so owner is notified of DELETE or REMOVEs
  5242.        
  5243.         if ((msg==MM_DELETEITEM) || (msg==MM_REMOVEITEM))
  5244.           NotifyMsg = UCN_DELETEDITEM;
  5245.         else
  5246.           NotifyMsg = UCN_CHANGEDITEM;
  5247.         WinSendMsg(UCMData->hwndOwner,
  5248.                    WM_CONTROL,
  5249.                    MPFROM2SHORT(UCMData->UCMenuID, NotifyMsg ),
  5250.                    MPFROMSHORT( SHORT1FROMMP( mp1 ) ) );
  5251.  
  5252.         rc = SEND_TO_MENU;
  5253.  
  5254.         UCMenuUpdateMenu( UCMData->hwndMenu, FALSE );
  5255.  
  5256.         return rc;
  5257.       }
  5258.  
  5259.     case MM_SETITEMATTR:
  5260.     case MM_ENDMENUMODE:
  5261.     case MM_ISITEMVALID:
  5262.     case MM_ITEMIDFROMPOSITION:
  5263.     case MM_ITEMPOSITIONFROMID:
  5264.     case MM_QUERYITEM:
  5265.     case MM_QUERYITEMATTR:
  5266.     case MM_QUERYITEMCOUNT:
  5267.     case MM_QUERYITEMRECT:
  5268.     case MM_QUERYSELITEMID:
  5269.     case MM_SELECTITEM:
  5270.     case WM_QUERYCONVERTPOS:
  5271.     case WM_SETWINDOWPARAMS:
  5272.     case WM_QUERYWINDOWPARAMS:
  5273.       return SEND_TO_MENU;
  5274.  
  5275.     case MM_STARTMENUMODE:
  5276.       return POST_TO_MENU;
  5277.  
  5278.     case MM_QUERYITEMTEXTLENGTH:
  5279.       { MENUITEM mi;
  5280.  
  5281.         WinSendMsg(UCMData->hwndMenu,
  5282.                    MM_QUERYITEM,
  5283.                    MPFROM2SHORT((SHORT)mp1, TRUE),
  5284.                    MPFROMP(&mi));
  5285.  
  5286.         if ( ! ( mi.afStyle & MIS_OWNERDRAW ) ) {
  5287.           return SEND_TO_MENU;
  5288.         } else {
  5289.           if (mi.hItem && ITEM(&mi, pszText))
  5290.             return (MPARAM)strlen(ITEM(&mi, pszText));
  5291.           else
  5292.             return (MPARAM)0;
  5293.         } // endif
  5294.       }
  5295.  
  5296.     case MM_QUERYITEMTEXT:
  5297.       { MENUITEM mi;
  5298.  
  5299.         if (!SHORT2FROMMP(mp1) || !mp2) {
  5300.           return FALSE;
  5301.         } // endif
  5302.         WinSendMsg(UCMData->hwndMenu,
  5303.                    MM_QUERYITEM,
  5304.                    MPFROM2SHORT((SHORT)mp1, TRUE),
  5305.                    MPFROMP(&mi));
  5306.  
  5307.         if ( ! ( mi.afStyle & MIS_OWNERDRAW ) ) {
  5308.           return SEND_TO_MENU;
  5309.         } else {
  5310.           PSZ pszText;
  5311.  
  5312.           if (mi.hItem && (pszText = ITEM(&mi, pszText))) {
  5313.             strncpy((PSZ)mp2, pszText, SHORT2FROMMP(mp1));
  5314.             pszText[SHORT2FROMMP(mp1)]='\0';
  5315.             return (MRESULT)strlen(pszText);
  5316.           } else {
  5317.             return (MRESULT)0;
  5318.           } /* endif */
  5319.         } /* endif */
  5320.       }
  5321.  
  5322.     case MM_SETITEMTEXT:
  5323.       { MENUITEM mi;
  5324.  
  5325.         WinSendMsg(UCMData->hwndMenu,
  5326.                    MM_QUERYITEM,
  5327.                    MPFROM2SHORT((SHORT)mp1, TRUE),
  5328.                    MPFROMP(&mi));
  5329.  
  5330.         if ( ! ( mi.afStyle & MIS_OWNERDRAW ) ) {
  5331.           return SEND_TO_MENU;
  5332.         } else {
  5333.           if (mi.hItem) {
  5334.             PSZ pszText = ITEM(&mi, pszText);
  5335.  
  5336.             if (pszText)
  5337.               MyFree(pszText);
  5338.             pszText = MyMalloc(strlen((PSZ)mp2)+1);
  5339.             strcpy(pszText, (PSZ)mp2);
  5340.             ITEM(&mi, pszText) = pszText;
  5341.             WinSendMsg( UCMData->hwndOwner,
  5342.                     WM_CONTROL,
  5343.                     MPFROM2SHORT(UCMData->UCMenuID, UCN_TEXT ),
  5344.                     MPFROMSHORT( mi.id ) );
  5345.             UCMenuUpdateMenu( UCMData->hwndMenu, TRUE );
  5346.             return (MRESULT)TRUE;
  5347.           } else {
  5348.             return (MRESULT)FALSE;
  5349.           } /* endif */
  5350.         } /* endif */
  5351.       }
  5352.  
  5353.     /*┌────────────────────┐
  5354.       │ Scrolling messages │
  5355.       └────────────────────┘*/
  5356.     case WM_VSCROLL:
  5357.       /*┌─────────────────────────┐
  5358.         │ Vertical Scroll message │
  5359.         └─────────────────────────┘*/
  5360.       switch (SHORT2FROMMP(mp2)) {
  5361.         case SB_LINEDOWN:
  5362.           /*┌────────────────────────────────────────────────────────────┐
  5363.             │ SB_LINEDOWN : We query the first item height and use it to │
  5364.             │ scroll the menu up                                         │
  5365.             └────────────────────────────────────────────────────────────┘*/
  5366.           { SWP swp;
  5367.             SHORT SliderPos;
  5368.             SHORT MaxPos;
  5369.             LONG  deltay;
  5370.  
  5371.             WinQueryWindowPos(UCMData->hwndHide, &swp );
  5372.  
  5373.             deltay = ( swp.cy - SUM_MENU_FRAME_THICK ) / 2;
  5374.  
  5375.             /*┌────────────────────────────────────────┐
  5376.               │ Query the scrollbar range and position │
  5377.               └────────────────────────────────────────┘*/
  5378.             MaxPos = SHORT2FROMMP(WinSendMsg(UCMData->hwndScroll,
  5379.                                              SBM_QUERYRANGE,
  5380.                                              (MPARAM)0,
  5381.                                              (MPARAM)0));
  5382.             SliderPos = (SHORT)WinSendMsg(UCMData->hwndScroll,
  5383.                                           SBM_QUERYPOS,
  5384.                                           (MPARAM)0,
  5385.                                           (MPARAM)0);
  5386.  
  5387.             /*┌────────────────────────────────────────────────────────┐
  5388.               │ Set the new position : don't scroll beyond the maximum │
  5389.               └────────────────────────────────────────────────────────┘*/
  5390.             if (SliderPos + deltay > MaxPos) {
  5391.               deltay -= SliderPos + deltay - MaxPos;
  5392.             } /* endif */
  5393.  
  5394.             WinPostMsg(UCMData->hwndScroll,
  5395.                        SBM_SETPOS,
  5396.                        MPFROMSHORT(SliderPos + deltay),
  5397.                        (MPARAM)0);
  5398.  
  5399.             WinQueryWindowPos(UCMData->hwndMenu, &swp);
  5400.             WinSetWindowPos(UCMData->hwndMenu,
  5401.                             HWND_TOP,
  5402.                             swp.x,
  5403.                             swp.y + deltay,
  5404.                             0,
  5405.                             0,
  5406.                             SWP_MOVE|SWP_SHOW);
  5407.           } break;
  5408.  
  5409.         case SB_LINEUP:
  5410.           /*┌────────────────────────────────────────────────────────────┐
  5411.             │ SB_LINEUP : We query the first item height and use it to   │
  5412.             │ scroll the menu down                                       │
  5413.             └────────────────────────────────────────────────────────────┘*/
  5414.           { SWP   swp;
  5415.             SHORT SliderPos;
  5416.             SHORT MinPos;
  5417.             LONG  deltay;
  5418.  
  5419.             WinQueryWindowPos( UCMData->hwndHide, &swp );
  5420.  
  5421.             deltay = ( swp.cy - SUM_MENU_FRAME_THICK ) / 2;
  5422.  
  5423.             /*┌────────────────────────────────────────┐
  5424.               │ Query the scrollbar range and position │
  5425.               └────────────────────────────────────────┘*/
  5426.             MinPos = SHORT1FROMMP(WinSendMsg(UCMData->hwndScroll,
  5427.                                              SBM_QUERYRANGE,
  5428.                                              (MPARAM)0,
  5429.                                              (MPARAM)0));
  5430.             SliderPos = (SHORT)WinSendMsg(UCMData->hwndScroll,
  5431.                                           SBM_QUERYPOS,
  5432.                                           (MPARAM)0,
  5433.                                           (MPARAM)0);
  5434.  
  5435.             /*┌───────────────────────────────────────────────────┐
  5436.               │ Set the new position : don't scroll < the minimum │
  5437.               └───────────────────────────────────────────────────┘*/
  5438.             if (SliderPos - deltay < MinPos) {
  5439.               deltay -= MinPos - SliderPos + deltay;
  5440.             } /* endif */
  5441.  
  5442.             WinPostMsg(UCMData->hwndScroll,
  5443.                        SBM_SETPOS,
  5444.                        MPFROMSHORT(SliderPos - deltay),
  5445.                        (MPARAM)0);
  5446.  
  5447.             WinQueryWindowPos(UCMData->hwndMenu, &swp);
  5448.             WinSetWindowPos(UCMData->hwndMenu,
  5449.                             HWND_TOP,
  5450.                             swp.x,
  5451.                             swp.y - deltay,
  5452.                             0,
  5453.                             0,
  5454.                             SWP_MOVE|SWP_SHOW);
  5455.           } break;
  5456.       } /* endswitch */
  5457.       break;
  5458.  
  5459.     case WM_HSCROLL:
  5460.       /*┌───────────────────────────┐
  5461.         │ Horizontal Scroll message │
  5462.         └───────────────────────────┘*/
  5463.       switch (SHORT2FROMMP(mp2)) {
  5464.         case SB_LINERIGHT:
  5465.           /*┌────────────────────────────────────────────────────────────┐
  5466.             │ SB_LINERIGHT: We query the first item width and use it to  │
  5467.             │ scroll the menu to the left                                │
  5468.             └────────────────────────────────────────────────────────────┘*/
  5469.           { SWP swp;
  5470.             SHORT SliderPos;
  5471.             SHORT MaxPos;
  5472.             LONG  deltax;
  5473.  
  5474.             WinQueryWindowPos( UCMData->hwndHide, &swp );
  5475.  
  5476.             deltax = ( swp.cx - SUM_MENU_FRAME_THICK ) / 2;
  5477.  
  5478.             /*┌────────────────────────────────────────┐
  5479.               │ Query the scrollbar range and position │
  5480.               └────────────────────────────────────────┘*/
  5481.             MaxPos = SHORT2FROMMP(WinSendMsg(UCMData->hwndScroll,
  5482.                                              SBM_QUERYRANGE,
  5483.                                              (MPARAM)0,
  5484.                                              (MPARAM)0));
  5485.             SliderPos = (SHORT)WinSendMsg(UCMData->hwndScroll,
  5486.                                           SBM_QUERYPOS,
  5487.                                           (MPARAM)0,
  5488.                                           (MPARAM)0);
  5489.  
  5490.             /*┌────────────────────────────────────────────────────────┐
  5491.               │ Set the new position : don't scroll beyond the maximum │
  5492.               └────────────────────────────────────────────────────────┘*/
  5493.             if (SliderPos + deltax > MaxPos) {
  5494.               deltax -= SliderPos + deltax - MaxPos;
  5495.             } /* endif */
  5496.  
  5497.             WinPostMsg(UCMData->hwndScroll,
  5498.                        SBM_SETPOS,
  5499.                        MPFROMSHORT(SliderPos + deltax),
  5500.                        (MPARAM)0);
  5501.  
  5502.             WinQueryWindowPos(UCMData->hwndMenu, &swp);
  5503.             WinSetWindowPos(UCMData->hwndMenu,
  5504.                             HWND_TOP,
  5505.                             swp.x - deltax,
  5506.                             swp.y,
  5507.                             0,
  5508.                             0,
  5509.                             SWP_MOVE|SWP_SHOW);
  5510.           } break;
  5511.  
  5512.         case SB_LINELEFT:
  5513.           /*┌────────────────────────────────────────────────────────────┐
  5514.             │ SB_LINELEFT: We query the first item width  and use it to  │
  5515.             │ scroll the menu right                                      │
  5516.             └────────────────────────────────────────────────────────────┘*/
  5517.           { SWP   swp;
  5518.             SHORT SliderPos;
  5519.             SHORT MinPos;
  5520.             LONG  deltax;
  5521.  
  5522.             WinQueryWindowPos( UCMData->hwndHide, &swp );
  5523.  
  5524.             deltax = ( swp.cx - SUM_MENU_FRAME_THICK ) / 2;
  5525.  
  5526.             /*┌────────────────────────────────────────┐
  5527.               │ Query the scrollbar range and position │
  5528.               └────────────────────────────────────────┘*/
  5529.             MinPos = SHORT1FROMMP(WinSendMsg(UCMData->hwndScroll,
  5530.                                              SBM_QUERYRANGE,
  5531.                                              (MPARAM)0,
  5532.                                              (MPARAM)0));
  5533.             SliderPos = (SHORT)WinSendMsg(UCMData->hwndScroll,
  5534.                                           SBM_QUERYPOS,
  5535.                                           (MPARAM)0,
  5536.                                           (MPARAM)0);
  5537.  
  5538.             /*┌────────────────────────────────────────────────────────┐
  5539.               │ Set the new position : don't scroll beyond the minimum │
  5540.               └────────────────────────────────────────────────────────┘*/
  5541.             if (SliderPos - deltax < MinPos) {
  5542.               deltax -= MinPos - SliderPos + deltax;
  5543.             } /* endif */
  5544.  
  5545.             WinPostMsg(UCMData->hwndScroll,
  5546.                        SBM_SETPOS,
  5547.                        MPFROMSHORT(SliderPos - deltax),
  5548.                        (MPARAM)0);
  5549.  
  5550.             WinQueryWindowPos(UCMData->hwndMenu, &swp);
  5551.             WinSetWindowPos(UCMData->hwndMenu,
  5552.                             HWND_TOP,
  5553.                             swp.x + deltax,
  5554.                             swp.y,
  5555.                             0,
  5556.                             0,
  5557.                             SWP_MOVE|SWP_SHOW);
  5558.           } break;
  5559.       } /* endswitch */
  5560.       break;
  5561.  
  5562.     case WM_ADJUSTWINDOWPOS:
  5563.       { PSWP pswp = (PSWP)mp1;
  5564.  
  5565.         if (pswp->fl & (SWP_MOVE | SWP_SIZE)) {
  5566.           //(MAM) changed this from Post to Send to prevent delayed repainting
  5567.           WinSendMsg(hwnd,                                
  5568.                      WM_SIZE,
  5569.                      (MPARAM)0,
  5570.                      MPFROM2SHORT(pswp->cx, pswp->cy));
  5571.         } /* endif */
  5572.  
  5573.         if (pswp->fl & SWP_ACTIVATE) {
  5574.           pswp->fl &= (ULONG)~SWP_ACTIVATE;
  5575.           WinSetWindowPos(hwnd,
  5576.                           HWND_TOP,
  5577.                           0,
  5578.                           0,
  5579.                           0,
  5580.                           0,
  5581.                           SWP_ZORDER | SWP_ACTIVATE);
  5582.         } /* endif */
  5583.       } break;
  5584.  
  5585.     case WM_SIZE:
  5586.     { //SWP swp;
  5587.       LONG  cx = SHORT1FROMMP(mp2);
  5588.       LONG  cy = SHORT2FROMMP(mp2);
  5589.  
  5590.       if (cx<=0 || cy<=0 || !(UCMData->hwndScroll) || !(UCMData->hwndHide) || !(UCMData->hwndMenu)) break;
  5591.  
  5592. //    WinQueryWindowPos(UCMData->hwndMenu, &swp);
  5593.  
  5594.       /* Set scroll window over entire area */
  5595.       WinSetWindowPos(UCMData->hwndScroll,
  5596.                       HWND_TOP,
  5597.                       0,
  5598.                       0,
  5599.                       cx,
  5600.                       cy,
  5601.                       SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW);
  5602.  
  5603.       /* Set hide to cover area, inset by borders */
  5604.       WinSetWindowPos(UCMData->hwndHide,
  5605.                       HWND_TOP,
  5606.                       UCM_FRAME_THICK,
  5607.                       UCM_FRAME_THICK,
  5608.                       cx - SUM_UCM_FRAME_THICK,
  5609.                       cy - SUM_UCM_FRAME_THICK,
  5610.                       SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW);
  5611.  
  5612.       //7@P5d Moved set of menu window position to UCMenuCheckScrolling()
  5613.  
  5614.       UCMenuCheckScrolling(hwnd);
  5615.     } break;
  5616.  
  5617.     case WM_SHOW:
  5618.       // We can get this message after WM_DESTROY has freed our
  5619.       // instance data, so check the pointer first!
  5620.       if (UCMData != NULL) {
  5621.         if (UCMData->hwndScroll)
  5622.           WinShowWindow(UCMData->hwndScroll, (BOOL)mp1);
  5623.   
  5624.         if (UCMData->hwndHide)
  5625.           WinShowWindow(UCMData->hwndHide, (BOOL)mp1);
  5626.   
  5627.         if (UCMData->hwndMenu)
  5628.           WinShowWindow(UCMData->hwndMenu, (BOOL)mp1);
  5629.       }
  5630.       break;
  5631.  
  5632.     case WM_DESTROY:
  5633.       {
  5634.  
  5635.         if (UCMData->usItem != 0) {   //(MAM) There is an open submenu, close it before destory
  5636.            MENUITEM OpenItem;
  5637.            if ((BOOL)WinSendMsg(UCMData->hwndMenu,
  5638.                       MM_QUERYITEM,
  5639.                       MPFROM2SHORT(UCMData->usItem,TRUE),
  5640.                       MPFROMP(&OpenItem)))
  5641.              WinSendMsg(OpenItem.hwndSubMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0L);
  5642.         }
  5643.  
  5644.         WinSubclassWindow( UCMData->hwndMenu, (PFNWP)UCMData->OldMenuProc);
  5645.         if (UCMData->hwndHelpInstance) {
  5646.            WinDestroyHelpInstance( UCMData->hwndHelpInstance );
  5647.         } // endif
  5648.  
  5649.         UCMenuFreeMenuData( UCMData->hwndMenu );
  5650.         //free all UCMenu instance data
  5651.         if ( UCMData->pszFontNameSize ) {
  5652.            MyFree( UCMData->pszFontNameSize );
  5653.         } // endif
  5654.         if ( UCMData->hpsMem ) {
  5655.            HDC hdcMem;
  5656.            hdcMem = GpiQueryDevice( UCMData->hpsMem );
  5657.            //(MAM) Destroy PS before closing DC since PM cannot
  5658.            //disassociate a micro PS from its DC.
  5659.            GpiDestroyPS( UCMData->hpsMem );
  5660.            DevCloseDC( hdcMem );
  5661.         } // endif
  5662.         if ( UCMData->AccelTable ){
  5663.            MyFree( UCMData->AccelTable );
  5664.         } // endif
  5665.  
  5666.         //(MAM) destroy other windows also.  Since Scroll, Hide, and Menu windows are
  5667.         // child windows, they will be destroyed by PM after this message is processed.
  5668.         // We must explicitly destroy non-child windows:
  5669.  
  5670.         if ( UCMData->hwndCM )                   // context menu
  5671.           WinDestroyWindow( UCMData->hwndCM );
  5672.         if ( UCMData->hwndBubble )
  5673.           WinDestroyWindow(UCMData->hwndBubble); // bubble window
  5674.  
  5675.         WinSetWindowPtr(hwnd, QWL_UCMDATA, NULL);
  5676.         MyFree(UCMData);
  5677.         return 0;
  5678.       }
  5679.  
  5680.     default:
  5681.      return (WinDefWindowProc(hwnd, msg, mp1, mp2));
  5682.  
  5683.   } // endswitch
  5684.   return (MRESULT)FALSE;
  5685. }
  5686.  
  5687. //----------------------------------------------------------------------------
  5688. // HideWndProc
  5689. //----------------------------------------------------------------------------
  5690. // :pfunction res=&IDF_HIDEWNDPROC. name='HideWndProc' text='Hide window procedure'.
  5691. // Window procedure of the Hide class, processes WM_PAINT, WM_CONTEXT and WM_COMMAND
  5692. // :syntax name='HideWndProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  5693. // :fparams.
  5694. // :fparam name='hwnd' type='HWND' io='input' .
  5695. // Hide window handle
  5696. // :fparam name='msg' type='ULONG' io='input' .
  5697. // Message
  5698. // :fparam name='mp1' type='MPARAM' io='input'.
  5699. // First parameter
  5700. // :fparam name='mp2' type='MPARAM' io='input'.
  5701. // Second parameter
  5702. // :freturns.
  5703. // :fparam name='mresult' type='MRESULT' io='return'.
  5704. // Return code of a PM message.
  5705. // :efparams.
  5706. // :remarks.
  5707. // :epfunction.
  5708. //----------------------------------------------------------------------------
  5709. MRESULT EXPENTRY HideWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  5710. {
  5711. PUCMDATA UCMData;
  5712.  
  5713.   UCMData = WinQueryWindowPtr(hwnd, 0L);
  5714.  
  5715.   switch (msg) {
  5716.      case WM_PRESPARAMCHANGED:
  5717.           {
  5718.              if ( (SHORT)mp1 == PP_BACKGROUNDCOLOR ) {
  5719.                 ULONG Color, x;
  5720.                 HPS hps;
  5721.  
  5722.                 WinQueryPresParam( hwnd,
  5723.                                    (SHORT)mp1,
  5724.                                    0L, &x,
  5725.                                    (ULONG)sizeof Color,
  5726.                                    &Color,
  5727.                                    QPF_NOINHERIT);
  5728.                 if ( UCMData && ( x == (SHORT)mp1 ) ){
  5729.                    // We don't want a dithered color because we will also use it
  5730.                    // to draw lines, and in this case only pure colors are used
  5731.                    // -> we will to have exactly the same color all over the ucmenu
  5732.                    hps = WinGetPS( hwnd );
  5733.                    if ( hps ){
  5734.                       UCMData->BgColor = GpiQueryNearestColor( hps, (ULONG)0, (LONG)Color );
  5735.                       UCMenuUpdateMenu( UCMData->hwndMenu, FALSE );
  5736.                       WinReleasePS( hps );
  5737.                       WinSendMsg( UCMData->hwndOwner,
  5738.                                   WM_CONTROL,
  5739.                                   MPFROM2SHORT(UCMData->UCMenuID, UCN_COLOR ),
  5740.                                   MPFROMSHORT( 0 ) );
  5741.                    } // endif
  5742.                 } else {
  5743.                    WinRemovePresParam( hwnd, PP_BACKGROUNDCOLOR );
  5744.                 } // endif
  5745.              } else {
  5746.                 UCMenuPresParamChanged(UCMData, hwnd, mp1 );
  5747.              } // endif
  5748.              return((MRESULT)0);
  5749.           }
  5750. //  case WM_MOUSEMOVE:
  5751. //     {
  5752. //        PUCMDATA  UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  5753. //        if ( UCMData->Style & UCS_PROMPTING ){
  5754. //           HWND hwndUCM   = WinQueryWindow( hwnd, QW_OWNER );
  5755. //           HWND hwndOwner = WinQueryWindow( hwndUCM, QW_OWNER );
  5756. //           WinSendMsg( hwndOwner,
  5757. //                       WM_CONTROL,
  5758. //                       MPFROM2SHORT( WinQueryWindowUShort( hwndUCM, QWS_ID ), UCN_MOUSEMOVE ),
  5759. //                       (MPARAM)0);
  5760. //           return (MRESULT)TRUE;
  5761. //        } else {
  5762. //           return (MRESULT)FALSE;
  5763. //        } // endif
  5764. //     }
  5765.  
  5766.     case WM_CREATE:
  5767.  
  5768.          WinSetWindowPtr(hwnd, 0L, (PUCMDATA)mp1);
  5769.          return((MRESULT)0);
  5770.  
  5771. // case WM_INITMENU:
  5772. //    {
  5773. //       PUCMDATA UCMData = (PUCMDATA)mp1;
  5774. //
  5775. //       // ----------------------------------------------------------
  5776. //       // -- Received when the context menu is about to be displayed
  5777. //       // -- Set the scrollbar as active window so that the contextual
  5778. //       // -- help looks in its help subtable (this is the only
  5779. //       // -- frame window available with a fixed ID)
  5780. //       // ----------------------------------------------------------
  5781. //       WinSendMsg( UCMData->hwndHelpInstance,
  5782. //                   HM_SET_ACTIVE_WINDOW,
  5783. //                   (MPARAM) WinQueryWindow( hwnd, QW_PARENT ),
  5784. //                   (MPARAM) WinQueryWindow( hwnd, QW_PARENT ) );
  5785. //       return WinDefWindowProc( hwnd, msg, mp1, mp2);
  5786. //    }
  5787.    case WM_CONTEXTMENU:
  5788.  
  5789.       /*┌──────────────────────────────────────────────────────────────┐
  5790.         │ Show the pop-up menu                                         │
  5791.         └──────────────────────────────────────────────────────────────┘*/
  5792.       {
  5793.  
  5794.          UCMenuContextMenu(UCMData->hwndUCM,
  5795.                            UCMData->hwndMenu,
  5796.                            (ULONG)mp1);
  5797.          return (MRESULT) TRUE;
  5798.       }
  5799.  
  5800.     case WM_MENUEND:{
  5801.       /* Context menu is terminating... re-enable bubble help window */
  5802.       if (UCMData->Style & UCS_BUBBLEHELP)
  5803.         WinSendMsg(UCMData->hwndBubble, MSG_ENABLE_BUBBLE, 0L, 0L);
  5804.       return 0;
  5805.       }
  5806.  
  5807.     case WM_COMMAND: {
  5808.  
  5809.       /* We only get WM_COMMAND messages here from the toolbar context menu. */
  5810.       /* If the context menu is application-supplied, we just pass the       */
  5811.       /* message on to the application.  Otherwise, we process options on    */
  5812.       /* the built-in toolbar context menu.                                  */
  5813.       if (UCMData->hwndUserCM != NULLHANDLE) { // App supplied the context menu
  5814.  
  5815.         WinSendMsg(UCMData->hwndOwner,  // To owner (app)
  5816.                    WM_CONTROL,
  5817.                    MPFROM2SHORT( UCMData->UCMenuID, UCN_CMITEM ) ,
  5818.                    MPFROM2SHORT( SHORT1FROMMP( mp1 ), UCMData->ContextID  ) );
  5819.         return 0;
  5820.       }
  5821.  
  5822.       #if !defined(UCMUI)  // We don't support any UI functions
  5823.         return 0;
  5824.       #else
  5825.       switch (SHORT1FROMMP(mp1)) {
  5826.         case IDM_UCM_DELETE:
  5827.           {
  5828.             /*┌──────────────────────────────────────────────────────────────┐
  5829.               │ Delete the menu item (ContextID = itemID)                    │
  5830.               └──────────────────────────────────────────────────────────────┘*/
  5831.  
  5832.             WinSendMsg(UCMData->hwndCMOrig,
  5833.                        MM_DELETEITEM,
  5834.                        MPFROM2SHORT(UCMData->ContextID, TRUE),
  5835.                        (MPARAM)0);
  5836.           }
  5837.           return (MRESULT)TRUE;
  5838.  
  5839.         case IDM_UCM_CREATE:
  5840.           /*┌──────────────────────────────────────────────────────────────┐
  5841.             │ Add a new item in the UCMenu : use the settings notebook     │
  5842.             └──────────────────────────────────────────────────────────────┘*/
  5843.           {
  5844.  
  5845.             UCMData->bItemCreation = TRUE;
  5846.             UCMData->hwndTemp = WinQueryWindow(hwnd, QW_OWNER);
  5847.             WinDlgBox(HWND_DESKTOP,
  5848.                       UCMData->hwndTemp,  //---hwndUCM
  5849.                       UCMenuSettingsDlgProc,
  5850.                       UCMData->hModUCM,
  5851.                       IDD_UCMSETTINGS,
  5852.                       (PVOID)UCMData);
  5853.             UCMData->hwndTemp = NULLHANDLE;
  5854.           }
  5855.           return (MRESULT)TRUE;
  5856.  
  5857.         case IDM_UCM_EDIT:
  5858.           /*┌──────────────────────────────────────────────────────────────┐
  5859.             │ Edit an item : call the settings notebook                    │
  5860.             └──────────────────────────────────────────────────────────────┘*/
  5861.           {
  5862.  
  5863.             UCMData->bItemCreation = FALSE;
  5864.             UCMData->hwndTemp = WinQueryWindow(hwnd, QW_OWNER);
  5865.             WinDlgBox(HWND_DESKTOP,
  5866.                       UCMData->hwndTemp,  //---hwndUCM
  5867.                       UCMenuSettingsDlgProc,
  5868.                       UCMData->hModUCM,
  5869.                       IDD_UCMSETTINGS,
  5870.                       (PVOID)UCMData);
  5871.             UCMData->hwndTemp = NULLHANDLE;
  5872.           }
  5873.           return (MRESULT)TRUE;
  5874.  
  5875.         case IDM_UCM_DEFAULT:
  5876.           /*┌──────────────────────────────────────────────────────────────┐
  5877.             │ Get the default template (from the resource)                 │
  5878.             └──────────────────────────────────────────────────────────────┘*/
  5879.           UCMenuLoadDefault( UCMData->hwndUCM );
  5880.           break;
  5881.  
  5882.  
  5883.         case IDM_UCM_LOAD:
  5884.           /*┌──────────────────────────────────────────────────────────────┐
  5885.             │ Load a template from a file                                  │
  5886.             └──────────────────────────────────────────────────────────────┘*/
  5887.           { FILEDLG FileDlg;
  5888.             ULONG  ulBufLen;
  5889.             UCHAR  szPath[CCHMAXPATH];
  5890.             PSZ    pszIndex;
  5891.  
  5892.  
  5893.             UCMData->hwndTemp = WinQueryWindow(hwnd, QW_OWNER);
  5894.             szPath[CCHMAXPATH-1] = '\0';
  5895.             strncpy( szPath, UCMData->szTemplatePath, CCHMAXPATH );
  5896.             strncat( szPath, "*.bar", CCHMAXPATH );
  5897.             memset(&FileDlg, 0, sizeof(FileDlg));
  5898.             FileDlg.cbSize = sizeof(FileDlg);
  5899.             FileDlg.fl     = FDS_OPEN_DIALOG | FDS_CENTER;
  5900.             FileDlg.szFullFile[CCHMAXPATH-1] = '\0';
  5901.             strncpy( FileDlg.szFullFile, szPath, CCHMAXPATH );
  5902.             WinFileDlg(HWND_DESKTOP, hwnd, &FileDlg);
  5903.  
  5904.             if (FileDlg.lReturn == DID_OK) {
  5905.               PVOID pBuffer;
  5906.               pBuffer = UCMenuLoadTemplate( FileDlg.szFullFile, &ulBufLen );
  5907.               if (pBuffer) {
  5908.                 UCMenuNew( UCMData->hwndTemp, pBuffer );
  5909.                 MyFree( pBuffer );
  5910.               } /* endif */
  5911.               pszIndex = strrchr( FileDlg.szFullFile, '\\' );
  5912.               if ( pszIndex ) {
  5913.                  *( pszIndex + 1 ) = '\0';
  5914.               } /* endif */
  5915.               strncpy( UCMData->szTemplatePath, FileDlg.szFullFile, CCHMAXPATH );
  5916.             } /* endif */
  5917.  
  5918.           } break;
  5919.  
  5920.  
  5921.         case IDM_UCM_SAVEAS:
  5922.           /*┌──────────────────────────────────────────────────────────────┐
  5923.             │ Saves the template to a file                                 │
  5924.             └──────────────────────────────────────────────────────────────┘*/
  5925.           { FILEDLG FileDlg;
  5926.             UCHAR   szPath[CCHMAXPATH];
  5927.             PSZ     pszIndex;
  5928.  
  5929.             UCMData->hwndTemp = WinQueryWindow(hwnd, QW_OWNER);
  5930.             szPath[CCHMAXPATH-1] = '\0';
  5931.             strncpy( szPath, UCMData->szTemplatePath, CCHMAXPATH );
  5932.             strncat( szPath, "*.bar", CCHMAXPATH );
  5933.             memset(&FileDlg, 0, sizeof(FileDlg));
  5934.             FileDlg.cbSize = sizeof(FileDlg);
  5935.             FileDlg.fl     = FDS_SAVEAS_DIALOG | FDS_CENTER;
  5936.             strncpy( FileDlg.szFullFile, szPath, CCHMAXPATH );
  5937.             WinFileDlg(HWND_DESKTOP, hwnd, &FileDlg);
  5938.  
  5939.             if (FileDlg.lReturn == DID_OK) {
  5940.               UCMenuSaveTemplate(UCMData->hwndTemp, FileDlg.szFullFile);
  5941.               pszIndex = strrchr( FileDlg.szFullFile, '\\' );
  5942.               if ( pszIndex ) {
  5943.                  *( pszIndex + 1 ) = '\0';
  5944.               } /* endif */
  5945.               strncpy( UCMData->szTemplatePath, FileDlg.szFullFile, CCHMAXPATH );
  5946.             } /* endif */
  5947.           } break;
  5948.  
  5949.         case IDM_UCM_STYLE:
  5950.           /*┌──────────────────────────────────────────────────────────────┐
  5951.             │ Popup the ucmenu styles dialog                               │
  5952.             └──────────────────────────────────────────────────────────────┘*/
  5953.           {
  5954.             UCMData->hwndTemp = WinQueryWindow(hwnd, QW_OWNER);
  5955.  
  5956.             WinDlgBox(HWND_DESKTOP,
  5957.                       UCMData->hwndTemp,
  5958.                       UCMenuStyleDlgProc,
  5959.                       UCMData->hModUCM,
  5960.                       IDD_UCMNSTYLE,
  5961.                       (PVOID)UCMData);
  5962.             UCMData->hwndTemp = NULLHANDLE;
  5963.           }
  5964.           return (MRESULT)TRUE;
  5965.  
  5966.        default:
  5967.             {
  5968.            
  5969.                UCMData->hwndTemp = UCMData->hwndOwner;
  5970.                WinSendMsg(UCMData->hwndOwner,
  5971.                           WM_CONTROL,
  5972.                           MPFROM2SHORT( UCMData->UCMenuID, UCN_CMITEM ) ,
  5973.                           MPFROM2SHORT( SHORT1FROMMP( mp1 ), UCMData->ContextID  ) );
  5974.             }
  5975.       } // endswitch of WM_COMMAND item ID
  5976.       #endif // UCMUI
  5977.  
  5978.       break;  // end of WM_COMMAND processing
  5979.       }
  5980.  
  5981.     case WM_PAINT:
  5982.       /*┌────────────────────────────────────────────────────────┐
  5983.         │ We fill the rectangle with the UCMData->BgColor color. │
  5984.         │ We draw an inside frame                                │
  5985.         └────────────────────────────────────────────────────────┘*/
  5986.       { HPS hPS;
  5987.         RECTL rcl;
  5988.         SWP swp;
  5989.         ULONG BgColorIndex;
  5990.  
  5991.         hPS = WinBeginPaint(hwnd, (HPS)NULL, &rcl);
  5992.         BgColorIndex = UCMenuSelectColor( UCMData->BgColor, hPS );
  5993.         WinFillRect(hPS, &rcl, BgColorIndex);
  5994.  
  5995.         /*┌──────────────────────────────────────────────┐
  5996.           │ Draw lines around the menu for the 3D effect │
  5997.           └──────────────────────────────────────────────┘*/
  5998.         if (UCMData->Style & UCS_FRAMED) {
  5999.           WinQueryWindowPos( WinQueryWindow( hwnd, QW_TOP ), &swp );
  6000.           rcl.xLeft   = swp.x - MENU_FRAME_THICK;
  6001.           rcl.yBottom = swp.y - MENU_FRAME_THICK;
  6002.           rcl.xRight  = swp.x + swp.cx + MENU_FRAME_THICK;
  6003.           rcl.yTop    = swp.y + swp.cy + MENU_FRAME_THICK;
  6004.           UCMenu3DFrame( hPS, &rcl, 0 );
  6005.         }
  6006.         WinEndPaint(hPS);
  6007.       } break;
  6008.  
  6009.     case DM_DRAGOVER:
  6010.       // -------------------------------------------------------------------
  6011.       // -- We get this message when the drag icon is moved over our window.
  6012.       // -- We must verify whether or not we want to accept the drop.
  6013.       // -------------------------------------------------------------------
  6014.       return (MRESULT)(UCMenuDragOver(UCMData, hwnd,(PDRAGINFO) mp1));
  6015.  
  6016.     case DM_DROP:
  6017.       // --------------------------------------------------------
  6018.       // -- Some application has just Dropped something on us !!
  6019.       // --------------------------------------------------------
  6020.       UCMenuDrop(hwnd, (PDRAGINFO)mp1) ;
  6021.       return (MRESULT)0;
  6022.  
  6023.      default:
  6024.        return (WinDefWindowProc(hwnd, msg, mp1, mp2));
  6025.   } // endswitch
  6026.  
  6027.   return (MRESULT)FALSE;
  6028. }
  6029.  
  6030. //----------------------------------------------------------------------------
  6031. // SubmenuWndProc
  6032. //----------------------------------------------------------------------------
  6033. // :pfunction res=&IDF_SUBMWNDPROC. name='SubmenuWndProc' text='Submenu window procedure'.
  6034. // Window procedure of the submenus
  6035. // :syntax name='SubmenuWndProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  6036. // :fparams.
  6037. // :fparam name='hwnd' type='HWND' io='input' .
  6038. // Submenu window handle
  6039. // :fparam name='msg' type='ULONG' io='input' .
  6040. // Message
  6041. // :fparam name='mp1' type='MPARAM' io='input'.
  6042. // First parameter
  6043. // :fparam name='mp2' type='MPARAM' io='input'.
  6044. // Second parameter
  6045. // :freturns.
  6046. // :fparam name='mresult' type='MRESULT' io='return'.
  6047. // Return code of a PM message.
  6048. // :efparams.
  6049. // :remarks.
  6050. // We process the WM_ADJUSTWINDOWPOS message to position the window on the right
  6051. // of the nebu item instead under it for vertical ucmenus
  6052. // :epfunction.
  6053. //----------------------------------------------------------------------------
  6054. MRESULT EXPENTRY SubmenuWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  6055. {
  6056.    PUCMDATA  UCMData = (PUCMDATA)WinQueryWindowPtr(hwnd, 0L);
  6057.  
  6058.    switch (msg) {
  6059.  
  6060. //  case WM_BUTTON2DOWN:
  6061. //  case WM_BUTTON1DOWN: {
  6062. //        /* On any button down, release capture and disable the bubble  */
  6063. //        /* help window.  It will be re-enabled when the button is      */
  6064. //        /* released (or drag/drop done, in that case).                 */
  6065. //
  6066. //        if (UCMData->Style & UCS_BUBBLEHELP)
  6067. //          WinSendMsg(UCMData->hwndBubble, MSG_DISABLE_BUBBLE, 0L, 0L);
  6068. //
  6069. //        if (UCMData->HoverCapture) {
  6070. //          WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  6071. //          UCMData->HoverCapture = FALSE;
  6072. //        }
  6073. //        
  6074. //        if (msg == WM_BUTTON2DOWN)  // Drag/drop does not work if default proc gets this
  6075. //          break;                    // ??? should use WinQuerySysValue(...SV_BEGINDRAG...)
  6076. //        return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); // Pass this on
  6077. //        }
  6078. //
  6079. //
  6080. //  case WM_BUTTON2UP:
  6081. //  case WM_BUTTON1UP: {
  6082. //        MRESULT rc;
  6083. //
  6084. //        /* First let normal window proc process the UP message */
  6085. //        /* It will POST a WM_COMMAND to our UCMenu window if   */
  6086. //        /* the mouse is still on the menu item.                */
  6087. //        rc = UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); 
  6088. //
  6089. //        /* Simulate a mouse-move so that we will recapture the */
  6090. //        /* mouse if needed.  Set a flag for the WM_MOUSEMOVE   */
  6091. //        /* code to recognize this is a fake movement.          */
  6092. //
  6093. //        UCMData->HoverMsg = msg;
  6094. //        if (UCMData->Style & UCS_BUBBLEHELP)
  6095. //          WinSendMsg(UCMData->hwndBubble, MSG_ENABLE_BUBBLE, 0L, 0L);
  6096. //
  6097. //
  6098. //        /* NOTE: This message must be POSTED so it arrives         */
  6099. //        /* after WM_COMMAND has been received and UCN_ITEMSELECTED */
  6100. //        /* processed by the application.  Otherwise the app could  */
  6101. //        /* invoke a dialog in response to UCN_ITEMSELECTED and     */
  6102. //        /* cause us to lose mouse capture tracking.                */
  6103. //
  6104. //        WinPostMsg(hwnd, WM_MOUSEMOVE, mp1, mp2);
  6105. //        return rc;
  6106. //        }
  6107. //     
  6108. //  case WM_MOUSEMOVE:
  6109. //     {
  6110. //        USHORT   usId;      /* ID of menu item under mouse */
  6111. //        POINTL   ptl;       /* Mouse position in the window */
  6112. //        HWND hwndUCM   = WinQueryWindow( UCMData->hwndMenu, QW_OWNER );
  6113. //        HWND hwndOwner = WinQueryWindow( hwndUCM, QW_OWNER );
  6114. //        HWND HwndAt;        /* Window at mouse position */
  6115. //        BOOL Inside    = TRUE;
  6116. //        BOOL ButtonDown= FALSE;
  6117. //
  6118. //        /* If our app is not the active window, just pass it on */
  6119. //        if (!(UCMData->Active))
  6120. //          return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 );
  6121. //
  6122. //        /* See if any mouse button is pressed (and this is not from a BUTTONUP msg above). */
  6123. //        if ((WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) && (UCMData->HoverMsg != WM_BUTTON1UP))
  6124. //          ButtonDown = TRUE;
  6125. //        if ((WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) && (UCMData->HoverMsg != WM_BUTTON2UP))
  6126. //          ButtonDown = TRUE;
  6127. //        UCMData->HoverMsg = WM_NULL;
  6128. //
  6129. //        ptl.x = (ULONG) SHORT1FROMMP( mp1 );
  6130. //        ptl.y = (ULONG) SHORT2FROMMP( mp1 );
  6131. //
  6132. //        /* Note we must test entire desktop window hierarchy for PM */
  6133. //        /* to tell us if the point is over a window which obscures  */
  6134. //        /* our own.  If we search only our own window hierarchy, we */
  6135. //        /* will detect movements whenever the pointer is inside our */
  6136. //        /* window rectangle, even if our window is covered by       */
  6137. //        /* some other application.  Searching the desktop hierarchy */
  6138. //        /* is bad for performance, but PM gives us no other way to  */
  6139. //        /* detect (for sure) when the mouse leaves our menu window. */
  6140. //
  6141. //        WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
  6142. //        HwndAt = WinWindowFromPoint(HWND_DESKTOP, &ptl, TRUE);
  6143. //        if (HwndAt != hwnd)
  6144. //          Inside = FALSE;
  6145. //
  6146. //        /* Restore point to my coordinate system */
  6147. //        ptl.x = (ULONG) SHORT1FROMMP( mp1 );
  6148. //        ptl.y = (ULONG) SHORT2FROMMP( mp1 );
  6149. //
  6150. //        /* If mouse is over another window (even if within the menu */
  6151. //        /* window rectangle), we don't use it.  Coord mapping       */
  6152. //        /* routine will be fooled by overlapping windows.           */
  6153. //
  6154. //        if (!Inside)
  6155. //          usId = 0;
  6156. //        else
  6157. //          usId  = UCMenuIdFromCoord(hwnd, &ptl ); // Where is it?
  6158. //
  6159. //        if (usId != UCMData->HoverID) {               // Tell owner of any change
  6160. //          if (UCMData->Style & UCS_PROMPTING)         // ...if they want to know.
  6161. //            WinSendMsg( hwndOwner, WM_CONTROL,
  6162. //                        MPFROM2SHORT( WinQueryWindowUShort( hwndUCM, QWS_ID ), UCN_MOUSEMOVE ),
  6163. //                        MPFROMSHORT( usId ) );
  6164. //          if (UCMData->Style & UCS_BUBBLEHELP) {      // ...if bubble needs to know
  6165. //            BOOL Deactivate = TRUE;                   // Bubble should be deactivated
  6166. //            if ((HwndAt == UCMData->hwndMenu) ||              // ... unless ptr
  6167. //    //          (HwndAt == UCMData->hwndBubble) ||
  6168. //    //          (HwndAt == WinQueryWindow(UCMData->hwndMenu, QW_PARENT)) ||  // hide window
  6169. //                (WinQueryWindow(HwndAt,QW_OWNER)==UCMData->hwndMenu))  // is over any TB menu
  6170. //                Deactivate = FALSE;
  6171. //            WinSendMsg(UCMData->hwndBubble,           
  6172. //                        MSG_ITEMCHANGE, MPFROM2SHORT(usId, Deactivate), MPFROMHWND(hwnd));
  6173. //          }
  6174. //        }
  6175. //        UCMData->HoverID = usId;                      // Save for next time
  6176. //
  6177. //        /* We (UCMenus) will capture the mouse if:               */
  6178. //        /*  - The mouse is inside the menu window                */
  6179. //        /*  - We don't already have it captured                  */
  6180. //        /*  - No buttons are pressed                             */
  6181. //
  6182. //        if ((Inside) && (!UCMData->HoverCapture) && (!ButtonDown)) {
  6183. //           WinSetCapture(HWND_DESKTOP, hwnd);
  6184. //           UCMData->HoverCapture = TRUE;
  6185. //        }
  6186. //
  6187. //        /* We release capture if:                                */
  6188. //        /*  - Mouse is outside the menu window                   */
  6189. //        /*  - No buttons down                                    */
  6190. //        /*  - We have capture set                                */
  6191. //
  6192. //        if ((!Inside) && (!ButtonDown) && (UCMData->HoverCapture)) {
  6193. //           WinSetCapture(HWND_DESKTOP, NULLHANDLE);    // Stop capture
  6194. //           UCMData->HoverCapture = FALSE;              // No longer captured
  6195. //           UCMData->HoverID = 0;
  6196. //        }
  6197. //
  6198. //        return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); // Pass this on
  6199. //     }
  6200.  
  6201.  
  6202.     case MM_INSERTITEM:
  6203.     case MM_SETITEM:
  6204.        {
  6205.           PMENUITEM pMi = 0;
  6206.           USHORT    NewID, NotifyMsg;
  6207.           MRESULT   rc;
  6208.  
  6209.           switch (msg) {
  6210.           case MM_INSERTITEM:
  6211.              pMi = (PMENUITEM)mp1;
  6212.              // Check if the id is already used
  6213.              NewID = UCMenuGetNewID( UCMData->hwndMenu, pMi->id, UCMData );
  6214.              if ( NewID != pMi->id) {
  6215.                 pMi->id = NewID;
  6216.                 if ( pMi->hItem ){
  6217.                    ITEM( pMi, usId ) = NewID;
  6218.                 } // endif
  6219.              } /* endif */
  6220.              break;
  6221.           case MM_SETITEM:
  6222.              pMi = (PMENUITEM)mp2;
  6223.              // The item was already in the menu, so its
  6224.              // id should be correct
  6225.             break;
  6226.           } // endswitch
  6227.  
  6228.           //(MAM) Don't allow BREAK on any menu item.
  6229.           pMi->afStyle = pMi->afStyle & ~MIS_BREAK;
  6230.  
  6231.           if ( pMi && pMi->hItem ){
  6232.              // Set the id also in ucmitem
  6233.              // --
  6234.              ITEM( pMi, usId ) = pMi->id;
  6235.              // Load the btimap
  6236.              // --
  6237.              UCMenuLoadItemBmp(pMi, UCMData );
  6238.           } // endif
  6239.  
  6240.           rc = UCMData->OldSubMenuProc(hwnd, msg, mp1, mp2);
  6241.  
  6242.           // if an item was added, notify application (AFTER the insert is done)
  6243.           if (msg==MM_INSERTITEM)
  6244.             NotifyMsg = UCN_ADDEDITEM;
  6245.           else
  6246.             NotifyMsg = UCN_CHANGEDITEM;
  6247.           WinSendMsg( UCMData->hwndOwner,
  6248.                   WM_CONTROL,
  6249.                   MPFROM2SHORT( UCMData->UCMenuID, NotifyMsg ),
  6250.                   MPFROMSHORT( pMi->id ) );
  6251.  
  6252.           return rc;
  6253.        }
  6254.  
  6255.     //(MAM) Added DELETE processing here for submenus.  Any MM_DELETEITEM type
  6256.     // request received by the main menu for a submenu item will be done here.
  6257.     case MM_DELETEITEM:
  6258.     case MM_REMOVEITEM:
  6259.     case MM_SETITEMHANDLE: {
  6260.         MRESULT rc;
  6261.         USHORT  NotifyMsg;
  6262.  
  6263.         if ( msg == MM_DELETEITEM ){
  6264.            MENUITEM mi;
  6265.  
  6266.            if ( WinSendMsg(UCMData->hwndMenu, MM_QUERYITEM, mp1, MPFROMP(&mi)) &&
  6267.                 mi.hItem ){
  6268.               if ( ITEM( &mi, pszBmp ) ){
  6269.                 MyFree( ITEM( &mi, pszBmp ) );
  6270.               }
  6271.               if ( ITEM( &mi, pszText ) ){
  6272.                 MyFree( ITEM( &mi, pszText ) );
  6273.               }
  6274.               if ( ITEM( &mi, pszAction ) ){
  6275.                 MyFree( ITEM( &mi, pszAction ) );
  6276.               }
  6277.               if ( ITEM( &mi, pszData ) ){
  6278.                 MyFree( ITEM( &mi, pszData ) );
  6279.               }
  6280.               if ( ITEM( &mi, pszParameters ) ){
  6281.                 MyFree( ITEM( &mi, pszParameters ) );
  6282.               }
  6283.               if ( ITEM( &mi, hBmp ) ){
  6284.                 GpiDeleteBitmap( ITEM( &mi, hBmp ) );
  6285.               }
  6286.               MyFree( (PVOID)mi.hItem );
  6287.               if ( mi.hwndSubMenu ){
  6288.                  UCMenuFreeMenuData( mi.hwndSubMenu );
  6289.               } // endif
  6290.            } // endif
  6291.  
  6292.         } // endif
  6293.  
  6294.         rc = UCMData->OldSubMenuProc(hwnd, msg, mp1, mp2);
  6295.      // if ((USHORT)WinSendMsg(hwnd, MM_QUERYITEMCOUNT, MPVOID, MPVOID) == 0) {
  6296.      //   /* Just deleted last item of a submenu.  Remove submenu attribute */
  6297.      //   /* of the parent menu item.                                       */
  6298.      //   //...not implemented yet: define a new mssage, UCMENU_QUERYSUBMENUPARENT
  6299.      //   //...which returns the item ID of the parent item of the
  6300.      //   //...submenu.  Implement the message by enumerating all the parent items
  6301.      //   //...and look for our window handle in the MENUITEM.hwndSubMenu field.
  6302.      //   //...When found, remove MIA_SUBMENU attribute, set hwndSubMenu to NULL,
  6303.      //   //...and destroy this submenu window.
  6304.      // }
  6305.  
  6306.         if ((msg==MM_DELETEITEM) || (msg==MM_REMOVEITEM))
  6307.           NotifyMsg = UCN_DELETEDITEM;
  6308.         else
  6309.           NotifyMsg = UCN_CHANGEDITEM;
  6310.         WinSendMsg( UCMData->hwndOwner,
  6311.                    WM_CONTROL,
  6312.                    MPFROM2SHORT( UCMData->UCMenuID, NotifyMsg ),
  6313.                    MPFROMSHORT( SHORT1FROMMP( mp1 ) ) );
  6314.  
  6315.         return rc;
  6316.         }
  6317.  
  6318.      case WM_CONTEXTMENU:
  6319.         {
  6320.          /*┌──────────────────────────────────────────────────────────────┐
  6321.            │ Show the pop-up menu                                         │
  6322.            └──────────────────────────────────────────────────────────────┘*/
  6323.  
  6324.            UCMenuContextMenu(UCMData->hwndUCM,
  6325.                              hwnd,
  6326.                              (ULONG)mp1);
  6327.            return (MRESULT) TRUE;
  6328.         }
  6329.      case WM_SYSCOLORCHANGE:
  6330.         // Don't let original menu window proc process this.
  6331.         return((MRESULT)0);
  6332.  
  6333.      case WM_PRESPARAMCHANGED:
  6334.           {
  6335.           MRESULT rc;
  6336.              UCMenuPresParamChanged( UCMData, hwnd, mp1 );
  6337.              rc = UCMData->OldSubMenuProc(hwnd, msg, mp1, mp2);
  6338.              /* Need to dismiss submenu or font changes have odd effects */
  6339.              WinSendMsg(hwnd, MM_ENDMENUMODE, MPFROMSHORT(TRUE), MPVOID);
  6340.              return rc;
  6341.           }
  6342.  
  6343.      case WM_ADJUSTWINDOWPOS:
  6344.        { PSWP pswp;
  6345.          ULONG Style       = WinQueryWindowULong(UCMData->hwndUCM, QWL_STYLE);
  6346.  
  6347.          pswp = (PSWP)mp1;
  6348.  
  6349.          if ( UCMData && ( pswp->fl & SWP_MOVE ) && !WinIsWindowShowing( hwnd ) ) {
  6350.            RECTL rect;
  6351.            WinSendMsg(UCMData->hwndMenu,
  6352.                       MM_QUERYITEMRECT,
  6353.                       MPFROM2SHORT(UCMData->usItem,TRUE),
  6354.                       MPFROMP(&rect));
  6355.            switch (Style & 0x07) {
  6356.              case CMS_VERT:
  6357.                pswp->y += (rect.yTop   - rect.yBottom);
  6358.                pswp->x += (rect.xRight - rect.xLeft);
  6359.                break;
  6360.              case CMS_MATRIX:
  6361.                pswp->x += (rect.xRight - rect.xLeft);
  6362.                break;
  6363.            } // endswitch
  6364.          } // endif
  6365.  
  6366.          return (MRESULT)(UCMData->OldSubMenuProc(hwnd, msg, mp1, mp2));
  6367.        }
  6368.  
  6369.      default:
  6370.        {
  6371.           return (UCMenuDrgDrpMsg(UCMData, hwnd, msg, mp1, mp2, UCMData->OldSubMenuProc));
  6372.        }
  6373.    } // endswitch
  6374.    return 0;
  6375. }
  6376.  
  6377. //----------------------------------------------------------------------------
  6378. void _Optlink UCMenuCreateBubbleWindow(HWND UCMenuHwnd, UCMDATA *UCMData)
  6379. //----------------------------------------------------------------------------
  6380. // Create the bubble-help window.
  6381. //----------------------------------------------------------------------------
  6382. {
  6383.   /* Register class with room for 1 pointer */
  6384.   WinRegisterClass( (HAB)NULLHANDLE, BUBBLECLASS, (PFNWP)BubbleWndProc, 0L, (ULONG)sizeof(PVOID) );
  6385.  
  6386.   /* Create the bubble window  */
  6387.   // CS_SAVEBITS makes the bubble disappear faster, but can cause incorrect
  6388.   // painting of windows under it if they change while the bubble is up (esp menus)
  6389.   UCMData->hwndBubble = WinCreateWindow(HWND_DESKTOP,
  6390.                                         BUBBLECLASS,    // Bubble class window
  6391.                                         "",
  6392.                                   //    WS_SAVEBITS,    // Window style
  6393.                                         0L,             // Window style
  6394.                                         0,0,0,0,        // Size set by window proc as needed
  6395.                                         UCMenuHwnd,     // Owner
  6396.                                         HWND_TOP,
  6397.                                         0,              // ID is not used
  6398.                                         UCMData,        // Pass ptr to global data
  6399.                                         NULL);          // No pres params
  6400.  
  6401.    if (UCMData->pszFontNameSize[0] != '\0')
  6402.      WinSetPresParam( UCMData->hwndBubble, PP_FONTNAMESIZE,  // Make it same font as menu
  6403.                       strlen(UCMData->pszFontNameSize) + 1,
  6404.                       UCMData->pszFontNameSize);
  6405.  
  6406.  
  6407. //----------------------------------------------------------------------------
  6408. MRESULT EXPENTRY BubbleWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  6409. //----------------------------------------------------------------------------
  6410. // Bubble-help window procedure.
  6411. //----------------------------------------------------------------------------
  6412. {
  6413. #define BUBBLE_MARGIN_TOP        3
  6414. #define BUBBLE_MARGIN_BOT        3
  6415. #define BUBBLE_MARGIN_LEFT       3
  6416. #define BUBBLE_MARGIN_RIGHT      3
  6417. typedef struct { /*--- Bubble help window instance data ---*/
  6418.    UCMDATA      *UCMData            ;             // Ptr to UCMenu instance data
  6419.    char         *Text               ;             // Current bubble text
  6420.    USHORT       CurrID              ;             // Menu ID of current item
  6421.    HWND         CurrMenu            ;             // Handle of menu or submenu
  6422.    BOOL         Disabled            ;             // Bubble is currently disabled
  6423.    BOOL         Active              ;             // Bubble window is currently active
  6424.    POINTL       OffMenuPos          ;             // Point at which pointer left the toolbar
  6425.    BOOL         OffMenuActive       ;             // Was bubble active when pointer left?
  6426.    POINTL       StemPoint           ;             // X,Y coordinate of tip of stem (desktop)
  6427.    ULONG        TextHeight,TextWidth;             // Dimensions of text including margin
  6428.    ULONG        StemHeight,StemWidth;             // Dimensions of stem (not rectangular)
  6429.    LONG         XPos, YPos          ;             // X,Y pos of bbl window (desktop)
  6430.    BOOL         OnTop               ;             // Bubble is above menu item
  6431.    ULONG        DismissTimer        ;             // Handle of autodismiss timer
  6432. } BBLDATA, *PBBLDATA;
  6433.  
  6434. // "Active" means delay has been satisified already and bubble should
  6435. // update as pointer moves from item to item.  It does NOT mean the bubble
  6436. // is visible on the screen (e.g. if pointer is over a SPACER item, the
  6437. // bubble is still active, but not displayed since there is no help text).
  6438. //
  6439. // "Disabled" means the bubble window is not to be displayed (because some
  6440. // other interaction is in progress on the toolbar, such as a context menu).
  6441. // When bubble is disabled it is by definition also in-Active.  When re-enabled
  6442. // it will become active again after the normal delay period.
  6443.  
  6444. BBLDATA *BblData;   /* Ptr to bubble-instance data.  Not valid until after WM_CREATE */
  6445.  
  6446.   BblData = (BBLDATA *)WinQueryWindowPtr(hwnd, 0L);
  6447.  
  6448.   switch (msg) {
  6449.     case WM_CREATE:
  6450.       /* Create and initialize bubble-help instance data */
  6451.       BblData = MyMalloc(sizeof(BBLDATA));
  6452.       memset(BblData, 0x00, sizeof(BBLDATA));
  6453.  
  6454.       BblData->UCMData = (UCMDATA *)mp1;  /* MP1 is ptr to UCM instance data */
  6455.       WinSetWindowPtr(hwnd, 0L, BblData);
  6456.       return 0;
  6457.  
  6458.     case WM_DESTROY:
  6459.       WinStopTimer((HAB)NULLHANDLE, hwnd, TIMER_BUBBLE); // Cancel any pending update
  6460.       /* Free storage we have before quiting */
  6461.       if (BblData->Text != NULL)
  6462.         MyFree(BblData->Text);
  6463.       MyFree(BblData);
  6464.       break;
  6465.  
  6466.     case MSG_DISABLE_BUBBLE:
  6467.       /* Disable bubble until MSG_ENABLE_BUBBLE occures. */
  6468.       BblData->Disabled = TRUE;
  6469.       BblData->Active = FALSE;
  6470.       WinStopTimer((HAB)NULLHANDLE, hwnd, TIMER_BUBBLE); // Cancel any pending update
  6471.       WinSetWindowPos(hwnd, HWND_TOP, 0,0,0,0, SWP_HIDE);
  6472.       return 0;
  6473.  
  6474.     case MSG_ENABLE_BUBBLE: {
  6475.       USHORT TempID;
  6476.  
  6477.       BblData->Disabled = FALSE;
  6478.       /* Send fake itemchange message to start delay period */
  6479.       TempID = BblData->CurrID;
  6480.       BblData->CurrID = 0;  // Force update
  6481.       WinSendMsg(hwnd, MSG_ITEMCHANGE, MPFROM2SHORT(TempID,FALSE), MPFROMHWND(BblData->CurrMenu));
  6482.       return 0;
  6483.       }
  6484.  
  6485.     case MSG_ITEMCHANGE: {
  6486.       /* mp1 = (SHORT) new item ID               */
  6487.       /*       (BOOL) deactivate if ID=0 (T/F)   */
  6488.       /* mp2 = (HWND) menu window                */
  6489.       POINTL PtrPos;
  6490.       HWND   NewHwnd;
  6491.  
  6492.       /* Pointer has moved on a menu item.  If item is different */
  6493.       /* than last time, schedule bubble window update.          */
  6494.  
  6495.       if (SHORT1FROMMP(mp1) == BblData->CurrID)
  6496.         return 0;  // Do nothing if no change
  6497.  
  6498.       BblData->CurrID = SHORT1FROMMP(mp1);
  6499.       BblData->CurrMenu = HWNDFROMMP(mp2);
  6500.  
  6501.       /* If item ID is zero, pointer moved off toolbar.  If     */
  6502.       /* caller says to deactivate, hide bubble and delay before*/
  6503.       /* showing again.  Otherwise keep current active status.  */
  6504.  
  6505.       if (BblData->CurrID == 0) {
  6506.         WinSetWindowPos(hwnd, HWND_TOP, 0,0,0,0, SWP_HIDE);
  6507.         WinStopTimer((HAB)NULLHANDLE, hwnd, TIMER_BUBBLE); // Cancel any pending update
  6508.         if ((BOOL)SHORT2FROMMP(mp1))  // Caller says deactivate
  6509.           BblData->Active = FALSE;
  6510.         return 0;
  6511.       }
  6512.  
  6513.       /* If we are disabled, no need to schedule update */
  6514.       if (BblData->Disabled)
  6515.         return 0;
  6516.  
  6517.       /* If bubble is already active,  update immediately w/new data */
  6518.       /* otherwise delay before showing it.  If delay time is set to */
  6519.       /* less than minimum,  fake an immediate timer event (e.g. no  */
  6520.       /* delay at all).                                              */
  6521.  
  6522.       if (BblData->Active)
  6523.         WinSendMsg(hwnd, MSG_UPDATE_BUBBLE, 0L, 0L);
  6524.       else {
  6525.         if (BblData->UCMData->BubbleDelay < MIN_BUBBLE_DELAY)
  6526.           WinSendMsg(hwnd, WM_TIMER, MPFROMSHORT(TIMER_BUBBLE_FAKE), 0L);
  6527.         else
  6528.           WinStartTimer((HAB)NULLHANDLE, hwnd, TIMER_BUBBLE, BblData->UCMData->BubbleDelay);
  6529.       }
  6530.  
  6531.       return 0;
  6532.       }
  6533.  
  6534.     case WM_TIMER:
  6535.       switch (SHORT1FROMMP(mp1)) {
  6536.         case TIMER_BUBBLE: {
  6537.           POINTL PtrPos;
  6538.           /* Real PM timer event occured.  Stop timer. */
  6539.           WinStopTimer((HAB)NULLHANDLE, hwnd, TIMER_BUBBLE);
  6540.           /* If pointer has moved off window (but window proc has not noticed yet) */
  6541.           /* then do not activate the bubble.                                      */
  6542.           WinQueryPointerPos(HWND_DESKTOP, &PtrPos);
  6543.           if (WinWindowFromPoint(HWND_DESKTOP, &PtrPos, TRUE) != BblData->CurrMenu)
  6544.             return 0;
  6545.           /* else fall through next case... */
  6546.           }
  6547.         case TIMER_BUBBLE_FAKE:
  6548.           /* Display bubble help now */
  6549.           BblData->Active = TRUE;  // Bubble is now active
  6550.           WinSendMsg(hwnd, MSG_UPDATE_BUBBLE, 0L, 0L);
  6551.           return 0;
  6552.         case TIMER_BBLAUTODISMISS:
  6553.           /* Time to remove the bubble help */
  6554.           WinSendMsg(hwnd, MSG_ITEMCHANGE, MPFROM2SHORT(0, TRUE), MPFROMHWND(BblData->CurrMenu));
  6555.           WinStopTimer((HAB)0, hwnd, BblData->DismissTimer);
  6556.           return 0;
  6557.       }
  6558.       break;
  6559.  
  6560.  
  6561.     case MSG_UPDATE_BUBBLE: {
  6562.       /* Update the bubble window with current data.  If window */
  6563.       /* is not disabled, show it.                              */
  6564.       HPS Hps;
  6565.       RECTL   TextBox;
  6566.       RECTL   itemRect;
  6567.       POINTL  BubblePt;
  6568.       QBUBBLEDATA QueryData;
  6569.       MENUITEM Item;
  6570.  
  6571.       if (BblData->CurrID == 0) { // should not happen
  6572.         return 0;
  6573.       }
  6574.  
  6575.       /* Calculate window size needed */
  6576.  
  6577.       if (BblData->Text != NULL) // free any previous data
  6578.         MyFree(BblData->Text);
  6579.  
  6580.       QueryData.BubbleText = NULL;   // Setup for call to application
  6581.       QueryData.MenuItem   = &Item;
  6582.       if ((BOOL)WinSendMsg(BblData->CurrMenu, MM_QUERYITEM, MPFROM2SHORT(BblData->CurrID,TRUE), MPFROMP(&Item))) {
  6583.         WinSendMsg(BblData->UCMData->hwndOwner,
  6584.                    WM_CONTROL,
  6585.                    MPFROM2SHORT(BblData->UCMData->UCMenuID, UCN_QRYBUBBLEHELP),
  6586.                    MPFROMP(&QueryData));
  6587.       }
  6588.  
  6589.       /* If app gave us a string to use, make a copy and then free application's string */
  6590.       if (QueryData.BubbleText != NULL) {
  6591.         BblData->Text = MyStrdup(QueryData.BubbleText);
  6592.         MyFree(QueryData.BubbleText);
  6593.       }
  6594.       else
  6595.         BblData->Text = NULL;
  6596.  
  6597.       /* If there is no text, just hide the bubble window (it will still be 'active') */
  6598.       if ((BblData->Text == NULL) || (BblData->Text[0] == '\0')) {
  6599.         WinSetWindowPos(hwnd, HWND_TOP, 0,0,0,0, SWP_HIDE);
  6600.         return 0;
  6601.       }
  6602.  
  6603.       /* Calculate window size needed to contain text */
  6604.  
  6605.       Hps = WinGetPS(hwnd);    //@P4m
  6606.       TextBox.xLeft = 0;
  6607.       TextBox.yBottom = 0;
  6608.       TextBox.xRight = MAX_INT;
  6609.       TextBox.yTop = MAX_INT;
  6610.       WinDrawText(Hps, -1, BblData->Text, &TextBox, 0L, 0L, DT_QUERYEXTENT|DT_LEFT|DT_VCENTER);
  6611.       WinReleasePS(Hps);       //@P4a
  6612.  
  6613.       BblData->TextWidth = BUBBLE_MARGIN_LEFT+BUBBLE_MARGIN_RIGHT+(TextBox.xRight - TextBox.xLeft);
  6614.       BblData->TextHeight= BUBBLE_MARGIN_TOP +BUBBLE_MARGIN_BOT  +(TextBox.yTop - TextBox.yBottom);
  6615.       BblData->StemHeight= BblData->TextHeight;
  6616.       BblData->StemWidth = BblData->StemHeight/2;
  6617.       BblData->OnTop     = TRUE;
  6618.  
  6619.       /* Minimum bubble width is wide enough for two rounded corners, a stem base     */
  6620.       /* and some extra.                                                              */
  6621.       BblData->TextWidth = max(BblData->TextWidth, BblData->TextHeight + BblData->TextHeight/2);
  6622.  
  6623.       /* Get position of the item in the menu window */
  6624.       if (!(BOOL)WinSendMsg(BblData->CurrMenu, MM_QUERYITEMRECT, MPFROM2SHORT(BblData->CurrID, TRUE), MPFROMP(&itemRect))) {
  6625.       }
  6626.  
  6627.       /* Map to desktop coordinates.  */
  6628.  
  6629.       BblData->StemPoint.x = itemRect.xLeft + ((itemRect.xRight-itemRect.xLeft)/2);
  6630.       BblData->StemPoint.y = itemRect.yTop;
  6631.       WinMapWindowPoints(BblData->CurrMenu, HWND_DESKTOP, &(BblData->StemPoint), 1L);
  6632.  
  6633.       /* If bubble is over top of screen, flip to underside of menu item */
  6634.       if (BblData->StemPoint.y + BblData->TextHeight + BblData->StemHeight > WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN)) {
  6635.         BblData->OnTop = FALSE;   // Put bubble under the menu item
  6636.         BblData->StemPoint.y = BblData->StemPoint.y - (itemRect.yTop-itemRect.yBottom);
  6637.       }
  6638.  
  6639.       /* If tip of stem is off the screen (x-dimension), bring it back */
  6640.       BblData->StemPoint.x = min(max(0L, (LONG)BblData->StemPoint.x), WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN));
  6641.  
  6642.       /* Try to position bubble window 1/4 MaxHeight to the left  of the stem tip. */
  6643.       /* This gives a nice look to the stem and bubble.                            */
  6644.  
  6645.       BblData->XPos = min(max(0L,(LONG)(BblData->StemPoint.x-(LONG)(BblData->TextHeight/4))), WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN)-BblData->TextWidth);
  6646.       if (BblData->OnTop)
  6647.         BblData->YPos = BblData->StemPoint.y;
  6648.       else
  6649.         BblData->YPos = BblData->StemPoint.y - BblData->TextHeight - BblData->StemHeight;
  6650.  
  6651.       /* Size/position the bubble window.  Hide it so background will be */
  6652.       /* restored (since we don't repaint our entire window area).       */
  6653.       WinSetWindowPos(hwnd, HWND_TOP, BblData->XPos,
  6654.                                       BblData->YPos,
  6655.                                       BblData->TextWidth,
  6656.                                       BblData->TextHeight+BblData->StemHeight,
  6657.                                       SWP_MOVE|SWP_SIZE|SWP_HIDE);
  6658.  
  6659.       /* Map stem point to bubble window coordinates after move/size */
  6660.       WinMapWindowPoints(HWND_DESKTOP, hwnd, &(BblData->StemPoint), 1L);
  6661.  
  6662.       /* If we are not disabled, show window and force repaint */
  6663.       if (!BblData->Disabled) {
  6664.         // We must wait for all WM_PAINT msgs to be processed by other windows run off our
  6665.         // message queue, or they may not be updated before our semi-transparent window
  6666.         // is displayed, resulting in those windows not appearing to have been updated.
  6667.         {QMSG QMsg;
  6668.         while(WinPeekMsg((HAB)0, &QMsg, NULLHANDLE, WM_PAINT, WM_PAINT, PM_REMOVE))
  6669.           WinDispatchMsg((HAB)0, &QMsg);
  6670.         }
  6671.         WinSetWindowPos(hwnd, HWND_TOP, 0,0,0,0, SWP_SHOW|SWP_ZORDER);
  6672.         WinInvalidateRect(hwnd, NULL, FALSE);
  6673.         /* Start timer to autodismiss the bubble, min timeout is 1 second */
  6674.         BblData->DismissTimer = WinStartTimer((HAB)0, hwnd, TIMER_BBLAUTODISMISS, max(1000L,BblData->UCMData->BubbleRead));
  6675.       }
  6676.       return 0;
  6677.       }
  6678.  
  6679.     case WM_PAINT:
  6680.       {
  6681.       HPS    Hps;                       /* Presentation Space handle    */
  6682.       RECTL  Rect;                      /* Rectangle coordinates        */
  6683.       POINTL Pt;                        /* String screen coordinates    */
  6684.       POINTL StemPts[3];                /* Points in stem polygon       */
  6685.       POLYGON PolyInfo;                 /* Polygon information          */
  6686.       SWP    SizePos;                   /* Size/pos of the window       */
  6687.       ULONG  Rounding;                  /* Corner rounding factor       */
  6688.       LONG   SlantOffset;               /* Offset of tip for slant angle*/
  6689.       LONG   SlantDir;                  /* +/-1 slant direction         */
  6690.  
  6691.       Hps = WinBeginPaint(hwnd, 0L, &Rect);  /* Get PS to draw */
  6692.       WinQueryWindowPos(hwnd, &SizePos);     /* Get window size*/
  6693.  
  6694.       /* Draw bubble rectangle with rounded corners */
  6695.  
  6696.       Pt.x = 0;                      // Lower left corner
  6697.       if (BblData->OnTop)
  6698.         Pt.y = BblData->StemHeight;
  6699.       else
  6700.         Pt.y = 0;
  6701.       GpiMove(Hps, &Pt);
  6702.       Pt.x = BblData->TextWidth-1;   // Upper right corner
  6703.       Pt.y = Pt.y + BblData->TextHeight-1;
  6704.  
  6705.       Rounding = BblData->TextHeight/2;
  6706.       GpiSetColor(Hps, CLR_YELLOW);
  6707.       GpiBox(Hps, DRO_FILL,    &Pt, Rounding, Rounding); // Draw filled rect
  6708.       GpiSetColor(Hps, CLR_BLACK);
  6709.       GpiBox(Hps, DRO_OUTLINE, &Pt, Rounding, Rounding); // Draw outline
  6710.  
  6711.       /* Change slant angle if tip is on right side of bubble */
  6712.       SlantOffset = BblData->TextHeight / 2;
  6713.       SlantDir    = 1;
  6714.       if (BblData->StemPoint.x > BblData->TextWidth/2)
  6715.         SlantDir = -1;
  6716.  
  6717.       /* Calculate X position of stem verticies */
  6718.       /* [0] = left base corner                 */
  6719.       /* [1] = tip                              */
  6720.       /* [2] = right base corner                */
  6721.       
  6722.       StemPts[1].x = BblData->StemPoint.x;        // Tip is fixed position
  6723.       StemPts[0].x = StemPts[1].x + (SlantOffset * SlantDir);
  6724.       StemPts[2].x = StemPts[0].x + (BblData->StemWidth * SlantDir);
  6725.  
  6726.       /* Set Y position of stem verticies */
  6727.       StemPts[1].y = BblData->StemPoint.y;        // Tip position is fixed
  6728.       if (BblData->OnTop)                         // Base above or below tip
  6729.         StemPts[0].y = BblData->StemHeight;
  6730.       else
  6731.         StemPts[0].y = BblData->TextHeight-1;
  6732.       StemPts[2].y = StemPts[0].y;
  6733.  
  6734.       /* Draw polygon starting at first stem point */
  6735.       GpiMove(Hps, &(StemPts[0]));
  6736.       PolyInfo.aPointl = StemPts;    // Describe polygon
  6737.       PolyInfo.ulPoints = 3;
  6738.       GpiSetColor(Hps, CLR_YELLOW);
  6739.       GpiPolygons(Hps, 1L, &PolyInfo, 0L, 0L);  // Draw filled stem
  6740.       GpiSetColor(Hps, CLR_BLACK);
  6741.       GpiMove(Hps, &(StemPts[0]));              // Draw outline
  6742.       GpiLine(Hps, &(StemPts[1]));
  6743.       GpiLine(Hps, &(StemPts[2]));
  6744.  
  6745.       /* Draw the text offset by bottom and left margins and stem size */
  6746.  
  6747.       Rect.xLeft = BUBBLE_MARGIN_LEFT;
  6748.       Rect.xRight = BblData->TextWidth;
  6749.       if (BblData->OnTop)
  6750.         Rect.yBottom = BUBBLE_MARGIN_BOT+BblData->StemHeight;
  6751.       else
  6752.         Rect.yBottom = BUBBLE_MARGIN_BOT;
  6753.       Rect.yTop = Rect.yBottom + BblData->TextHeight;
  6754.       WinDrawText(Hps, -1, BblData->Text, &Rect, 0L, 0L, DT_LEFT|DT_BOTTOM|DT_TEXTATTRS);
  6755.  
  6756.       WinEndPaint(Hps);  
  6757.       return 0;
  6758.       }
  6759.   }
  6760.  
  6761.   return WinDefWindowProc(hwnd, msg, mp1, mp2);
  6762. }
  6763.  
  6764. //----------------------------------------------------------------------------
  6765. void UCMenuReloadAllBitmaps(HWND hwndMenu, UCMDATA *UCMData)
  6766. //----------------------------------------------------------------------------
  6767. // Reload all the menu bitmaps calling ourself recursively for submenus.
  6768. //----------------------------------------------------------------------------
  6769. {
  6770.   MENUITEM      Mi;          // PM menu item data
  6771.   UCMITEM       *UCMItem;    // UCMenus item data
  6772.   USHORT        NbOfItems;   // # of items in this menu
  6773.   USHORT        i, itemID;
  6774.  
  6775.   NbOfItems = SHORT1FROMMR(WinSendMsg(hwndMenu, MM_QUERYITEMCOUNT, NULL, NULL));
  6776.  
  6777.   for (i=0 ; i<NbOfItems ; i++ ) {
  6778.     itemID = (USHORT)WinSendMsg(hwndMenu,
  6779.                                 MM_ITEMIDFROMPOSITION,
  6780.                                 MPFROMSHORT(i),
  6781.                                 NULL);
  6782.     WinSendMsg(hwndMenu,
  6783.                MM_QUERYITEM,
  6784.                MPFROM2SHORT(itemID, FALSE),
  6785.                MPFROMP(&Mi));
  6786.  
  6787.     /* If there is valid UCMenu item data, delete current bitmap */
  6788.     /* and reload it.                                            */
  6789.  
  6790.     UCMItem = (UCMITEM *)Mi.hItem;
  6791.     if (UCMItem != NULL) {
  6792.       if (UCMItem->hBmp != NULLHANDLE) {
  6793.         GpiDeleteBitmap(UCMItem->hBmp);
  6794.         UCMItem->hBmp = NULLHANDLE;
  6795.       }
  6796.       UCMenuLoadItemBmp(&Mi, UCMData);
  6797.     }
  6798.  
  6799.     /* If this is a submenu item, call again for submenu */
  6800.  
  6801.     if (Mi.afStyle & MIS_SUBMENU) 
  6802.       UCMenuReloadAllBitmaps(Mi.hwndSubMenu, UCMData);
  6803.  
  6804.   } // for each item in menu
  6805. }
  6806.  
  6807.  
  6808. //----------------------------------------------------------------------------
  6809. // MenuWndProc
  6810. //----------------------------------------------------------------------------
  6811. // :pfunction res=&IDF_MENUWNDPROC. name='MenuWndProc' text='Menu window procedure'.
  6812. // Window procedure of the menus
  6813. // :syntax name='MenuWndProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  6814. // :fparams.
  6815. // :fparam name='hwnd' type='HWND' io='input' .
  6816. // Menu window handle
  6817. // :fparam name='msg' type='ULONG' io='input' .
  6818. // Message
  6819. // :fparam name='mp1' type='MPARAM' io='input'.
  6820. // First parameter
  6821. // :fparam name='mp2' type='MPARAM' io='input'.
  6822. // Second parameter
  6823. // :freturns.
  6824. // :fparam name='mresult' type='MRESULT' io='return'.
  6825. // Return code of a PM message.
  6826. // :efparams.
  6827. // :remarks.
  6828. // :epfunction.
  6829. //----------------------------------------------------------------------------
  6830. MRESULT EXPENTRY MenuWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  6831. {
  6832. PUCMDATA  UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  6833.  
  6834.    switch (msg) {
  6835.      #if defined(MSG_DEBUGMESSAGE)
  6836.      case MSG_DEBUGMESSAGE:
  6837.        WinMessageBox(HWND_DESKTOP,hwnd,(char *)mp2,(char *)mp1,0,MB_OK|MB_INFORMATION);
  6838.        return 0;
  6839.      #endif
  6840.  
  6841.     case WM_MOUSEMOVE: {
  6842.           USHORT   usId;      /* ID of menu item under mouse */
  6843.           POINTL   ptl;       /* Mouse position in the window */
  6844.  
  6845.           /* If our app is not the active window, just pass it on */
  6846.           if (!(UCMData->Active))
  6847.             return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 );
  6848.  
  6849.           /* See what item the mouse is over */
  6850.           ptl.x = (ULONG) SHORT1FROMMP( mp1 );
  6851.           ptl.y = (ULONG) SHORT2FROMMP( mp1 );
  6852.           usId  = UCMenuIdFromCoord(hwnd, &ptl );
  6853.  
  6854.           /* If mouse has moved to a different item, send notifications */
  6855.  
  6856.           if (usId != UCMData->HoverID) {            
  6857.             if (UCMData->Style & UCS_PROMPTING)     // Tell owner if they want to know
  6858.               WinSendMsg( UCMData->hwndOwner, WM_CONTROL,
  6859.                           MPFROM2SHORT( UCMData->UCMenuID, UCN_MOUSEMOVE ),
  6860.                           MPFROMSHORT( usId ) );
  6861.  
  6862.             if (UCMData->Style & UCS_BUBBLEHELP)    // Tell bubble if it needs to know
  6863.               WinSendMsg(UCMData->hwndBubble,           
  6864.                           MSG_ITEMCHANGE, MPFROM2SHORT(usId, FALSE), MPFROMHWND(hwnd));
  6865.           }
  6866.           UCMData->HoverID = usId;                  // Save for next time
  6867.  
  6868.           /* Start/reset timer to check that pointer is still in this window */
  6869.           if ((UCMData->Style & UCS_PROMPTING) || (UCMData->Style & UCS_BUBBLEHELP))
  6870.             UCMData->MenuPtrTimer = WinStartTimer((HAB)0, hwnd, TIMER_PTRCHECK, PTR_CHECK_DELAY);
  6871.  
  6872.           return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); // Pass this on
  6873.           }
  6874.  
  6875.     case WM_BUTTON2DOWN:
  6876.     case WM_BUTTON1DOWN:
  6877.           /* On any button down, disable the bubble help window.  It  */
  6878.           /* will be re-enabled when the button is released (or       */
  6879.           /* drag/drop done, in that case).                           */
  6880.   
  6881.           if (UCMData->Style & UCS_BUBBLEHELP)
  6882.             WinSendMsg(UCMData->hwndBubble, MSG_DISABLE_BUBBLE, 0L, 0L);
  6883.  
  6884.           /* Don't pass button 2 to real menu proc since it will attempt to */
  6885.           /* select the item.  We also have to return FALSE or drag/drop    */
  6886.           /* will not work (no WM_BEGINDRAG will occure).  So for button 2  */
  6887.           /* we must do what the default window proc normally does (e.g.    */
  6888.           /* activate the frame window).                                    */
  6889.           if (msg == WM_BUTTON2DOWN) {
  6890.             WinSetActiveWindow(HWND_DESKTOP, hwnd);  // Will activate my frame
  6891.             return FALSE;                            // Tell PM we did not process it
  6892.           }
  6893.  
  6894.           /* For button 1, let normal menu proc handle as usual */
  6895.  
  6896.           return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); // Pass this on
  6897.  
  6898.     case WM_BUTTON2UP:
  6899.     case WM_BUTTON1UP: {
  6900.           MRESULT rc;
  6901.   
  6902.           /* First let normal window proc process the UP message */
  6903.           /* It will POST a WM_COMMAND to our UCMenu window if   */
  6904.           /* the mouse is still on the menu item.                */
  6905.           rc = UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); 
  6906.   
  6907.           /* Simulate a mouse-move so that we will restart the   */
  6908.           /* bubble-help window.                                 */
  6909.   
  6910.           if (UCMData->Style & UCS_BUBBLEHELP)
  6911.             WinSendMsg(UCMData->hwndBubble, MSG_ENABLE_BUBBLE, 0L, 0L);
  6912.   
  6913.           /* NOTE: This message must be POSTED so it arrives         */
  6914.           /* after WM_COMMAND has been received and UCN_ITEMSELECTED */
  6915.           /* processed by the application.                           */
  6916.           //...need to see if ptr is still in the window before doing
  6917.           //...this since MOUSEMOVE code assumes ptr is in the window.
  6918.   
  6919.           WinPostMsg(hwnd, WM_MOUSEMOVE, mp1, mp2);
  6920.           return rc;
  6921.           }
  6922.  
  6923.     case WM_TIMER: {
  6924.           POINTL Point;
  6925.  
  6926.        // if (SHORT1FROMMP(mp1) == TIMER_SYSCLRCHANGE) {
  6927.        //       UCMenuReloadAllBitmaps(WinQueryWindow( hwnd, QW_OWNER ), UCMData);
  6928.        //       UCMenuUpdateMenu( hwnd, FALSE );
  6929.        //       WinStopTimer((HAB)0, hwnd, TIMER_SYSCLRCHANGE);
  6930.        //       return 0;
  6931.        //  }
  6932.        //  else if (SHORT1FROMMP(mp1) != TIMER_PTRCHECK) // Pass on other timer events
  6933.            if (SHORT1FROMMP(mp1) != TIMER_PTRCHECK) // Pass on other timer events
  6934.              break;
  6935.  
  6936.           /* See if the pointer is still in the window.  If not, */
  6937.           /* notify the owner and bubble help windows.  Also, if */
  6938.           /* application became inactive.                        */
  6939.           WinQueryPointerPos(HWND_DESKTOP, &Point);
  6940.  
  6941.           if ((WinWindowFromPoint(HWND_DESKTOP, &Point, TRUE) != hwnd) ||
  6942.              (!UCMData->Active)) {
  6943.             BOOL Disable;
  6944.  
  6945.             if (UCMData->Style & UCS_PROMPTING)     // Tell owner if they want to know
  6946.               WinSendMsg( UCMData->hwndOwner, WM_CONTROL,
  6947.                           MPFROM2SHORT(UCMData->UCMenuID, UCN_MOUSEMOVE ),
  6948.                           MPFROMSHORT( 0 ) );
  6949.   
  6950.             //...should disable bubble only if new window is not part of the
  6951.             //...UCMenu control (e.g. not the menu, submenu, or hide window).
  6952.             Disable = TRUE;
  6953.             if (UCMData->Style & UCS_BUBBLEHELP)    // Tell bubble to disable itself
  6954.               WinSendMsg(UCMData->hwndBubble,           
  6955.                           MSG_ITEMCHANGE, MPFROM2SHORT(0, Disable), MPFROMHWND(hwnd));
  6956.             UCMData->HoverID = 0;                   // Save for next time
  6957.  
  6958.             WinStopTimer((HAB)0, hwnd, UCMData->MenuPtrTimer);
  6959.           }
  6960.           return 0;
  6961.           }
  6962.  
  6963. //  case WM_BUTTON2DOWN:
  6964. //  case WM_BUTTON1DOWN: {
  6965. //        /* On any button down, release capture and disable the bubble  */
  6966. //        /* help window.  It will be re-enabled when the button is      */
  6967. //        /* released (or drag/drop done, in that case).                 */
  6968. //
  6969. //        if (UCMData->Style & UCS_BUBBLEHELP)
  6970. //          WinSendMsg(UCMData->hwndBubble, MSG_DISABLE_BUBBLE, 0L, 0L);
  6971. //
  6972. //        if (UCMData->HoverCapture) {
  6973. //          WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  6974. //          UCMData->HoverCapture = FALSE;
  6975. //        }
  6976. //        
  6977. //        if (msg == WM_BUTTON2DOWN)  // Drag/drop does not work if default proc gets this
  6978. //          break;                    // ??? should use WinQuerySysValue(...SV_BEGINDRAG...)
  6979. //        return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); // Pass this on
  6980. //        }
  6981. //
  6982. //  case WM_BUTTON2UP:
  6983. //  case WM_BUTTON1UP: {
  6984. //        MRESULT rc;
  6985. //
  6986. //        /* First let normal window proc process the UP message */
  6987. //        /* It will POST a WM_COMMAND to our UCMenu window if   */
  6988. //        /* the mouse is still on the menu item.                */
  6989. //        rc = UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); 
  6990. //
  6991. //        /* Simulate a mouse-move so that we will recapture the */
  6992. //        /* mouse if needed.  Set a flag for the WM_MOUSEMOVE   */
  6993. //        /* code to recognize this is a fake movement.          */
  6994. //
  6995. //        UCMData->HoverMsg = msg;
  6996. //        if (UCMData->Style & UCS_BUBBLEHELP)
  6997. //          WinSendMsg(UCMData->hwndBubble, MSG_ENABLE_BUBBLE, 0L, 0L);
  6998. //
  6999. //        /* NOTE: This message must be POSTED so it arrives         */
  7000. //        /* after WM_COMMAND has been received and UCN_ITEMSELECTED */
  7001. //        /* processed by the application.  Otherwise the app could  */
  7002. //        /* invoke a dialog in response to UCN_ITEMSELECTED and     */
  7003. //        /* cause us to lose mouse capture tracking.                */
  7004. //
  7005. //        WinPostMsg(hwnd, WM_MOUSEMOVE, mp1, mp2);
  7006. //        return rc;
  7007. //        }
  7008. //     
  7009. //  case WM_MOUSEMOVE:
  7010. //     {
  7011. //        USHORT   usId;      /* ID of menu item under mouse */
  7012. //        POINTL   ptl;       /* Mouse position in the window */
  7013. //        HWND hwndUCM   = WinQueryWindow( hwnd, QW_OWNER );
  7014. //        HWND hwndOwner = WinQueryWindow( hwndUCM, QW_OWNER );
  7015. //        HWND HwndAt;        /* Window at mouse position */
  7016. //        BOOL Inside    = TRUE;
  7017. //        BOOL ButtonDown= FALSE;
  7018. //
  7019. //        /* If our app is not the active window, just pass it on */
  7020. //        if (!(UCMData->Active))
  7021. //          return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 );
  7022. //
  7023. //        /* See if any mouse button is pressed (and this is not from a BUTTONUP msg above). */
  7024. //        if ((WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) && (UCMData->HoverMsg != WM_BUTTON1UP))
  7025. //          ButtonDown = TRUE;
  7026. //        if ((WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) && (UCMData->HoverMsg != WM_BUTTON2UP))
  7027. //          ButtonDown = TRUE;
  7028. //        UCMData->HoverMsg = WM_NULL;
  7029. //
  7030. //        ptl.x = (ULONG) SHORT1FROMMP( mp1 );
  7031. //        ptl.y = (ULONG) SHORT2FROMMP( mp1 );
  7032. //
  7033. //        /* Note we must test entire desktop window hierarchy for PM */
  7034. //        /* to tell us if the point is over a window which obscures  */
  7035. //        /* our own.  If we search only our own window hierarchy, we */
  7036. //        /* will detect movements whenever the pointer is inside our */
  7037. //        /* window rectangle, even if our window is covered by       */
  7038. //        /* some other application.  Searching the desktop hierarchy */
  7039. //        /* is bad for performance, but PM gives us no other way to  */
  7040. //        /* detect (for sure) when the mouse leaves our menu window. */
  7041. //
  7042. //        WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
  7043. //        HwndAt = WinWindowFromPoint(HWND_DESKTOP, &ptl, TRUE);
  7044. //        if (HwndAt != hwnd)
  7045. //          Inside = FALSE;
  7046. //
  7047. //        /* Restore point to my coordinate system */
  7048. //        ptl.x = (ULONG) SHORT1FROMMP( mp1 );
  7049. //        ptl.y = (ULONG) SHORT2FROMMP( mp1 );
  7050. //
  7051. //        /* If mouse is over another window (even if within the menu */
  7052. //        /* window rectangle), we don't use it.  Coord mapping       */
  7053. //        /* routine will be fooled by overlapping windows.           */
  7054. //
  7055. //        if (!Inside)
  7056. //          usId = 0;
  7057. //        else
  7058. //          usId  = UCMenuIdFromCoord(hwnd, &ptl ); // Where is it?
  7059. //
  7060. //        if (usId != UCMData->HoverID) {               // Tell owner of any change
  7061. //          if (UCMData->Style & UCS_PROMPTING)         // ...if they want to know.
  7062. //            WinSendMsg( hwndOwner, WM_CONTROL,
  7063. //                        MPFROM2SHORT( WinQueryWindowUShort( hwndUCM, QWS_ID ), UCN_MOUSEMOVE ),
  7064. //                        MPFROMSHORT( usId ) );
  7065. //          if (UCMData->Style & UCS_BUBBLEHELP) {      // ...if bubble needs to know
  7066. //            BOOL Deactivate = TRUE;                   // Bubble should be deactivated
  7067. //            if ((HwndAt == UCMData->hwndMenu) ||              // ... unless ptr
  7068. //       //       (HwndAt == UCMData->hwndBubble) ||
  7069. //       //       (HwndAt == WinQueryWindow(UCMData->hwndMenu, QW_PARENT)) ||  // hide window
  7070. //                (WinQueryWindow(HwndAt,QW_OWNER)==UCMData->hwndMenu))  // is over any TB menu
  7071. //                Deactivate = FALSE;
  7072. //            WinSendMsg(UCMData->hwndBubble,           
  7073. //                        MSG_ITEMCHANGE, MPFROM2SHORT(usId, Deactivate), MPFROMHWND(hwnd));
  7074. //          }
  7075. //        }
  7076. //        UCMData->HoverID = usId;                      // Save for next time
  7077. //
  7078. //        /* We (UCMenus) will capture the mouse if:               */
  7079. //        /*  - The mouse is inside the menu window                */
  7080. //        /*  - We don't already have it captured                  */
  7081. //        /*  - No buttons are pressed                             */
  7082. //
  7083. //        if ((Inside) && (!UCMData->HoverCapture) && (!ButtonDown)) {
  7084. //           WinSetCapture(HWND_DESKTOP, hwnd);
  7085. //           UCMData->HoverCapture = TRUE;
  7086. //        }
  7087. //
  7088. //        /* We release capture if:                                */
  7089. //        /*  - Mouse is outside the menu window                   */
  7090. //        /*  - No buttons down                                    */
  7091. //        /*  - We have capture set                                */
  7092. //
  7093. //        if ((!Inside) && (!ButtonDown) && (UCMData->HoverCapture)) {
  7094. //           WinSetCapture(HWND_DESKTOP, NULLHANDLE);    // Stop capture
  7095. //           UCMData->HoverCapture = FALSE;              // No longer captured
  7096. //           UCMData->HoverID = 0;
  7097. //        }
  7098. //
  7099. //        return UCMData->OldMenuProc( hwnd, msg, mp1, mp2 ); // Pass this on
  7100. //     }
  7101.  
  7102.     case MM_INSERTITEM:
  7103.     case MM_SETITEM:
  7104.        {
  7105.           PMENUITEM pMi = 0;
  7106.           USHORT    NewID;
  7107.  
  7108.           switch (msg) {
  7109.           case MM_INSERTITEM:
  7110.              pMi = (PMENUITEM)mp1;
  7111.              // Check if the id is already used
  7112.              NewID = UCMenuGetNewID( UCMData->hwndMenu, pMi->id, UCMData );
  7113.              if ( NewID != pMi->id) {
  7114.                 pMi->id = NewID;
  7115.                 if ( pMi->hItem ){
  7116.                    ITEM( pMi, usId ) = NewID;
  7117.                 } // endif
  7118.              } /* endif */
  7119.              break;
  7120.           case MM_SETITEM:
  7121.              pMi = (PMENUITEM)mp2;
  7122.             break;
  7123.           } // endswitch
  7124.  
  7125.           //(MAM) set MIA_NODISMISS attribute on all submenu placeholder items to
  7126.           // prevent dismiss of submenu during drag/drop and context menu operations.
  7127.           if (pMi->afStyle & MIS_SUBMENU)
  7128.             pMi->afAttribute = pMi->afAttribute | MIA_NODISMISS;
  7129.  
  7130.           //(MAM) remove MIS_BREAK from all items
  7131.           pMi->afStyle = pMi->afStyle & (USHORT) ~MIS_BREAK;
  7132.  
  7133.           if ( pMi && pMi->hItem ){
  7134.              // Set the id also in ucmitem
  7135.              // --
  7136.              ITEM( pMi, usId ) = pMi->id;
  7137.              // Load the bitmap
  7138.              // --
  7139.              UCMenuLoadItemBmp(pMi, UCMData );
  7140.           } // endif
  7141.  
  7142.           return UCMData->OldMenuProc(hwnd, msg, mp1, mp2);
  7143.        }
  7144.      case WM_TRANSLATEACCEL:
  7145.           {
  7146.              PQMSG       QMsg       = (PQMSG)mp1;
  7147.  
  7148.              if(QMsg->msg == WM_CHAR) {
  7149.                 USHORT flags = SHORT1FROMMP(QMsg->mp1);
  7150.                 USHORT VK = SHORT2FROMMP(QMsg->mp2);
  7151.  
  7152.                 if((flags & KC_SHIFT) && !(flags & KC_PREVDOWN) && (flags & KC_VIRTUALKEY) && !(flags & KC_LONEKEY)) {
  7153.                   if(VK == VK_F10) {
  7154.                      WinSendMsg(hwnd, WM_CONTEXTMENU, (MPARAM)0, 0L);
  7155.                      return((MRESULT)0);
  7156.                   }
  7157.                 }
  7158.                 if(!(flags & KC_PREVDOWN) && (flags & KC_VIRTUALKEY) && (VK==VK_F1)) {
  7159.                      RECTL Rectl;
  7160.                      POINTL ptl;
  7161.                      ULONG ContextID;
  7162.                      ULONG SelectedItem = (ULONG) WinSendMsg(hwnd, MM_QUERYSELITEMID, 0L, 0L);
  7163.  
  7164.                      WinSendMsg(hwnd, MM_QUERYITEMRECT, (MPARAM)SelectedItem, MPFROMP(&Rectl));
  7165.                      ptl.x = Rectl.xLeft   + (Rectl.xRight - Rectl.xLeft)/2;
  7166.                      ptl.y = Rectl.yBottom + (Rectl.yTop - Rectl.yBottom)/2;
  7167.                      ContextID = UCMenuIdFromCoord(hwnd, &ptl);
  7168.                      WinSendMsg( UCMData->hwndOwner,
  7169.                                  WM_HELP,
  7170.                                  MPFROM2SHORT( ContextID, UCMData->UCMenuID),
  7171.                                  MPFROM2SHORT( CMDSRC_UCMENU, 0 ) );
  7172.                      return((MRESULT)0);
  7173.                 }
  7174.  
  7175.                 if(!(flags & KC_PREVDOWN) && (flags & KC_CHAR)) {
  7176.                    return (MRESULT) TranslateAccel(UCMData, hwnd, SHORT1FROMMP(QMsg->mp2), QMsg);
  7177.                 }
  7178.  
  7179.                 return (UCMenuDrgDrpMsg(UCMData, hwnd, msg, mp1, mp2, UCMData->OldMenuProc));
  7180.              }
  7181.           } // endcase
  7182.           return(MRESULT)0;
  7183.     case WM_CONTEXTMENU:
  7184.        UCMenuContextMenu(UCMData->hwndUCM,
  7185.                          hwnd,
  7186.                          (ULONG)mp1);
  7187.        return (MRESULT) TRUE;
  7188.  
  7189.      case WM_BUTTON2DBLCLK:
  7190.        break;
  7191.  
  7192. //   case WM_BUTTON2DOWN:
  7193. //     // ----------------------------------------------------------------
  7194. //     // -- Keep that message here, else drag and drop won't work
  7195. //     // -- (this prevent the message from being processed by the default
  7196. //     // -- menu window procedure)
  7197. //     // ----------------------------------------------------------------
  7198. //     break;
  7199.  
  7200.      case WM_SYSCOLORCHANGE:
  7201.        // Don't let original menu window proc get this since we handle
  7202.        // color changes ourself.
  7203.        return((MRESULT)0);
  7204.  
  7205.      case WM_PRESPARAMCHANGED:
  7206.           {
  7207.              ULONG x;
  7208.  
  7209.              if ((LONG)mp1 == PP_MENUBACKGROUNDCOLOR) {
  7210.                 // We will also receive 2 messages for the menu bg hilite and menu bg disabled colors
  7211.                 // We don't need them so we don't process them
  7212.                 LONG lColor;
  7213.                 LONG lNearestColor;
  7214.                 HPS hps;
  7215.  
  7216.                 WinQueryPresParam( hwnd,
  7217.                                    (SHORT)mp1,
  7218.                                    0L, &x,
  7219.                                    (ULONG)sizeof lColor,
  7220.                                    &lColor,
  7221.                                    QPF_NOINHERIT );
  7222.                 if (x == (SHORT)mp1) {
  7223.                    hps = WinGetPS( hwnd );
  7224.                    lNearestColor = GpiQueryNearestColor( hps, (ULONG)0, (LONG)lColor );
  7225.                    WinReleasePS( hps );
  7226.  
  7227.                    if ( lColor == lNearestColor ) {
  7228.                       // -- Update the color
  7229.                       UCMData->ItemBgColor = lColor;
  7230.  
  7231.                       // -- When background color changes, must reload all bitmaps
  7232.                       // -- to get mapping from original bitmap colors (not current
  7233.                       // -- colors).
  7234.                       UCMenuReloadAllBitmaps(UCMData->hwndUCM, UCMData);
  7235.  
  7236.                       // -- Warn the owner
  7237.                       WinSendMsg( UCMData->hwndOwner,
  7238.                                   WM_CONTROL,
  7239.                                   MPFROM2SHORT( UCMData->UCMenuID, UCN_COLOR ),
  7240.                                   MPFROMSHORT( 0 ) );
  7241.  
  7242.                       // This will cause a WM_UPDATEFRAME to be sent to the owner (the ucmenu)
  7243.                       // If we were processing the 2 following PP_* in the same way, we would have
  7244.                       // the ucmenu repainted 3 times (pretty ugly isn't it? :-) )
  7245.                       UCMData->bProcessingPP = TRUE;
  7246.                       return UCMData->OldMenuProc( hwnd, msg, mp1, mp2);
  7247.                    } else {
  7248.                       // -----------------------------
  7249.                       // -- We want only solid colors
  7250.                       // -----------------------------
  7251.                       WinSetPresParam( hwnd,
  7252.                                        PP_MENUBACKGROUNDCOLOR,
  7253.                                        sizeof lNearestColor,
  7254.                                        &lNearestColor);
  7255.                       return (MRESULT)FALSE;
  7256.                    } // endif
  7257.                 } else {
  7258.                    WinRemovePresParam( hwnd, PP_MENUBACKGROUNDCOLOR );
  7259.                 } // endif
  7260.              } else if (LONGFROMMP(mp1) == PP_FONTNAMESIZE) {
  7261.                 char FontNameSize[MAX_FONTNAMELEN] ;
  7262.                 WinQueryPresParam( hwnd,
  7263.                                    PP_FONTNAMESIZE,
  7264.                                    0L, &x,
  7265.                                    (ULONG)MAX_FONTNAMELEN,
  7266.                                    FontNameSize,
  7267.                                    QPF_NOINHERIT );
  7268.                 if (x == PP_FONTNAMESIZE) {
  7269.                    // A font pres parameter was set... update our font info
  7270.                    if (UCMData->pszFontNameSize)
  7271.                       MyFree(UCMData->pszFontNameSize);
  7272.                    if ( UCMData->pszFontNameSize = MyMalloc(strlen(FontNameSize)+1) ) {
  7273.                       strcpy(UCMData->pszFontNameSize, FontNameSize );
  7274.                       WinSendMsg( UCMData->hwndOwner,
  7275.                                   WM_CONTROL,
  7276.                                   MPFROM2SHORT( UCMData->UCMenuID, UCN_FONT ),
  7277.                                   MPFROMSHORT( 0 ) );
  7278.                       /* Tell the bubble-help window about font changes */
  7279.                       if (UCMData->Style & UCS_BUBBLEHELP)
  7280.                         WinSetPresParam(UCMData->hwndBubble, PP_FONTNAMESIZE, strlen(FontNameSize)+1, FontNameSize);
  7281.                    }
  7282.                    UCMData->bProcessingPP = TRUE;
  7283.                    return UCMData->OldMenuProc( hwnd, msg, mp1, mp2);
  7284.                    // This will cause a WM_UPDATEFRAME to be sent to the owner (the ucmenu)
  7285.                 } else {
  7286.                    // The font pres parameter was removed.
  7287.                    WinRemovePresParam( hwnd, PP_FONTNAMESIZE );
  7288.                    /* Tell the bubble-help window about font changes */
  7289.                    if (UCMData->Style & UCS_BUBBLEHELP)
  7290.                      WinRemovePresParam( UCMData->hwndBubble, PP_FONTNAMESIZE );
  7291.                 } // if FONTNAMESIZE param was set
  7292.  
  7293.              } else {
  7294.                 break;
  7295.              } // endif
  7296.           }
  7297.           return UCMData->OldMenuProc( hwnd, msg, mp1, mp2);
  7298.  
  7299.      default:
  7300.        {
  7301.           return (UCMenuDrgDrpMsg(UCMData, hwnd, msg, mp1, mp2, UCMData->OldMenuProc));
  7302.        }
  7303.    } // endswitch
  7304.  
  7305.    return (MRESULT)0;
  7306. }
  7307.  
  7308. //----------------------------------------------------------------------------
  7309. // UCMenuLoadItemBmp
  7310. //----------------------------------------------------------------------------
  7311. // :pfunction res=&IDF_UCMLOADITEMBMP. name='UCMenuLoadItemBmp' text='Find and load the bitmap of a ucmenu item'.
  7312. // If a ucmenu item has no bitmap, find it and load it.
  7313. // :syntax name='UCMenuLoadItemBmp' params='pUCMitem, pUCMData' return='nothing' .
  7314. // :fparams.
  7315. // :fparam name='pUCMItem' type='PUCMITEM' io='input/output' .
  7316. // Pointer to a ucmenu item structure.
  7317. // :fparam name='pUCMData' type='PUCMDATA' io='input' .
  7318. // Pointer to the ucmenu data structure.
  7319. // :freturns.
  7320. // :fparam name='-' type='VOID' io='return'.
  7321. // Nothing.
  7322. // :efparams.
  7323. // :remarks.
  7324. // :epfunction.
  7325. //----------------------------------------------------------------------------
  7326. VOID _Optlink UCMenuLoadItemBmp( MENUITEM *Item, PUCMDATA UCMData )
  7327. {
  7328. UCMITEM *pUCMI = NULL;
  7329.  
  7330.    if (Item)
  7331.      pUCMI = (UCMITEM *)Item->hItem;  // Get ptr to UCMITEM from menu item struct
  7332.  
  7333.    /* Don't load bitmap if pointers are invalid, there is already */
  7334.    /* a bitmap loaded, or this is a SPACER type item.             */
  7335.  
  7336.    if ( pUCMI && !pUCMI->hBmp && !(Item->afStyle & MIS_SPACER) ) {
  7337.       char  BmpPathStr[MAXPATHL];
  7338.       HPS hPS = WinGetPS( UCMData->hwndMenu );
  7339.       LONG lID = 0;
  7340.       BOOL BinOK;
  7341.  
  7342.       if (pUCMI->pszBmp ){
  7343.    
  7344.         /* A bitmap string was specified.  It may be a resource ID or */
  7345.         /* a BMP file name.                                           */
  7346.     
  7347.         /* Attempt conversion of bitmap string to resource ID */
  7348.         lID = UCMString2Int(pUCMI->pszBmp, &BinOK);
  7349.     
  7350.         if (BinOK) { // Bitmap is a resource ID, so load it from resources
  7351.           pUCMI->hBmp = (ULONG)GpiLoadBitmap(hPS,
  7352.                                              UCMData->hModBmp,
  7353.                                              lID,
  7354.                                              0,
  7355.                                              0);
  7356.           pUCMI->ulFlags &= ~UCMI_BMPFROMFILE;
  7357.           pUCMI->ulFlags = (pUCMI->ulFlags & 0x0000FFFFL) | (lID << 16);
  7358.         }
  7359.         else { // Bitmap is a file name, so load it from file
  7360.            UCMenuGetBitmapFullName( UCMData, pUCMI->pszBmp, BmpPathStr );
  7361.            pUCMI->hBmp = UCMenuLoadBitmap( BmpPathStr );
  7362.            pUCMI->ulFlags |= UCMI_BMPFROMFILE;
  7363.            pUCMI->ulFlags = pUCMI->ulFlags & 0x0000FFFFL;
  7364.         }
  7365.       } // a pszBmp string was specified
  7366.       else {
  7367.            pUCMI->ulFlags &= ~UCMI_BMPFROMFILE;
  7368.            pUCMI->ulFlags = pUCMI->ulFlags & 0x0000FFFFL;
  7369.       }
  7370.  
  7371.       /* If bitmap could not be loaded, load default as specified in UCMINFO */
  7372.    
  7373.       if (!pUCMI->hBmp) {
  7374.         /* Attempt conversion of bitmap string to resource ID */
  7375.         lID = UCMString2Int(UCMData->szDefaultBitmap, &BinOK);
  7376.         if (BinOK) { // Bitmap is a resource ID, so load it from resources
  7377.           pUCMI->hBmp = (ULONG)GpiLoadBitmap(hPS,
  7378.                                              UCMData->hModBmp,
  7379.                                              lID,
  7380.                                              0,
  7381.                                              0);
  7382.         }
  7383.         else { // Bitmap is a file name, so load it from file
  7384.            UCMenuGetBitmapFullName( UCMData, UCMData->szDefaultBitmap, BmpPathStr );
  7385.            pUCMI->hBmp = UCMenuLoadBitmap( BmpPathStr );
  7386.         }
  7387.       }
  7388.    
  7389.       /* Finally, if still no go, use our own default bitmap resource */
  7390.    
  7391.       if ( !pUCMI->hBmp )
  7392.         pUCMI->hBmp = GpiLoadBitmap( hPS, UCMData->hModUCM, UCMENUID_DEFAULTBMP, 0, 0 );
  7393.  
  7394.       // If we are mapping background colors, do the mapping now
  7395.  
  7396.       if (UCMData->Style & (UCS_CHNGBMPBG|UCS_CHNGBMPBG_AUTO))
  7397.         UCMenuSetBmpBgColor(pUCMI, UCMData, hPS);
  7398.  
  7399.       WinReleasePS( hPS );
  7400.  
  7401.    } // if data is valid
  7402. }
  7403.  
  7404. #if defined(UCMUI)
  7405. //----------------------------------------------------------------------------
  7406. // UCMenuSettingsDlgProc
  7407. //----------------------------------------------------------------------------
  7408. // :pfunction res=&IDF_UCMSETTDLGPROC. name='UCMenuSettingsDlgProc' text='UCMenu settings notebook dialog procedure'.
  7409. // Dialog procedure of the ucmenu settings notebook
  7410. // :syntax name='UCMenuSettingsDlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  7411. // :fparams.
  7412. // :fparam name='hwnd' type='HWND' io='input' .
  7413. // Notebook window handle
  7414. // :fparam name='msg' type='ULONG' io='input' .
  7415. // Message
  7416. // :fparam name='mp1' type='MPARAM' io='input'.
  7417. // First parameter
  7418. // :fparam name='mp2' type='MPARAM' io='input'.
  7419. // Second parameter
  7420. // :freturns.
  7421. // :fparam name='mresult' type='MRESULT' io='return'.
  7422. // Return code of a PM message.
  7423. // :efparams.
  7424. // :remarks.
  7425. // :epfunction.
  7426. //----------------------------------------------------------------------------
  7427. MRESULT EXPENTRY  UCMenuSettingsDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  7428. {
  7429.   switch (msg) {
  7430.     case WM_CONTROL:
  7431.       switch (SHORT2FROMMP(mp1)) {
  7432.       case BKN_PAGESELECTED:
  7433.          // The last focused window of a page is stored in its QWL_USER
  7434.          // The QWL_USER is initialized in the WM_INITDLG of each page
  7435.          {
  7436.             PAGESELECTNOTIFY notif =  * (PAGESELECTNOTIFY *)mp2;
  7437.             HWND hNewPage = (HWND)WinSendMsg( notif.hwndBook,
  7438.                                      BKM_QUERYPAGEWINDOWHWND,
  7439.                                      MPFROMLONG( notif.ulPageIdNew),
  7440.                                      MPFROMLONG(0L));
  7441.  
  7442.             if (hNewPage) {
  7443.                WinPostMsg( hNewPage, GETTING_FOCUS, 0L, 0L );
  7444.             } // endif
  7445.          }
  7446.  
  7447.  
  7448.          break;
  7449.       default:
  7450.         break;
  7451.       } // endswitch
  7452.       break;
  7453.  
  7454.     case WM_INITDLG:
  7455.       { HWND hwndPage;
  7456.         RECTL rcl;
  7457.         SWP swp;
  7458.         POINTL pt[2];
  7459.         HWND hwndNB = WinWindowFromID(hwnd, IDC_UCMNB);
  7460.         LONG PageID1, PageID2, PageID0;
  7461.         ULONG Color = SYSCLR_WINDOWSTATICTEXT;
  7462.         PUCMDATA UCMData = (PUCMDATA)mp2;
  7463.  
  7464. //      if ( UCMData->hwndHelpInstance ) {
  7465. //         // -------------------------------------------------
  7466. //         // -- The contextual help would work without that
  7467. //         // -- We do it so that the focus goes back on this
  7468. //         // -- dialog after a contextual help invoked from it
  7469. //         // -- has been dismissed ( else the focus goes back
  7470. //         // -- to the closest winassociated window in the
  7471. //         // -- parent and owner chain )
  7472. //         // -------------------------------------------------
  7473. //         WinAssociateHelpInstance( UCMData->hwndHelpInstance, hwnd );
  7474. //      } // endif
  7475.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)UCMData);
  7476.         UCMData->hwndSettings = hwnd;
  7477.  
  7478.         WinSendMsg(hwndNB, BKM_SETNOTEBOOKCOLORS,
  7479.                    MPFROMLONG(SYSCLR_DIALOGBACKGROUND),
  7480.                    MPFROMLONG(BKA_BACKGROUNDMAJORCOLORINDEX));
  7481.         WinSendMsg(hwndNB, BKM_SETNOTEBOOKCOLORS,
  7482.                    MPFROMLONG(SYSCLR_DIALOGBACKGROUND),
  7483.                    MPFROMLONG(BKA_BACKGROUNDMINORCOLORINDEX));
  7484.         WinSendMsg(hwndNB, BKM_SETNOTEBOOKCOLORS,
  7485.                    MPFROMLONG(SYSCLR_DIALOGBACKGROUND),
  7486.                    MPFROMLONG(BKA_BACKGROUNDPAGECOLORINDEX));
  7487.         WinSetPresParam(hwndNB, PP_FOREGROUNDCOLORINDEX, 4 , &Color);
  7488.         /*┌──────────────────────────────────────────────────────────────┐
  7489.           │ Insert the pages (2 or 3) in the notebook control            │
  7490.           └──────────────────────────────────────────────────────────────┘*/
  7491.         if (UCMData->bItemCreation) {
  7492.           PageID0 = (LONG)WinSendMsg(hwndNB,
  7493.                                       BKM_INSERTPAGE,
  7494.                                       (MPARAM)0,
  7495.                                       MPFROM2SHORT(BKA_MAJOR | BKA_AUTOPAGESIZE, BKA_FIRST));
  7496.         } /* endif */
  7497.         PageID1 = (LONG) WinSendMsg(hwndNB,
  7498.                                     BKM_INSERTPAGE,
  7499.                                     (MPARAM)0,
  7500.                                     MPFROM2SHORT(BKA_MAJOR | BKA_AUTOPAGESIZE, BKA_LAST));
  7501.         PageID2 = (LONG) WinSendMsg(hwndNB,
  7502.                                     BKM_INSERTPAGE,
  7503.                                     (MPARAM)0,
  7504.                                     MPFROM2SHORT(BKA_MAJOR | BKA_AUTOPAGESIZE, BKA_LAST));
  7505.         /*┌──────────────────────────────────────────────────────────────┐
  7506.           │ Set the tabs dimensions                                      │
  7507.           └──────────────────────────────────────────────────────────────┘*/
  7508.         WinSendMsg(hwndNB,
  7509.                    BKM_SETDIMENSIONS,
  7510.                    MPFROM2SHORT(90,30),
  7511.                    (MPARAM)BKA_MAJORTAB);
  7512.         WinSendMsg(hwndNB,
  7513.                    BKM_SETDIMENSIONS,
  7514.                    MPFROM2SHORT(0,0),
  7515.                    (MPARAM)BKA_MINORTAB);
  7516.         /*┌──────────────────────────────────────────────────────────────┐
  7517.           │ Get the coord. of the client area                            │
  7518.           └──────────────────────────────────────────────────────────────┘*/
  7519.         pt[0].x =   0;  //
  7520.         pt[0].y =   0;  // coord of the corners of the nb pages (dialogs)
  7521.         pt[1].x = 203;  //  in the rc file -- all are the same size
  7522.         pt[1].y = 136;  //
  7523.  
  7524.         WinMapDlgPoints( hwndNB, pt, 2, 1 );        // dlg to NB control
  7525.  
  7526.         rcl.xLeft    = pt[0].x;
  7527.         rcl.yBottom  = pt[0].y;
  7528.         rcl.xRight   = pt[1].x;
  7529.         rcl.yTop     = pt[1].y;
  7530.  
  7531.         // get the size to give to the NB control
  7532.         WinSendMsg(hwndNB,
  7533.                    BKM_CALCPAGERECT,
  7534.                    MPFROMP(&rcl),
  7535.                    (MPARAM)FALSE);
  7536.  
  7537.         // size the NB control to fit around the pages
  7538.         WinSetWindowPos( hwndNB,
  7539.                          HWND_TOP,
  7540.                          0,
  7541.                          0,
  7542.                          rcl.xRight-rcl.xLeft,
  7543.                          rcl.yTop-rcl.yBottom,
  7544.                          SWP_SIZE );
  7545.  
  7546.         // Size the dialog window to fit around the NB control
  7547.         // (MAM) but account for the OK/Cancel buttons below it.
  7548.         WinQueryWindowPos( hwndNB, &swp );
  7549.         rcl.xLeft = 0;
  7550.         rcl.yBottom = 0;
  7551.         rcl.xRight = swp.x + swp.cx;
  7552.         rcl.yTop = swp.y + swp.cy;
  7553.         // calculate the size of the frame given the size of the client
  7554.         // only the size of the rect is considered
  7555.         WinCalcFrameRect( hwnd, &rcl, FALSE );
  7556.         WinSetWindowPos( hwnd,
  7557.                          HWND_TOP,
  7558.                          0,
  7559.                          0,
  7560.                          rcl.xRight-rcl.xLeft,
  7561.                          rcl.yTop-rcl.yBottom,
  7562.                          SWP_SIZE );
  7563.  
  7564.         /*┌──────────────────────────────────────────────────────────────┐
  7565.           │ Load dialogs (0,) 1 and 2                                    │
  7566.           └──────────────────────────────────────────────────────────────┘*/
  7567.         if (UCMData->bItemCreation) {
  7568.         /*┌──────────────┐
  7569.           │ >> PAGE 0 << │
  7570.           └──────────────┘*/
  7571.           hwndPage = WinLoadDlg(hwnd,
  7572.                                 hwnd,
  7573.                                 UCMenuNBP0DlgProc,
  7574.                                 UCMData->hModUCM,
  7575.                                 IDD_UCMNBP0,
  7576.                                 (PVOID)UCMData);
  7577.  
  7578.         /*┌───────────────┐
  7579.           │ Tab text      │
  7580.           └───────────────┘*/
  7581.           WinSendMsg(hwndNB,
  7582.                      BKM_SETTABTEXT,
  7583.                      (MPARAM)PageID0,
  7584.                      MPFROMP( nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_POSITION, 0 ) ) );
  7585.         /*┌───────────────┐
  7586.           │ Set page hwnd │
  7587.           └───────────────┘*/
  7588.           WinSendMsg(hwndNB,
  7589.                      BKM_SETPAGEWINDOWHWND,
  7590.                      (MPARAM)PageID0,
  7591.                      MPFROMHWND(hwndPage));
  7592.         } /* endif */
  7593.         WinSetOwner( hwndPage, hwndNB );
  7594.         /*┌──────────────┐
  7595.           │ >> PAGE 1 << │
  7596.           └──────────────┘*/
  7597.         hwndPage = WinLoadDlg(hwnd,
  7598.                               hwnd,
  7599.                               UCMenuNBP1DlgProc,
  7600.                               UCMData->hModUCM,
  7601.                               IDD_UCMNBP1,
  7602.                               (PVOID)UCMData);
  7603.  
  7604.         /*┌───────────────┐
  7605.           │ Tab text      │
  7606.           └───────────────┘*/
  7607.         WinSendMsg(hwndNB,
  7608.                    BKM_SETTABTEXT,
  7609.                    (MPARAM)PageID2,
  7610.                     MPFROMP( nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_GENERAL, 0 ) ) );
  7611.         /*┌───────────────┐
  7612.           │ Set page hwnd │
  7613.           └───────────────┘*/
  7614.         WinSendMsg(hwndNB,
  7615.                    BKM_SETPAGEWINDOWHWND,
  7616.                    (MPARAM)PageID2,
  7617.                    MPFROMHWND(hwndPage));
  7618.         WinSetOwner( hwndPage, hwndNB );
  7619.         /*┌──────────────┐
  7620.           │ >> PAGE 2 << │
  7621.           └──────────────┘*/
  7622.         hwndPage = WinLoadDlg(hwnd,
  7623.                               hwnd,
  7624.                               UCMenuNBP2DlgProc,
  7625.                               UCMData->hModUCM,
  7626.                               IDD_UCMNBP2,
  7627.                               (PVOID)UCMData);
  7628.         /*┌───────────────┐
  7629.           │ Tab text      │
  7630.           └───────────────┘*/
  7631.         WinSendMsg(hwndNB,
  7632.                    BKM_SETTABTEXT,
  7633.                    (MPARAM)PageID1,
  7634.                     MPFROMP( nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_ACTION, 0 ) ) );
  7635.         /*┌───────────────┐
  7636.           │ Set page hwnd │
  7637.           └───────────────┘*/
  7638.         WinSendMsg(hwndNB,
  7639.                    BKM_SETPAGEWINDOWHWND,
  7640.                    (MPARAM)PageID1,
  7641.                    MPFROMHWND(hwndPage));
  7642.         WinSetOwner( hwndPage, hwndNB );
  7643.         /*┌───────────────┐
  7644.           │ Set focus     │
  7645.           └───────────────┘*/
  7646.         if (UCMData->bItemCreation) {
  7647.            WinPostMsg( UCMData->hwndPage0, GETTING_FOCUS, 0L, 0L );
  7648.         } else {
  7649.            WinPostMsg( UCMData->hwndPage2, GETTING_FOCUS, 0L, 0L );
  7650.         } // endif
  7651.  
  7652.       } break;
  7653.  
  7654.     // (MAM) Added processing of OK/CANCEL buttons, simplified exit
  7655.     //       processing of notebook pages (all exit processing now
  7656.     //       done here instead of in each page dialog proc).
  7657.     case WM_COMMAND:
  7658.       switch (SHORT1FROMMP(mp1)) {
  7659.         case DID_CANCEL:
  7660.           WinDismissDlg(hwnd, DID_CANCEL);
  7661.           return 0;
  7662.         case DID_OK:
  7663.           {
  7664.             PUCMDATA UCMData;
  7665.             UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  7666.             if (UCMData->bItemCreation) {
  7667.               /* Create item.  Dismiss if no error. */
  7668.               if (UCMenuNBP0OK(hwnd))
  7669.                 WinDismissDlg(hwnd, DID_OK);
  7670.               return 0;
  7671.             }
  7672.             else {
  7673.               /* Do "OK" processing, then dismiss */
  7674.               UCMenuNBP1OK(UCMData->hwndPage1);
  7675.               UCMenuNBP2OK(UCMData->hwndPage2);
  7676.               WinDismissDlg(hwnd, DID_OK);  /* We are done */
  7677.               return 0;
  7678.             } /* endif */
  7679.           } /* OK case */
  7680.  
  7681.       } /* switch */
  7682.       break;
  7683.  
  7684.     case WM_CLOSE:
  7685.       // (MAM) Close from system menu is now CANCEL function
  7686.       WinDismissDlg(hwnd, DID_CANCEL);
  7687.       return 0;
  7688.  
  7689.     case WM_DESTROY:
  7690.      {
  7691.      /*┌────────────────────────────────────────────┐
  7692.        │ Dismiss the dialog and destroy the windows │
  7693.        └────────────────────────────────────────────┘*/
  7694.          PUCMDATA UCMData;
  7695.          UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  7696.  
  7697.          if (UCMData->bItemCreation) {
  7698.            WinDismissDlg(UCMData->hwndPage0, TRUE);
  7699.            WinDestroyWindow(UCMData->hwndPage0);
  7700.          } /* endif */
  7701.          WinDismissDlg(UCMData->hwndPage1, TRUE);
  7702.          WinDismissDlg(UCMData->hwndPage2, TRUE);
  7703.          WinDestroyWindow(UCMData->hwndPage1);
  7704.          WinDestroyWindow(UCMData->hwndPage2);
  7705.       }
  7706.       break;
  7707.  
  7708.     default:
  7709.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  7710.   } /* endswitch */
  7711.   return (MRESULT)0;
  7712. }
  7713. #endif
  7714.  
  7715. #if defined(UCMUI)
  7716. //----------------------------------------------------------------------------
  7717. // UCMenuNBP1DlgProc
  7718. //----------------------------------------------------------------------------
  7719. // :pfunction res=&IDF_PG1DLGPROC. name='UCMenuNBP1DlgProc' text='UCMenu settings notebook page 1 dialog procedure'.
  7720. // Dialog procedure of the page 1 of the ucmenu settings notebook
  7721. // :syntax name='UCMenuNBP1DlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  7722. // :fparams.
  7723. // :fparam name='hwnd' type='HWND' io='input' .
  7724. // Notebook page 1 window handle
  7725. // :fparam name='msg' type='ULONG' io='input' .
  7726. // Message
  7727. // :fparam name='mp1' type='MPARAM' io='input'.
  7728. // First parameter
  7729. // :fparam name='mp2' type='MPARAM' io='input'.
  7730. // Second parameter
  7731. // :freturns.
  7732. // :fparam name='mresult' type='MRESULT' io='return'.
  7733. // Return code of a PM message.
  7734. // :efparams.
  7735. // :remarks.
  7736. // :epfunction.
  7737. //----------------------------------------------------------------------------
  7738. MRESULT EXPENTRY  UCMenuNBP1DlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  7739. {
  7740.   switch (msg) {
  7741.     case WM_INITDLG:
  7742.       {
  7743.         PUCMDATA UCMData = (PUCMDATA)mp2;
  7744.  
  7745.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)UCMData);
  7746.         UCMData->hwndPage1 = hwnd;
  7747.         UCMenuNBP1Initialize(UCMData, hwnd);
  7748.       }
  7749.       break;
  7750.  
  7751. //  case WM_ACTIVATE:
  7752. //    if (SHORT1FROMMP(mp1)) {
  7753. //      WinSendMsg(WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW,
  7754. //                 (MPARAM)hwnd, (MPARAM)hwnd);
  7755. //    } else {
  7756. //      // clear active help window when this window is deactivated - this is
  7757. //      // necessary for message box help, etc. to work properly
  7758. //      WinSendMsg(WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW,
  7759. //                 NULLHANDLE, NULLHANDLE);
  7760. //    } /* endif */
  7761. //    return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  7762.  
  7763.     case GETTING_FOCUS:
  7764.        WinSetFocus( HWND_DESKTOP, WinWindowFromID( hwnd, IDC_UCMNBP1TITLE ) );
  7765.      break;
  7766.  
  7767.     case WM_COMMAND:
  7768.       switch (SHORT1FROMMP(mp1)) {
  7769.         case IDB_UCMNBP1UNDO:
  7770.              {
  7771.                 PUCMDATA UCMData;
  7772.                 UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  7773.                 UCMenuNBP1Initialize(UCMData, hwnd);
  7774.                 return (MRESULT)0;
  7775.              }
  7776.  
  7777.         // (MAM) removed OK and CANCEL processing...
  7778.  
  7779.         case IDB_UCMNBP1LOAD:
  7780.           /*┌─────────────────────────┐
  7781.             │ Load a bitmap           │
  7782.             └─────────────────────────┘*/
  7783.         {  FILEDLG FileDlg;
  7784.            PUCMDATA UCMData;
  7785.            MENUITEM mi;
  7786.            UCHAR    szPath[CCHMAXPATH];
  7787.            PSZ      pszIndex;
  7788.            UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  7789.            memset(&FileDlg, 0, sizeof(FileDlg));
  7790.  
  7791.            if ( ! UCMData->bItemCreation ) {
  7792.               WinSendMsg(UCMData->hwndTemp,
  7793.                          MM_QUERYITEM,
  7794.                          MPFROM2SHORT( UCMData->ContextID, TRUE ),
  7795.                          MPFROMP(&mi));
  7796.            }
  7797.  
  7798.            FileDlg.cbSize     = sizeof(FileDlg);
  7799.            FileDlg.fl         = FDS_OPEN_DIALOG | FDS_CENTER;
  7800.            FileDlg.pfnDlgProc = BitmapFileDlgProc;
  7801.            FileDlg.ulUser     = (ULONG) UCMData;
  7802.  
  7803.            if ( ! UCMData->bItemCreation && ITEM( &mi, pszBmp ) ) {
  7804.               strcpy((PSZ)(&(FileDlg.szFullFile)), (PSZ)(ITEM(&mi, pszBmp)));
  7805.            } else {
  7806.               szPath[CCHMAXPATH-1] = '\0';
  7807.               strncpy( szPath, UCMData->szBitmapPath, CCHMAXPATH );
  7808.               strncat( szPath, "*.bmp", CCHMAXPATH );
  7809.               strncpy( FileDlg.szFullFile, szPath, CCHMAXPATH );
  7810.            }
  7811.            WinFileDlg( HWND_DESKTOP, hwnd, &FileDlg );
  7812.  
  7813.  
  7814.            if ( FileDlg.lReturn == DID_OK ) {
  7815.               // -- UCMData->hBmpTemp has been updated by the subclassed  filedlgproc
  7816.               WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), TRUE );
  7817.               UCMenuNBP1UpdateBmp( hwnd, FileDlg.szFullFile );
  7818.               pszIndex = strrchr( FileDlg.szFullFile, '\\' );
  7819.               if ( pszIndex ) {
  7820.                  *( pszIndex + 1 ) = '\0';
  7821.               } /* endif */
  7822.               strncpy( UCMData->szBitmapPath, FileDlg.szFullFile, CCHMAXPATH );
  7823.            } // endif
  7824.         }
  7825.         break;
  7826.  
  7827.         case IDB_UCMNBP1EDIT :
  7828.         {
  7829.            PSZ pszTxt = MyMalloc( MAXPATHL );
  7830.            WinQueryDlgItemText(hwnd, IDC_UCMNBP1FILENAME, (LONG)MAXPATHL, pszTxt);
  7831.  
  7832.            UCMenuEditBmpFile( hwnd, pszTxt );
  7833.  
  7834.         }
  7835.         break;
  7836.  
  7837.  
  7838.         case IDB_UCMNBP1PREDEFINED :
  7839.         {
  7840.            ULONG ulResult;
  7841.            PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER );
  7842.  
  7843.            if ( !UCMData ) {
  7844.               return (MRESULT)FALSE;
  7845.            } // endif
  7846.  
  7847.            ulResult = WinDlgBox( HWND_DESKTOP,
  7848.                                  hwnd,
  7849.                                  ResBmpDlgProc,
  7850.                                  UCMData->hModUCM,
  7851.                                  IDD_RESBMP,
  7852.                                  (PVOID)UCMData );
  7853.            if ( ulResult && ( ulResult != DID_ERROR ) ){
  7854.               HBITMAP hbmp;
  7855.               HPS     hPS = WinGetPS( UCMData->hwndMenu );
  7856.               hbmp = (ULONG)GpiLoadBitmap( hPS,
  7857.                                            UCMData->hModBmp,
  7858.                                            UCMData->ulBmpTempId,
  7859.                                            0,
  7860.                                            0);
  7861.               WinReleasePS( hPS );
  7862.               if ( hbmp ) {
  7863.                  CHAR szBmpId[22];
  7864.                  sprintf( szBmpId, "%i", UCMData->ulBmpTempId );
  7865.                  UCMData->hBmpTemp = hbmp;
  7866.                  UCMData->bBmpTempFromFile = FALSE;
  7867.                  WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), FALSE );
  7868.  
  7869.                  UCMenuNBP1UpdateBmp( hwnd, szBmpId );
  7870.               } // endif
  7871.            } // endif
  7872.         }
  7873.         break;
  7874.  
  7875.         case IDB_UCMNBP1NOBMP :
  7876.         {
  7877.            PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER );
  7878.  
  7879.            if ( !UCMData ) {
  7880.               return (MRESULT)FALSE;
  7881.            } // endif
  7882.  
  7883.            UCMData->hBmpTemp = 0;
  7884.            UCMData->bBmpTempFromFile = FALSE;
  7885.            WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), FALSE );
  7886.  
  7887.            UCMenuNBP1UpdateBmp( hwnd, "" );
  7888.         }
  7889.         break;
  7890.  
  7891.         case IDB_UCMNBP1CREATE :
  7892.         {
  7893.            PUCMDATA UCMData = (PUCMDATA) WinQueryWindowULong( hwnd, QWL_USER );
  7894.            WinDlgBox( HWND_DESKTOP,
  7895.                       hwnd,
  7896.                       UCMenuCreateBmpDlgProc,
  7897.                       UCMData->hModUCM,
  7898.                       IDD_UCMGETBMPNAME,
  7899.                       (PVOID)UCMData );
  7900.         }
  7901.         break;
  7902.  
  7903.       } // endswitch
  7904.       break;
  7905.  
  7906.     case UCMNBP1_NEWBMP:
  7907.     {
  7908.        PSZ pszFileName = (PSZ)mp1;
  7909.        PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER );
  7910.  
  7911.        HBITMAP hBmp = UCMenuLoadBitmap( pszFileName );
  7912.  
  7913.        if ( hBmp ) {
  7914.           UCMData->hBmpTemp = hBmp;
  7915.           UCMData->bBmpTempFromFile = TRUE;
  7916.           UCMenuNBP1UpdateBmp( hwnd, pszFileName );
  7917.        } // endif
  7918.        WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1LOAD ),   TRUE );
  7919.        WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1CREATE ), TRUE );
  7920.        WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ),   TRUE );
  7921.        WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1PREDEFINED ),   TRUE );
  7922.     } break;
  7923.  
  7924.     case WM_PAINT:
  7925.     { MPARAM rc;
  7926.       HPS    hPS;
  7927.       SWP    swp;
  7928.       RECTL  rcl;
  7929.       POINTL pt;
  7930.       BITMAPINFOHEADER BmpInfo;
  7931.       PUCMDATA UCMData;
  7932.       UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  7933.  
  7934.       rc = WinDefDlgProc(hwnd, msg, mp1, mp2);
  7935.  
  7936.       if ( UCMData->hBmpTemp ) {
  7937.         hPS = WinGetPS( hwnd );
  7938.         WinQueryWindowPos( WinWindowFromID( hwnd, IDC_UCMNBP1BITMAP ), &swp );
  7939.  
  7940.         GpiQueryBitmapParameters( UCMData->hBmpTemp, &BmpInfo );
  7941.         pt.x = (BmpInfo.cx > swp.cx ? swp.x : swp.x + (swp.cx - BmpInfo.cx)/2);
  7942.         pt.y = (BmpInfo.cy > swp.cy ? swp.y : swp.y + (swp.cy - BmpInfo.cy)/2);
  7943.         rcl.xLeft   = 0;
  7944.         rcl.yBottom = 0;
  7945.         rcl.xRight  = swp.cx;
  7946.         rcl.yTop    = swp.cy;
  7947.         WinDrawBitmap( hPS,
  7948.                        UCMData->hBmpTemp,
  7949.                        &rcl,
  7950.                        &pt,
  7951.                        0,
  7952.                        0,
  7953.                        DBM_NORMAL );
  7954.         WinReleasePS( hPS );
  7955.       } // endif
  7956.       return rc;
  7957.     }
  7958.  
  7959.     case WM_HELP:
  7960.       switch (SHORT1FROMMP(mp1)) {
  7961.       case IDB_UCMNBP1HELP:
  7962.          {
  7963.             PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER);
  7964.  
  7965.             UCMenuDisplayHelp( UCMData,
  7966.                        (USHORT)PANEL_ITEMBMP,
  7967.                        (USHORT)UCN_HLP_NB_BMP );
  7968.  
  7969.          }
  7970.          break;
  7971.       default:
  7972.          return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  7973.       } // endswitch
  7974.       break;
  7975.  
  7976.     default:
  7977.       return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  7978.  
  7979.   } // endswitch
  7980.  
  7981.   return (MRESULT)0;
  7982. }
  7983. #endif
  7984.  
  7985. #if defined(UCMUI)
  7986. //----------------------------------------------------------------------------
  7987. // UCMenuNBP1Initialize : Not for the user's doc
  7988. //----------------------------------------------------------------------------
  7989. // :pfunction res=&IDF_INITPG1. name='UCMenuNBP1Initialize' text='Initializes the page 1 of the settings notebook' .
  7990. // This function initializes the page 1 of the settings notebook
  7991. // :syntax name='UCMenuNBP1Initialize' params='UCMData, hwnd' return='-' .
  7992. // :fparams.
  7993. // :fparam name='UCMData' type='PUCMDATA' io='input' .
  7994. // Pointer to the UCMDATA structure
  7995. // :fparam name='hwnd' type='HWND' io='input' .
  7996. // Page 1 window handle.
  7997. // :freturns.
  7998. // :fparam name='-' type='VOID' io='-'.
  7999. // Nothing
  8000. // :efparams.
  8001. // :remarks.
  8002. // :related.
  8003. // :epfunction.
  8004. //----------------------------------------------------------------------------
  8005. VOID _Optlink UCMenuNBP1Initialize(PUCMDATA UCMData, HWND hwnd)
  8006. {
  8007.    if (UCMData->bItemCreation) {
  8008.      /*┌──────────────────────────────────────────────────────────────┐
  8009.        │ Item Creation : blank the fields                             │
  8010.        └──────────────────────────────────────────────────────────────┘*/
  8011.      RECTL rcl;
  8012.      SWP   swp;
  8013.      HPS   hPS = WinGetPS( hwnd );
  8014.  
  8015.      WinSetDlgItemText( hwnd, IDC_UCMNBP1TITLE, "" );
  8016.  
  8017.      UCMData->hBmpTemp = 0;
  8018.      UCMData->bBmpTempFromFile = FALSE;
  8019.      WinQueryWindowPos( WinWindowFromID( hwnd, IDC_UCMNBP1BITMAP ), &swp );
  8020.      rcl.xLeft   = swp.x;
  8021.      rcl.yBottom = swp.y;
  8022.      rcl.xRight  = swp.x + swp.cx;
  8023.      rcl.yTop    = swp.y + swp.cy;
  8024.      WinFillRect( hPS, &rcl, SYSCLR_DIALOGBACKGROUND );
  8025.      WinSetDlgItemText( hwnd, IDC_UCMNBP1FILENAME, 0 );
  8026.      WinReleasePS( hPS );
  8027.  
  8028.      WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), FALSE );
  8029.  
  8030.    } else {
  8031.      /*┌──────────────────────────────────────────────────────────────┐
  8032.        │ Editing : get the data from the item                         │
  8033.        └──────────────────────────────────────────────────────────────┘*/
  8034.      MENUITEM mi;
  8035.      PSZ      pszTxt;
  8036.      SWP      swp;
  8037.      RECTL    rcl;
  8038.      POINTL   pt;
  8039.      HPS      hPS = WinGetPS(hwnd);
  8040.      HWND     hwndUCM;
  8041.      BITMAPINFOHEADER BmpInfo;
  8042.      ULONG    ulSize;
  8043.  
  8044.      hwndUCM = UCMData->hwndTemp;
  8045.  
  8046.  
  8047.      memset(&mi, 0, sizeof(MENUITEM));
  8048.      /*┌─────────────────────────────┐
  8049.        │ Query item                  │
  8050.        └─────────────────────────────┘*/
  8051.      WinSendMsg(hwndUCM,
  8052.                 MM_QUERYITEM,
  8053.                 MPFROM2SHORT(UCMData->ContextID, TRUE),
  8054.                 MPFROMP(&mi));
  8055.  
  8056.      /*┌─────────────────────────────┐
  8057.        │ Query item text             │
  8058.        └─────────────────────────────┘*/
  8059.        if (mi.hItem && ITEM(&mi, pszText)) {
  8060.          ulSize = strlen(ITEM(&mi, pszText));
  8061.          pszTxt = MyMalloc(ulSize + 1);
  8062.          if (pszTxt) {
  8063.            strcpy(pszTxt, ITEM(&mi, pszText));
  8064.            WinSetDlgItemText(hwnd, IDC_UCMNBP1TITLE, pszTxt);
  8065.            MyFree(pszTxt);
  8066.          } else {
  8067.            WinSetDlgItemText(hwnd, IDC_UCMNBP1TITLE, "");
  8068.          } /* endif */
  8069.        } else {
  8070.          WinSetDlgItemText(hwnd, IDC_UCMNBP1TITLE, "");
  8071.        } /* endif */
  8072.  
  8073.      WinQueryWindowPos( WinWindowFromID( hwnd, IDC_UCMNBP1BITMAP ), &swp );
  8074.  
  8075.      rcl.xLeft   = swp.x;
  8076.      rcl.yBottom = swp.y;
  8077.      rcl.xRight  = swp.x + swp.cx;
  8078.      rcl.yTop    = swp.y + swp.cy;
  8079.      WinFillRect( hPS, &rcl, SYSCLR_DIALOGBACKGROUND );
  8080.  
  8081.      WinSetDlgItemText( hwnd, IDC_UCMNBP1FILENAME, "" );
  8082.  
  8083.      if ( mi.hItem && ITEM( &mi, hBmp ) ) {
  8084.      /*┌─────────────────────────────┐
  8085.        │ Query item bitmap           │
  8086.        └─────────────────────────────┘*/
  8087.  
  8088.        GpiQueryBitmapParameters( UCMData->hBmpTemp = ITEM(&mi, hBmp), &BmpInfo );
  8089.        pt.x = ( BmpInfo.cx > swp.cx ? swp.x : swp.x + ( swp.cx - BmpInfo.cx )/2 );
  8090.        pt.y = ( BmpInfo.cy > swp.cy ? swp.y : swp.y + ( swp.cy - BmpInfo.cy )/2 );
  8091.        rcl.xLeft   = 0;
  8092.        rcl.yBottom = 0;
  8093.        rcl.xRight  = swp.cx;
  8094.        rcl.yTop    = swp.cy;
  8095.        WinDrawBitmap( hPS,
  8096.                       UCMData->hBmpTemp = ITEM( &mi, hBmp ),
  8097.                       &rcl,
  8098.                       &pt,
  8099.                       0,
  8100.                       0,
  8101.                       DBM_NORMAL );
  8102.         WinSetDlgItemText( hwnd, IDC_UCMNBP1FILENAME, ITEM( &mi, pszBmp ) );
  8103.         if ( ITEM( &mi, ulFlags ) & UCMI_BMPFROMFILE ){
  8104.            UCMData->bBmpTempFromFile = TRUE;
  8105.            WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), TRUE );
  8106.         } else {
  8107.            UCMData->bBmpTempFromFile = FALSE;
  8108.            WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), FALSE );
  8109.         } // endif
  8110.      } else {
  8111.         UCMData->hBmpTemp = 0;
  8112.         UCMData->bBmpTempFromFile = FALSE;
  8113.         WinEnableWindow( WinWindowFromID( hwnd, IDB_UCMNBP1EDIT ), FALSE );
  8114.      } // endif
  8115.  
  8116.      WinReleasePS( hPS );
  8117.  
  8118.  
  8119.    } // endif
  8120. }
  8121. #endif
  8122.  
  8123. #if defined(UCMUI)
  8124. //----------------------------------------------------------------------------
  8125. // UCMenuNBP2DlgProc
  8126. //----------------------------------------------------------------------------
  8127. // :pfunction res=&IDF_PG2DLGPROC. name='UCMenuNBP2DlgProc' text='UCMenu settings notebook page 2 dialog procedure'.
  8128. // Dialog procedure of the page 2 of the ucmenu settings notebook
  8129. // :syntax name='UCMenuNBP2DlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  8130. // :fparams.
  8131. // :fparam name='hwnd' type='HWND' io='input' .
  8132. // Notebook page 2 window handle
  8133. // :fparam name='msg' type='ULONG' io='input' .
  8134. // Message
  8135. // :fparam name='mp1' type='MPARAM' io='input'.
  8136. // First parameter
  8137. // :fparam name='mp2' type='MPARAM' io='input'.
  8138. // Second parameter
  8139. // :freturns.
  8140. // :fparam name='mresult' type='MRESULT' io='return'.
  8141. // Return code of a PM message.
  8142. // :efparams.
  8143. // :remarks.
  8144. // :epfunction.
  8145. //----------------------------------------------------------------------------
  8146. MRESULT EXPENTRY  UCMenuNBP2DlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  8147. {
  8148.   switch (msg) {
  8149.     case WM_INITDLG:
  8150.       {
  8151.         PUCMDATA UCMData = (PUCMDATA)mp2;
  8152.  
  8153.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)UCMData);
  8154.  
  8155.         UCMData->hwndPage2 = hwnd;
  8156.        /*┌──────────────────────────────────────────────────────────────┐
  8157.          │ Set maximum length of the fields                             │
  8158.          └──────────────────────────────────────────────────────────────┘*/
  8159.         WinSendDlgItemMsg(hwnd,
  8160.                           IDC_UCMNBP2FLIST,
  8161.                           EM_SETTEXTLIMIT,
  8162.                           MPFROMSHORT(255),
  8163.                           (MPARAM)0);
  8164.         WinSendDlgItemMsg(hwnd,
  8165.                           IDC_UCMNBP2PARAMS,
  8166.                           EM_SETTEXTLIMIT,
  8167.                           MPFROMSHORT(255),
  8168.                           (MPARAM)0);
  8169.         UCMenuNBP2Initialize(UCMData, hwnd);
  8170.       } break;
  8171.  
  8172. //  case WM_ACTIVATE:
  8173. //    if (SHORT1FROMMP(mp1)) {
  8174. //      WinSendMsg(WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW,
  8175. //                 (MPARAM)hwnd, (MPARAM)hwnd);
  8176. //    } else {
  8177. //      // clear active help window when this window is deactivated - this is
  8178. //      // necessary for message box help, etc. to work properly
  8179. //      WinSendMsg(WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW,
  8180. //                 NULLHANDLE, NULLHANDLE);
  8181. //    } /* endif */
  8182. //    return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8183.  
  8184.     case GETTING_FOCUS:
  8185.        WinSetFocus( HWND_DESKTOP, WinWindowFromID( hwnd, IDC_UCMNBP2FLIST ) );
  8186.      break;
  8187.  
  8188.     case WM_CONTROL:
  8189.        {
  8190.           switch ( SHORT1FROMMP( mp1 ) ) {
  8191.           case IDC_UCMNBP2FLIST:
  8192.              switch ( SHORT2FROMMP( mp1 ) ){
  8193.              case CBN_LBSELECT:
  8194.              {
  8195.                 SHORT sIndex;
  8196.                 CHAR pszDesc[MAXDESCLEN];
  8197.                 sIndex = (USHORT)WinSendMsg( HWNDFROMMP( mp2 ), LM_QUERYSELECTION, MPFROMSHORT( LIT_FIRST ), (MPARAM)0 );
  8198.                 sIndex = (USHORT)WinSendDlgItemMsg(hwnd,
  8199.                                                    IDC_UCMNBP2DLIST,
  8200.                                                    LM_QUERYITEMTEXT,
  8201.                                                    MPFROM2SHORT( sIndex, MAXDESCLEN ),
  8202.                                                    MPFROMP( pszDesc ) );
  8203.                 WinSetDlgItemText( hwnd, IDC_UCMNBP2DESC, pszDesc );
  8204.                 return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8205.              }
  8206.              default:
  8207.                return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8208.                break;
  8209.              } // endswitch
  8210.           default:
  8211.              return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8212.           } // endswitch
  8213.  
  8214.        }
  8215.      break;
  8216.  
  8217.     case UCMENU_ACTIONSINSERTED:
  8218.       // -- This message is posted by the owner to let me know that
  8219.       // -- the list of actions was filled. What I have to do is hilite the
  8220.       // -- current action in the list or, if it's not in it, add it to the
  8221.       // -- list and highlight it.
  8222.       { MENUITEM mi;
  8223.         PSZ      pszTxt, pszParams;
  8224.         CHAR     pszDesc[MAXDESCLEN];
  8225.         PUCMDATA UCMData;
  8226.  
  8227.         WinShowWindow( WinWindowFromID( hwnd, IDC_UCMNBP2LOADING ), FALSE );
  8228.  
  8229.         UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  8230.  
  8231.         memset(&mi, 0, sizeof(MENUITEM));
  8232.  
  8233.         if (!(UCMData->bItemCreation)) {
  8234.            //-- Query item
  8235.            WinSendMsg(UCMData->hwndTemp,
  8236.                       MM_QUERYITEM,
  8237.                       MPFROM2SHORT(UCMData->ContextID, TRUE),
  8238.                       MPFROMP(&mi));
  8239.         }
  8240.  
  8241.         if (mi.hItem) {
  8242.           pszTxt = ITEM(&mi, pszAction);
  8243.           pszParams = ITEM(&mi, pszParameters);
  8244.           if (pszTxt) {
  8245.             SHORT  sIndex;
  8246.  
  8247.             if (pszParams) {
  8248.               WinSetDlgItemText(hwnd, IDC_UCMNBP2PARAMS, pszParams);
  8249.             } else {
  8250.               WinSetDlgItemText(hwnd, IDC_UCMNBP2PARAMS, "");
  8251.             } /* endif */
  8252.  
  8253.             sIndex = (USHORT)WinSendDlgItemMsg(hwnd,
  8254.                                                IDC_UCMNBP2FLIST,
  8255.                                                LM_SEARCHSTRING,
  8256.                                                MPFROM2SHORT(LSS_CASESENSITIVE, LIT_FIRST),
  8257.                                                MPFROMP(pszTxt));
  8258.             if (sIndex==LIT_NONE || sIndex==LIT_ERROR) {
  8259.                //-- Add it to the list
  8260.                sIndex = (USHORT) WinSendDlgItemMsg(hwnd,
  8261.                                                    IDC_UCMNBP2FLIST,
  8262.                                                    LM_INSERTITEM,
  8263.                                                    (MPARAM)LIT_END,
  8264.                                                    MPFROMP(pszTxt));
  8265.                WinSendDlgItemMsg(hwnd,
  8266.                                  IDC_UCMNBP2DLIST,
  8267.                                  LM_INSERTITEM,
  8268.                                  (MPARAM)LIT_END,
  8269.                                  MPFROMP(""));
  8270.                WinSetDlgItemText(hwnd, IDC_UCMNBP2DESC, "");
  8271.             } else {
  8272.                WinSendDlgItemMsg(hwnd,
  8273.                                  IDC_UCMNBP2DLIST,
  8274.                                  LM_QUERYITEMTEXT,
  8275.                                  MPFROM2SHORT( sIndex, MAXDESCLEN ),
  8276.                                  MPFROMP( pszDesc ) );
  8277.                WinSetDlgItemText( hwnd, IDC_UCMNBP2DESC, pszDesc );
  8278.             } // endif
  8279.             //-- Select it
  8280.             WinSendDlgItemMsg(hwnd,
  8281.                               IDC_UCMNBP2FLIST,
  8282.                               LM_SELECTITEM,
  8283.                               MPFROMSHORT(sIndex),
  8284.                               MPFROMSHORT(TRUE));
  8285.           } else {
  8286.             WinSetDlgItemText(hwnd, IDC_UCMNBP2PARAMS, "");
  8287.           } /* endif */
  8288.         } /* endif */
  8289.       } break;
  8290.  
  8291.     case WM_COMMAND:
  8292.       switch (SHORT1FROMMP(mp1)) {
  8293.         case IDB_UCMNBP2UNDO:
  8294.              {
  8295.                 PUCMDATA UCMData;
  8296.                 UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  8297.                 // -- Empty the functions list because it will be filled again
  8298.                 WinSendDlgItemMsg(hwnd,
  8299.                                   IDC_UCMNBP2FLIST,
  8300.                                   LM_DELETEALL,
  8301.                                   (MPARAM)0,
  8302.                                   (MPARAM)0);
  8303.                 WinSendDlgItemMsg(hwnd,
  8304.                                   IDC_UCMNBP2DLIST,
  8305.                                   LM_DELETEALL,
  8306.                                   (MPARAM)0,
  8307.                                   (MPARAM)0);
  8308.                 UCMenuNBP2Initialize(UCMData, hwnd);
  8309.                 return(MRESULT)0;
  8310.              }
  8311.  
  8312.         // (MAM) removed OK and CANCEL processing...
  8313.  
  8314.       } /* endswitch */
  8315.       break;
  8316.  
  8317.     case WM_HELP:
  8318.       switch (SHORT1FROMMP(mp1)) {
  8319.       case IDB_UCMNBP2HELP:
  8320.          {
  8321.             PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER);
  8322.             UCMenuDisplayHelp( UCMData,
  8323.                        (USHORT)PANEL_ITEMACTION,
  8324.                        (USHORT)UCN_HLP_NB_ACTION);
  8325.          }
  8326.          break;
  8327.       default:
  8328.         return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8329.         break;
  8330.       } // endswitch
  8331.       break;
  8332.  
  8333.     default:
  8334.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  8335.  
  8336.   } /* endswitch */
  8337.   return (MRESULT)0;
  8338. }
  8339. #endif
  8340.  
  8341. #if defined(UCMUI)
  8342. //----------------------------------------------------------------------------
  8343. // UCMenuNBP2Initialize : Not for the user's doc
  8344. //----------------------------------------------------------------------------
  8345. // :pfunction res=&IDF_INITPG2. name='UCMenuNBP2Initialize' text='Initializes the page 2 of the settings notebook' .
  8346. // This function initializes the page2  of the settings notebook
  8347. // :syntax name='UCMenuNBP2Initialize' params='UCMData, hwnd' return='-' .
  8348. // :fparams.
  8349. // :fparam name='UCMData' type='PUCMDATA' io='input' .
  8350. // Pointer to the UCMDATA structure
  8351. // :fparam name='hwnd' type='HWND' io='input' .
  8352. // Page 2 window handle.
  8353. // :freturns.
  8354. // :fparam name='-' type='VOID' io='-'.
  8355. // Nothing
  8356. // :efparams.
  8357. // :remarks.
  8358. // :related.
  8359. // :epfunction.
  8360. //----------------------------------------------------------------------------
  8361. VOID  _Optlink UCMenuNBP2Initialize(PUCMDATA UCMData, HWND hwnd)
  8362. {
  8363.  
  8364.    WinSetDlgItemText(hwnd, IDC_UCMNBP2FLIST, "");
  8365.    WinSetDlgItemText(hwnd, IDC_UCMNBP2PARAMS, "");
  8366.    WinSetDlgItemText(hwnd, IDC_UCMNBP2DESC, "");
  8367.    WinShowWindow( WinWindowFromID( hwnd, IDC_UCMNBP2LOADING ), TRUE );
  8368.  
  8369.  
  8370.    /*┌──────────────────────────────────────────────────────────────┐
  8371.      │ Add an entry in the list of actions : ExecuteProgram.        │
  8372.      │ It's an internal action.                                     │
  8373.      └──────────────────────────────────────────────────────────────┘*/
  8374.    if ( !( UCMData->Style & UCS_NODEFAULTACTION ) ){
  8375.       WinSendDlgItemMsg(hwnd,
  8376.                         IDC_UCMNBP2FLIST,
  8377.                         LM_INSERTITEM,
  8378.                         (MPARAM)LIT_FIRST,
  8379.                         MPFROMP(&UCM_ACTION_EXEC));
  8380.       //-- Add the corresponding entry in the listbox of description
  8381.       //-- This listbox is not displayed, just used to store the descriptions
  8382.       WinSendDlgItemMsg(hwnd,
  8383.                         IDC_UCMNBP2DLIST,
  8384.                         LM_INSERTITEM,
  8385.                         (MPARAM)LIT_FIRST,
  8386.                         MPFROMP( nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_DESCEXEC, 0 ) ) );
  8387.    } // endif
  8388.  
  8389.    //-- It's better to change the way we fill the list. Now we post a message to the
  8390.    //-- owner to let him know he can fill in the list. Before, it had to be synchronous
  8391.    //-- Now, the owner can query its internal list (call an EPM macro) and fill the
  8392.    //-- listbox when he's ready
  8393.    WinSendMsg( WinQueryWindow(UCMData->hwndTemp, QW_OWNER),
  8394.                WM_CONTROL,
  8395.                MPFROM2SHORT( WinQueryWindowUShort( UCMData->hwndTemp, QWS_ID ),
  8396.                              UCN_QRYACTIONLIST ),
  8397.                MPFROMHWND( UCMData->hwndTemp ) );
  8398. }
  8399. #endif
  8400.  
  8401. #if defined(UCMUI)
  8402. //----------------------------------------------------------------------------
  8403. // UCMenuNBP0DlgProc
  8404. //----------------------------------------------------------------------------
  8405. // :pfunction res=&IDF_PG0DLGPROC. name='UCMenuNBP0DlgProc' text='UCMenu settings notebook page 0 dialog procedure'.
  8406. // Dialog procedure of the page 0 of the ucmenu settings notebook
  8407. // :syntax name='UCMenuNBP0DlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  8408. // :fparams.
  8409. // :fparam name='hwnd' type='HWND' io='input' .
  8410. // Notebook page 0 window handle
  8411. // :fparam name='msg' type='ULONG' io='input' .
  8412. // Message
  8413. // :fparam name='mp1' type='MPARAM' io='input'.
  8414. // First parameter
  8415. // :fparam name='mp2' type='MPARAM' io='input'.
  8416. // Second parameter
  8417. // :freturns.
  8418. // :fparam name='mresult' type='MRESULT' io='return'.
  8419. // Return code of a PM message.
  8420. // :efparams.
  8421. // :remarks.
  8422. // :epfunction.
  8423. //----------------------------------------------------------------------------
  8424. MRESULT EXPENTRY  UCMenuNBP0DlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  8425. {
  8426.   switch (msg) {
  8427.     case WM_INITDLG:
  8428.       {
  8429.         PUCMDATA UCMData = (PUCMDATA)mp2;
  8430.  
  8431.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)UCMData);
  8432.         UCMData->hwndPage0 = hwnd;
  8433.         UCMenuNBP0Initialize(UCMData, hwnd);
  8434.       }
  8435.       break;
  8436.  
  8437. //  case WM_ACTIVATE:
  8438. //    if (SHORT1FROMMP(mp1)) {
  8439. //      WinSendMsg(WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW,
  8440. //                 (MPARAM)hwnd, (MPARAM)hwnd);
  8441. //    } else {
  8442. //      // clear active help window when this window is deactivated - this is
  8443. //      // necessary for message box help, etc. to work properly
  8444. //      WinSendMsg(WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW,
  8445. //                 NULLHANDLE, NULLHANDLE);
  8446. //    } /* endif */
  8447. //    return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8448.  
  8449.     case GETTING_FOCUS:
  8450.        WinSetFocus( HWND_DESKTOP, WinWindowFromID( hwnd, IDC_UCMNBP0END ) );
  8451.      break;
  8452.  
  8453.     case WM_COMMAND:
  8454.       switch (SHORT1FROMMP(mp1)) {
  8455.         case IDB_UCMNBP0UNDO:
  8456.              {
  8457.                 PUCMDATA UCMData;
  8458.                 UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  8459.                 UCMenuNBP0Initialize(UCMData, hwnd);
  8460.              }
  8461.              break;
  8462.  
  8463.         // (MAM) removed OK and CANCEL processing
  8464.  
  8465.       } /* endswitch */
  8466.       break;
  8467.  
  8468.     case WM_HELP:
  8469.       switch (SHORT1FROMMP(mp1)) {
  8470.       case IDB_UCMNBP0HELP:
  8471.          {
  8472.             PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER);
  8473.             UCMenuDisplayHelp( UCMData,
  8474.                        (USHORT)PANEL_ITEMPOS,
  8475.                        (USHORT) UCN_HLP_NB_CREATE);
  8476.          }
  8477.          break;
  8478.       default:
  8479.         return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8480.         break;
  8481.       } // endswitch
  8482.       break;
  8483.  
  8484.     default:
  8485.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  8486.  
  8487.   } // endswitch
  8488.   return (MRESULT)0;
  8489. }
  8490. #endif
  8491.  
  8492. #if defined(UCMUI)
  8493. //----------------------------------------------------------------------------
  8494. // UCMenuNBP0Initialize : Not for the user's doc
  8495. //----------------------------------------------------------------------------
  8496. // :pfunction res=&IDF_INITPG0. name='UCMenuNBP0Initialize' text='Initializes the page 0 of the settings notebook' .
  8497. // This function initializes the page 0 of the settings notebook
  8498. // :syntax name='UCMenuNBP0Initialize' params='UCMData, hwnd' return='-' .
  8499. // :fparams.
  8500. // :fparam name='UCMData' type='PUCMDATA' io='input' .
  8501. // Pointer to the UCMDATA structure
  8502. // :fparam name='hwnd' type='HWND' io='input' .
  8503. // Page 0 window handle.
  8504. // :freturns.
  8505. // :fparam name='-' type='VOID' io='-'.
  8506. // Nothing
  8507. // :efparams.
  8508. // :remarks.
  8509. // :related.
  8510. // :epfunction.
  8511. //----------------------------------------------------------------------------
  8512.  
  8513. VOID  _Optlink UCMenuNBP0Initialize(PUCMDATA UCMData, HWND hwnd)
  8514. {
  8515.    if (!(UCMData->ContextID)) {
  8516.      /*┌──────────────────────────────────────────────────────────────┐
  8517.        │ No context ID means no item is selected. So the only place   │
  8518.        │ we can insert the item is the end. We don't need the 2       │
  8519.        │ buttons : we hide them.                                      │
  8520.        └──────────────────────────────────────────────────────────────┘*/
  8521.      WinShowWindow(WinWindowFromID(hwnd, IDC_UCMNBP0AFTER), FALSE);
  8522.      WinShowWindow(WinWindowFromID(hwnd, IDC_UCMNBP0BEFORE), FALSE);
  8523.    } /* endif */
  8524.    WinSendMsg(WinWindowFromID(hwnd, IDC_UCMNBP0END), BM_SETCHECK, (MPARAM)1, (MPARAM)0);
  8525.    WinSendMsg(WinWindowFromID(hwnd, IDC_UCMNBP0REGULAR), BM_SETCHECK, (MPARAM)1, (MPARAM)0);
  8526. }
  8527. #endif
  8528.  
  8529. #if defined(UCMUI)
  8530. //----------------------------------------------------------------------------
  8531. // UCMenuNBP1OK : Not for the user's doc
  8532. //----------------------------------------------------------------------------
  8533. // :pfunction res=&IDF_NBPG1OK. name='UCMenuNBP1OK' text='Processes the OK button for the page 1' .
  8534. // This function processes the OK button for the page 1 of the settings notebook
  8535. // :syntax name='UCMenuNBP1OK' params='hwnd' return='-' .
  8536. // :fparams.
  8537. // :fparam name='hwnd' type='HWND' io='input' .
  8538. // Page 1 window handle.
  8539. // :freturns.
  8540. // :fparam name='-' type='VOID' io='-'.
  8541. // Nothing
  8542. // :efparams.
  8543. // :remarks.
  8544. // :related.
  8545. // :epfunction.
  8546. //----------------------------------------------------------------------------
  8547. VOID  _Optlink UCMenuNBP1OK(HWND hwnd)
  8548. { MENUITEM mi;
  8549.   ULONG ulLen;
  8550.   PSZ   pszTitle;
  8551.   PUCMDATA UCMData;
  8552.  
  8553.   UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  8554.  
  8555.   /*┌──────────────────────┐
  8556.     │ Query the item data  │
  8557.     └──────────────────────┘*/
  8558.   memset(&mi, 0, sizeof(MENUITEM));
  8559.   WinSendMsg(UCMData->hwndCMOrig,
  8560.              MM_QUERYITEM,
  8561.              MPFROM2SHORT(UCMData->ContextID, TRUE),
  8562.              MPFROMP(&mi));
  8563.  
  8564.   /*┌──────────────────────┐
  8565.     │ Query the text       │
  8566.     └──────────────────────┘*/
  8567.   ulLen = WinQueryDlgItemTextLength(hwnd, IDC_UCMNBP1TITLE);
  8568.   if (ulLen) {
  8569.     pszTitle = MyMalloc(ulLen+1);
  8570.     if (pszTitle) {
  8571.       WinQueryDlgItemText(hwnd,
  8572.                           IDC_UCMNBP1TITLE,
  8573.                           ulLen+1,
  8574.                           pszTitle);
  8575.       /*┌──────────────────────┐
  8576.         │ Set the item text    │
  8577.         └──────────────────────┘*/
  8578.       if (mi.hItem) {
  8579.          if ( !ITEM(&mi,pszText) || strcmp(ITEM(&mi,pszText),pszTitle) ) {
  8580.             WinSendMsg( WinQueryWindow(UCMData->hwndTemp, QW_OWNER),
  8581.                     WM_CONTROL,
  8582.                     MPFROM2SHORT( WinQueryWindowUShort( UCMData->hwndTemp, QWS_ID ), UCN_TEXT ),
  8583.                     MPFROMSHORT( mi.id ) );
  8584.          } // endif
  8585.  
  8586.         if (ITEM(&mi, pszText)) {
  8587.           PSZ OldText = ITEM(&mi, pszText);
  8588.           PSZ StrPtr;
  8589.           if(StrPtr=strstr(OldText, "~")) {
  8590.              RemoveAccelItem(UCMData, StrPtr[1]);
  8591.           }
  8592.           MyFree(ITEM(&mi, pszText));
  8593.         }
  8594.  
  8595.         ITEM(&mi, pszText) = pszTitle;
  8596.         if(pszTitle && pszTitle[0]){
  8597.            PSZ StrPtr;
  8598.            if(StrPtr = strstr(pszTitle, "~")) {
  8599.               AddAccelItem(UCMData, StrPtr[1], UCMData->ContextID);
  8600.            }
  8601.         }
  8602.       } // endif
  8603.       //-- don't free pszTitle !
  8604.     } // endif
  8605.   } else {
  8606.       if (mi.hItem) {
  8607.         if (ITEM(&mi, pszText)) {
  8608.           PSZ OldText = ITEM(&mi, pszText);
  8609.           PSZ StrPtr;
  8610.           if(StrPtr=strstr(OldText, "~")) {
  8611.              RemoveAccelItem(UCMData, StrPtr[1]);
  8612.           }
  8613.           MyFree(ITEM(&mi, pszText));
  8614.         }
  8615.         ITEM(&mi, pszText) = 0;
  8616.      } // endif mi.hItem
  8617.   } // endif ulLen
  8618.  
  8619.   /*┌──────────────────────┐
  8620.     │ Go for the bitmap now│
  8621.     └──────────────────────┘*/
  8622.  
  8623.   /*┌────────────────────────────────────────┐
  8624.     │ Is there a filename set in the dialog ?│
  8625.     │ No means no bitmap is requested        │
  8626.     └────────────────────────────────────────┘*/
  8627.   ulLen = WinQueryDlgItemTextLength(hwnd, IDC_UCMNBP1FILENAME);
  8628.   if (ulLen) {
  8629.     PSZ pszBitmap = MyMalloc(ulLen+1);
  8630.  
  8631.     if (pszBitmap) {
  8632.       WinQueryDlgItemText(hwnd,
  8633.                           IDC_UCMNBP1FILENAME,
  8634.                           ulLen+1,
  8635.                           pszBitmap);
  8636.       if (ITEM(&mi, pszBmp)) {
  8637.          MyFree(ITEM(&mi, pszBmp));
  8638.       } // endif
  8639.       ITEM(&mi, pszBmp) = pszBitmap;
  8640.     } // endif
  8641.  
  8642.     if (ITEM(&mi,hBmp)!=UCMData->hBmpTemp) {
  8643.        WinSendMsg( WinQueryWindow( UCMData->hwndTemp, QW_OWNER ),
  8644.                    WM_CONTROL,
  8645.                    MPFROM2SHORT( WinQueryWindowUShort( UCMData->hwndTemp, QWS_ID ), UCN_BITMAP ),
  8646.                    MPFROMSHORT( mi.id) );
  8647.     } // endif
  8648.  
  8649.     ITEM(&mi, hBmp)   =  UCMData->hBmpTemp;
  8650.     if ( UCMData->bBmpTempFromFile ){
  8651.        ITEM( &mi, ulFlags ) |= UCMI_BMPFROMFILE;
  8652.     } else {
  8653.        ITEM( &mi, ulFlags ) &= ~UCMI_BMPFROMFILE;
  8654.     } // endif
  8655.   } else {
  8656.       if (ITEM(&mi, pszBmp)) {
  8657.          MyFree(ITEM(&mi, pszBmp));
  8658.       } // endif
  8659.       ITEM(&mi, pszBmp) = 0;
  8660.  
  8661.     if (ITEM(&mi,hBmp)!=UCMData->hBmpTemp) {
  8662.        WinSendMsg( WinQueryWindow( UCMData->hwndTemp, QW_OWNER ),
  8663.                    WM_CONTROL,
  8664.                    MPFROM2SHORT( WinQueryWindowUShort( UCMData->hwndTemp, QWS_ID ), UCN_BITMAP ),
  8665.                    MPFROMSHORT( mi.id) );
  8666.     } // endif
  8667.  
  8668.     ITEM(&mi, hBmp)   =  0;
  8669.     if ( UCMData->bBmpTempFromFile ){
  8670.        ITEM( &mi, ulFlags ) |= UCMI_BMPFROMFILE;
  8671.     } else {
  8672.        ITEM( &mi, ulFlags ) &= ~UCMI_BMPFROMFILE;
  8673.     } // endif
  8674.   } // endif
  8675.   /*┌──────────────────────┐
  8676.     │ Set the item back    │
  8677.     └──────────────────────┘*/
  8678.   WinSendMsg(UCMData->hwndCMOrig,
  8679.              MM_SETITEM,
  8680.              MPFROM2SHORT(0, TRUE),
  8681.              MPFROMP(&mi));
  8682. }
  8683. #endif
  8684.  
  8685. #if defined(UCMUI)
  8686. //----------------------------------------------------------------------------
  8687. // UCMenuNBP2OK : Not for the user's doc
  8688. //----------------------------------------------------------------------------
  8689. // :pfunction res=&IDF_NBPG2OK. name='UCMenuNBP2OK' text='Processes the OK button for the page 2' .
  8690. // This function processes the OK button for the page 2 of the settings notebook
  8691. // :syntax name='UCMenuNBP2OK' params='hwnd' return='-' .
  8692. // :fparams.
  8693. // :fparam name='hwnd' type='HWND' io='input' .
  8694. // Page 2 window handle.
  8695. // :freturns.
  8696. // :fparam name='-' type='VOID' io='-'.
  8697. // Nothing
  8698. // :efparams.
  8699. // :remarks.
  8700. // :related.
  8701. // :epfunction.
  8702. //----------------------------------------------------------------------------
  8703. VOID  _Optlink UCMenuNBP2OK(HWND hwnd)
  8704. {
  8705.   PSZ      pszFunction, pszParams;
  8706.   MENUITEM mi;
  8707.   ULONG    ulLen1, ulLen2;
  8708.   PUCMDATA UCMData;
  8709.  
  8710.   UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  8711.  
  8712.   /*┌──────────────────────────────────────────────────────────────┐
  8713.     │ We query the function selected by the user and the params    │
  8714.     └──────────────────────────────────────────────────────────────┘*/
  8715.   ulLen1 = WinQueryDlgItemTextLength(hwnd, IDC_UCMNBP2FLIST) + 1;
  8716.   pszFunction = MyMalloc(ulLen1);
  8717.   ulLen2 = WinQueryDlgItemTextLength(hwnd, IDC_UCMNBP2PARAMS) + 1;
  8718.   pszParams = MyMalloc(ulLen2);
  8719.   if (pszFunction) {
  8720.     WinQueryDlgItemText(hwnd,
  8721.                         IDC_UCMNBP2FLIST,
  8722.                         ulLen1,
  8723.                         pszFunction);
  8724.     if (pszParams) {
  8725.       WinQueryDlgItemText(hwnd,
  8726.                           IDC_UCMNBP2PARAMS,
  8727.                           ulLen2,
  8728.                           pszParams);
  8729.     } /* endif */
  8730.     memset(&mi, 0, sizeof(MENUITEM));
  8731.     //-- Query item
  8732.     WinSendMsg(UCMData->hwndCMOrig,
  8733.                MM_QUERYITEM,
  8734.                MPFROM2SHORT(UCMData->ContextID, TRUE),
  8735.                MPFROMP(&mi));
  8736.  
  8737.     if ( !ITEM(&mi,pszAction) || strcmp(ITEM(&mi,pszAction),pszFunction) ) {
  8738.        WinSendMsg( WinQueryWindow(UCMData->hwndTemp, QW_OWNER),
  8739.                WM_CONTROL,
  8740.                MPFROM2SHORT( WinQueryWindowUShort( UCMData->hwndTemp, QWS_ID ), UCN_ACTION ),
  8741.                MPFROMSHORT( mi.id ) );
  8742.     } // endif
  8743.  
  8744.     if (ITEM(&mi, pszAction)){
  8745.        MyFree (ITEM(&mi, pszAction));
  8746.     }
  8747.     if (ITEM(&mi, pszParameters)){
  8748.        MyFree (ITEM(&mi, pszParameters));
  8749.     }
  8750.  
  8751.     ITEM(&mi, pszAction) = pszFunction;
  8752.     ITEM(&mi, pszParameters) = pszParams;
  8753.     WinSendMsg(UCMData->hwndCMOrig,
  8754.                MM_SETITEM,
  8755.                MPFROM2SHORT(0, TRUE),
  8756.                MPFROMP(&mi));
  8757.   } // endif
  8758. }
  8759. #endif
  8760.  
  8761. #if defined(UCMUI)
  8762. //----------------------------------------------------------------------------
  8763. // UCMenuStyleDlgProc
  8764. //----------------------------------------------------------------------------
  8765. // :pfunction res=&IDF_STYLEDLGPROC. name='UCMenuStyleDlgProc' text='Style dialog procedure'.
  8766. // Dialog procedure of the style dialog
  8767. // :syntax name='UCMenuStyleDlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  8768. // :fparams.
  8769. // :fparam name='hwnd' type='HWND' io='input' .
  8770. // Style dialog window handle
  8771. // :fparam name='msg' type='ULONG' io='input' .
  8772. // Message
  8773. // :fparam name='mp1' type='MPARAM' io='input'.
  8774. // First parameter
  8775. // :fparam name='mp2' type='MPARAM' io='input'.
  8776. // Second parameter
  8777. // :freturns.
  8778. // :fparam name='mresult' type='MRESULT' io='return'.
  8779. // Return code of a PM message.
  8780. // :efparams.
  8781. // :remarks.
  8782. // :epfunction.
  8783. //----------------------------------------------------------------------------
  8784. MRESULT EXPENTRY  UCMenuStyleDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  8785. {
  8786.   switch (msg) {
  8787.     case WM_INITDLG:
  8788.       {
  8789.          PUCMDATA UCMData = (PUCMDATA)mp2;
  8790.  
  8791.          // Store UCMData in the user field of the dialog
  8792.          WinSetWindowULong(hwnd, QWL_USER, (ULONG)UCMData);
  8793.          InitializeStyleDlg(UCMData, hwnd);
  8794.  
  8795. //       if ( UCMData->hwndHelpInstance ) {
  8796. //          // -------------------------------------------------
  8797. //          // -- The contextual help would work without that
  8798. //          // -- We do it so that the focus goes back on this
  8799. //          // -- dialog after a contextual help invoked from it
  8800. //          // -- has been dismissed ( else the focus goes back
  8801. //          // -- to the closest winassociated window in the
  8802. //          // -- parent and owner chain )
  8803. //          // -------------------------------------------------
  8804. //          WinAssociateHelpInstance( UCMData->hwndHelpInstance, hwnd );
  8805. //       } // endif
  8806.       }
  8807.       break;
  8808.  
  8809.     case WM_CONTROL:
  8810.        switch (SHORT1FROMMP(mp1)) {
  8811.           case IDC_UCMNSTLFORCESIZE:
  8812.           {
  8813.              USHORT usChkst;
  8814.  
  8815.              // This checkbox used to have the opposite effect
  8816.              usChkst     = !WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLFORCESIZE);
  8817.  
  8818.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCX),
  8819.                                usChkst?TRUE:FALSE);
  8820.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCY),
  8821.                                usChkst?TRUE:FALSE);
  8822.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCXLABEL),
  8823.                                usChkst?TRUE:FALSE);
  8824.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCYLABEL),
  8825.                                usChkst?TRUE:FALSE);
  8826.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLIGNORE),
  8827.                                usChkst?TRUE:FALSE);
  8828.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLOR),
  8829.                                usChkst?TRUE:FALSE);
  8830.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLAND),
  8831.                                usChkst?TRUE:FALSE);
  8832.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLBOX),
  8833.                                usChkst?TRUE:FALSE);
  8834.  
  8835.           }
  8836.           break;
  8837.           case IDC_UCMNSTLBUBBLE:
  8838.           {
  8839.              USHORT usChkst;
  8840.  
  8841.              usChkst     = WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLBUBBLE);
  8842.  
  8843.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLDELAY),
  8844.                                usChkst?TRUE:FALSE);
  8845.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLREAD),
  8846.                                usChkst?TRUE:FALSE);
  8847.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLDELAYLABEL),
  8848.                                usChkst?TRUE:FALSE);
  8849.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLREADLABEL),
  8850.                                usChkst?TRUE:FALSE);
  8851.              WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLMSECLABEL),
  8852.                                usChkst?TRUE:FALSE);
  8853.  
  8854.           }
  8855.           break;
  8856.        }
  8857.        break;
  8858.     case WM_COMMAND:
  8859.       switch (SHORT1FROMMP(mp1)) {
  8860.         case IDB_UCMNSTLOK:
  8861.           UCMenuStyleDlgOK(hwnd);
  8862.           WinDismissDlg( hwnd, TRUE );
  8863.           return (MRESULT)0;
  8864.         case IDB_UCMNSTLCANCEL:
  8865.           WinDismissDlg(hwnd, FALSE);
  8866.           break;
  8867.       } // endswitch
  8868.       break;
  8869.  
  8870.     case WM_HELP:
  8871.       switch (SHORT1FROMMP(mp1)) {
  8872.       case IDB_UCMNSTLHELP:
  8873.          {
  8874.             PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER);
  8875.             UCMenuDisplayHelp( UCMData,
  8876.                        (USHORT)PANEL_STYLE,
  8877.                        (USHORT)UCN_HLP_STYLE );
  8878.          }
  8879.          break;
  8880.       default:
  8881.         return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  8882.         break;
  8883.       } // endswitch
  8884.  
  8885.     default:
  8886.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  8887.  
  8888.   } /* endswitch */
  8889.   return (MRESULT)0;
  8890. }
  8891. #endif
  8892.  
  8893. #if defined(UCMUI)
  8894. //----------------------------------------------------------------------------
  8895. // UCMenuDisplayHelp : Not for the user's doc
  8896. //----------------------------------------------------------------------------
  8897. // :pfunction res=&IDF_DISPLAYHLP. name='UCMenuDisplayHelp' text='Pops up a help panel' .
  8898. // This function pops up a style dialog after eventually getting the help instance.
  8899. // :syntax name='UCMenuDisplayHelp' params='UCMData, PanelID, CustomID' return='-'.
  8900. // :fparams.
  8901. // :fparam name='UCMData' type='PUCMDATA' io='output.
  8902. // Pointer to the UCMDATA structure
  8903. // :fparam name='PanelID' type='USHORT' io='input' .
  8904. // ID of the panel to pop up.
  8905. // :fparam name='CustomID' type='USHORT' io='input' .
  8906. // ID ID posted to the owner with UCN_HLP_*  WM_CONTROL notification code in case of custom help.
  8907. // :freturns.
  8908. // :fparam name='-' type='VOID' io='-'.
  8909. // Nothing
  8910. // :efparams.
  8911. // :remarks.
  8912. // :related.
  8913. // :epfunction.
  8914. //----------------------------------------------------------------------------
  8915. VOID  _Optlink UCMenuDisplayHelp(PUCMDATA UCMData, USHORT usPanelID, USHORT usCustomID )
  8916. {
  8917.  
  8918.    if ( UCMData->Style & UCS_CUSTOMHLP ){
  8919.       WinSendMsg( UCMData->hwndOwner,
  8920.                   WM_CONTROL,
  8921.                   MPFROM2SHORT( UCMData->UCMenuID, usCustomID ),
  8922.                   (MPARAM)0 );
  8923.    } else {
  8924.       if ( !UCMData->hwndHelpInstance ) {
  8925.          HELPINIT      hmiHelpData;
  8926.  
  8927.          //-- Initialize the help
  8928.          hmiHelpData.cb                       = (ULONG) sizeof(HELPINIT);
  8929.          hmiHelpData.ulReturnCode             = 0L;
  8930.          hmiHelpData.pszTutorialName          = NULL;
  8931.  
  8932.          hmiHelpData.phtHelpTable             = NULL;
  8933.  
  8934.          hmiHelpData.hmodAccelActionBarModule = (HMODULE)NULL;
  8935.          hmiHelpData.idAccelTable             = 0L;
  8936.          hmiHelpData.idActionBar              = 0L;
  8937.          hmiHelpData.pszHelpWindowTitle       = nlsgetmessage( WinQueryAnchorBlock( UCMData->hwndMenu ), UCMData->hModUCM, NLS_UCMHLP, 0 );
  8938.  
  8939.          hmiHelpData.hmodHelpTableModule      = 0L;
  8940.  
  8941.          hmiHelpData.fShowPanelId             = 0L;
  8942.          hmiHelpData.pszHelpLibraryName       = "UCMENUS.HLP";
  8943.  
  8944.          UCMData->hwndHelpInstance = WinCreateHelpInstance( WinQueryAnchorBlock(UCMData->hwndOwner),
  8945.                                                             &hmiHelpData );
  8946.       } // endif
  8947.       if (UCMData->hwndHelpInstance) {
  8948.          WinSendMsg( UCMData->hwndHelpInstance,
  8949.                      HM_DISPLAY_HELP,
  8950.                      MPFROMSHORT( usPanelID ),
  8951.                      MPFROMSHORT( HM_RESOURCEID ));
  8952.       } // endif
  8953.    } // endif
  8954. }
  8955. #endif
  8956.  
  8957. #if defined(UCMUI)
  8958. //----------------------------------------------------------------------------
  8959. // InitializeStyleDlg : Not for the user's doc
  8960. //----------------------------------------------------------------------------
  8961. // :pfunction res=&IDF_INITSTYLDLG. name='InitializeStyleDlg' text='Initializes the style dialog' .
  8962. // This function initializes the style dialog
  8963. // :syntax name='InitializeStyleDlg' params='UCMData, hwnd' return='-'.
  8964. // :fparams.
  8965. // :fparam name='UCMData' type='PUCMDATA' io='output.
  8966. // Pointer to the UCMDATA structure
  8967. // :fparam name='hwnd' type='HWND' io='input' .
  8968. // Style dialog window handle.
  8969. // :freturns.
  8970. // :fparam name='-' type='VOID' io='-'.
  8971. // Nothing
  8972. // :efparams.
  8973. // :remarks.
  8974. // :related.
  8975. // :epfunction.
  8976. //----------------------------------------------------------------------------
  8977. VOID  _Optlink InitializeStyleDlg(PUCMDATA UCMData, HWND hwnd)
  8978. {
  8979.    RECTL rect;
  8980.  
  8981.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCX),
  8982.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8983.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCY),
  8984.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8985.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCXLABEL),
  8986.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8987.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLCYLABEL),
  8988.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8989.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLIGNORE),
  8990.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8991.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLOR),
  8992.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8993.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLAND),
  8994.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8995.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLBOX),
  8996.                      (UCMData->Style&UCS_FORCESIZE)?TRUE:FALSE);
  8997.  
  8998.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLDELAY),
  8999.                      (UCMData->Style&UCS_BUBBLEHELP)?TRUE:FALSE);
  9000.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLREAD),
  9001.                      (UCMData->Style&UCS_BUBBLEHELP)?TRUE:FALSE);
  9002.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLREADLABEL),
  9003.                      (UCMData->Style&UCS_BUBBLEHELP)?TRUE:FALSE);
  9004.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLDELAYLABEL),
  9005.                      (UCMData->Style&UCS_BUBBLEHELP)?TRUE:FALSE);
  9006.    WinEnableWindow(WinWindowFromID(hwnd, IDC_UCMNSTLMSECLABEL),
  9007.                      (UCMData->Style&UCS_BUBBLEHELP)?TRUE:FALSE);
  9008.  
  9009.    if (UCMData->Style&UCS_FORCESIZE) {
  9010.       rect.xLeft = 0;
  9011.       rect.xRight = UCMData->cx;
  9012.       rect.yBottom = 0;
  9013.       rect.yTop = UCMData->cy;
  9014.    } else {
  9015.       USHORT usItemID;
  9016.  
  9017.       if ( !( usItemID = UCMData->ContextID ) ) {
  9018.          usItemID = (USHORT)WinSendMsg( UCMData->hwndCMOrig, MM_ITEMIDFROMPOSITION, MPFROMSHORT(1), (MPARAM)0 );
  9019.       }  // endif
  9020.       if ( !WinSendMsg(UCMData->hwndCMOrig, MM_QUERYITEMRECT, MPFROM2SHORT( usItemID, TRUE ), MPFROMP( &rect ) ) ){
  9021.          rect.xLeft = 0;
  9022.          rect.xRight = UCMData->cx;
  9023.          rect.yBottom = 0;
  9024.          rect.yTop = UCMData->cy;
  9025.       } // endif
  9026.    } // endif
  9027.  
  9028.    WinSetDlgItemShort( hwnd, IDC_UCMNSTLCX, (USHORT)(rect.xRight - rect.xLeft), FALSE );
  9029.    WinSetDlgItemShort( hwnd, IDC_UCMNSTLCY, (USHORT)(rect.yTop - rect.yBottom), FALSE );
  9030.  
  9031.    WinSendDlgItemMsg(hwnd, IDC_UCMNSTLBUBBLE,
  9032.               BM_SETCHECK,
  9033.               (UCMData->Style&UCS_BUBBLEHELP) ? (MPARAM)1 : (MPARAM)0,
  9034.               (MPARAM)0);
  9035.  
  9036.    WinSetDlgItemShort(hwnd, IDC_UCMNSTLDELAY, UCMData->BubbleDelay, FALSE);
  9037.    WinSetDlgItemShort(hwnd, IDC_UCMNSTLREAD,  UCMData->BubbleRead,  FALSE);
  9038.  
  9039.    WinSendDlgItemMsg(hwnd, IDC_UCMNSTLFORCESIZE,
  9040.               BM_SETCHECK,
  9041.               (UCMData->Style&UCS_FORCESIZE) ? (MPARAM)0 : (MPARAM)1,
  9042.               (MPARAM)0);
  9043.    WinSendDlgItemMsg(hwnd, IDC_UCMNSTLTEXT,
  9044.               BM_SETCHECK,
  9045.               (UCMData->Style&UCS_NOTEXT) ? (MPARAM)0 : (MPARAM)1,
  9046.               (MPARAM)0);
  9047.    WinSendDlgItemMsg(hwnd, IDC_UCMNSTLFRAMED,
  9048.               BM_SETCHECK,
  9049.               (UCMData->Style&UCS_FRAMED) ? (MPARAM)1 : (MPARAM)0,
  9050.               (MPARAM)0);
  9051.    WinSendDlgItemMsg(hwnd, IDC_UCMNSTLIGNORE,
  9052.               BM_SETCHECK,
  9053.               (UCMData->Style&UCS_SHRINK_BLEND) ? (MPARAM)0 : (MPARAM)1,
  9054.               (MPARAM)0);
  9055.    if ( UCMData->Style&UCS_SHRINK_BLEND ) {
  9056.       WinSendDlgItemMsg(hwnd, IDC_UCMNSTLOR,
  9057.                  BM_SETCHECK,
  9058.                  (UCMData->Style&UCS_SHRINK_OR) ? (MPARAM)1 : (MPARAM)0,
  9059.                  (MPARAM)0);
  9060.       WinSendDlgItemMsg(hwnd, IDC_UCMNSTLAND,
  9061.                  BM_SETCHECK,
  9062.                  (UCMData->Style&UCS_SHRINK_OR) ? (MPARAM)0 : (MPARAM)1,
  9063.                  (MPARAM)0);
  9064.    } // endif
  9065. }
  9066. #endif
  9067.  
  9068. #if defined(UCMUI)
  9069. //----------------------------------------------------------------------------
  9070. // UCMenuStyleDlgOK : Not for the user's doc
  9071. //----------------------------------------------------------------------------
  9072. // :pfunction res=&IDF_STYLDLGOK. name='UCMenuStyleDlgOK' text='Processes the OK button for the style dialog' .
  9073. // This function processes the OK button for the style dialog
  9074. // :syntax name='UCMenuStyleDlgOK' params='hwnd' return='-'.
  9075. // :fparams.
  9076. // :fparam name='hwnd' type='HWND' io='input' .
  9077. // Style dialog window handle.
  9078. // :freturns.
  9079. // :fparam name='-' type='VOID' io='-'.
  9080. // Nothing
  9081. // :efparams.
  9082. // :remarks.
  9083. // :related.
  9084. // :epfunction.
  9085. //----------------------------------------------------------------------------
  9086. VOID  _Optlink UCMenuStyleDlgOK(HWND hwnd)
  9087. {
  9088.    USHORT usChkst;
  9089.    PUCMDATA UCMData;
  9090.    ULONG Style;
  9091.  
  9092.    UCMData = (PUCMDATA)WinQueryWindowULong(hwnd, QWL_USER);
  9093.    Style = UCMData->Style;
  9094.  
  9095.    usChkst = !WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLFORCESIZE);
  9096.    if (usChkst) {
  9097.       SHORT sC;
  9098.  
  9099.       Style |= UCS_FORCESIZE;
  9100.       WinQueryDlgItemShort( hwnd, IDC_UCMNSTLCX, &sC, FALSE );
  9101.       UCMData->cx = (sC>4)?((ULONG) sC):4lu;
  9102.       WinQueryDlgItemShort( hwnd, IDC_UCMNSTLCY, &sC, FALSE );
  9103.       UCMData->cy = (sC>10)?((ULONG) sC):10lu;
  9104.    } else {
  9105.       Style &= ~UCS_FORCESIZE;
  9106.    } // endif
  9107.  
  9108.    usChkst = WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLBUBBLE);
  9109.    if (usChkst) {
  9110.       SHORT sC;
  9111.  
  9112.       Style |= UCS_BUBBLEHELP;
  9113.       WinQueryDlgItemShort( hwnd, IDC_UCMNSTLDELAY, &sC, FALSE );
  9114.       UCMData->BubbleDelay = (ULONG) sC;
  9115.       WinQueryDlgItemShort( hwnd, IDC_UCMNSTLREAD, &sC, FALSE );
  9116.       UCMData->BubbleRead = (ULONG) sC;
  9117.    } else {
  9118.       Style &= ~UCS_BUBBLEHELP;
  9119.    } // endif
  9120.  
  9121.  
  9122.  
  9123.    usChkst = WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLTEXT);
  9124.    if (usChkst) {
  9125.       Style &= ~UCS_NOTEXT;
  9126.    } else {
  9127.       Style |= UCS_NOTEXT;
  9128.    } // endif
  9129.  
  9130.    usChkst = WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLFRAMED);
  9131.    if (usChkst) {
  9132.       Style |= UCS_FRAMED;
  9133.    } else {
  9134.       Style &= ~UCS_FRAMED;
  9135.    } // endif
  9136.  
  9137.    usChkst = WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLIGNORE);
  9138.    if (usChkst) {
  9139.       Style &= ~UCS_SHRINK_BLEND;
  9140.    } else {
  9141.       Style |= UCS_SHRINK_BLEND;
  9142.    } // endif
  9143.  
  9144.    usChkst = WinQueryButtonCheckstate(hwnd,IDC_UCMNSTLOR);
  9145.    if (usChkst) {
  9146.       Style |= UCS_SHRINK_OR;
  9147.    } else {
  9148.       Style &= ~UCS_SHRINK_OR;
  9149.    } // endif
  9150.  
  9151.    // Send message to update style:
  9152.    WinSendMsg(UCMData->hwndUCM, UCMENU_SETSTYLE, MPFROMLONG(Style), 
  9153.               MPFROM2SHORT(UCMData->cx, UCMData->cy));
  9154.  
  9155.    // Notify owner of change
  9156.    WinSendMsg( UCMData->hwndOwner,
  9157.                WM_CONTROL,
  9158.                MPFROM2SHORT( UCMData->UCMenuID, UCN_STYLE ),
  9159.                MPFROMSHORT( 0 ) );
  9160.  
  9161.    UCMenuUpdateMenu( UCMData->hwndMenu, TRUE );
  9162. }
  9163. #endif
  9164.  
  9165. //----------------------------------------------------------------------------
  9166. // UCMenuUpdateMenu : Not for the user's doc
  9167. //----------------------------------------------------------------------------
  9168. // :pfunction res=&IDF_UPDMENU. name='UCMenuUpdateMenu' text='Updates the display of the ucmenu' .
  9169. // This function refreshes the display of the UCMenu according to the latest changes
  9170. // :syntax name='UCMenuUpdateMenu' params='hwndMenu' return='-'.
  9171. // :fparams.
  9172. // :fparam name='hwndMenu' type='HWND' io='input' .
  9173. // Menu window handle.
  9174. // :freturns.
  9175. // :fparam name='-' type='VOID' io='-'.
  9176. // Nothing
  9177. // :efparams.
  9178. // :remarks.
  9179. // :related.
  9180. // :epfunction.
  9181. //----------------------------------------------------------------------------
  9182. VOID  _Optlink UCMenuUpdateMenu( HWND hwndMenu, BOOL UpdateSubmenus )
  9183. {
  9184.    MENUITEM mi;
  9185.    USHORT ItemID;
  9186.    ULONG Item, NumberOfItems;
  9187.    SWP    swp;
  9188.    PUCMDATA UCMData;
  9189.    ULONG OldMaxVerticalWidth;
  9190.    ULONG OldMaxHorizontalHeight;
  9191.    BOOL    UCMSizeChanged = 0;
  9192.    HWND hwndUCM = WinQueryWindow(hwndMenu, QW_OWNER);
  9193.    ULONG Style = WinQueryWindowULong(hwndUCM, QWL_STYLE);
  9194.  
  9195.    UCMData = (PUCMDATA)WinQueryWindowULong(hwndUCM,QWL_UCMDATA);
  9196.  
  9197.    /* If update is disabled by owner, don't do this */
  9198.    if (UCMData->DisableUpdate)
  9199.      return;
  9200.  
  9201.    //(MAM) Submenus must be updated if anything has changed that
  9202.    // could change the size of the submenu items (e.g. text on
  9203.    // a submenu item, forced size change, various style changes, etc).
  9204.    // Normally, PM asks for the size of submenu items only once (the
  9205.    // first time they are drawn) and assumes they nver change -- even
  9206.    // if the submenu is dismissed and re-started.  To trick PM into
  9207.    // resizing the submenu items, we make a no-affect change to the
  9208.    // presentation parameters.  When that happens, PM will send us
  9209.    // WM_MEASUREITEM messages again, giving us the chance to change the
  9210.    // item sizes. 
  9211.  
  9212.    if (UpdateSubmenus) {
  9213.      if (UCMData->pszFontNameSize != NULL)
  9214.        WinSetPresParam( UCMData->hwndMenu,
  9215.                       PP_FONTNAMESIZE,
  9216.                       strlen(UCMData->pszFontNameSize)+1,
  9217.                       UCMData->pszFontNameSize);
  9218.      else
  9219.        WinSetPresParam( UCMData->hwndMenu,
  9220.                       PP_FONTNAMESIZE,
  9221.                       strlen(UCM_DEFAULTFONT)+1,
  9222.                       UCM_DEFAULTFONT);
  9223.    }
  9224.  
  9225.    OldMaxHorizontalHeight = UCMData->MaxHorizontalHeight;
  9226.    OldMaxVerticalWidth    = UCMData->MaxVerticalWidth;
  9227.  
  9228.    NumberOfItems = (ULONG)WinSendMsg( hwndMenu,
  9229.                                      MM_QUERYITEMCOUNT, 0L, 0L);
  9230.    for(Item=0; Item<NumberOfItems; Item++) {
  9231.       ItemID = (USHORT)WinSendMsg(hwndMenu,
  9232.                                   MM_ITEMIDFROMPOSITION,
  9233.                                   MPFROMSHORT(Item),
  9234.                                   (MPARAM)0);
  9235.  
  9236.       WinSendMsg(hwndMenu,
  9237.                  MM_QUERYITEM,
  9238.                  MPFROM2SHORT(ItemID, TRUE),
  9239.                  MPFROMP(&mi));
  9240.  
  9241.       WinSendMsg(hwndMenu,
  9242.                  MM_SETITEM,
  9243.                  MPFROM2SHORT(0, TRUE),
  9244.                  MPFROMP(&mi));
  9245.    }
  9246.  
  9247.    GetMaxItemSize(UCMData, hwndUCM, hwndMenu);
  9248.  
  9249.    UCMenuSize(hwndMenu, Style);
  9250.  
  9251.    WinQueryWindowPos(UCMData->hwndUCM, &swp);
  9252.  
  9253.    if (Style & CMS_MATRIX) {
  9254.      USHORT Count, Rows;
  9255.      Count = (USHORT)WinSendMsg(hwndMenu, MM_QUERYITEMCOUNT, MPVOID, MPVOID);
  9256.      /* Calculate actual size of matrix menu */
  9257.      if ((Style & CMS_MATRIX_HORZ) != CMS_MATRIX_HORZ)
  9258.        swp.cx = min(Count,UCMData->NbOfCols) * UCMData->MaxVerticalWidth    + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  9259.  
  9260.      Rows = Count / max(1,UCMData->NbOfCols);  // Full rows (don't div by zero!)
  9261.      if ((Rows * UCMData->NbOfCols) < Count)   // Partial row?
  9262.        Rows++;
  9263.      if ((Style & CMS_MATRIX_VERT) != CMS_MATRIX_VERT)
  9264.        swp.cy = Rows * UCMData->MaxHorizontalHeight + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  9265.      /* This would be theoretical size based on num of rows and cols given by creator */
  9266. //   swp.cx = UCMData->MaxVerticalWidth    * UCMData->NbOfCols + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  9267. //   swp.cy = UCMData->MaxHorizontalHeight * UCMData->NbOfRows + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  9268.      if ((UCMData->MaxHorizontalHeight != OldMaxHorizontalHeight) ||
  9269.         (UCMData->MaxVerticalWidth != OldMaxVerticalWidth))
  9270.        UCMSizeChanged = 1;
  9271.     }
  9272.  
  9273.    if (Style & CMS_VERT ) {
  9274.      swp.cx = UCMData->MaxVerticalWidth + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  9275.      if (UCMData->MaxVerticalWidth != OldMaxVerticalWidth)
  9276.        UCMSizeChanged = 1;
  9277.    } /* endif */
  9278.  
  9279.    if (Style & CMS_HORZ) {
  9280.      swp.cy = UCMData->MaxHorizontalHeight + SUM_UCM_FRAME_THICK + SUM_MENU_FRAME_THICK;
  9281.      if (UCMData->MaxHorizontalHeight != OldMaxHorizontalHeight)
  9282.        UCMSizeChanged = 1;
  9283.    } /* endif */
  9284.  
  9285.    WinSetWindowPos(UCMData->hwndUCM, HWND_TOP, 0, 0, swp.cx, swp.cy, SWP_SIZE);
  9286.  
  9287.    /* Size change notification depends on style of the menu (horz style  */
  9288.    /* notifies only if vert dimension changes, vert style notifies only  */
  9289.    /* if horz dimension changes, matrix notifies if either change).      */
  9290.  
  9291.    if ( UCMSizeChanged ) {
  9292.       WinSendMsg( UCMData->hwndOwner,
  9293.                   WM_CONTROL,
  9294.                   MPFROM2SHORT( UCMData->UCMenuID, UCN_SIZE ),
  9295.                   MPFROMSHORT( 0 ) );
  9296.    } // endif
  9297.  
  9298.    UCMenuUnselectAll( hwndMenu );
  9299. }
  9300.  
  9301.  
  9302. //----------------------------------------------------------------------------
  9303. // UCMenuUnselectAll : Not for the user's doc
  9304. //----------------------------------------------------------------------------
  9305. // :pfunction res=&IDF_UNSELALL. name='UCMenuUnselectAll' text='Unselects all the item of a menu' .
  9306. // This function unselects all the items of a menu and closes the open submenus
  9307. // :syntax name='UCMenuUnselectAll' params='hwndMenu' return='-'.
  9308. // :fparams.
  9309. // :fparam name='hwndMenu' type='HWND' io='input' .
  9310. // Menu window handle.
  9311. // :freturns.
  9312. // :fparam name='-' type='VOID' io='-'.
  9313. // Nothing
  9314. // :efparams.
  9315. // :remarks.
  9316. // :related.
  9317. // :epfunction.
  9318. //----------------------------------------------------------------------------
  9319. VOID _Optlink    UCMenuUnselectAll(HWND hwndMenu)
  9320. {
  9321.    WinSendMsg( hwndMenu, MM_SELECTITEM, MPFROM2SHORT( MIT_NONE, TRUE ), MPFROM2SHORT( 0, TRUE ));
  9322. }
  9323.  
  9324. //----------------------------------------------------------------------------
  9325. // UCMenuGetNewID : Not for the user's doc
  9326. //----------------------------------------------------------------------------
  9327. // :pfunction res=&IDF_NEWID. name='UCMenuGetNewID' text='Get an unused menu ID' .
  9328. // This function returns an unused menu ID
  9329. // :syntax name='UCMenuGetNewID' params='hwndMenu, sID, UCMData' return='ID'.
  9330. // :fparams.
  9331. // :fparam name='hwndMenu' type='HWND' io='input' .
  9332. // Menu window handle.
  9333. // :fparam name='sID' type='SHORT' io='input' .
  9334. // ID used if it doesn't exist already, or MIT_NONE
  9335. // :fparam name='UCMData' type='PUCMDATA' io='input' .
  9336. // UCMData structure associated to the menu, it may not be yet in the QWL_USER
  9337. // :freturns.
  9338. // :fparam name='ID' type='USHORT' io='return'.
  9339. // Max of the IDs + 1 or min - 1 or 0 if failed
  9340. // :efparams.
  9341. // :remarks.
  9342. // :related.
  9343. // :epfunction.
  9344. //----------------------------------------------------------------------------
  9345. USHORT _Optlink UCMenuGetNewID(HWND hwndMenu, SHORT sID, PUCMDATA UCMData)
  9346. {
  9347.   USHORT   NbOfItems=0, ItemID=0, usIndex=0;
  9348.   MENUITEM mi;
  9349.   BOOL     bIDFound;
  9350.  
  9351.   if ( sID == MIT_NONE ){
  9352.      bIDFound = TRUE;
  9353.   } else {
  9354.      bIDFound = FALSE;
  9355.   } // endif
  9356.  
  9357.   memset(&mi, 0, sizeof(MENUITEM));
  9358.  
  9359.   /*┌────────────────────────────────┐
  9360.     │ Query the Number of menu items │
  9361.     └────────────────────────────────┘*/
  9362.   NbOfItems = (USHORT)WinSendMsg(hwndMenu,
  9363.                                  MM_QUERYITEMCOUNT,
  9364.                                  (MPARAM)0,
  9365.                                  (MPARAM)0);
  9366.  
  9367.   for (usIndex=0 ; usIndex<NbOfItems ; usIndex++) {
  9368.     /*┌───────────────────┐
  9369.       │ Query the item id │
  9370.       └───────────────────┘*/
  9371.     ItemID = (SHORT)WinSendMsg(hwndMenu,
  9372.                                MM_ITEMIDFROMPOSITION,
  9373.                                MPFROMSHORT(usIndex),
  9374.                                (MPARAM)0);
  9375.     if ( ItemID == sID ) {
  9376.        bIDFound = TRUE;
  9377.     } // endif
  9378.  
  9379.     /*┌───────────────────┐
  9380.       │ Get the max & min │
  9381.       └───────────────────┘*/
  9382.     if (ItemID>UCMData->MaxID && ItemID<0xFFF0)
  9383.       UCMData->MaxID = ItemID;
  9384.  
  9385.     if (ItemID<(UCMData->MinID) && ItemID>0) {
  9386.       UCMData->MinID = ItemID;
  9387.     } /* endif */
  9388.  
  9389.     /*┌───────────────────┐
  9390.       │ Submenu ?         │
  9391.       └───────────────────┘*/
  9392.     WinSendMsg(hwndMenu,
  9393.                MM_QUERYITEM,
  9394.                MPFROM2SHORT(ItemID, FALSE),
  9395.                MPFROMP(&mi));
  9396.  
  9397.     if (mi.hwndSubMenu) {
  9398.       /*┌───────────────────┐
  9399.         │ recursive call    │
  9400.         └───────────────────┘*/
  9401.       USHORT usSubMenuFound = UCMenuGetNewID( mi.hwndSubMenu, sID, UCMData );
  9402.       if ( (LONG)usSubMenuFound != (LONG)sID ){
  9403.          bIDFound = TRUE;
  9404.       } // endif
  9405.     } /* endif */
  9406.   } /* endfor */
  9407.  
  9408.   if ( !bIDFound ) {
  9409.      return sID;
  9410.   } // endif
  9411.  
  9412.   if (UCMData->MaxID < 0xFFF0) {
  9413.     ItemID = UCMData->MaxID + 1;
  9414.   } else
  9415.   if (UCMData->MinID > 1) {
  9416.     ItemID = UCMData->MinID - 1;
  9417.   } else {
  9418.     ItemID = 0;
  9419.   } /* endif */
  9420.   return (ItemID);
  9421. }
  9422.  
  9423. #if defined(UCMUI)
  9424. //----------------------------------------------------------------------------
  9425. // UCMenuNBP0OK : Not for the user's doc
  9426. //----------------------------------------------------------------------------
  9427. // :pfunction res=&IDF_NBPG0OK. name='UCMenuNBP0OK' text='Processes the OK button for the page 0' .
  9428. // This function processes the OK button for the page 0 of the settings notebook
  9429. // :syntax name='UCMenuNBP0OK' params='hwndPage' return='-' .
  9430. // :fparams.
  9431. // :fparam name='hwndPage' type='HWND' io='input' .
  9432. // Page 0 window handle.
  9433. // :freturns.
  9434. // :fparam name='-' type='BOOL' io='-'.
  9435. // True if processed OK.
  9436. // :efparams.
  9437. // :remarks.
  9438. // :related.
  9439. // :epfunction.
  9440. //----------------------------------------------------------------------------
  9441. BOOL _Optlink UCMenuNBP0OK(HWND hwndPage)
  9442. {
  9443.   MENUITEM mi, oldmi;
  9444.   USHORT   usState = 0;
  9445.   PUCMDATA UCMData;
  9446.  
  9447.   UCMData = (PUCMDATA)WinQueryWindowULong(hwndPage, QWL_USER);
  9448.  
  9449.   memset(&mi, 0, sizeof(MENUITEM));
  9450.  
  9451.   /*┌──────────────────────────────────────────────────────────────┐
  9452.     │ Query the state of the check box                             │
  9453.     └──────────────────────────────────────────────────────────────┘*/
  9454.   usState = (USHORT)WinSendDlgItemMsg(UCMData->hwndPage0,
  9455.                                       IDC_UCMNBP0STATIC,
  9456.                                       BM_QUERYCHECK,
  9457.                                       (MPARAM)0,
  9458.                                       (MPARAM)0);
  9459.   if ( usState ){
  9460.      mi.afStyle = MIS_STATIC | MIS_OWNERDRAW;
  9461.   } else {
  9462.      usState = (USHORT)WinSendDlgItemMsg(UCMData->hwndPage0,
  9463.                                          IDC_UCMNBP0REGULAR,
  9464.                                          BM_QUERYCHECK,
  9465.                                          (MPARAM)0,
  9466.                                          (MPARAM)0);
  9467.      if ( usState ) {
  9468.         mi.afStyle = MIS_OWNERDRAW;
  9469.      } else {
  9470.         mi.afStyle = ( MIS_SPACER | MIS_OWNERDRAW ) & ~MIS_TEXT;
  9471.      } // endif
  9472.   } // endif
  9473.  
  9474.   /*┌──────────────────────────────────────────────────────────────┐
  9475.     │ Query the position                                           │
  9476.     └──────────────────────────────────────────────────────────────┘*/
  9477.   WinSendMsg(UCMData->hwndTemp,
  9478.              MM_QUERYITEM,
  9479.              MPFROM2SHORT(UCMData->ContextID, TRUE),
  9480.              MPFROMP(&oldmi));
  9481.  
  9482.   usState = (USHORT)WinSendDlgItemMsg(UCMData->hwndPage0,
  9483.                                       IDC_UCMNBP0END,
  9484.                                       BM_QUERYCHECK,
  9485.                                       (MPARAM)0,
  9486.                                       (MPARAM)0);
  9487.   if (usState) {
  9488.     mi.iPosition = MIT_END;
  9489.   } else {
  9490.     usState = (USHORT)WinSendDlgItemMsg(UCMData->hwndPage0,
  9491.                                         IDC_UCMNBP0AFTER,
  9492.                                         BM_QUERYCHECK,
  9493.                                         (MPARAM)0,
  9494.                                         (MPARAM)0);
  9495.     if (usState) {
  9496.       mi.iPosition = oldmi.iPosition + 1;
  9497.     } else {
  9498.       mi.iPosition = oldmi.iPosition;
  9499.     } // endif
  9500.   } // endif
  9501.  
  9502.   /*┌──────────────────────────────────────────────────────────────┐
  9503.     │ Query the item ID                                            │
  9504.     │ We actually have to find an unused one.                      │
  9505.     └──────────────────────────────────────────────────────────────┘*/
  9506.   UCMData->MaxID = 0;
  9507.   UCMData->MinID = 0xFFFF;
  9508.   mi.id = UCMenuGetNewID( UCMData->hwndMenu, MIT_NONE, UCMData ) + 1;
  9509.  
  9510.   /*┌─────────────────────────────────┐
  9511.     │Create the item handle structure │
  9512.     └─────────────────────────────────┘*/
  9513.   mi.hItem = (LONG)MyMalloc(sizeof(UCMITEM));
  9514.   if (mi.hItem) {
  9515.     ULONG ulLen;
  9516.  
  9517.     memset((PVOID)mi.hItem, 0, sizeof(UCMITEM));
  9518.  
  9519.     /*┌─────────────────────────────────┐
  9520.       │ Query title text                │
  9521.       └─────────────────────────────────┘*/
  9522.     ulLen = WinQueryDlgItemTextLength(UCMData->hwndPage1, IDC_UCMNBP1TITLE);
  9523.     if (ulLen) {
  9524.       PSZ pszTitle = MyMalloc(ulLen+1);
  9525.       if (pszTitle) {
  9526.         PSZ StrPtr;
  9527.         WinQueryDlgItemText(UCMData->hwndPage1,
  9528.                             IDC_UCMNBP1TITLE,
  9529.                             ulLen+1,
  9530.                             pszTitle);
  9531.         ITEM(&mi, pszText) = pszTitle;
  9532.         if(StrPtr = strstr(pszTitle, "~")) {
  9533.            if(StrPtr[1]) {
  9534.               AddAccelItem(UCMData, StrPtr[1], mi.id);
  9535.            }
  9536.         }
  9537.       } /* endif */
  9538.     } /* endif */
  9539.  
  9540.     /*┌─────────────────────────────────┐
  9541.       │ Go for the bitmap               │
  9542.       └─────────────────────────────────┘*/
  9543.  
  9544.     //---- Is there a file name specified in the dialog ?
  9545.     ulLen = WinQueryDlgItemTextLength(UCMData->hwndPage1, IDC_UCMNBP1FILENAME);
  9546.     if (ulLen) {
  9547.       PSZ pszBitmap = MyMalloc(ulLen+1);
  9548.  
  9549.       if (pszBitmap) {
  9550.         WinQueryDlgItemText(UCMData->hwndPage1,
  9551.                             IDC_UCMNBP1FILENAME,
  9552.                             ulLen+1,
  9553.                             pszBitmap);
  9554.         ITEM(&mi, pszBmp) = pszBitmap;
  9555.       } /* endif */
  9556.       ITEM(&mi, hBmp)    = UCMData->hBmpTemp;
  9557.       if ( UCMData->bBmpTempFromFile ){
  9558.          ITEM( &mi, ulFlags ) |= UCMI_BMPFROMFILE;
  9559.       } else {
  9560.          ITEM( &mi, ulFlags ) &= ~UCMI_BMPFROMFILE;
  9561.       } // endif
  9562.     } /* endif */
  9563.  
  9564.     /*┌─────────────────────────────────┐
  9565.       │ Go for the action               │
  9566.       └─────────────────────────────────┘*/
  9567.     if ( ! ( mi.afStyle & MIS_SPACER ) ){
  9568.       // We don't want any actions associated with spacer items
  9569.       PSZ      pszFunction, pszParams;
  9570.       ULONG    ulLen1, ulLen2;
  9571.  
  9572.       ulLen1 = WinQueryDlgItemTextLength(UCMData->hwndPage2, IDC_UCMNBP2FLIST) + 1;
  9573.       ulLen2 = WinQueryDlgItemTextLength(UCMData->hwndPage2, IDC_UCMNBP2PARAMS) + 1;
  9574.       pszFunction = MyMalloc(ulLen1);
  9575.       pszParams   = MyMalloc(ulLen2);
  9576.       if (pszFunction) {
  9577.          WinQueryDlgItemText( UCMData->hwndPage2,
  9578.                               IDC_UCMNBP2FLIST,
  9579.                               ulLen1,
  9580.                               pszFunction );
  9581.          if (pszParams) {
  9582.             WinQueryDlgItemText( UCMData->hwndPage2,
  9583.                                  IDC_UCMNBP2PARAMS,
  9584.                                  ulLen2,
  9585.                                  pszParams );
  9586.          } // endif
  9587.  
  9588.          ITEM(&mi, pszAction) = pszFunction;
  9589.          ITEM(&mi, pszParameters) = pszParams;
  9590.  
  9591.       } /* endif */
  9592.  
  9593.     } // endif
  9594.   } /* endif */
  9595.  
  9596.  
  9597.   ITEM(&mi, pszData) = NULL;
  9598.  
  9599.   //-- Last check-up before adding item :
  9600.   /*┌──────────────────────────────────────┐
  9601.     │ Last check-up before we add the item │
  9602.     └──────────────────────────────────────┘*/
  9603.   if (mi.hItem && ((ITEM(&mi, hBmp) && ITEM(&mi, pszBmp))||ITEM(&mi,pszText)||(mi.afStyle & MIS_SPACER))) {
  9604.      WinSendMsg(UCMData->hwndCMOrig,
  9605.                 MM_INSERTITEM,
  9606.                 MPFROMP(&mi),
  9607.                 (MPARAM)0);
  9608.     return TRUE;
  9609.   } else {
  9610.        WinMessageBox(HWND_DESKTOP,
  9611.                      HWND_DESKTOP,
  9612.                      nlsgetmessage( WinQueryAnchorBlock( hwndPage ), UCMData->hModUCM, NLS_ITEMADDERROR, 0 ),
  9613.                      nlsgetmessage( WinQueryAnchorBlock( hwndPage ), UCMData->hModUCM, NLS_ERROR, 1 ),
  9614.                      0,
  9615.                      MB_OK | MB_ERROR | MB_APPLMODAL);
  9616.        return FALSE;
  9617.   } /* endif */
  9618. }
  9619. #endif
  9620.  
  9621. //----------------------------------------------------------------------------
  9622. // UCMenuExecuteProgram :
  9623. //----------------------------------------------------------------------------
  9624. // :pfunction res=&IDF_EXECPRGM. name='UCMenuExecuteProgram' text='Executes a program' .
  9625. // This function executes the specified .EXE
  9626. // :syntax name='UCMenuExecuteProgram' params='pszProgName' return='-' .
  9627. // :fparams.
  9628. // :fparam name='psz' type='PSZ' io='input' .
  9629. // String containing the name of the program, followed by some parameters.
  9630. // :freturns.
  9631. // :fparam name='-' type='VOID' io='-'.
  9632. // Nothing
  9633. // :efparams.
  9634. // :remarks.
  9635. // The program is executed synchronously in the same thread.
  9636. // :related.
  9637. // :epfunction.
  9638. //----------------------------------------------------------------------------
  9639. VOID _System UCMenuExecuteProgram(PSZ pszName)
  9640. {
  9641.   PSZ   pszAppli, pszParams;
  9642.   ULONG ulLen;
  9643.  
  9644.   if (pszName) {
  9645.     ulLen = strlen(pszName) + 2;
  9646.     pszParams = MyMalloc(ulLen);
  9647.     if (pszParams) {
  9648.       PSZ psz;
  9649.       strcpy(pszParams, pszName);
  9650.       MyFree( pszName );
  9651.       pszParams[ulLen-1] = '\0';
  9652.       psz = strchr(pszParams, ' ');
  9653.       if (psz) {
  9654.          *psz = '\0';
  9655.          pszAppli = MyStrdup(pszParams);
  9656.       } else {
  9657.          pszAppli = pszParams;
  9658.          pszParams = 0;
  9659.       } // endif
  9660.       if (pszAppli) {
  9661.         RESULTCODES res;
  9662.  
  9663.         DosExecPgm(NULL,
  9664.                    0,
  9665.                    EXEC_SYNC,
  9666.                    pszParams,
  9667.                    NULL,
  9668.                    &res,
  9669.                    pszAppli);
  9670.         MyFree(pszAppli);
  9671.       } /* endif */
  9672.       MyFree(pszParams);
  9673.     } /* endif */
  9674.   } /* endif */
  9675. }
  9676.  
  9677. #if defined(UCMUI)
  9678. //----------------------------------------------------------------------------
  9679. // UCMenuEditBmpFileT2
  9680. //----------------------------------------------------------------------------
  9681. // :pfunction res=&IDF_EDITBMPFILET2. name='UCMenuEditBmpFileT2' text='Edit a bitmap file' .
  9682. // This function starts iconedit with the provided bitmap file name.
  9683. // It is started by UCMenuEditBmpFile in a second thread.
  9684. // :syntax name='UCMenuEditBmpFileT2' params='pArgs' return='-' .
  9685. // :fparams.
  9686. // :fparam name='pArgs' type='PVOID' io='input' .
  9687. // Points to &colon.
  9688. // :dl compact.
  9689. // :dt.hwnd
  9690. // :dd.HWND, handle of the calling notebook page.
  9691. // :dt.pszFileName
  9692. // :dd.PSZ, bitmap file name, freed by UCMenuEditBmpFileT2.
  9693. // Freed by UCMenuEditBmpFileT2.
  9694. // :freturns.
  9695. // :fparam name='-' type='VOID' io='-'.
  9696. // Nothing
  9697. // :efparams.
  9698. // :remarks.
  9699. // The calling convention must be _System because this function
  9700. // is used in a DosCreateThread.
  9701. // :related.
  9702. // UCMenuEditBmpFile
  9703. // :epfunction.
  9704. //----------------------------------------------------------------------------
  9705. VOID _System UCMenuEditBmpFileT2(PVOID pArgs)
  9706. {
  9707.    if ( pArgs ) {
  9708.       PSZ pszArgs, pszFileName, pszIndex;
  9709.       ULONG ulFileNameLength, ulEditorNameLength;
  9710.       PSZ pszBmpEditorName = "iconedit.exe";
  9711.       HWND hwndNBP1;
  9712.       RESULTCODES resultCodes;
  9713.       HAB hab;
  9714.       HMQ hmq;
  9715.       PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwndNBP1, QWL_USER );
  9716.  
  9717.       hab = WinInitialize(0);
  9718.       hmq = WinCreateMsgQueue( hab, 0 );
  9719.       hwndNBP1 = *( (HWND *)pArgs );
  9720.  
  9721.       WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1LOAD ),   FALSE );
  9722.       WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1CREATE ), FALSE );
  9723.       WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1EDIT ),   FALSE );
  9724.       WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1PREDEFINED ),   FALSE );
  9725.  
  9726.       pszFileName = *( (PSZ*)( (HWND*)pArgs + 1 ) );
  9727.  
  9728.       ulEditorNameLength = strlen( pszBmpEditorName );
  9729.       ulFileNameLength = strlen( pszFileName );
  9730.  
  9731.       pszArgs = MyMalloc( ulEditorNameLength + ulFileNameLength + 3 );
  9732.       strcpy( pszArgs, pszBmpEditorName );
  9733.       pszIndex = pszArgs + ulEditorNameLength + 1;
  9734.       strcpy( pszIndex, pszFileName );
  9735.       *( pszIndex + ulFileNameLength + 1 ) = '\0';
  9736.  
  9737.       if ( DosExecPgm( NULL, (LONG)0, EXEC_SYNC, pszArgs, NULL, &resultCodes, pszBmpEditorName ) ){
  9738.         WinMessageBox( HWND_DESKTOP, hwndNBP1,
  9739.                        nlsgetmessage( hab, UCMData->hModUCM, NLS_ERROR, 3 ),
  9740.                        nlsgetmessage( hab, UCMData->hModUCM, NLS_NOICESTART, 4 ),
  9741.                        0, MB_OK | MB_ICONEXCLAMATION );
  9742.       }
  9743.  
  9744.       MyFree( pszArgs );
  9745.       MyFree( pArgs );
  9746.  
  9747.       if (resultCodes.codeTerminate==TC_EXIT) {
  9748.          WinSendMsg( hwndNBP1, UCMNBP1_NEWBMP, MPFROMP( pszFileName ), (MPARAM)0 );
  9749.       } else {
  9750.          WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1LOAD ),   TRUE );
  9751.          WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1CREATE ), TRUE );
  9752.          WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1EDIT ),   TRUE );
  9753.          WinEnableWindow( WinWindowFromID( hwndNBP1, IDB_UCMNBP1PREDEFINED ),   TRUE );
  9754.       } // endif
  9755.  
  9756.       MyFree( pszFileName );
  9757.  
  9758.       WinDestroyMsgQueue( hmq );
  9759.       WinTerminate( hab );
  9760.    } // endif
  9761. }
  9762. #endif
  9763.  
  9764. #if defined(UCMUI)
  9765. //----------------------------------------------------------------------------
  9766. // UCMenuEditBmpFile
  9767. //----------------------------------------------------------------------------
  9768. // :pfunction res=&IDF_EDITBMPFILE. name='UCMenuEditBmpFile' text='Edit a bitmap file' .
  9769. // This function starts UCMenuEditBmpFileT2 in a second thread.
  9770. // :syntax name='UCMenuEditBmpFile' params='hwndNBP1, pszBmpFileName' return='-' .
  9771. // :fparams.
  9772. // :fparam name='hwndNBP1' type='HWND' io='input' .
  9773. // Handle of the calling notebook page.
  9774. // :fparam name='pszBmpFileName' type='PSZ' io='input' .
  9775. // Name of the bitmap file to edit, freed by UCMenuEditBmpFileT2.
  9776. // :freturns.
  9777. // :fparam name='-' type='VOID' io='-'.
  9778. // Nothing
  9779. // :efparams.
  9780. // :remarks.
  9781. // :related.
  9782. // UCMenuEditBmpFileT2
  9783. // :epfunction.
  9784. //----------------------------------------------------------------------------
  9785. VOID _Optlink UCMenuEditBmpFile(HWND hwndNBP1, PSZ pszBmpFileName)
  9786. {
  9787.    TID tid;
  9788.    PVOID pArgs;
  9789.    PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwndNBP1, QWL_USER );
  9790.  
  9791.    pArgs =  MyMalloc( sizeof( HWND ) + sizeof( PSZ ) );
  9792.  
  9793.    if ( pArgs && pszBmpFileName ) {
  9794.       *( (HWND *)pArgs ) = hwndNBP1;
  9795.       *( (PSZ*)( (HWND *)pArgs + 1 ) ) = pszBmpFileName;
  9796.       if ( DosCreateThread( &tid, (PFNTHREAD)UCMenuEditBmpFileT2, (ULONG)pArgs, 0, 8192 ) ){
  9797.          WinMessageBox( HWND_DESKTOP, hwndNBP1,
  9798.                         nlsgetmessage( WinQueryAnchorBlock( hwndNBP1 ), UCMData->hModUCM, NLS_ERROR, 0 ),
  9799.                         nlsgetmessage( WinQueryAnchorBlock( hwndNBP1 ), UCMData->hModUCM, NLS_NOICESTART, 1 ),
  9800.                         0, MB_OK | MB_ICONEXCLAMATION );
  9801.        } // endif
  9802.    } else {
  9803.       WinMessageBox( HWND_DESKTOP, hwndNBP1,
  9804.                      nlsgetmessage( WinQueryAnchorBlock( hwndNBP1 ), UCMData->hModUCM, NLS_ERROR, 0 ),
  9805.                      nlsgetmessage( WinQueryAnchorBlock( hwndNBP1 ), UCMData->hModUCM, NLS_NOBMPFN, 1 ),
  9806.                      0, MB_OK | MB_ICONEXCLAMATION );
  9807.    } // endif
  9808.  
  9809. }
  9810. #endif
  9811.  
  9812. #if defined(UCMUI)
  9813. //----------------------------------------------------------------------------
  9814. // UCMenuCreateBmpFile
  9815. //----------------------------------------------------------------------------
  9816. // :pfunction res=&IDF_CREATEBMPFILE. name='UCMenuCreateBmpFile' text='Create a bitmap file' .
  9817. // This function create a 16 color bitmap file given a name and size.
  9818. // :syntax name='UCMenuCreateBmpFile' params='pszBmpFileName, cx, cy, bpp' return='bSuccess' .
  9819. // :fparams.
  9820. // :fparam name='pszBmpFileName' type='PSZ' io='input' .
  9821. // Name of the bitmap file to create.
  9822. // :fparam name='cx' type='ULONG' io='input' .
  9823. // Width in pixels of the bitmap.
  9824. // :fparam name='cy' type='ULONG' io='input' .
  9825. // Height in pixels of the bitmap.
  9826. // :freturns.
  9827. // :fparam name='bSuccess' type='BOOL' io='return'.
  9828. // True if successful.
  9829. // :efparams.
  9830. // :remarks.
  9831. // :related.
  9832. // :epfunction.
  9833. //----------------------------------------------------------------------------
  9834. BOOL _Optlink UCMenuCreateBmpFile( PSZ pszBmpFileName, ULONG cx, ULONG cy )
  9835. {
  9836.   FILEHANDLE              File;
  9837.   ULONG                   rc;
  9838.   PBITMAPFILEHEADER2      pbfh2  = NULL;
  9839.   PBITMAPINFOHEADER2      pbih2  = NULL;
  9840.   PBITMAPINFO2            pbmi2  = NULL;
  9841.   ULONG                   ulColorTableSize;
  9842.   PBYTE                   pData  = NULL;
  9843.   ULONG                   ulDataSize;
  9844.   BOOL                    bSuccess = FALSE;
  9845.  
  9846.   //--- open the file
  9847.   File = OPENWRITE( pszBmpFileName );
  9848.   if (File == NULLFILE){
  9849.      goto ExitLoadBMP;
  9850.   } // endif
  9851.  
  9852.   /* Write the bitmap info header............................................*/
  9853.   ulColorTableSize = 16 * sizeof( RGB2 );
  9854.   pbfh2 = ( PBITMAPFILEHEADER2 )MyMalloc( sizeof( *pbfh2 ) + ulColorTableSize );
  9855.   if ( !pbfh2 ){
  9856.      goto ExitLoadBMP;
  9857.   } // endif
  9858.  
  9859.   // Fill in the BITMAPFILEHEADER2 structure
  9860.   pbfh2->usType  = BFT_BMAP;
  9861.   pbfh2->cbSize  = sizeof( *pbfh2 );
  9862.   pbfh2->offBits = sizeof( *pbfh2 ) + ulColorTableSize;
  9863.  
  9864.   /* We now assign a bunch of pointers to make the code more readable........*/
  9865.   pbih2 = &pbfh2->bmp2;
  9866.   pbmi2 = (PBITMAPINFO2)pbih2;
  9867.  
  9868.   // Fill in the BITMAPFILEINFOHEADER2 structure
  9869.   memset(  pbih2, '\0', sizeof( *pbih2 ) );
  9870.   pbih2->cbFix = sizeof( *pbih2 );
  9871.   pbih2->cx = cx;
  9872.   pbih2->cy = cy;
  9873.   pbih2->cPlanes = 1;
  9874.   pbih2->cBitCount = 4;
  9875.  
  9876.   // Now fill in the color table
  9877.   pbmi2->argbColor[0].bRed      = 0;
  9878.   pbmi2->argbColor[0].bGreen    = 0;
  9879.   pbmi2->argbColor[0].bBlue     = 0;
  9880.   pbmi2->argbColor[0].fcOptions = 0;
  9881.   pbmi2->argbColor[1].bRed      = 0;
  9882.   pbmi2->argbColor[1].bGreen    = 0;
  9883.   pbmi2->argbColor[1].bBlue     = 0x80;
  9884.   pbmi2->argbColor[1].fcOptions = 0;
  9885.   pbmi2->argbColor[2].bRed      = 0;
  9886.   pbmi2->argbColor[2].bGreen    = 0x80;
  9887.   pbmi2->argbColor[2].bBlue     = 0;
  9888.   pbmi2->argbColor[2].fcOptions = 0;
  9889.   pbmi2->argbColor[3].bRed      = 0;
  9890.   pbmi2->argbColor[3].bGreen    = 0x80;
  9891.   pbmi2->argbColor[3].bBlue     = 0x80;
  9892.   pbmi2->argbColor[3].fcOptions = 0;
  9893.   pbmi2->argbColor[4].bRed      = 0x80;
  9894.   pbmi2->argbColor[4].bGreen    = 0;
  9895.   pbmi2->argbColor[4].bBlue     = 0;
  9896.   pbmi2->argbColor[4].fcOptions = 0;
  9897.   pbmi2->argbColor[5].bRed      = 0x80;
  9898.   pbmi2->argbColor[5].bGreen    = 0;
  9899.   pbmi2->argbColor[5].bBlue     = 0x80;
  9900.   pbmi2->argbColor[5].fcOptions = 0;
  9901.   pbmi2->argbColor[6].bRed      = 0x80;
  9902.   pbmi2->argbColor[6].bGreen    = 0x80;
  9903.   pbmi2->argbColor[6].bBlue     = 0;
  9904.   pbmi2->argbColor[6].fcOptions = 0;
  9905.   pbmi2->argbColor[7].bRed      = 0x80;
  9906.   pbmi2->argbColor[7].bGreen    = 0x80;
  9907.   pbmi2->argbColor[7].bBlue     = 0x80;
  9908.   pbmi2->argbColor[7].fcOptions = 0;
  9909.   pbmi2->argbColor[8].bRed      = 0xC9;
  9910.   pbmi2->argbColor[8].bGreen    = 0xC9;
  9911.   pbmi2->argbColor[8].bBlue     = 0xC9;
  9912.   pbmi2->argbColor[8].fcOptions = 0;
  9913.   pbmi2->argbColor[9].bRed      = 0;
  9914.   pbmi2->argbColor[9].bGreen    = 0;
  9915.   pbmi2->argbColor[9].bBlue     = 0xFF;
  9916.   pbmi2->argbColor[9].fcOptions = 0;
  9917.   pbmi2->argbColor[10].bRed      = 0;
  9918.   pbmi2->argbColor[10].bGreen    = 0xFF;
  9919.   pbmi2->argbColor[10].bBlue     = 0;
  9920.   pbmi2->argbColor[10].fcOptions = 0;
  9921.   pbmi2->argbColor[11].bRed      = 0;
  9922.   pbmi2->argbColor[11].bGreen    = 0xFF;
  9923.   pbmi2->argbColor[11].bBlue     = 0xFF;
  9924.   pbmi2->argbColor[11].fcOptions = 0;
  9925.   pbmi2->argbColor[12].bRed      = 0xFF;
  9926.   pbmi2->argbColor[12].bGreen    = 0;
  9927.   pbmi2->argbColor[12].bBlue     = 0;
  9928.   pbmi2->argbColor[12].fcOptions = 0;
  9929.   pbmi2->argbColor[13].bRed      = 0xFF;
  9930.   pbmi2->argbColor[13].bGreen    = 0;
  9931.   pbmi2->argbColor[13].bBlue     = 0xFF;
  9932.   pbmi2->argbColor[13].fcOptions = 0;
  9933.   pbmi2->argbColor[14].bRed      = 0xFF;
  9934.   pbmi2->argbColor[14].bGreen    = 0xFF;
  9935.   pbmi2->argbColor[14].bBlue     = 0;
  9936.   pbmi2->argbColor[14].fcOptions = 0;
  9937.   pbmi2->argbColor[15].bRed      = 0xFF;
  9938.   pbmi2->argbColor[15].bGreen    = 0xFF;
  9939.   pbmi2->argbColor[15].bBlue     = 0xFF;
  9940.  
  9941.   /* We write a 2.0 image and so we write a bitmap-file header-2 structure...*/
  9942.   rc = WRITEFILE( pbfh2, 1, sizeof( *pbfh2 ) + ulColorTableSize, File );
  9943.   // ! The prototype of fwrite says that the number should be after the size, but
  9944.   // only their product matters, and having the size instead of the number when
  9945.   // there is only one item allows better error checking
  9946.   if ( rc != ( sizeof( *pbfh2 ) + ulColorTableSize ) ){
  9947.      goto ExitLoadBMP;
  9948.   } // endif
  9949.  
  9950.   /* Read the bitmap data, the read size is derived using the magic formula..*/
  9951.   /* The bitmap scan line is aligned on a doubleword boundary................*/
  9952.   /* The size of the scan line is the number of pels times the bpp...........*/
  9953.   /* After aligning it, we divide by 4 to get the number of bytes, and.......*/
  9954.   /* multiply by the number of scan lines and the number of pel planes.......*/
  9955.   ulDataSize = ( ( ( 4 * cx ) + 31) / 32) * 4 * cy;
  9956.   pData = ( PBYTE )MyMalloc( ulDataSize );
  9957.   if ( !pData ){
  9958.      goto ExitLoadBMP;
  9959.   }
  9960.   memset( pData, '\0', ulDataSize );
  9961.   rc = WRITEFILE( pData, 1, ulDataSize, File );
  9962.   if ( rc != ulDataSize ){
  9963.      goto ExitLoadBMP;
  9964.   } // endif
  9965.  
  9966.   bSuccess = TRUE;
  9967.  
  9968. ExitLoadBMP:
  9969.   if ( pData ){
  9970.      MyFree(pData);
  9971.   } // endif
  9972.   if ( pbfh2 ){
  9973.      MyFree( pbfh2 );
  9974.   } // endif
  9975.   CLOSEFILE( File );
  9976.   return bSuccess;
  9977. }
  9978. #endif
  9979.  
  9980. #if defined(UCMUI)
  9981. //----------------------------------------------------------------------------
  9982. // UCMenuNBP1UpdateBmp
  9983. //----------------------------------------------------------------------------
  9984. // :pfunction res=&IDF_NBP1UPDBMP. name='UCMenuNBP1UpdateBmp' text='Update the display of the bitmap in the notebook' .
  9985. // Sets the bitmap of the page 1 of the notebook.
  9986. // :syntax name='UCMenuNBP1UpdateBmp' params='hwnd, hBmp, pszFileName' return='-' .
  9987. // :fparams.
  9988. // :fparam name='hwnd' type='HWND' io='input' .
  9989. // Handle of the notebook page 1
  9990. // :fparam name='hBmp' type='HBITMAP' io='input' .
  9991. // Handle of the bitmap.
  9992. // :fparam name='pszFileName' type='PSZ' io='input' .
  9993. // File name to display for the bitmap.
  9994. // :freturns.
  9995. // :fparam name='-' type='VOID' io='-'.
  9996. // Nothing
  9997. // :efparams.
  9998. // :remarks.
  9999. // :related.
  10000. // :epfunction.
  10001. //----------------------------------------------------------------------------
  10002. VOID _Optlink UCMenuNBP1UpdateBmp(HWND hwnd, PSZ pszFileName)
  10003. {
  10004.    RECTL  rcl;
  10005.    SWP    swp;
  10006.    HPS    hPS = WinGetPS( hwnd );
  10007.  
  10008.    WinQueryWindowPos( WinWindowFromID( hwnd, IDC_UCMNBP1BITMAP ), &swp );
  10009.  
  10010.    rcl.xLeft   = swp.x;
  10011.    rcl.yBottom = swp.y;
  10012.    rcl.xRight  = swp.x + swp.cx;
  10013.    rcl.yTop    = swp.y + swp.cy;
  10014.    WinFillRect( hPS, &rcl, SYSCLR_DIALOGBACKGROUND );
  10015.  
  10016.    WinReleasePS(hPS);
  10017.  
  10018.    WinInvalidateRect( hwnd, &rcl, TRUE );
  10019.  
  10020.    WinSetDlgItemText(hwnd,
  10021.                      IDC_UCMNBP1FILENAME,
  10022.                      pszFileName);
  10023.  
  10024. }
  10025. #endif
  10026.  
  10027. //----------------------------------------------------------------------------
  10028. // UCMenuLoadDefault
  10029. //----------------------------------------------------------------------------
  10030. // :function res=&IDF_UCMLOADDEF. name='UCMenuLoadDefault' text='Loads the default new ucmenu'.
  10031. // This function updates the ucmenu with the default template.
  10032. // :syntax name='UCMenuLoadDefault' params='hwndUCMenu' return='bSuccess' .
  10033. // :fparams.
  10034. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  10035. // Handle of the ucmenu
  10036. // :freturns.
  10037. // :fparam name='bSuccess' type='BOOL' io='return'.
  10038. // True if successful, FALSE else
  10039. // :efparams.
  10040. // :remarks.
  10041. // :related.
  10042. // :efunction.
  10043. //----------------------------------------------------------------------------
  10044. BOOL APIENTRY UCMenuLoadDefault( HWND hwndUCMenu )
  10045. {
  10046.   MRESULT mr;
  10047.   PVOID   pTmplt;
  10048.   HMODULE hModule = NULLHANDLE;
  10049.   USHORT  MenuID  = 0;
  10050.   HWND    hwndNewMenu = NULLHANDLE, hwndOldMenu;
  10051.   ULONG   ulVersion = UCMTMPLVERSION;
  10052.   PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong(hwndUCMenu, QWL_UCMDATA);
  10053.  
  10054.   WinSendMsg( UCMData->hwndOwner,
  10055.                               WM_CONTROL,
  10056.                               MPFROM2SHORT( UCMData->UCMenuID,
  10057.                                             UCN_QRYTEMPLATEMODULE ),
  10058.                               MPFROMP(&hModule));
  10059.   hwndOldMenu = UCMData->hwndMenu;
  10060.  
  10061.   mr = WinSendMsg( UCMData->hwndOwner,
  10062.                                    WM_CONTROL,
  10063.                                    MPFROM2SHORT( UCMData->UCMenuID,
  10064.                                                  UCN_QRYDEFTEMPLATEID ),
  10065.                                    MPFROMP( &MenuID ) );
  10066.   if ( mr ){
  10067.      hwndNewMenu = WinLoadMenu( HWND_OBJECT,
  10068.                                 hModule,
  10069.                                 MenuID );
  10070.   } else {
  10071.      mr = WinSendMsg( UCMData->hwndOwner,
  10072.                                       WM_CONTROL,
  10073.                                       MPFROM2SHORT( UCMData->UCMenuID,
  10074.                                                     UCN_QRYDEFTEMPLATE ),
  10075.                                       MPFROMP( &pTmplt ) );
  10076.  
  10077.      if ( mr ){
  10078.         if ( *( (PULONG)pTmplt ) == UCMTMPLSIG ){
  10079.            ulVersion = *( (PULONG)( (PBYTE)pTmplt + 4 ) );
  10080.            hwndNewMenu = WinCreateMenu( HWND_OBJECT, (PVOID)((PBYTE)pTmplt + 8 ) );
  10081.         } else {
  10082. //           ulVersion = 0;
  10083. //           hwndNewMenu = WinCreateMenu( HWND_OBJECT, pTmplt );
  10084.            return FALSE;
  10085.         } // endif
  10086.         MyFree( pTmplt );
  10087.      } /* endif */
  10088.   } /* endif */
  10089.  
  10090.   if ( hwndNewMenu ) {
  10091.      UCMData->AccelTable->cAccel = 0;
  10092.      UCMenuLoadMenuData( hwndNewMenu, UCMData, ulVersion, hwndUCMenu );
  10093.      UCMenuReplaceMenu( hwndOldMenu, hwndNewMenu );
  10094.   } /* endif */
  10095.  
  10096.   return TRUE;
  10097. }
  10098.  
  10099. //----------------------------------------------------------------------------
  10100. // UCMenuNew
  10101. //----------------------------------------------------------------------------
  10102. // :function res=&IDF_UCMNEW. name='UCMenuNew' text='Loads a new menu in the ucmenu'.
  10103. // This function updates the ucmenu with a new template.
  10104. // :syntax name='UCMenuNew' params='hwndUCMenu, pTemplate' return='bSuccess' .
  10105. // :fparams.
  10106. // :fparam name='hwndUCMenu' type='HWND' io='input' .
  10107. // Handle of the ucmenu
  10108. // :fparam name='pTemplate' type='PVOID' io='input' .
  10109. // Template of the new menu.
  10110. // :freturns.
  10111. // :fparam name='bSuccess' type='BOOL' io='return'.
  10112. // True if successful, FALSE else
  10113. // :efparams.
  10114. // :remarks.
  10115. // :related.
  10116. // :efunction.
  10117. //----------------------------------------------------------------------------
  10118. BOOL APIENTRY UCMenuNew( HWND hwndUCMenu, PVOID pTemplate )
  10119. {
  10120.    HWND  hwndScroll = WinQueryWindow( hwndUCMenu, QW_TOP );
  10121.    HWND  hwndHide   = WinQueryWindow( hwndScroll, QW_TOP );
  10122.    PUCMDATA UCMData = (PUCMDATA) WinQueryWindowULong( hwndUCMenu, QWL_UCMDATA );
  10123.    HWND  hwndNewMenu;
  10124.    ULONG ulVersion;
  10125.  
  10126.    // (MAM) fixed test of unititialized variable
  10127.  
  10128.    if ( UCMData && UCMData->hwndMenu ) {
  10129.       HWND hwndOldMenu = UCMData->hwndMenu;
  10130.       UCMData->AccelTable->cAccel = 0;
  10131.  
  10132.       // Load new-style template (with signature).   Remove comments to
  10133.       // accomodate older (no sig) templates, but then we cannot detect
  10134.       // attempts to load non-UCMenu template files.
  10135.  
  10136.       if ( *( (PULONG)pTemplate ) == UCMTMPLSIG ){
  10137.          ulVersion = *( (PULONG)( (PBYTE)pTemplate + 4 ) );
  10138.          hwndNewMenu = WinCreateMenu( hwndHide, (PVOID)((PBYTE)pTemplate + 8 ) );
  10139.       } else {
  10140. //         ulVersion = 0;
  10141. //         hwndNewMenu = WinCreateMenu( hwndHide, pTemplate );
  10142.          return FALSE;
  10143.       } // endif
  10144.  
  10145.       UCMenuLoadMenuData( hwndNewMenu, UCMData, ulVersion, hwndUCMenu );
  10146.  
  10147.       UCMenuReplaceMenu( hwndOldMenu, hwndNewMenu );
  10148.  
  10149.       return TRUE;
  10150.    } else {
  10151.       return FALSE;
  10152.    } // endif
  10153. }
  10154.  
  10155. //----------------------------------------------------------------------------
  10156. // UCMenuReplaceMenu : not for the user's doc
  10157. //----------------------------------------------------------------------------
  10158. // :pfunction res=&IDF_REPMENU. name='UCMenuReplaceMenu' text='Loads a new menu in the ucmenu'.
  10159. // This function replaces the menu of a ucmenu with a new one.
  10160. // :syntax name='UCMenuReplaceMenu' params='hwndOldMenu, hwndNewMenu' return='-' .
  10161. // :fparams.
  10162. // :fparam name='hwndOldMenu' type='HWND' io='input' .
  10163. // Handle of the old menu
  10164. // :fparam name='hwndNewMenu' type='HWND' io='input' .
  10165. // Handle of the new menu
  10166. // :freturns.
  10167. // :fparam name='-' type='VOID' io='-'.
  10168. // Nothing
  10169. // :efparams.
  10170. // :remarks.
  10171. // Used when we load templates
  10172. // :related.
  10173. // :epfunction.
  10174. //----------------------------------------------------------------------------
  10175. VOID _Optlink UCMenuReplaceMenu(HWND hwndOldMenu, HWND hwndNewMenu)
  10176. {
  10177.   HWND hwndOwner   = WinQueryWindow(hwndOldMenu , QW_OWNER);
  10178.   HWND hwndParent  = WinQueryWindow(hwndOldMenu , QW_PARENT);
  10179.  
  10180.  
  10181.   if (hwndOldMenu && hwndNewMenu) {
  10182.     PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong(hwndOldMenu, QWL_USER);
  10183.  
  10184.     UCMenuFreeMenuData(hwndOldMenu);
  10185.     WinDestroyWindow(hwndOldMenu);
  10186.  
  10187.     UCMData->hwndMenu = hwndNewMenu;
  10188.  
  10189.     WinSetOwner(hwndNewMenu, hwndOwner);
  10190.     WinSetParent(hwndNewMenu, hwndParent, TRUE);
  10191.  
  10192.     // The presparam change has to be done before subclassing the menu, else it fails
  10193.     // (Here, we want to have PRESPARAMCHANGED processed by the default routines only,
  10194.     //  since everything is not set up yet)
  10195.     WinSetPresParam( hwndNewMenu, PP_FONTNAMESIZE,
  10196.                      strlen( UCMData->pszFontNameSize ) + 1,
  10197.                      UCMData->pszFontNameSize );
  10198.     WinSetPresParam( hwndNewMenu, PP_MENUBACKGROUNDCOLOR, sizeof UCMData->ItemBgColor, &(UCMData->ItemBgColor) );
  10199.  
  10200.     UCMData->OldMenuProc = (PFNWP)WinQueryWindowPtr(hwndNewMenu, QWP_PFNWP);
  10201.     UCMData->OldMenuProc = (PFNWP)WinSubclassWindow(hwndNewMenu, (PFNWP)MenuWndProc);
  10202.  
  10203.     UCMenuNotifAll( UCMData, hwndNewMenu, UCN_ADDEDITEM );
  10204.  
  10205.     UCMenuUpdateMenu(hwndNewMenu, FALSE);
  10206.  
  10207.   } // endif
  10208. }
  10209.  
  10210. //----------------------------------------------------------------------------
  10211. // UCMenuInitDrag : not for the user's doc
  10212. //----------------------------------------------------------------------------
  10213. // :pfunction res=&IDF_INITDRAG. name='UCMenuInitDrag' text='Performs initializations at the start of a drag'.
  10214. // This function does some initializations at the beginning of a drag.
  10215. // :syntax name='UCMenuInitDrag' params='hwnd' return='initOK'.
  10216. // :fparams.
  10217. // :fparam name='hwnd' type='HWND' io='input' .
  10218. // Handle of the window from which the drag occurs ( it should be a menu )
  10219. // :fparam name='x' type='SHORT' io='input' .
  10220. // X coordinate of the pointer at the beginning of the drag.
  10221. // :fparam name='y' type='SHORT' io='input' .
  10222. // Y coordinate of the pointer at the beginning of the drag.
  10223. // :freturns.
  10224. // :fparam name='initOK' type='BOOL' io='return'.
  10225. // The initialization went OK
  10226. // :efparams.
  10227. // :remarks.
  10228. // :related.
  10229. // :epfunction.
  10230. //----------------------------------------------------------------------------
  10231.  
  10232. BOOL _Optlink UCMenuInitDrag(HWND hwnd, SHORT x, SHORT y)
  10233. {
  10234.   DRAGITEM                 DragItem;
  10235.   DRAGIMAGE                DragImage;
  10236.   DRAGINFO                *pDragInfo;
  10237.   POINTL                   ptl;
  10238.   MENUITEM                 mItem;
  10239.   HBITMAP                  hBitmap;
  10240.   PID                      pid;
  10241.   TID                      tid;
  10242.   PUCMDATA                 UCMData;
  10243.   BOOL                     bFileBitmap = FALSE;
  10244.   // (MAM) Added flag to delete newly loaded bitmap after drag
  10245.   BOOL                     DeleteBitmap = FALSE;  
  10246.   QMSG                     QMsg;
  10247.  
  10248.   UCMData = (PUCMDATA) WinQueryWindowULong(hwnd , QWL_USER);
  10249.  
  10250.   // ------------------------------------------
  10251.   // -- First check if drag and drop is allowed
  10252.   // ------------------------------------------
  10253.   if ( UCMData->Style & UCS_NO_DM) {
  10254.      return FALSE;
  10255.   } // endif
  10256.  
  10257.   WinQueryWindowProcess( hwnd, &pid, &tid );
  10258.  
  10259.   ptl.x = x;
  10260.   ptl.y = y;
  10261.   UCMData->ContextID = UCMenuIdFromCoord(hwnd, &ptl);
  10262.   if ( ! UCMData->ContextID ) {
  10263.      return FALSE;
  10264.   } // endif
  10265.   memset(&mItem, 0, sizeof(MENUITEM));
  10266.   WinSendMsg(hwnd, MM_QUERYITEM, MPFROM2SHORT(UCMData->ContextID, FALSE), MPFROMP(&mItem)); 
  10267.  
  10268.   if (mItem.hItem && ITEM(&mItem, hBmp)) {
  10269. //  PSZ pszFileExt;
  10270.     BOOL BinOK;
  10271.     hBitmap = ITEM(&mItem, hBmp);
  10272.     // ------------------------------------------------------
  10273.     // -- pszBmp can be a bitmap ID or a file name.  If it
  10274.     // -- converts to binary without error we set bFileBitmap
  10275.     // -- to TRUE.
  10276.     // ------------------------------------------------------
  10277.     if (ITEM(&mItem, pszBmp)) {  // There is a bitmap string...
  10278.        UCMString2Int(ITEM(&mItem, pszBmp), &BinOK);
  10279.        if ((!BinOK) && !(UCMData->Style & UCS_NO_DM_RENDER_TO_BMP))
  10280.          bFileBitmap = TRUE;    // Not a number, must be a filename
  10281.     }
  10282. //...old method, non-NLS...
  10283. //  pszFileExt = strrchr( ITEM( &mItem, pszBmp ), '.' );
  10284. //
  10285. //  if ( !(UCMData->Style & UCS_NO_DM_RENDER_TO_BMP)
  10286. //    && pszFileExt
  10287. //    && strlen(pszFileExt)>3
  10288. //    && toupper(pszFileExt[1])=='B'
  10289. //    && toupper(pszFileExt[2])=='M'
  10290. //    && toupper(pszFileExt[3])=='P' ) {
  10291. //     bFileBitmap = TRUE;
  10292. //  } // endif
  10293.   } else {
  10294.     // fix 03/07/95 (MAM)
  10295.     // Cannot use DrgGetPS()/DrgReleasePS() during WM_BEGINDRAG processing.
  10296.     // We must get our own PS to load the bitmap.
  10297.     HPS hps;
  10298.     HDC hdc;
  10299.     SIZEL PSSize={0,0};
  10300.     DEVOPENSTRUC DevOS={NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  10301.  
  10302.     /* Create memory device context to load bitmap */
  10303.     hdc = DevOpenDC((HAB)NULLHANDLE, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&DevOS, NULLHANDLE);
  10304.     hps = GpiCreatePS((HAB)NULLHANDLE, hdc, &PSSize, GPIA_ASSOC | PU_PELS | GPIT_MICRO);
  10305.     if (mItem.afStyle & MIS_SPACER) /* Give spacer items a different look */
  10306.       hBitmap = GpiLoadBitmap( hps, UCMData->hModUCM, UCMENUID_SPACERBMP,  0, 0 );
  10307.     else
  10308.       hBitmap = GpiLoadBitmap( hps, UCMData->hModUCM, UCMENUID_DEFAULTBMP, 0, 0 );
  10309.  
  10310.     GpiDestroyPS(hps);
  10311.     DevCloseDC(hdc);
  10312.     DeleteBitmap = TRUE;  /* Delete this bitmap afer drag is done */
  10313.   } // endif
  10314.  
  10315.   // ---------------------------------------------------------------------
  10316.   // -- If we are dragging an open nodismiss submenu, we close it before
  10317.   // -- Else it would cause problems when it is dropped on another ucmenu
  10318.   // -- where UCMData->oldSubMenuProc is not yet set
  10319.   // ---------------------------------------------------------------------
  10320.   if ( WinSendMsg( hwnd,
  10321.                    MM_QUERYITEMATTR,
  10322.                    MPFROM2SHORT( mItem.id, FALSE ),
  10323.                    MPFROMSHORT( MIA_HILITED ) ) ){
  10324.      WinSendMsg( hwnd,
  10325.                  MM_SETITEMATTR,
  10326.                  MPFROM2SHORT( mItem.id, FALSE ),
  10327.                  MPFROM2SHORT( MIA_HILITED, FALSE ) );
  10328.      if (mItem.hwndSubMenu) {
  10329.         UCMenuUnselectAll( UCMData->hwndMenu );
  10330.      } // endif
  10331.   } // endif
  10332.  
  10333.   pDragInfo = DrgAllocDraginfo(1);
  10334.   if (pDragInfo == NULL) {
  10335.     return 0;
  10336.   }
  10337.  
  10338.   // -------------------------------------------------------------------------------------
  10339.   // -- DC_REMOVEABLEMEDIA prevents the desktop from doing a move by default
  10340.   // -- Else, whenever an item with a bitmap file is mistakenly dropped on the desktop,
  10341.   // -- the file is moved into the desktop directory and the ucmenu can not find it again
  10342.   // -------------------------------------------------------------------------------------
  10343.   DragItem.fsControl         = DC_REMOVEABLEMEDIA;
  10344.  
  10345.   DragItem.ulItemID          = UCMData->ContextID;
  10346.  
  10347.   // ------------------------------------------------------------------------------
  10348.   // -- We can either render as a bitmap file or as a ucmenu item
  10349.   // -- We will fill them only if it can be rendered as a bitmap file
  10350.   // -- In case   a ucmenu item rendering is wanted, a DM_RENDER will be necessary
  10351.   // ------------------------------------------------------------------------------
  10352.   DragItem.hstrContainerName = 0;
  10353.   DragItem.hstrSourceName    = 0;
  10354.  
  10355.   DragItem.hwndItem          = hwnd;                 // -- hwnd of the source window (ie menu or submenu)
  10356.   DragItem.hstrTargetName    = 0;
  10357.   DragItem.fsSupportedOps    = DO_COPYABLE | DO_MOVEABLE;
  10358.   if ( bFileBitmap ) {
  10359.      PSZ   pszNameOnly;
  10360.      PSZ   pszFullNameCopy;
  10361.  
  10362.      // -------------------------------------------------------------------------------------
  10363.      // -- If the item can be rendered  as a bitmap file, we set it up so that its true type
  10364.      // -- and native RMF are those of an actual BMP file -> the order in the following
  10365.      // -- strings is important. Else, some applications, eg iconedit, won't accept it.
  10366.      // -------------------------------------------------------------------------------------
  10367.      DragItem.hstrType = DrgAddStrHandle( DRT_BITMAP "," DRT_UCMITEM ","  DRT_TEXT "," DRT_UNKNOWN );
  10368.      if (UCMData->Style&UCS_NO_DM_DISCARD) {
  10369.         DragItem.hstrRMF  = DrgAddStrHandle("<DRM_OS2FILE, DRF_TEXT>,<DRM_UCMITEM, DRF_UNKNOWN>");
  10370.      } else {
  10371.         DragItem.hstrRMF  = DrgAddStrHandle("<DRM_OS2FILE, DRF_TEXT>,(DRM_UCMITEM, DRM_DISCARD)X(DRF_UNKNOWN)");
  10372.      } // endif
  10373.  
  10374.      pszFullNameCopy = MyStrdup( ITEM( &mItem, pszBmp ) );
  10375.      pszNameOnly = strrchr( pszFullNameCopy, '\\' );
  10376.      pszNameOnly++;
  10377.      DragItem.hstrSourceName    = DrgAddStrHandle( pszNameOnly );
  10378.      * pszNameOnly = '\0';
  10379.      DragItem.hstrContainerName = DrgAddStrHandle( pszFullNameCopy );
  10380.   } else {
  10381.      DragItem.hstrType = DrgAddStrHandle(DRT_UCMITEM ", " DRT_UNKNOWN);
  10382.      if (UCMData->Style&UCS_NO_DM_DISCARD) {
  10383.         DragItem.hstrRMF  = DrgAddStrHandle("<DRM_UCMITEM, DRF_UNKNOWN>");
  10384.      } else {
  10385.         DragItem.hstrRMF  = DrgAddStrHandle("(DRM_UCMITEM, DRM_DISCARD)X(DRF_UNKNOWN)");
  10386.      } // endif
  10387.   } // endif
  10388.  
  10389.   DragImage.cb               = sizeof(DRAGIMAGE);
  10390.   DragImage.hImage           = hBitmap;
  10391.   DragImage.fl               = DRG_BITMAP;
  10392.   DragImage.cxOffset         = 0;
  10393.   DragImage.cyOffset         = 0;
  10394.  
  10395.   //(MAM) Allow submenus to be source of drag operations, just like main menus
  10396.   pDragInfo->hwndSource      = hwnd;
  10397. //pDragInfo->hwndSource      = UCMData->hwndMenu;   // -- always the handle of the menu, never of the submenu
  10398.   DrgSetDragitem(pDragInfo, &DragItem, sizeof(DRAGITEM), 0);
  10399.  
  10400.   /* Dispatch any waiting messages */
  10401.   while (WinPeekMsg((HAB)NULLHANDLE, &QMsg, NULLHANDLE, 0, 0, PM_REMOVE)) {
  10402.     WinDispatchMsg((HAB)NULLHANDLE, &QMsg);
  10403.   }
  10404.  
  10405.   DrgDrag(hwnd,
  10406.           pDragInfo,
  10407.           &DragImage,
  10408.           1,
  10409.           VK_BUTTON2,
  10410.           DRAGDEBUG);
  10411.  
  10412.   // (MAM) Delete bitmap we loaded just for dragging
  10413.   if (DeleteBitmap)
  10414.     GpiDeleteBitmap(hBitmap);
  10415.  
  10416.   DrgAccessDraginfo          (pDragInfo);
  10417.   DrgDeleteDraginfoStrHandles(pDragInfo);
  10418.   DrgFreeDraginfo            (pDragInfo);
  10419.  
  10420.   return TRUE;
  10421. }
  10422.  
  10423. //----------------------------------------------------------------------------
  10424. // UCMenuDrgDrpMsg : not for the user's doc
  10425. //----------------------------------------------------------------------------
  10426. // :pfunction res=&IDF_DRGDRPMSG. name='UCMenuDrgDrpMsg' text='Processes the drag&drop messages'.
  10427. // This function processes the drag & drop messages  for the menu & ucmenu window procedures
  10428. // :syntax name='UCMenuDrgDrpMsg' params='hwnd, msg, mp1, mp2, WindowProc ' return='rc'.
  10429. // :fparams.
  10430. // :fparam name='hwnd' type='HWND' io='input' .
  10431. // Handle of the window where the message occurs
  10432. // :fparam name='msg' type='ULONG' io='input' .
  10433. // Message given to the window proc
  10434. // :fparam name='mp1' type='MPARAM' io='input' .
  10435. // First parameter of the message given to the window proc
  10436. // :fparam name='mp2' type='MPARAM' io='input' .
  10437. // Second parameter of the message given to the window proc
  10438. // :fparam name='WindowProc' type='PFNWP' io='input' .
  10439. // Window porcedure to call if we do not process the message.
  10440. // :freturns.
  10441. // :fparam name='rc' type='MRESULT' io='return'.
  10442. // Return code for a PM message
  10443. // :efparams.
  10444. // :remarks.
  10445. // :related.
  10446. // :epfunction.
  10447. //----------------------------------------------------------------------------
  10448.  
  10449. MRESULT _Optlink UCMenuDrgDrpMsg(PUCMDATA UCMData, HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, PFNWP WindowProc)
  10450. {
  10451.   switch (msg) {
  10452.      #if defined(MSG_DEBUGMESSAGE)
  10453.      case MSG_DEBUGMESSAGE:
  10454.        WinMessageBox(HWND_DESKTOP,HWND_DESKTOP,(char *)mp1,"Debug message:",0,MB_OK);
  10455.        return 0;
  10456.      #endif
  10457.  
  10458.      case WM_BEGINDRAG: {
  10459.        MRESULT rc;
  10460.        POINTL  CurrMousePos;
  10461.  
  10462.        rc = (MRESULT) UCMenuInitDrag( hwnd, SHORT1FROMMP(mp1), SHORT2FROMMP(mp1) );
  10463.        /* Re-enable bubble help when drag is done.  It was disabled when */
  10464.        /* the BUTTONxDOWN that started the drag occured.                 */
  10465.        if (UCMData->Style & UCS_BUBBLEHELP) {
  10466.          /* We lose track of the mouse position during drag/drop, so we  */
  10467.          /* send a fake mousemove message to regain tracking.            */
  10468.          WinQueryPointerPos(HWND_DESKTOP, &CurrMousePos);
  10469.          WinMapWindowPoints(HWND_DESKTOP, hwnd, &CurrMousePos, 1);
  10470.          WinSendMsg(hwnd, WM_MOUSEMOVE, MPFROM2SHORT(CurrMousePos.x, CurrMousePos.y), MPFROM2SHORT(1, KC_NONE));
  10471.          /* If button 2 was not release (e.g. drag was termianted by  */
  10472.          /* ESC key, PF1 or some other way), recapture mouse so we    */
  10473.          /* will see the BUTTON2UP message and re-enable bubble help  */
  10474.          /* at that time.  If drag ended normally (button 2 is up)    */
  10475.          /* then we can just re-enable the bubble-help now.           */
  10476. //...OK? if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) {
  10477. //         WinSetCapture(HWND_DESKTOP, hwnd);
  10478. //         UCMData->HoverCapture = TRUE;
  10479. //       }
  10480. //       else {
  10481.            WinSendMsg(UCMData->hwndBubble, MSG_ENABLE_BUBBLE, 0L, 0L);
  10482. //       }
  10483.        }
  10484.        return rc;
  10485.        }
  10486.  
  10487.      case DM_ENDCONVERSATION:
  10488.        // -- All our "conversation resources" are released before returning
  10489.        // -- from DM_RENDER so we do nothing here.
  10490.        return (MRESULT)0;
  10491.  
  10492.      case DM_RENDERPREPARE:
  10493.        // -- Since we don't set DC_PREPARE in the DRAGITEM structures from the
  10494.        // -- dragged items, this message should never be received
  10495.        // -- In case this would happen, should we DrgFreeDragTransfer
  10496.        // --  the DRAGTRANSFER structure?
  10497.        return (MRESULT)FALSE;
  10498.  
  10499.      case DM_RENDER:
  10500.        { PDRAGTRANSFER  pdxfer;
  10501.          MENUITEM     * pMiTransfer;
  10502.          UCMITEM      * pUCMTransfer;
  10503.          UCHAR          pszRMF[30];      // -- "<DRM_UCMITEM,DRF_UNKNOWN>" must fit in
  10504.          BOOL           bSuccess = TRUE;
  10505.  
  10506.          pdxfer = (PDRAGTRANSFER)mp1;
  10507.  
  10508.          DrgQueryStrName(pdxfer->hstrSelectedRMF, sizeof(pszRMF), pszRMF);
  10509.          if ( strstr( pszRMF, "<DRM_UCMITEM,DRF_UNKNOWN>" ) )
  10510.          {
  10511.             CHAR pszItemPtr[20];
  10512.   
  10513.             // ---------------------------------------------------------------
  10514.             // -- ulTargetInfo contains the address of the shared memory
  10515.             // --  if source and target are in different processes and 0 else
  10516.             // ---------------------------------------------------------------
  10517.             if (pdxfer->ulTargetInfo) {
  10518.                DosSubSetMem ( (PVOID)(pdxfer->ulTargetInfo), 0, 4000 );
  10519.                DosSubAllocMem( (PVOID)(pdxfer->ulTargetInfo),(PVOID)&pMiTransfer, sizeof(MENUITEM) );
  10520.             } else {
  10521.                pMiTransfer = MyMalloc( sizeof(MENUITEM) );
  10522.             } // endif
  10523.   
  10524.             memset( pMiTransfer, 0, sizeof(MENUITEM) );
  10525.             WinSendMsg(hwnd,
  10526.                        MM_QUERYITEM,
  10527.                        MPFROM2SHORT((SHORT)(pdxfer->pditem->ulItemID), TRUE),
  10528.                        MPFROMP(pMiTransfer));
  10529.             if (pMiTransfer->hItem && pdxfer->ulTargetInfo) {
  10530.                // --------------------------------------------------------------------
  10531.                // -- pMiTransfer->hItem is a pointer to a UCMItem structure which is
  10532.                // -- allocated in our process, so we have to copy it in shared mem too
  10533.                // --------------------------------------------------------------------
  10534.                UCMITEM * pUCMItem;
  10535.   
  10536.                pUCMItem = (UCMITEM*)(pMiTransfer->hItem);
  10537.                DosSubAllocMem( (PVOID)(pdxfer->ulTargetInfo),(PPVOID)&(pMiTransfer->hItem), sizeof(UCMITEM) );
  10538.   
  10539.                ITEM(pMiTransfer, hBmp   ) = pUCMItem->hBmp;
  10540.                ITEM(pMiTransfer, pszBmp ) = SubMemStrdup( (PVOID)(pdxfer->ulTargetInfo), pUCMItem->pszBmp );
  10541.                ITEM(pMiTransfer, pszText) = SubMemStrdup( (PVOID)(pdxfer->ulTargetInfo), pUCMItem->pszText );
  10542.                ITEM(pMiTransfer, pszAction) = SubMemStrdup( (PVOID)(pdxfer->ulTargetInfo), pUCMItem->pszAction );
  10543.                ITEM(pMiTransfer, pszParameters ) = SubMemStrdup( (PVOID)(pdxfer->ulTargetInfo), pUCMItem->pszParameters );
  10544.                ITEM(pMiTransfer, pszData) = SubMemStrdup( (PVOID)(pdxfer->ulTargetInfo), pUCMItem->pszData );
  10545.             } // endif
  10546.   
  10547.             sprintf( pszItemPtr, "%u", pMiTransfer );
  10548.             pdxfer->pditem->hstrSourceName = DrgAddStrHandle( pszItemPtr );
  10549.   
  10550.          } else if ( strstr( pszRMF, "<DRM_OS2FILE,DRF_TEXT>" ) ){
  10551.             // ---------------------------------------------------
  10552.             // -- A bmp file rendering is requested
  10553.             // -- We tell the target to do it by itself!
  10554.             // -- (we supplied all the necessary informations)
  10555.             // ---------------------------------------------------
  10556.             pdxfer->fsReply = DMFL_NATIVERENDER;
  10557.             bSuccess = FALSE;
  10558.          } else {
  10559.             // ------------------------------------
  10560.             // -- We don't know how to render that
  10561.             // ------------------------------------
  10562.             bSuccess = FALSE;
  10563.          } // endif RMF checking
  10564.   
  10565.          if (pdxfer->ulTargetInfo){
  10566.             DosSubUnsetMem((PVOID)(pdxfer->ulTargetInfo));
  10567.             DosFreeMem((PVOID)(pdxfer->ulTargetInfo));
  10568.          } // endif
  10569.   
  10570.          // ---------------------------------------------------------------------
  10571.          // -- Free the drag transfer structure
  10572.          // ---------------------------------------------------------------------
  10573.          DrgDeleteStrHandle( pdxfer->hstrSelectedRMF );
  10574.          DrgFreeDragtransfer( pdxfer );
  10575.  
  10576.          return (MRESULT)bSuccess;
  10577.        }
  10578.  
  10579.      case DM_DISCARDOBJECT:
  10580.      // ------------------------------------------------------------------
  10581.      // -- Discard a menu item (dragged to the shredder for instance)
  10582.      // -- We return DRR_SOURCE, which means we handle the delete action
  10583.      // ------------------------------------------------------------------
  10584.        {
  10585.          WinSendMsg(WinQueryWindow(hwnd, QW_OWNER),
  10586.                     MM_DELETEITEM,
  10587.                     MPFROM2SHORT(UCMData->ContextID, TRUE),
  10588.                     (MPARAM)0);
  10589.        }
  10590.        return (MRESULT)DRR_SOURCE;
  10591.  
  10592.      case DM_DRAGOVER:
  10593.       // --------------------------------------------------------------------
  10594.       // -- We get this message when the drag icon is moved over our window.
  10595.       // -- We draw an emphasis frame around the item
  10596.       // -- We must verify whether or not we want to accept the drop.
  10597.       // --------------------------------------------------------------------
  10598.       {
  10599.          RECTL    rcl;
  10600.          POINTL   ptl;
  10601.          USHORT   targetID;
  10602.          BOOL     fSuccess, fSuccess2;
  10603.          MENUITEM mi;
  10604.  
  10605.          ptl.x = SHORT1FROMMP( mp2 );
  10606.          ptl.y = SHORT2FROMMP( mp2 );
  10607.          WinMapWindowPoints( HWND_DESKTOP, hwnd, &ptl, 1);
  10608.          targetID = UCMenuIdFromCoord(hwnd, &ptl);
  10609.  
  10610.          if (UCMData->TargetID != targetID) {
  10611.             HPS hps  = DrgGetPS( hwnd );
  10612.  
  10613.             // Remove the frame of the quitted item
  10614.             fSuccess  = (BOOL) WinSendMsg( hwnd,
  10615.                                            MM_QUERYITEMRECT,
  10616.                                            MPFROM2SHORT( UCMData->TargetID, TRUE ),
  10617.                                            MPFROMP( &rcl ));
  10618.             fSuccess2 = (BOOL) WinSendMsg( hwnd,
  10619.                                            MM_QUERYITEM,
  10620.                                            MPFROM2SHORT( UCMData->TargetID, TRUE ),
  10621.                                            MPFROMP( &mi ) );
  10622.             if ( fSuccess && fSuccess2 ){
  10623.                ULONG ColorIndex;
  10624.  
  10625.                if (WinIsMenuItemChecked(hwnd,UCMData->TargetID)) {
  10626.                   ColorIndex = CLR_BLACK;
  10627.                } else if ( mi.afStyle & MIS_SPACER ){
  10628.                   ColorIndex = UCMenuSelectColor( UCMData->BgColor, hps );
  10629.                } else {
  10630.                   ColorIndex = UCMenuSelectColor( UCMData->ItemBgColor, hps );
  10631.                } // endif
  10632.  
  10633.                rcl.xLeft   += 1;
  10634.                rcl.yBottom += 1;
  10635.                rcl.yTop    -= 1;
  10636.                rcl.xRight  -= 1;
  10637.  
  10638.                WinDrawBorder( hps, &rcl, 1, 1, ColorIndex, 0, DB_PATCOPY);
  10639.             } // endif
  10640.  
  10641.             // -- Draw a frame around the entered item
  10642.             fSuccess = (BOOL) WinSendMsg( hwnd,
  10643.                                           MM_QUERYITEMRECT,
  10644.                                           MPFROM2SHORT( targetID, TRUE ),
  10645.                                           MPFROMP( &rcl ));
  10646.             if (fSuccess) {
  10647.                rcl.xLeft   += 1;
  10648.                rcl.yBottom += 1;
  10649.                rcl.yTop    -= 1;
  10650.                rcl.xRight  -= 1;
  10651.  
  10652.                WinDrawBorder( hps, &rcl, 1, 1, CLR_BLACK, 0, DB_PATCOPY);
  10653.             } // endif
  10654.  
  10655.             UCMData->TargetID = targetID;
  10656.  
  10657.             DrgReleasePS( hps );
  10658.  
  10659.          } // endif UCMData->TargetID != targetID
  10660.  
  10661.  
  10662.          return (MRESULT)(UCMenuDragOver(UCMData, hwnd,(PDRAGINFO) mp1));
  10663.  
  10664.       }
  10665.  
  10666.  
  10667.     case DM_DRAGLEAVE:
  10668.       // -------------------------------------------------------------
  10669.       // -- We get this message when the drag icon leaves our window.
  10670.       // -- If any clean up is needed, this is the place.
  10671.       // -------------------------------------------------------------
  10672.       {
  10673.  
  10674.          UCMenuRemoveDropEmphasis( UCMData, hwnd );
  10675.  
  10676.          return (MRESULT)0;
  10677.       }
  10678.  
  10679.     #if defined(UCMUI)
  10680.     case DM_DROPHELP:
  10681.       // ---------------------------------------------------------------------
  10682.       // -- Help for Drag Drop.  This message is POSTED to use if the user
  10683.       // -- pressed F1 during a drag operation.  Note that the WM_BEGINDRAG
  10684.       // -- processing has already completed since this is posted, not sent.
  10685.       // ---------------------------------------------------------------------
  10686.       {
  10687.  
  10688.          UCMenuDisplayHelp( UCMData,
  10689.                             (USHORT)PANEL_DM,
  10690.                             (USHORT)UCN_HLP_DM );
  10691.          return (MRESULT)0;
  10692.       }
  10693.     #endif
  10694.  
  10695.     case DM_DROP:
  10696.       // ---------------------------------------------------------------------
  10697.       // -- Some application has just Dropped something on us !!
  10698.       // ---------------------------------------------------------------------
  10699.       UCMenuDrop(hwnd, (PDRAGINFO)mp1) ;
  10700.       return (MRESULT)0;
  10701.  
  10702.     case DM_RENDERCOMPLETE:
  10703.       // ----------------------------------------------------------------------------------
  10704.       // -- Some application has just Dropped something on us, but it was
  10705.       // -- an incomplete drop specification.  So we asked for a rendering with DM_RENDER.
  10706.       // -- However, in all the cases we process the rendering we need is done when we
  10707.       // -- get the reply from DM_RENDER, so we do nothing here.
  10708.       // -- We would do something eg if the source had to copy a file for us and was
  10709.       // -- doing it asynchronously, but we just need the names and location of bmp files,
  10710.       // -- which are given in the DM_RENDER reply.
  10711.       // ----------------------------------------------------------------------------------
  10712.       return (MRESULT)0;
  10713.  
  10714.     default:
  10715.       return WindowProc(hwnd, msg, mp1, mp2);
  10716.  
  10717.    } // endswitch
  10718. }
  10719.  
  10720. //----------------------------------------------------------------------------
  10721. // UCMenuRemoveDropEmphasis : not for the user's doc
  10722. //----------------------------------------------------------------------------
  10723. // :pfunction res=&IDF_RMVEMPH. name='UCMenuRemoveDropEmphasis'
  10724. //   text='Called to remove the current drop emphasis'.
  10725. // This function is called to remove the emphasis frame drawn around the item being
  10726. //  currently dragged over.
  10727. // :syntax name='UCMenuRemoveDropEmphasis' params='UCMData, hwnd' return='-'.
  10728. // :fparams.
  10729. // :fparam name='UCMData' type='PUCMDATA' io='input' .
  10730. // Pointer to the structure associated to the ucmenu.
  10731. // :fparam name='hwnd' type='HWND' io='input' .
  10732. // Handle of the droppee window.
  10733. // :freturns.
  10734. // :fparam name='-' type='VOID' io='-'.
  10735. // Nothing
  10736. // :efparams.
  10737. // :remarks.
  10738. // :related.
  10739. // :epfunction.
  10740. //----------------------------------------------------------------------------
  10741. VOID _Optlink UCMenuRemoveDropEmphasis( PUCMDATA UCMData, HWND hwnd )
  10742. {
  10743.    RECTL    rcl;
  10744.    BOOL     fSuccess, fSuccess2;
  10745.    MENUITEM mi;
  10746.  
  10747.    fSuccess  = (BOOL) WinSendMsg( hwnd,
  10748.                                   MM_QUERYITEMRECT,
  10749.                                   MPFROM2SHORT( UCMData->TargetID, TRUE ),
  10750.                                   MPFROMP( &rcl ) );
  10751.    fSuccess2 = (BOOL) WinSendMsg( hwnd,
  10752.                                   MM_QUERYITEM,
  10753.                                   MPFROM2SHORT( UCMData->TargetID, TRUE ),
  10754.                                   MPFROMP( &mi ) );
  10755.  
  10756.    if ( fSuccess && fSuccess2 ){
  10757.       ULONG ColorIndex;
  10758.       HPS hps   = DrgGetPS( hwnd );
  10759.  
  10760.       if (WinIsMenuItemChecked(hwnd,UCMData->TargetID)) {
  10761.          ColorIndex = CLR_BLACK;
  10762.       } else if ( mi.afStyle & MIS_SPACER ){
  10763.          ColorIndex = UCMenuSelectColor( UCMData->BgColor, hps );
  10764.       } else {
  10765.          ColorIndex = UCMenuSelectColor( UCMData->ItemBgColor, hps );
  10766.       } // endif
  10767.  
  10768.       rcl.xLeft   += 1;
  10769.       rcl.yBottom += 1;
  10770.       rcl.yTop    -= 1;
  10771.       rcl.xRight  -= 1;
  10772.  
  10773.       WinDrawBorder( hps, &rcl, 1, 1, ColorIndex, 0, DB_PATCOPY);
  10774.       DrgReleasePS( hps );
  10775.    } // endif
  10776.    UCMData->TargetID = 0;
  10777. }
  10778.  
  10779. //----------------------------------------------------------------------------
  10780. // UCMenuDragOver : not for the user's doc
  10781. //----------------------------------------------------------------------------
  10782. // :pfunction res=&IDF_DRGOVER. name='UCMenuDragOver' text='Called when a ucmenu is dragged over'.
  10783. // This function is called whenever something is being dragged over a ucmenu.
  10784. // :syntax name='UCMenuDragOver' params='hwnd, pDragInfo' return='rc'.
  10785. // :fparams.
  10786. // :fparam name='hwnd' type='HWND' io='input' .
  10787. // Handle of the droppee window (menu, submenu or hide).
  10788. // :fparam name='pDragInfo' type='PDRAGINFO' io='input' .
  10789. // Pointer to the draginfo structure
  10790. // :freturns.
  10791. // :fparam name='rc' type='MRESULT' io='return'.
  10792. // Return code for a PM DM_DRAGOVER message
  10793. // :efparams.
  10794. // :remarks.
  10795. // :related.
  10796. // :epfunction.
  10797. //----------------------------------------------------------------------------
  10798. MRESULT _Optlink UCMenuDragOver(PUCMDATA UCMData, HWND hwnd, PDRAGINFO pDraginfo)
  10799. {
  10800.  USHORT        usOperation, usIndicator;
  10801.  PDRAGITEM     pditem;
  10802.  ULONG         ulStyle = UCMData->Style;
  10803.  PUCMDATA      UCMDataSource;
  10804.  ULONG         ulStyleSource = 0;
  10805.  BOOL          bSameProcess;
  10806.  BOOL          IsUCMenu = FALSE;    // Source of drag is a UCMenu control
  10807.  PID           pidSource, pid;
  10808.  TID           tid;
  10809.  
  10810.  // -------------------------------------------------------------------------
  10811.  // -- In case we refuse, we answer only DOR_NODROP, not DOR_NEVERDROP or
  10812.  // -- DOR_NODROPOP, because it would prevent DM_DRAGOVER from being sent to
  10813.  // -- the menu, and we need it all the time in order to draw the drop
  10814.  // -- emphasis on the items (the items are not actual windows).
  10815.  // -------------------------------------------------------------------------
  10816.  
  10817.  // ------------------------------------------
  10818.  // -- First check if drag and drop is allowed
  10819.  // ------------------------------------------
  10820.  if ( UCMData->Style & UCS_NO_DM ) {
  10821.     return MPFROM2SHORT( DOR_NODROP, 0 );
  10822.  } // endif
  10823.  
  10824.  /* ---------------------------------------------------------------------- */
  10825.  /* Get access to the DRAGINFO structure.                                  */
  10826.  /* ---------------------------------------------------------------------- */
  10827.  DrgAccessDraginfo (pDraginfo);
  10828.  pditem = DrgQueryDragitemPtr (pDraginfo, 0);
  10829.  
  10830.  WinQueryWindowProcess( hwnd, &pid, &tid );
  10831.  WinQueryWindowProcess( pDraginfo->hwndSource, &pidSource, &tid );
  10832.  
  10833.  //(MAM) fixed terrible assumption that if drag was from another window in
  10834.  //      the same process, it must be a drag from another UCMenu.  Caused
  10835.  //      trap/hang if application has its own drag/drop implementation in
  10836.  //      addition to a UCMenu.
  10837.  
  10838.  bSameProcess = ( pid == pidSource );
  10839.  if ( bSameProcess ){
  10840.     HWND Owner;
  10841.     char Class[20] = "";
  10842.  
  10843.     // Check class name of source window... get UCMData of source only
  10844.     // if it is really a UCMenu window.  Check by looking at owner
  10845.     // of source window (menu or submenu).
  10846.  
  10847.     Owner = WinQueryWindow(pDraginfo->hwndSource, QW_OWNER);
  10848.     WinQueryClassName(Owner, sizeof(Class), Class);
  10849.     if (!strcmp(Class, UCMCLASS))
  10850.       IsUCMenu = TRUE;
  10851.     else {
  10852.       Owner = WinQueryWindow(Owner, QW_OWNER);
  10853.       WinQueryClassName(Owner, sizeof(Class), Class);
  10854.       if (!strcmp(Class, UCMCLASS))
  10855.         IsUCMenu = TRUE;
  10856.     }
  10857.  
  10858.     if (IsUCMenu) {
  10859.       UCMDataSource = (PUCMDATA) WinQueryWindowULong( pDraginfo->hwndSource, QWL_USER);
  10860.       ulStyleSource = UCMDataSource->Style;
  10861.     }
  10862.  } /* endif */
  10863.  
  10864.  /* ---------------------------------------------------------------------- */
  10865.  /* Determine if a drop can be accepted                                    */
  10866.  /* ---------------------------------------------------------------------- */
  10867.  usIndicator = DOR_DROP;
  10868.  if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 ){
  10869.     pDraginfo->usOperation = DO_UNKNOWN;
  10870.  } // endif
  10871.  usOperation = pDraginfo->usOperation;
  10872.  switch (pDraginfo->usOperation) {
  10873.    case DO_COPY:
  10874.      usOperation = DO_COPY;
  10875.      break;
  10876.    case DO_MOVE:
  10877.      usOperation = DO_MOVE;
  10878.      break;
  10879.    case DO_DEFAULT:
  10880.      {
  10881.         if ( !bSameProcess ) {
  10882.            usOperation = DO_COPY;
  10883.         } else if (  DrgVerifyRMF (pditem, "DRM_UCMITEM",  "DRF_UNKNOWN") ){
  10884.            // At this point we are sure that the process is the same for
  10885.            // source and target so it makes sense to compare the PUCMDATA
  10886.            // pointers to know whether we are in the same ucmenu or not
  10887.            if ( ( ulStyleSource & UCS_NO_DM_M_TO_OTHER ) && ( UCMData != UCMDataSource ) ) {
  10888.               usOperation = DO_COPY;
  10889.            } else {
  10890.               usOperation = DO_MOVE;
  10891.            } /* endif */
  10892.         } else if( DrgVerifyRMF(pditem, "DRM_OS2FILE", "DRF_TEXT") )  {
  10893.            usOperation = DO_COPY;
  10894.         } // endif
  10895.      }
  10896.      break;
  10897.    case DO_UNKNOWN:
  10898.       {
  10899.  
  10900.          usIndicator = DOR_NODROP;
  10901.  
  10902.          if ( !( UCMData->Style & UCS_NO_DM_ALT ) ){
  10903.             POINTL ptlPos;
  10904.             USHORT usItemid;
  10905.             ptlPos.x = pDraginfo->xDrop;
  10906.             ptlPos.y=  pDraginfo->yDrop;
  10907.             WinMapWindowPoints(HWND_DESKTOP, UCMData->hwndMenu, &ptlPos, 1);
  10908.             usItemid = UCMenuIdFromCoord( UCMData->hwndMenu, &ptlPos );
  10909.             if ( usItemid ){
  10910.                MENUITEM mi;
  10911.                memset( &mi, '\0', sizeof mi );
  10912.                if ( WinSendMsg( UCMData->hwndMenu,
  10913.                                 MM_QUERYITEM,
  10914.                                 MPFROM2SHORT( usItemid, FALSE ),
  10915.                                MPFROMP( &mi ) )
  10916.                     && !( mi.afStyle & MIS_SPACER ) ){
  10917.                   // We only accept alt drops over non spacer or non static items
  10918.                   // We also don't want alt drop over the hide window (in this case usItemid will be 0)
  10919.                   usIndicator = DOR_DROP;
  10920.                   usOperation = DO_COPY; // We will get a DO_UNKNOWN anyway in DM_DROP !!
  10921.                } // endif
  10922.             } // endif
  10923.          } // endif
  10924.       }
  10925.       break;
  10926.   default:
  10927.      usIndicator = DOR_NODROP;
  10928.      usOperation = 0;
  10929.  } // endswitch
  10930.  
  10931.  // --------------------------------------------------------------------------------
  10932.  // -- In order to support the drop, the source must support  a rendering
  10933.  // --  mechanims of <DRM_UCMENU,DRF_UNKNOWN> or <DRM_OS2FILE,DRF_UNKNOWN>
  10934.  // --  We also check the UCS_ flags  to know if the requested operation is allowed
  10935.  // --------------------------------------------------------------------------------
  10936.  if ( DrgVerifyRMF (pditem, "DRM_UCMITEM",  "DRF_UNKNOWN") ){
  10937.     //(MAM) source may be a submenu of this UCM, need OR conditition
  10938.     BOOL bSameUCM = (UCMData->hwndMenu==pDraginfo->hwndSource)||
  10939.                     (UCMData->hwndMenu==WinQueryWindow(pDraginfo->hwndSource, QW_OWNER));
  10940.     BOOL bMove    = (usOperation == DO_MOVE); // else it is a copy
  10941.  
  10942.  
  10943.     if ( bSameUCM && ( !bMove && ulStyle&UCS_NO_DM_C_INSIDE
  10944.                      || bMove && ulStyle&UCS_NO_DM_M_INSIDE )
  10945.      || !bSameUCM && ( !bMove && ( ulStyle&UCS_NO_DM_C_FROM_OTHER || ulStyleSource&UCS_NO_DM_C_TO_OTHER )
  10946.                      || bMove && ( ulStyle&UCS_NO_DM_M_FROM_OTHER || ulStyleSource&UCS_NO_DM_M_TO_OTHER ) ) ) {
  10947.        usIndicator = DOR_NODROP;
  10948.     } // endif
  10949.  } else if (  DrgVerifyRMF( pditem, "DRM_OS2FILE", "DRF_TEXT" )
  10950.            && DrgVerifyType( pditem, DRT_BITMAP ) )  {
  10951.     if ( UCMData->Style&UCS_NO_DM_RENDER_FROM_BMP ) {
  10952.        usIndicator = DOR_NODROP;
  10953.     } // endif
  10954.  } else {
  10955.     usIndicator = DOR_NODROP;
  10956.  } // endif
  10957.  
  10958.  
  10959.  DrgFreeDraginfo (pDraginfo);
  10960.  
  10961.  return (MRFROM2SHORT(usIndicator, usOperation));
  10962. }
  10963.  
  10964. //--------------------------------------------------------------------------//
  10965. //------------------------------- DROP CODE --------------------------------//
  10966. //--------------------------------------------------------------------------//
  10967. //----------------------------------------------------------------------------
  10968. // UCMenuDrop : not for the user's doc
  10969. //----------------------------------------------------------------------------
  10970. // :pfunction res=&IDF_DROP. name='UCMenuDrop' text='Called when something is dropped on a ucmenu'.
  10971. // This function is called whenever something is dropped on a ucmenu.
  10972. // :syntax name='UCMenuDrop' params='hwnd, pDragInfo' return='-'.
  10973. // :fparams.
  10974. // :fparam name='hwnd' type='HWND' io='input'.
  10975. // Handle of the window receiving the drop.
  10976. // :fparam name='pDragInfo' type='PDRAGINFO' io='input' .
  10977. // Pointer to the draginfo structure
  10978. // :freturns.
  10979. // :fparam name='-' type='VOID' io='-'.
  10980. // Nothing
  10981. // :efparams.
  10982. // :remarks.
  10983. // :related.
  10984. // :epfunction.
  10985. //----------------------------------------------------------------------------
  10986. VOID  _Optlink UCMenuDrop(HWND hwnd, PDRAGINFO pDraginfo)
  10987. {
  10988.    PDRAGITEM     pditem;
  10989.    TID           tid;
  10990.    PID           pidSource, pidTarget;
  10991.    BOOL          bAlt;
  10992.    PUCMDATA      UCMData = (PUCMDATA) WinQueryWindowULong( hwnd, QWL_USER );
  10993.  
  10994.  
  10995.    // ----------------------------------------------------------------------------
  10996.    // -- If we are on any window other than a submenu, pretend we are on the menu
  10997.    // ----------------------------------------------------------------------------
  10998.    if (WinQueryWindow( hwnd, QW_OWNER ) != UCMData->hwndMenu) {
  10999.       hwnd = UCMData->hwndMenu;
  11000.    } // endif
  11001.  
  11002.  
  11003.    UCMenuRemoveDropEmphasis( UCMData, hwnd);
  11004.  
  11005.  
  11006.    DrgAccessDraginfo (pDraginfo);
  11007.   
  11008.    // ----------------------------------------------------------------------------
  11009.    // -- Set up a flag to know whether ALT was pressed or not
  11010.    // ----------------------------------------------------------------------------
  11011.    if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 ){
  11012.       // !! If alt was pressed before beginning the drag, usOperation will be DO_MOVE !!
  11013.       pDraginfo->usOperation = DO_UNKNOWN;
  11014.       bAlt = TRUE;
  11015.    } else {
  11016.       bAlt = FALSE;
  11017.    } // endif
  11018.   
  11019.    if (!WinQueryWindowProcess( hwnd, &pidTarget, &tid )) {
  11020.       pidTarget = 0;
  11021.    } // endif
  11022.   
  11023.    if (!WinQueryWindowProcess( pDraginfo->hwndSource, &pidSource, &tid )) {
  11024.       pidSource = 0;
  11025.    } // endif
  11026.   
  11027.    pditem = DrgQueryDragitemPtr (pDraginfo, 0);
  11028.    if ( pditem ) {
  11029.      /* ---------------------------------------------------------------------- */
  11030.      /* Let's render                                                           */
  11031.      /* ---------------------------------------------------------------------- */
  11032.      /* We assume only one object is being dragged                             */
  11033.      /* ---------------------------------------------------------------------- */
  11034.      PDRAGTRANSFER   pDxfer;
  11035.      PVOID           pSharedMem;
  11036.      BOOL            bFullItemDropped;
  11037.      BOOL            bRenderSuccess = TRUE;
  11038.   
  11039.      // -- We ask the source to render
  11040.      pDxfer = DrgAllocDragtransfer(1);
  11041.      pDxfer->cb               = sizeof(DRAGTRANSFER);
  11042.      pDxfer->hwndClient       = hwnd;
  11043.      pDxfer->pditem           = pditem;
  11044.      pDxfer->hstrRenderToName = 0;
  11045.      pDxfer->usOperation      = pDraginfo->usOperation;
  11046.      pDxfer->fsReply          = 0;
  11047.      pDxfer->ulTargetInfo     = 0;
  11048.   
  11049.      if (DrgVerifyRMF( pditem, "DRM_UCMITEM", "DRF_UNKNOWN" )){
  11050.         // ------------------------------------------------------------------------
  11051.         // -- We want a full ucmenu item
  11052.         // ------------------------------------------------------------------------
  11053.         pDxfer->hstrSelectedRMF  = DrgAddStrHandle("<DRM_UCMITEM,DRF_UNKNOWN>");
  11054.         // ------------------------------------------------------------------------
  11055.         // -- In case the source is in another process, allocate some shared mem
  11056.         // ------------------------------------------------------------------------
  11057.         if (pidSource!=pidTarget) {
  11058.            // ------------------------------------------------------------------------
  11059.            // -- We will store in that mem the MENUITEM and UCMITEM structures
  11060.            // -- associated to an item, so one page (4K) should be enough
  11061.            // -- (We will use DosSubAllocMem, which has a granularity of 8 bytes and not 4096)
  11062.            // ------------------------------------------------------------------------
  11063.            DosAllocSharedMem( &pSharedMem, 0, 4000, PAG_READ | PAG_WRITE |  PAG_COMMIT | OBJ_GIVEABLE );
  11064.            DosSubSetMem( pSharedMem, DOSSUB_INIT, 4000 );
  11065.            DosGiveSharedMem( pSharedMem, pidSource, PAG_READ | PAG_WRITE );
  11066.            pDxfer->ulTargetInfo = (ULONG)pSharedMem;
  11067.         } // endif
  11068.         bFullItemDropped = TRUE;
  11069.      } else {
  11070.         // ------------------------------------------------------------------------
  11071.         // -- We are sure that this RMF is supported because of the DM_DRAGOVER processing
  11072.         // -- We will make a new ucmenu item using this bitmap
  11073.         // ------------------------------------------------------------------------
  11074.         pDxfer->hstrSelectedRMF = DrgAddStrHandle("<DRM_OS2FILE,DRF_TEXT>");
  11075.         bFullItemDropped = FALSE;
  11076.      } // endif
  11077.   
  11078.      // ------------------------------------------------------------------------
  11079.      // -- If it is a ucmenu item, we always ask the rendering
  11080.      // --   (because we render differently if the processes are not the same)
  11081.      // -- If it is a bmp file, we ask the rendering only if the filename is not provided.
  11082.      // ------------------------------------------------------------------------
  11083.      if ( bFullItemDropped || !pditem->hstrSourceName ) {
  11084.         bRenderSuccess = (BOOL)DrgSendTransferMsg( pDraginfo->hwndSource,
  11085.                                                    DM_RENDER,
  11086.                                                    (MPARAM)pDxfer,
  11087.                                                    (MPARAM)0 );
  11088.      } else {
  11089.         // ----------------------------------------------------------------
  11090.         // -- Bmp file whose name is provided : we can render by ourselves.
  11091.         // ----------------------------------------------------------------
  11092.         DrgDeleteStrHandle( pDxfer->hstrSelectedRMF );
  11093.      } // endif
  11094.   
  11095.      /* We must always free the drag xfer structure.  Target of DM_RENDER */
  11096.      /* must also free it because DrgSendTransferMsg() does a DosGive()   */
  11097.      /* to the target process but not DosFree().                          */
  11098.      DrgFreeDragtransfer( pDxfer );
  11099.   
  11100.      if ( bRenderSuccess ) {
  11101.         MENUITEM * pMiNew;
  11102.         HWND       hwndDest;
  11103.         POINTL     ptlPos;
  11104.         USHORT     usItemid;    // ID of the target item
  11105.         SHORT      sIndex;      // Index used to insert the item
  11106.         PSZ        pszRenderInfo;
  11107.         ULONG      ul;
  11108.   
  11109.         // -------------------------------------------------------
  11110.         // -- Decide which window will handle the item insertion
  11111.         // -------------------------------------------------------
  11112.         if ( WinQueryWindow( hwnd, QW_OWNER ) != UCMData->hwndMenu ){
  11113.            // -- If we are not on a submenu, the ucmenu will do the insertion
  11114.            hwndDest = WinQueryWindow( hwnd, QW_OWNER );
  11115.         } else {
  11116.            // -- If we are on a submenu, it can handle the insert by itself
  11117.            hwndDest = hwnd;
  11118.         } // endif
  11119.   
  11120.   
  11121.         // ----------------------------------------------------------------------------
  11122.         // -- Get the rendered information
  11123.         // ----------------------------------------------------------------------------
  11124.         ul = DrgQueryStrNameLen(pditem->hstrSourceName) + 1;
  11125.         pszRenderInfo = (PSZ)MyMalloc(ul);
  11126.         DrgQueryStrName(pditem->hstrSourceName,    // string handle
  11127.                         ul,                        // Nb of bytes
  11128.                         pszRenderInfo);            // buffer
  11129.   
  11130.         // ----------------------------------------------------------------------------
  11131.         // -- Use the rendered info to fill in the MENUITEM
  11132.         // ----------------------------------------------------------------------------
  11133.         {
  11134.            pMiNew = MyMalloc( sizeof(MENUITEM) );
  11135.            memset(pMiNew, 0, sizeof(MENUITEM));
  11136.            if ( bFullItemDropped ) {
  11137.   
  11138.               MENUITEM * pMiTransfered = 0;
  11139.   
  11140.               sscanf(pszRenderInfo, "%u", &pMiTransfered);
  11141.               pMiNew->iPosition   = pMiTransfered->iPosition;
  11142.               pMiNew->afStyle     = pMiTransfered->afStyle;
  11143.               pMiNew->afAttribute = pMiTransfered->afAttribute;
  11144.               pMiNew->id          = pMiTransfered->id;
  11145.               pMiNew->hwndSubMenu = pMiTransfered->hwndSubMenu;
  11146.               if ( pMiTransfered->hItem ){
  11147.                  pMiNew->hItem = (ULONG)MyMalloc(sizeof(UCMITEM));
  11148.                  memset((PVOID)pMiNew->hItem, 0, sizeof(UCMITEM));
  11149.                  ITEM(pMiNew, hBmp)    = ITEM(pMiTransfered, hBmp);
  11150.                  ITEM(pMiNew, pszBmp)  = MyStrdup( ITEM(pMiTransfered, pszBmp) );
  11151.                  ITEM(pMiNew, pszText) = MyStrdup( ITEM(pMiTransfered, pszText) );
  11152.                  ITEM(pMiNew, pszAction) = MyStrdup( ITEM(pMiTransfered, pszAction) );
  11153.                  ITEM(pMiNew, pszParameters) = MyStrdup( ITEM(pMiTransfered, pszParameters) );
  11154.                  ITEM(pMiNew, pszData) = MyStrdup( ITEM(pMiTransfered, pszData) );
  11155.               }
  11156.               if (pidSource==pidTarget) {
  11157.                  // -- Same process -> the transfered item has been allocated with MyMalloc
  11158.                  // -- Else, it is in shared mem, the whole shared mem bank will be freed
  11159.                  // --  at the end of UCMenuDrop
  11160.                  MyFree( pMiTransfered );
  11161.               } // endif
  11162.            } else {
  11163.               // -- We have here a bitmap file name
  11164.               ULONG ul2;
  11165.   
  11166.               pMiNew->hItem = (ULONG)MyMalloc(sizeof(UCMITEM));
  11167.               memset((PVOID)pMiNew->hItem, 0, sizeof(UCMITEM));
  11168.   
  11169.               ul2 = DrgQueryStrNameLen(pditem->hstrContainerName)+1;
  11170.               ((UCMITEM*)pMiNew->hItem)->pszBmp = MyMalloc(ul+ul2);
  11171.               DrgQueryStrName( pditem->hstrContainerName, ul2, ITEM(pMiNew,pszBmp));
  11172.               strcat( ITEM(pMiNew,pszBmp), pszRenderInfo );
  11173.               pMiNew->afStyle = MIS_OWNERDRAW;
  11174.            } // endif
  11175.         }
  11176.   
  11177.         // ----------------------------------------------------------------------------
  11178.         // -- Force the reloading of the bitmap if necessary
  11179.         // ----------------------------------------------------------------------------
  11180.         if ( pMiNew->hItem &&
  11181.             ( pidSource!=pidTarget || pDraginfo->usOperation==DO_COPY || pDraginfo->usOperation==DO_UNKNOWN ) ) {
  11182.            // ----------------------------------
  11183.            // -- Release the bitmap if necessary
  11184.            // ----------------------------------
  11185.            if ( ITEM(pMiNew,hBmp) &&
  11186.                 (pidSource!=pidTarget) &&
  11187.                 (pDraginfo->usOperation==DO_MOVE) ){
  11188.               GpiDeleteBitmap( ITEM(pMiNew,hBmp) );
  11189.            } // endif
  11190.            ITEM(pMiNew,hBmp) = 0;
  11191.         } // endif
  11192.   
  11193.         // -----------------------------------------------------------------------------
  11194.         // -- (MAM) remove any MIS_BREAK
  11195.         // -----------------------------------------------------------------------------
  11196.         pMiNew->afStyle &= (USHORT) ~MIS_BREAK;
  11197.   
  11198.         // ----------------------------------------------------------------------------
  11199.         // -- Query where the item has to be dropped (index in the menu)
  11200.         // ----------------------------------------------------------------------------
  11201.         ptlPos.x = pDraginfo->xDrop;
  11202.         ptlPos.y=  pDraginfo->yDrop;
  11203.         WinMapWindowPoints(HWND_DESKTOP, hwnd, &ptlPos, 1);
  11204.         usItemid = UCMenuIdFromCoord(hwnd, &ptlPos);
  11205.         if (usItemid) {
  11206.            RECTL    rect;
  11207.            if ( bAlt && ( hwnd == UCMData->hwndMenu ) ){
  11208.               MENUITEM mi;
  11209.               WinSendMsg( hwnd,
  11210.                           MM_QUERYITEM,
  11211.                           MPFROM2SHORT( usItemid, FALSE ), 
  11212.                           MPFROMP( &mi ) );
  11213.   
  11214.               if ( !( mi.afStyle & MIS_SUBMENU ) ){
  11215.               
  11216.                  mi.afStyle |= MIS_SUBMENU;
  11217.                  mi.hwndSubMenu = WinCreateWindow( HWND_OBJECT,
  11218.                                                    WC_MENU,
  11219.                                                    "",
  11220.                                                    0, // WS_*
  11221.                                                    0,
  11222.                                                    0,
  11223.                                                    0,
  11224.                                                    0,
  11225.                                                    UCMData->hwndMenu,
  11226.                                                    HWND_BOTTOM,
  11227.                                                    usItemid,
  11228.                                                    0,
  11229.                                                    0 );
  11230.                 WinSendMsg( WinQueryWindow( UCMData->hwndMenu, QW_OWNER ),  // ucmenu window
  11231.                             MM_SETITEM,
  11232.                             MPFROM2SHORT( usItemid, FALSE ), 
  11233.                             MPFROMP( &mi ) );
  11234.               } // endif
  11235.   
  11236.               hwndDest = hwnd = mi.hwndSubMenu;
  11237.            } // endif
  11238.   
  11239.            sIndex = (SHORT)WinSendMsg( hwnd,
  11240.                                        MM_ITEMPOSITIONFROMID,
  11241.                                        MPFROM2SHORT(usItemid, FALSE), 
  11242.                                        (MPARAM)0 );
  11243.            // -------------------------------------------------------------------------------------
  11244.            // -- If it is an item of a vertical ucmenu or of a submenu of an horizontal ucmenu, we
  11245.            // --  put the dropped item before if it is dropped over the top half and after else.
  11246.            // -- If it is an item of an horizontal ucmenu or of a submenu of a vertical ucmenu, we
  11247.            // --  put the dropped item before if it is dropped over the left half and after else.
  11248.            // -- A matrix ucmenu is here processed in the same way as an horizontal one.
  11249.            // -------------------------------------------------------------------------------------
  11250.            if ( WinSendMsg( hwnd, MM_QUERYITEMRECT, MPFROM2SHORT( usItemid, FALSE ), MPFROMP( &rect ) ) ) { 
  11251.               HWND hwndUCMDest = WinQueryWindow( hwnd, QW_OWNER );
  11252.               ULONG Style      = WinQueryWindowULong( hwndUCMDest, QWL_STYLE );
  11253.               if (   ( (Style & CMS_VERT) && (hwnd == UCMData->hwndMenu))  ||
  11254.                      (!(Style & CMS_VERT) && (hwnd != UCMData->hwndMenu)) ) {
  11255.                        if ( ptlPos.y < (rect.yTop+rect.yBottom)/2)
  11256.                          sIndex++;
  11257.               } else {
  11258.                  if ( ptlPos.x > (rect.xRight+rect.xLeft)/2) 
  11259.                    sIndex++;
  11260.               } // endif Style...
  11261.            } // endif WinSendMsg
  11262.   
  11263.         } else {
  11264.            sIndex = MIT_LAST;
  11265.         } // endif
  11266.   
  11267.         if (sIndex==MIT_LAST || sIndex==MIT_NONE) {
  11268.           // -------------------------------------------------------
  11269.           // -- Query item count : item insert after all the others
  11270.           // -------------------------------------------------------
  11271.           sIndex = (SHORT)WinSendMsg(hwnd,
  11272.                                      MM_QUERYITEMCOUNT,
  11273.                                      (MPARAM)0,
  11274.                                      (MPARAM)0);
  11275.         } // endif
  11276.   
  11277.         // -----------------------------------------------------------------------
  11278.         // -- Before dropping, we unselect all the items of the dest menu
  11279.         // -- because the open submenu of a nodismiss submenu item do not follow
  11280.         // -- it when this item is moved
  11281.         // -----------------------------------------------------------------------
  11282.         UCMenuUnselectAll( UCMData->hwndMenu );
  11283.   
  11284.         switch (pDraginfo->usOperation) {
  11285.           case DO_UNKNOWN:
  11286.              // This is for the Alt dropping
  11287.           case DO_COPY:
  11288.             {
  11289.                // --------------------------------------------------------------------------------
  11290.                // -- If dropped item was a submenu placeholder, turn it into a regular item.
  11291.                // --------------------------------------------------------------------------------
  11292.                pMiNew->afStyle     &= (USHORT)~MIS_SUBMENU;
  11293.                //(MAM) also remove NODISMISS attribute
  11294.                pMiNew->afAttribute &= (USHORT)~MIA_NODISMISS;
  11295.                pMiNew->hwndSubMenu  = NULLHANDLE;
  11296.                pMiNew->iPosition    = sIndex;
  11297.                pMiNew->id           = UCMenuGetNewID( UCMData->hwndMenu, MIT_NONE, UCMData );
  11298.   
  11299.                WinSendMsg(hwndDest,
  11300.                           MM_INSERTITEM,
  11301.                           MPFROMP(pMiNew),
  11302.                           (MPARAM)0);
  11303.   
  11304.             }
  11305.             break;
  11306.   
  11307.           case DO_MOVE:
  11308.             { SHORT sSourcePos    = pMiNew->iPosition;
  11309.               USHORT SourceMenuID = pMiNew->id;
  11310.   
  11311.               if ( ( pMiNew->hwndSubMenu && ( hwnd != UCMData->hwndMenu ) )
  11312.                    || pidSource!=pidTarget ){
  11313.                  // --------------------------------------------------------------------------
  11314.                  // -- Only one submenu level is supported
  11315.                  // -- If we move an item with a submenu into another one, we remove its submenu
  11316.                  // -- We don't move the submenus from other apps because it's too complicated...
  11317.                  // --------------------------------------------------------------------------
  11318.                  UCMenuFreeMenuData( pMiNew->hwndSubMenu );
  11319.                  WinDestroyWindow( pMiNew->hwndSubMenu );
  11320.                  pMiNew->afStyle    &= (USHORT)~MIS_SUBMENU; // turn into a normal item if submenu holder
  11321.                  pMiNew->afAttribute&= (USHORT)~MIA_NODISMISS;
  11322.                  pMiNew->hwndSubMenu = 0;
  11323.               } // endif
  11324.   
  11325.               if ( pditem->hwndItem == hwnd ) {
  11326.                 // --------------------------------------------------------------------------
  11327.                 // -- Same destination : the item interferes with its index
  11328.                 // --------------------------------------------------------------------------
  11329.                 if (sSourcePos<sIndex) {
  11330.                   pMiNew->iPosition = sIndex - 1;
  11331.                 } else {
  11332.                   pMiNew->iPosition = sIndex;
  11333.                 } // endif
  11334.               } else {
  11335.                 // --------------------------------------------------------------------------
  11336.                 // -- Different UCMenus : we need a new ID !
  11337.                 // --------------------------------------------------------------------------
  11338.                 pMiNew->id        = UCMenuGetNewID( UCMData->hwndMenu, MIT_NONE, UCMData );
  11339.                 pMiNew->iPosition = sIndex;
  11340.               } // endif
  11341.   
  11342.               if ( bFullItemDropped ) {
  11343.                  // --------------------------------------------------------------------------
  11344.                  // -- The dropped object was coming from a ucmenu
  11345.                  // --------------------------------------------------------------------------
  11346.                  if ( pidSource == pidTarget) {
  11347.                     MENUITEM mi;
  11348.                     WinSendMsg( pDraginfo->hwndSource,
  11349.                                 MM_QUERYITEM,
  11350.                              // (MAM) source may have been a submenu item, so we need
  11351.                              //       to search submenus also.
  11352.                              // MPFROM2SHORT( SourceMenuID, FALSE ),
  11353.                                 MPFROM2SHORT( SourceMenuID, TRUE  ),
  11354.                                 MPFROMP( &mi ) );
  11355.                     if ( mi.hItem ) {
  11356.                        if ( ITEM( &mi, pszBmp ) ){    MyFree( ITEM( &mi, pszBmp ) ); }
  11357.                        if ( ITEM( &mi, pszText ) ){   MyFree( ITEM( &mi, pszText ) ); }
  11358.                        if ( ITEM( &mi, pszAction ) ){ MyFree( ITEM( &mi, pszAction ) ); }
  11359.                        if ( ITEM( &mi, pszParameters ) ){ MyFree( ITEM( &mi, pszParameters ) ); }
  11360.                        if ( ITEM( &mi, pszData ) ){   MyFree( ITEM( &mi, pszData ) ); }
  11361.                     } // endif
  11362.                     WinSendMsg(WinQueryWindow(pDraginfo->hwndSource, QW_OWNER),
  11363.                                MM_REMOVEITEM,
  11364.                             // (MAM) Source item may have been a submenu, so we
  11365.                             //       need TRUE here to delete submenu source items.  This
  11366.                             //       is safe since all UCMenu item IDs should be unique.
  11367.                             // MPFROM2SHORT(SourceMenuID, FALSE),
  11368.                                MPFROM2SHORT(SourceMenuID, TRUE),
  11369.                                (MPARAM)0);
  11370.                  } else {
  11371.                     WinSendMsg(WinQueryWindow(pDraginfo->hwndSource, QW_OWNER),
  11372.                                MM_DELETEITEM,
  11373.                             // (MAM) Source item may have been a submenu, so we
  11374.                             //       need TRUE here to delete submenu source items.  This
  11375.                             //       is safe since all UCMenu item IDs should be unique.
  11376.                             // MPFROM2SHORT(SourceMenuID, FALSE),
  11377.                                MPFROM2SHORT(SourceMenuID, TRUE),
  11378.                                (MPARAM)0);
  11379.                  } // endif
  11380.               }
  11381.   
  11382.               WinSendMsg(hwndDest,
  11383.                          MM_INSERTITEM,
  11384.                          MPFROMP( pMiNew ),
  11385.                          (MPARAM)0 );
  11386.             } break;
  11387.           default:
  11388.             //-- invalid operation
  11389.             break;
  11390.         } // endswitch
  11391.         // ----------------------------------------------------------------------------------------
  11392.         // -- We can now free pMiNew, it was either allocated by us or by the source using MyMalloc
  11393.         // ----------------------------------------------------------------------------------------
  11394.         MyFree( pMiNew );
  11395.      } // endif render successful
  11396.   
  11397.   
  11398.      // ----------------------------------------------------------------------------------------
  11399.      // -- Now let's notify the source that it can release the resources it allocated for the rendering.
  11400.      // ----------------------------------------------------------------------------------------
  11401.      DrgSendTransferMsg( pDraginfo->hwndSource,
  11402.                          DM_ENDCONVERSATION,
  11403.                          (MPARAM)pditem->ulItemID,
  11404.                          (MPARAM)DMFL_TARGETSUCCESSFUL);
  11405.   
  11406.   
  11407.      // ---------------------------------------------------------------------------------------
  11408.      // -- If we did allocate shared memory, free it
  11409.      // ---------------------------------------------------------------------------------------
  11410.      if ( bFullItemDropped && pidSource!=pidTarget ) {
  11411.         DosSubUnsetMem( pSharedMem );
  11412.         DosFreeMem( pSharedMem );
  11413.      } // endif
  11414.   
  11415.    } // endif  pditem
  11416.   
  11417.    // ---------------------------------------------------------------------------------------
  11418.    // -- free the resource:
  11419.    // ---------------------------------------------------------------------------------------
  11420.    DrgDeleteDraginfoStrHandles (pDraginfo);
  11421.    DrgFreeDraginfo (pDraginfo);
  11422. }
  11423.  
  11424. //----------------------------------------------------------------------------
  11425. // UCMenuPresParamChanged : not for the user's doc
  11426. //----------------------------------------------------------------------------
  11427. // :pfunction res=&IDF_PPCHG. name='UCMenuPresParamChanged' text='Processes the presentation parameter changes'.
  11428. // This function is called within the WM_PRESPARAMCHANGED processing.
  11429. // :syntax name='UCMenuPresParamChanged' params='hwndUCM, hwnd, mp1' return='-'.
  11430. // :fparams.
  11431. // :fparam name='hwndUCM' type='HWND' io='input'.
  11432. // Handle of the ucmenu
  11433. // :fparam name='hwnd' type='HWND' io='input'.
  11434. // Handle of the window which received WM_PRESPARAMCHANGED
  11435. // :p.It can be any of the windows part of a UCMenu.
  11436. // :fparam name='mp1' type='MPARAM' io='input' .
  11437. // First parameter of the WM_PRESPARAMCHANGED message
  11438. // :freturns.
  11439. // :fparam name='-' type='VOID' io='-'.
  11440. // Nothing
  11441. // :efparams.
  11442. // :remarks.
  11443. // :related.
  11444. // :epfunction.
  11445. //----------------------------------------------------------------------------
  11446. VOID _Optlink UCMenuPresParamChanged(PUCMDATA UCMData, HWND hwnd, MPARAM mp1)
  11447. {
  11448.    ULONG x;
  11449.  
  11450.    if ( (SHORT)mp1 == PP_BACKGROUNDCOLOR ) {
  11451.       ULONG Color;
  11452.  
  11453.       WinQueryPresParam( hwnd,
  11454.                          (SHORT)mp1,
  11455.                          0L, &x,
  11456.                          (ULONG)sizeof Color,
  11457.                          &Color,
  11458.                          QPF_NOINHERIT);
  11459.       if (x == (SHORT)mp1) {
  11460.          // We tell the menu to change its color
  11461.          // It will change UCMData->ItemBgColor and have everything redrawn
  11462.          WinSetPresParam( UCMData->hwndMenu,
  11463.                           PP_MENUBACKGROUNDCOLOR,
  11464.                           sizeof Color,
  11465.                           &Color);
  11466.       } else {
  11467.          WinRemovePresParam( hwnd, PP_BACKGROUNDCOLOR );
  11468.       } // endif
  11469.    } else if ( (SHORT)mp1 == PP_FONTNAMESIZE ) {
  11470.       CHAR FontNameSize[100];
  11471.  
  11472.       WinQueryPresParam( hwnd,
  11473.                          (SHORT)mp1,
  11474.                          0L, &x,
  11475.                          100L,
  11476.                          FontNameSize,
  11477.                          QPF_NOINHERIT );
  11478.       if (x == (SHORT)mp1) {
  11479.          // We remove this presparam from the window, because when the context
  11480.          // menu pops up, it uses the PP__FONTNAMESIZE font of its owner and we want
  11481.          // it to always use the default menu font. (its owner is the Hide window)
  11482.          WinRemovePresParam( hwnd, PP_FONTNAMESIZE );
  11483.          // We tell the menu to change its fonts
  11484.          // It will change UCMData->pszFontNameSize and have everything redrawn
  11485.          WinSetPresParam( UCMData->hwndMenu,
  11486.                           PP_FONTNAMESIZE,
  11487.                           strlen(FontNameSize)+1,
  11488.                           FontNameSize);
  11489.          // Tell bubble window about font changes
  11490.          if (UCMData->Style & UCS_BUBBLEHELP)
  11491.            WinSetPresParam( UCMData->hwndBubble,
  11492.                             PP_FONTNAMESIZE,
  11493.                             strlen(FontNameSize)+1,
  11494.                             FontNameSize);
  11495.       } else {
  11496.          WinRemovePresParam( hwnd, PP_FONTNAMESIZE );
  11497.       } // endif
  11498.  
  11499.    } // endif
  11500. }
  11501.  
  11502. //----------------------------------------------------------------------------
  11503. // UCMenuGetExePath : not for the user's doc
  11504. //----------------------------------------------------------------------------
  11505. // :pfunction res=&IDF_GETEXEPATH. name='UCMenuGetExePath' text='Finds the path of the program which called the dll'.
  11506. // This function returns the path of the exe file which called the ucmenu dll
  11507. // :syntax name='UCMenuGetExePath' params='-' return='pszPath'.
  11508. // :fparams.
  11509. // :freturns.
  11510. // :fparam name='pszPath' type='PSZ' io='return'.
  11511. // String containing the path
  11512. // :efparams.
  11513. // :remarks.
  11514. // :related.
  11515. // :epfunction.
  11516. //---------------------------------------------------------------------------
  11517. PSZ _Optlink UCMenuGetExePath(VOID)
  11518. {
  11519.   PTIB  ptib;
  11520.   PPIB  ppib = 0;
  11521.   ULONG rc;
  11522.   PSZ   psz = 0;
  11523.   rc = DosGetInfoBlocks(&ptib, &ppib);
  11524.   if (!rc) {
  11525.     CHAR sz[CCHMAXPATH];
  11526.     strcpy(sz, ppib->pib_pchcmd);
  11527.     strupr( sz );
  11528.     psz = strstr(sz, ".EXE");
  11529.     while (psz && (psz >= sz) && (*psz != '\\')) psz --;
  11530.     if (psz) {
  11531.       *psz = '\0';
  11532.       psz = MyStrdup(sz);
  11533.     } // endif
  11534.   } // endif
  11535.   return psz;
  11536. }
  11537.  
  11538. //----------------------------------------------------------------------------
  11539. // UCMenuGetBitmapPath : not for the user's doc
  11540. //----------------------------------------------------------------------------
  11541. // :pfunction res=&IDF_BMPPATH. name='UCMenuGetBitmapPath' text='Finds the path of the given bitmap file'.
  11542. // This function finds the access path of a given file.
  11543. // :syntax name='UCMenuGetBitmapPath' params='UCMData, pszBmp, pszPathName' return='success'.
  11544. // :fparams.
  11545. // :fparam name='UCMData' type='PUCMDATA' io='input'.
  11546. // Pointer to the UCMData structure
  11547. // :fparam name='pszBmp' type='PSZ' io='input'.
  11548. // String of the searched filename, which can also include a path and a drive
  11549. // :fparam name='pszPathName' type='MPARAM' io='output' .
  11550. // Full name of path found or "", must already be allocated to MAXPATHL characters
  11551. // :freturns.
  11552. // :fparam name='success' type='USHORT' io='return'.
  11553. // O if successful
  11554. // :efparams.
  11555. // :remarks.
  11556. // We look for the file (including any given path ) in the current directory, then we keep only the filename
  11557. // and look for it in the dir of the exe file, and in the path of the UCMData->pszBitmapSearchPath
  11558. // environment variables.
  11559. // :related.
  11560. // :epfunction.
  11561. //----------------------------------------------------------------------------
  11562. USHORT _Optlink UCMenuGetBitmapPath( PUCMDATA UCMData, PSZ pszBmp, PSZ pszPathName )
  11563. {
  11564.    PSZ   BitmapFile;
  11565.    UCHAR BitmapFileName[MAXPATHL];
  11566.    PSZ   Path;
  11567.    BOOL  FirstToken;
  11568.    UCHAR szBitmapSearchPath[MAXPATHL];
  11569.    ULONG DriveNumber, LogicalDriveMap;
  11570.    ULONG DirPathLen = MAXPATHL;
  11571.    BYTE DirPath[MAXPATHL];
  11572.    APIRET rc;
  11573.  
  11574.    // Query the current path
  11575.    // --
  11576.    rc =  DosQueryCurrentDisk( &DriveNumber, &LogicalDriveMap );
  11577.    rc += DosQueryCurrentDir( DriveNumber, DirPath, &DirPathLen );
  11578.  
  11579.    // Put in BitmapFileName the full access name of the given bitmap name in
  11580.    // the current drive and directory
  11581.    // --
  11582.    if ( pszBmp[1] == ':' && pszBmp[2] == '\\' ) {
  11583.       // The given filename includes the dir and path
  11584.       // --
  11585.       BitmapFileName[0] = '\0';
  11586.    } else  {
  11587.       // Add the default drive at the beginning
  11588.       // --
  11589.       BitmapFileName[0] = 'A' + DriveNumber - 1;
  11590.       BitmapFileName[1] = ':';
  11591.       BitmapFileName[2] = '\0';
  11592.       if ( pszBmp[0] != '\\' ) {
  11593.          // Add "\", current directory, and "\" before pszBmp;
  11594.          // --
  11595.          strcat( BitmapFileName, "\\" );
  11596.          strcat( BitmapFileName, DirPath );
  11597.          strcat( BitmapFileName, "\\" );
  11598.       }
  11599.    } // endif
  11600.    strcat( BitmapFileName, pszBmp );
  11601.  
  11602.    // Now BitmapFileName contains the full access name of the bitmap
  11603.    // We copy the directory part of it in DirPath
  11604.    // --
  11605.    BitmapFile = strrchr( BitmapFileName, '\\' );
  11606.    BitmapFile[0] = '\0';
  11607.    strcpy( DirPath, BitmapFileName );
  11608.    if ( ( DirPath[1] == ':' ) && ( DirPath[2] == '\0' ) ){
  11609.       // Drive only, we have to add \ else it will look
  11610.       // in the current directory of this drive
  11611.       // --
  11612.       strcat( DirPath, "\\" );
  11613.    } // endif
  11614.  
  11615.    // Now we make BitmapFile point to the filename only
  11616.    // We use pszBmp instead of BitmapFileName because  BitmapFileName
  11617.    // will be used after and have its content changed
  11618.    // --
  11619.    if ( BitmapFile = strrchr( pszBmp, '\\' ) ) {
  11620.       BitmapFile++;
  11621.    } else {
  11622.       BitmapFile = pszBmp;
  11623.    }
  11624.  
  11625.  
  11626.    // Try loading the bitmap from the current path with the given prefixing path
  11627.    // --
  11628.    if ( ! DosSearchPath( 0, DirPath, BitmapFile, BitmapFileName, MAXPATHL) ) {
  11629.       strcpy( pszPathName, DirPath );
  11630.       return 0;
  11631.    } // endif
  11632.  
  11633.    // Try loading the bitmap file from the exe directory
  11634.    // --
  11635.    {
  11636.       PSZ ExePath = UCMenuGetExePath();
  11637.       if ( ! DosSearchPath( 0, ExePath, BitmapFile, BitmapFileName, MAXPATHL) ) {
  11638.          strcpy( pszPathName, ExePath );
  11639.          MyFree( ExePath );
  11640.          return 0;
  11641.       } // endif
  11642.       MyFree( ExePath );
  11643.    }
  11644.  
  11645.    // If search Paths were specified search them
  11646.    // --
  11647.    if ( UCMData->szBitmapSearchPath[0] ) {
  11648.       strcpy( szBitmapSearchPath, UCMData->szBitmapSearchPath );
  11649.       FirstToken = 1;
  11650.       while( Path = strtok( FirstToken?szBitmapSearchPath:0, " " ) ) {
  11651.          if ( ! DosSearchPath( 2, Path, BitmapFile, BitmapFileName, MAXPATHL ) ) {
  11652.             Path = strrchr( BitmapFileName, '\\' );
  11653.             Path[0] = '\0';
  11654.             strcpy( pszPathName, BitmapFileName );
  11655.             return 0;
  11656.          } // endif
  11657.          FirstToken = 0;
  11658.       } // endwhile
  11659.    } // endif
  11660.  
  11661.    pszPathName[0] = '\0';
  11662.    return 1;
  11663. }
  11664.  
  11665. //----------------------------------------------------------------------------
  11666. // UCMenuGetBitmapFullName : not for the user's doc
  11667. //----------------------------------------------------------------------------
  11668. // :pfunction res=&IDF_BMPFULLNAME. name='UCMenuGetBitmapFullName' text='Finds the full access name of the given bitmap file'.
  11669. // This functions looks for the given file or the default one in  all the suitable directories and returns its full access name
  11670. // :syntax name='UCMenuGetBitmapFullName' params='UCMData, pszBmp, pszPathName' return='success'.
  11671. // :fparams.
  11672. // :fparam name='UCMData' type='PUCMDATA' io='input'.
  11673. // Pointer to the UCMData structure
  11674. // :fparam name='pszBmp' type='PSZ' io='input'.
  11675. // String of the searched filename, which can also include a path and a drive
  11676. // :fparam name='pszFullName' type='MPARAM' io='output' .
  11677. // Full name including the path found or "", must already be allocated to MAXPATHL characters
  11678. // :freturns.
  11679. // :fparam name='success' type='USHORT' io='return'.
  11680. // O if successful
  11681. // :efparams.
  11682. // :remarks.
  11683. // We look for the file (including any given path ) in the current directory, then we keep only the filename
  11684. // and look for it in the dir of the exe file, and in the path of the UCMData->pszBitmapSearchPath
  11685. // environment variables.
  11686. // :related.
  11687. // :epfunction.
  11688. //----------------------------------------------------------------------------
  11689. USHORT _Optlink UCMenuGetBitmapFullName( PUCMDATA UCMData, PSZ pszBmp, PSZ pszFullName )
  11690. {
  11691.    USHORT rc;
  11692.    PSZ    BitmapFile;
  11693.  
  11694.    rc = UCMenuGetBitmapPath( UCMData, pszBmp, pszFullName );
  11695.  
  11696.    // Strip any path prefixing the bitmap file name
  11697.    // --
  11698.    if ( ! ( BitmapFile = strrchr( pszBmp, '\\' ) ) ) {
  11699.       BitmapFile = pszBmp;
  11700.    } else {
  11701.       BitmapFile++;
  11702.    }
  11703.  
  11704.    if ( ! rc ) {
  11705.       ULONG ulLen = strlen( pszFullName );
  11706.       if ( pszFullName[ulLen-1] != '\\' ){
  11707.          strcat( pszFullName, "\\" );
  11708.       } // endif
  11709.       strcat( pszFullName, BitmapFile );
  11710.       return 0;
  11711.    } // endif
  11712.  
  11713. //... default bitmap may be a resource ID or file name, this
  11714. //... no longer works
  11715. //
  11716. // if ( *( UCMData->szDefaultBitmap ) ) {
  11717. //    rc = UCMenuGetBitmapPath( UCMData, UCMData->szDefaultBitmap, pszFullName );
  11718. //
  11719. //    // Strip any path prefixing the bitmap file name
  11720. //    // --
  11721. //    if ( ! ( BitmapFile = strrchr( UCMData->szDefaultBitmap, '\\' ) ) ) {
  11722. //       BitmapFile = UCMData->szDefaultBitmap;
  11723. //    } else {
  11724. //       BitmapFile++;
  11725. //    }
  11726. //
  11727. //    if ( ! rc ) {
  11728. //       ULONG ulLen = strlen( pszFullName );
  11729. //       if ( pszFullName[ulLen-1] != '\\' ){
  11730. //          strcat( pszFullName, "\\" );
  11731. //       } // endif
  11732. //       strcat( pszFullName, BitmapFile );
  11733. //       return 0;
  11734. //    } // endif
  11735. // } // endif pszDefaultBitmap
  11736.  
  11737.    pszFullName[0] = '\0';
  11738.    return 1;
  11739. }
  11740.  
  11741. //----------------------------------------------------------------------------
  11742. // GetMaxItemSize : not for the user's doc
  11743. //----------------------------------------------------------------------------
  11744. // :pfunction res=&IDF_MAXITSZ. name='GetMaxItemSize' text='Finds the size of the biggest item and updates UCMData'.
  11745. // This functions looks for the given file or the default one in  all the suitable directories and returns its full access name
  11746. // :syntax name='GetMaxItemSize' params='UCMData, hwndUCMenu, hwndMenu' return='-'.
  11747. // :fparams.
  11748. // :fparam name='UCMData' type='PUCMDATA' io='input'.
  11749. // Pointer to the UCMData structure
  11750. // :fparam name='hwndUCMenu' type='HWND' io='input'.
  11751. // UCMenu window handle
  11752. // :fparam name='hwndMenu' type='HWND' io='input' .
  11753. // Menu window handle
  11754. // :freturns.
  11755. // :fparam name='-' type='VOID' io='-'.
  11756. // :efparams.
  11757. // :remarks.
  11758. // :related.
  11759. // :epfunction.
  11760. //----------------------------------------------------------------------------
  11761. VOID _Optlink GetMaxItemSize(PUCMDATA UCMData, HWND hwndUCMenu, HWND hwndMenu)
  11762. {
  11763.    ULONG NumberOfItems = 0;
  11764.    ULONG Item;
  11765.    ULONG cx, cy;
  11766.    USHORT ItemID;
  11767.    MENUITEM mi;
  11768.    ULONG MaxHorizontalHeight, MaxVerticalWidth;
  11769.    ULONG SumItemWidths  = 0;
  11770.    ULONG SumItemHeights = 0;
  11771.  
  11772.    // Do not put anything but the actual new values in UCMData
  11773.    MaxVerticalWidth = MaxHorizontalHeight = 0;
  11774.  
  11775.    NumberOfItems = (ULONG)WinSendMsg(hwndMenu,
  11776.                                      MM_QUERYITEMCOUNT, 0L, 0L);
  11777.  
  11778.    if (NumberOfItems == 0) {
  11779.      cx = WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); // Set empty toolbar to PM menu height
  11780.      UCMData->MaxHorizontalHeight = cx;
  11781.      UCMData->MaxVerticalWidth    = cx;
  11782.      UCMData->SumItemWidths  = cx;
  11783.      UCMData->SumItemHeights = cx;
  11784.      return;
  11785.    }
  11786.  
  11787.    for(Item=0; Item<NumberOfItems; Item++) {
  11788.       ItemID = (USHORT)WinSendMsg(hwndMenu,
  11789.                                   MM_ITEMIDFROMPOSITION,
  11790.                                   MPFROMSHORT(Item),
  11791.                                   (MPARAM)0);
  11792.       WinSendMsg(hwndMenu,
  11793.                  MM_QUERYITEM,
  11794.                  MPFROM2SHORT(ItemID,FALSE),
  11795.                  MPFROMP(&mi));
  11796.  
  11797.       if (mi.hItem) {
  11798.          UCMenuCalcUnscaledItemSize( (PUCMITEM)mi.hItem, UCMData->Style, hwndUCMenu, &cx, &cy );
  11799.          SumItemWidths  += cx;
  11800.          SumItemHeights += cy;
  11801.       } else {
  11802.          cx = cy = 0;
  11803.       } // endif
  11804.  
  11805.       if ( cx > MaxVerticalWidth) {
  11806.          MaxVerticalWidth = cx;
  11807.       } /* endif */
  11808.  
  11809.       if ( cy > MaxHorizontalHeight) {
  11810.          MaxHorizontalHeight = cy;
  11811.       } /* endif */
  11812.  
  11813.    }
  11814.  
  11815.    UCMData->MaxHorizontalHeight = MaxHorizontalHeight;
  11816.    UCMData->MaxVerticalWidth    = MaxVerticalWidth;
  11817.    UCMData->SumItemWidths  = SumItemWidths;
  11818.    UCMData->SumItemHeights = SumItemHeights;
  11819.  
  11820. }
  11821.  
  11822.  
  11823. //----------------------------------------------------------------------------
  11824. // TranslateAccel : not for the user's doc
  11825. //----------------------------------------------------------------------------
  11826. // :pfunction res=&IDF_TRNACC. name='TranslateAccel' text='Translates an accelerator'.
  11827. // This functions translates an accelerator
  11828. // :syntax name='TranslateAccel' params='UCMData, hwndMenu, Key, QMsg' return='success'.
  11829. // :fparams.
  11830. // :fparam name='UCMData' type='PUCMDATA' io='input'.
  11831. // Pointer to the UCMData structure
  11832. // :fparam name='hwndMenu' type='HWND' io='input'.
  11833. // Menu window handle
  11834. // :fparam name='Key' type='USHORT' io='input' .
  11835. // :fparam name='QMsg' type='PQMSG' io='output'.
  11836. // :freturns.
  11837. // :fparam name='success' type='BOOL' io='return'.
  11838. // 0 if failure.
  11839. // :efparams.
  11840. // :remarks.
  11841. // :related.
  11842. // :epfunction.
  11843. //----------------------------------------------------------------------------
  11844. BOOL _Optlink TranslateAccel(PUCMDATA UCMData, HWND HwndMenu, USHORT Key, PQMSG QMsg)
  11845. {
  11846.     ULONG NbOfItems = UCMData->AccelTable->cAccel;
  11847.     ULONG i;
  11848.     for(i=0; i<NbOfItems; i++) {
  11849.     //??? Accelerator keys don't work, and need to remove use of toupper()
  11850.     //ctype
  11851.     //   if(toupper(Key) == toupper(UCMData->AccelTable->aaccel[i].key)) {
  11852.     //      QMsg->hwnd = HwndMenu;
  11853.     //      QMsg->msg  = MM_SELECTITEM;
  11854.     //      QMsg->mp1  = (MPARAM)UCMData->AccelTable->aaccel[i].cmd;
  11855.     //      QMsg->mp2  = MPFROM2SHORT(0, 1);
  11856.     //      return 1;
  11857.     //   }
  11858.     }
  11859.     return 0;
  11860. }
  11861.  
  11862. //----------------------------------------------------------------------------
  11863. // AddAccelItem : not for the user's doc
  11864. //----------------------------------------------------------------------------
  11865. // :pfunction res=&IDF_ADDACC. name='AddAccelItem' text='Adds an accelerator item'.
  11866. // This functions adds an accelerator
  11867. // :syntax name='AddAccelItem' params='UCMData, Key, id' return='-'.
  11868. // :fparams.
  11869. // :fparam name='UCMData' type='PUCMDATA' io='input'.
  11870. // Pointer to the UCMData structure
  11871. // :fparam name='Key' type='USHORT' io='input' .
  11872. // :fparam name='id' type='ULONG' io='input'.
  11873. // :freturns.
  11874. // :fparam name='-' type='VOID' io='-'.
  11875. // :efparams.
  11876. // :remarks.
  11877. // :related.
  11878. // :epfunction.
  11879. //----------------------------------------------------------------------------
  11880. VOID  _Optlink AddAccelItem(PUCMDATA UCMData, USHORT Key, ULONG id)
  11881. {
  11882.    ULONG Item = UCMData->AccelTable->cAccel;
  11883.    ULONG i;
  11884.  
  11885.    for(i=0; i<Item; i++) {
  11886.       if(UCMData->AccelTable->aaccel[i].key == Key) {
  11887.          UCMData->AccelTable->aaccel[i].cmd = id;
  11888.          return;
  11889.       }
  11890.    }
  11891.  
  11892.    UCMData->AccelTable->aaccel[Item].key = Key;
  11893.    UCMData->AccelTable->aaccel[Item].fs = AF_CHAR+AF_ALT;
  11894.    UCMData->AccelTable->aaccel[Item].cmd = id;
  11895.    (UCMData->AccelTable->cAccel)++;
  11896. }
  11897.  
  11898. //----------------------------------------------------------------------------
  11899. // RemoveAccelItem : not for the user's doc
  11900. //----------------------------------------------------------------------------
  11901. // :pfunction res=&IDF_REMACC. name='RemoveAccelItem' text='Removes an accelerator item'.
  11902. // This functions removes an accelerator from the table in UCMData
  11903. // :syntax name='RemoveAccelItem' params='UCMData, Key' return='-'.
  11904. // :fparams.
  11905. // :fparam name='UCMData' type='PUCMDATA' io='input'.
  11906. // Pointer to the UCMData structure
  11907. // :fparam name='Key' type='USHORT' io='input' .
  11908. // :freturns.
  11909. // :fparam name='-' type='VOID' io='-'.
  11910. // :efparams.
  11911. // :remarks.
  11912. // :related.
  11913. // :epfunction.
  11914. //----------------------------------------------------------------------------
  11915. VOID _Optlink RemoveAccelItem(PUCMDATA UCMData, USHORT Key)
  11916. {
  11917.  
  11918.   ULONG i;
  11919.   for(i=0; i<UCMData->AccelTable->cAccel; i++) {
  11920.     if(Key == UCMData->AccelTable->aaccel[i].key) {
  11921.        break;
  11922.     }
  11923.   }
  11924.  
  11925.   if(i == UCMData->AccelTable->cAccel) {
  11926.      return;
  11927.   }
  11928.  
  11929.   if(i == (UCMData->AccelTable->cAccel-1)) {
  11930.      (UCMData->AccelTable->cAccel)--;
  11931.   }
  11932.  
  11933.   while(i < UCMData->AccelTable->cAccel) {
  11934.      memcpy(&(UCMData->AccelTable->aaccel[i]), &(UCMData->AccelTable->aaccel[i+1]), sizeof(ACCEL));
  11935.      i++;
  11936.   }
  11937.  
  11938.  (UCMData->AccelTable->cAccel)--;
  11939. }
  11940.  
  11941. #if defined(UCMUI)
  11942. //----------------------------------------------------------------------------
  11943. // BitmapFileDlgProc
  11944. //----------------------------------------------------------------------------
  11945. // :pfunction res=&IDF_BMPFILEDLGPROC. name='BitmapFileDlgProc' text='Subclassed file window procedure'.
  11946. // Checks that the given filename is a bitmap and loads it before dismissing the file dialog
  11947. // :syntax name='BitmapFileDlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  11948. // :fparams.
  11949. // :fparam name='hwnd' type='HWND' io='input' .
  11950. // File dialog window handle
  11951. // :fparam name='msg' type='ULONG' io='input' .
  11952. // Message
  11953. // :fparam name='mp1' type='MPARAM' io='input'.
  11954. // First parameter
  11955. // :fparam name='mp2' type='MPARAM' io='input'.
  11956. // Second parameter
  11957. // :freturns.
  11958. // :fparam name='mresult' type='MRESULT' io='return'.
  11959. // Return code of a PM message.
  11960. // :efparams.
  11961. // :remarks.
  11962. // :epfunction.
  11963. //----------------------------------------------------------------------------
  11964. MRESULT EXPENTRY  BitmapFileDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  11965. {
  11966.    switch (msg) {
  11967.    case FDM_VALIDATE:
  11968.       {
  11969.           HBITMAP  hBmp;
  11970.           PFILEDLG FileDlg = (PFILEDLG) WinQueryWindowULong( hwnd, QWL_USER );
  11971.           PUCMDATA UCMData = (PUCMDATA) FileDlg->ulUser;
  11972.  
  11973.           if ( hBmp = UCMenuLoadBitmap( FileDlg->szFullFile ) ) {
  11974.              UCMData->hBmpTemp = hBmp;
  11975.              UCMData->bBmpTempFromFile = TRUE;
  11976.              return (MRESULT)TRUE;
  11977.           } else {
  11978.              WinMessageBox( HWND_DESKTOP, hwnd,
  11979.                             nlsgetmessage ( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_BADBMPFN, 0 ),
  11980.                             nlsgetmessage ( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_LOADBMP, 1 ),
  11981.                             0, MB_OK | MB_ERROR);
  11982.              WinSetFocus( HWND_DESKTOP, WinWindowFromID( hwnd, DID_FILENAME_ED ) );
  11983.              return (MRESULT)FALSE;
  11984.           } // endif
  11985.       }
  11986.    default:
  11987.      return WinDefFileDlgProc( hwnd, msg, mp1, mp2 );
  11988.  
  11989.    } // endswitch
  11990. }
  11991. #endif
  11992.  
  11993. #if defined(UCMUI)
  11994. //----------------------------------------------------------------------------
  11995. // UCMenuCreateBmpDlgProc
  11996. //----------------------------------------------------------------------------
  11997. // :pfunction res=&IDF_CREATEBMPDLGPROC. name='UCMEnuCreateBmpDlgProc' text='Bitmap creation dialog procedure'.
  11998. // Let the user enter a file name and start iconedit to create this bitmap.
  11999. // :syntax name='UCMenuCreateBmpDlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  12000. // :fparams.
  12001. // :fparam name='hwnd' type='HWND' io='input' .
  12002. // File dialog window handle
  12003. // :fparam name='msg' type='ULONG' io='input' .
  12004. // Message
  12005. // :fparam name='mp1' type='MPARAM' io='input'.
  12006. // First parameter
  12007. // :fparam name='mp2' type='MPARAM' io='input'.
  12008. // Second parameter
  12009. // :freturns.
  12010. // :fparam name='mresult' type='MRESULT' io='return'.
  12011. // Return code of a PM message.
  12012. // :efparams.
  12013. // :remarks.
  12014. // :epfunction.
  12015. MRESULT EXPENTRY  UCMenuCreateBmpDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  12016. {
  12017.    PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER );
  12018.    switch (msg) {
  12019.       case WM_INITDLG:
  12020.       {
  12021.         WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp2 );
  12022.         WinSetDlgItemShort( hwnd, IDC_UCMBMPCX, ((PUCMDATA)mp2)->cx, FALSE );
  12023.         WinSetDlgItemShort( hwnd, IDC_UCMBMPCY, ((PUCMDATA)mp2)->cy, FALSE );
  12024.       }
  12025.       break;
  12026.       case WM_COMMAND:
  12027.       {
  12028.          switch (SHORT1FROMMP(mp1)) {
  12029.             case IDB_UCMBMPOK:
  12030.             {
  12031.                UCHAR pszText[MAXPATHL];
  12032.                PSZ pszFullName = MyMalloc( MAXPATHL ); // Will be freed by UCMenuEditBmpFile
  12033.  
  12034.                if ( pszFullName ) {
  12035.                   SHORT cx, cy;
  12036.                   *pszText = '\0';
  12037.                   *pszFullName = '\0';
  12038.                   WinQueryDlgItemText( hwnd, IDC_UCMBMPNAME, (LONG)MAXPATHL, pszText );
  12039.                   WinQueryDlgItemShort( hwnd, IDC_UCMBMPCX, &cx, FALSE );
  12040.                   WinQueryDlgItemShort( hwnd, IDC_UCMBMPCY, &cy, FALSE );
  12041.                   UCMenuGetBitmapFullName( UCMData, pszText, pszFullName );
  12042.                   // We do that just to check whether the file already exists or not
  12043.                   if ( *pszFullName!='\0' ){
  12044.                      if ( WinMessageBox( HWND_DESKTOP, hwnd,
  12045.                                          nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_OVERWRITE, 0 ),
  12046.                                          nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_OVERWRITETITLE, 1 ),
  12047.                                          0, MB_YESNO ) != MBID_YES ){
  12048.                         MyFree( pszFullName );
  12049.                         return (MRESULT)TRUE;
  12050.                      } // endif
  12051.                   } // endif
  12052.                   UCMenuCreateBmpFile( pszText, cx, cy );
  12053.                   UCMenuGetBitmapFullName( UCMData, pszText, pszFullName );
  12054.                   UCMenuEditBmpFile( UCMData->hwndPage1, pszFullName );
  12055.                } // endif
  12056.             }
  12057.             // Fall through
  12058.             case IDB_UCMBMPCANCEL:
  12059.                WinDismissDlg( hwnd, TRUE );
  12060.                break;
  12061.             default:
  12062.                return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12063.          }
  12064.       }  break;
  12065.  
  12066.       default:
  12067.          return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12068.  
  12069.    } // endswitch
  12070.  
  12071.    return (MRESULT) FALSE;
  12072. }
  12073. #endif
  12074.  
  12075. #if defined(UCMUI)
  12076. //----------------------------------------------------------------------------
  12077. // ResBmpDlgProc
  12078. //----------------------------------------------------------------------------
  12079. // :pfunction res=&IDF_RESBMPDLGPROC. name='ResBmpDlgProc' text='Resource bitmap selection dialog procedure'.
  12080. // Let the user pick a bitmap among those available in the resource.
  12081. // :syntax name='ResBmpDlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  12082. // :fparams.
  12083. // :fparam name='hwnd' type='HWND' io='input' .
  12084. // Dialog window handle
  12085. // :fparam name='msg' type='ULONG' io='input' .
  12086. // Message
  12087. // :fparam name='mp1' type='MPARAM' io='input'.
  12088. // First parameter
  12089. // :fparam name='mp2' type='MPARAM' io='input'.
  12090. // Second parameter
  12091. // :freturns.
  12092. // :fparam name='mresult' type='MRESULT' io='return'.
  12093. // Return code of a PM message.
  12094. // :efparams.
  12095. // :remarks.
  12096. // :epfunction.
  12097. MRESULT EXPENTRY  ResBmpDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  12098. {
  12099.    PUCMDATA UCMData = WinQueryWindowPtr( hwnd, 0 );
  12100.    switch (msg) {
  12101.       case WM_INITDLG:
  12102.       {
  12103.          UCMINFO  UCMInfo;
  12104.          HWND     hwndUCM;
  12105.          HWND     hOwner;
  12106.          PULONG   pId     = 0;
  12107.          ULONG    ulNbId  = 0;
  12108.  
  12109.          UCMData = (PUCMDATA)mp2;
  12110.          WinSetWindowPtr( hwnd, 0, UCMData );
  12111.  
  12112.          hwndUCM = WinQueryWindow( UCMData->hwndMenu, QW_OWNER );
  12113.          hOwner  = WinQueryWindow( hwndUCM, QW_OWNER );
  12114.  
  12115.          ulNbId = (ULONG)WinSendMsg( hOwner,
  12116.                               WM_CONTROL,
  12117.                               MPFROM2SHORT( WinQueryWindowUShort( hwndUCM, QWS_ID ), UCN_QRYRESBMP  ),
  12118.                               MPFROMP( &pId )  );
  12119.          if ( ulNbId && pId ){
  12120.             HWND     hwndUCM, hwndMenu;
  12121.             memset( &UCMInfo, 0, sizeof(UCMINFO) );
  12122.             UCMInfo.cb       = sizeof( UCMINFO );
  12123.             UCMInfo.hModule  = UCMData->hModBmp;
  12124.             UCMInfo.Style    = UCS_FRAMED | UCS_NOTEXT | UCS_NO_DM | UCS_NO_CM;
  12125.             if ( UCMData->Style & UCS_CHNGBMPBG ) {
  12126.                UCMInfo.Style |= UCS_CHNGBMPBG;
  12127.             } // endif
  12128.             if ( UCMData->Style & UCS_FORCESIZE ) {
  12129.                UCMInfo.Style |= UCS_FORCESIZE;
  12130.                UCMInfo.cx = UCMData->cx;
  12131.                UCMInfo.cy = UCMData->cy;
  12132.             } // endif
  12133.             UCMInfo.BgBmp       = UCMData->BgBmp;
  12134.             UCMInfo.BgColor     = UCMData->BgColor;
  12135.             UCMInfo.ItemBgColor = UCMData->ItemBgColor;
  12136.  
  12137.             hwndMenu = WinCreateWindow( HWND_OBJECT,
  12138.                                         WC_MENU,
  12139.                                         "",
  12140.                                         MS_ACTIONBAR,
  12141.                                         0,
  12142.                                         0,
  12143.                                         0,
  12144.                                         0,
  12145.                                         HWND_OBJECT,
  12146.                                         HWND_BOTTOM,
  12147.                                         7, // magic number ...
  12148.                                         0,
  12149.                                         0 );
  12150.             hwndUCM = UCMenuCreateFromHMenu(
  12151.                                           WinQueryAnchorBlock( hwnd ),
  12152.                                           hwnd,
  12153.                                           hwnd,
  12154.                                           CMS_HORZ,
  12155.                                           0,
  12156.                                           0,
  12157.                                           0,
  12158.                                           0,
  12159.                                           HWND_TOP,
  12160.                                           7,          // magic number ...
  12161.                                           hwndMenu,
  12162.                                           (PVOID)&UCMInfo );
  12163.  
  12164.             {
  12165.                PVOID pArgs;
  12166.  
  12167.                pArgs = MyMalloc( sizeof( HWND ) + sizeof( PULONG ) + sizeof( ULONG ) + sizeof( HWND ) );
  12168.  
  12169.                if ( pArgs ){
  12170.                   *( (HWND*)pArgs ) = hwnd;
  12171.                   *( (PULONG*)( (PBYTE)pArgs + sizeof( HWND ) ) ) = pId;
  12172.                   *( (PULONG)( (PBYTE)pArgs + sizeof( HWND ) + sizeof( PULONG ) ) ) = ulNbId;
  12173.                   *( (PHWND)( (PBYTE)pArgs + sizeof( HWND ) + sizeof( PULONG ) + sizeof( ULONG ) ) ) = hwndMenu;
  12174.  
  12175.                   WinSetDlgItemText( hwnd, IDC_RESBMPTEXT, nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_BMPLOADING, 0 ) );
  12176.  
  12177.                   DosCreateThread( &( UCMData->tid ), (PFNTHREAD)UCMenuLoadResBmp, (ULONG)pArgs, 0, 8192 );
  12178.                } // endif
  12179.             }
  12180.          } else {
  12181.             WinSetDlgItemText( hwnd, IDC_RESBMPTEXT, nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_NOBMPRES, 0 ) );
  12182.          } // endif
  12183.       }
  12184.       break;
  12185.       case WM_CONTROL:
  12186.       {
  12187.          switch ( SHORT1FROMMP( mp1 ) ){
  12188.          case 7: // ID of the ucmenu ...
  12189.             switch ( SHORT2FROMMP( mp1 ) ){
  12190.             case UCN_ITEMSELECTED:
  12191.                {
  12192.                   PUCMITEM pucmi = (PUCMITEM)mp2;
  12193.                   if ( pucmi ) {
  12194.                      sscanf( pucmi->pszBmp, "%i", &( UCMData->ulBmpTempId ) );
  12195.                   } else {
  12196.                      UCMData->ulBmpTempId = 0;
  12197.                   } // endif
  12198.                   WinDismissDlg( hwnd, (USHORT)1 );
  12199.                   return (MRESULT)TRUE;
  12200.                }
  12201.                break;
  12202.             default :
  12203.                return (MRESULT)0;
  12204.  
  12205.             } // endswitch
  12206.             break;
  12207.          default:
  12208.             return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12209.  
  12210.          } // endswitch
  12211.       }
  12212.       break;
  12213.       case WM_CLOSE:
  12214.          if ( DosWaitThread( &( UCMData->tid ), DCWW_NOWAIT ) != ERROR_THREAD_NOT_TERMINATED ){
  12215.             // Don't close unless the threaded loading ended, else trouble!
  12216.             return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12217.          } /* endif */;
  12218.          break;
  12219.       case WM_COMMAND:
  12220.       {
  12221.  
  12222.          switch ( SHORT1FROMMP( mp1 ) ) {
  12223.             case DID_CANCEL:
  12224.             case IDB_RESBMPCANCEL:
  12225.                if ( DosWaitThread( &( UCMData->tid ), DCWW_NOWAIT ) != ERROR_THREAD_NOT_TERMINATED ){
  12226.                   // Don't dismiss unless the threaded loading ended, else trouble!
  12227.                   WinDismissDlg( hwnd, 0 );
  12228.                } /* endif */;
  12229.                break;
  12230.             default:
  12231.                return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12232.          }
  12233.       }  break;
  12234.  
  12235.       default:
  12236.          return WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12237.          break;
  12238.    } // endswitch
  12239.  
  12240.    return (MRESULT) FALSE;
  12241. }
  12242. #endif
  12243.  
  12244.  
  12245. #if defined(UCMUI)
  12246. //----------------------------------------------------------------------------
  12247. // UCMDlgProc
  12248. //----------------------------------------------------------------------------
  12249. // :pfunction res=&IDF_UCMDLGPROC. name='UCMDlgProc' text='Buffet toolbar selection dialog procedure'.
  12250. // Let the user pick items from the buffet toolbar
  12251. // :syntax name='ResBmpDlgProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  12252. // :fparams.
  12253. // :fparam name='hwnd' type='HWND' io='input' .
  12254. // Dialog window handle
  12255. // :fparam name='msg' type='ULONG' io='input' .
  12256. // Message
  12257. // :fparam name='mp1' type='MPARAM' io='input'.
  12258. // First parameter
  12259. // :fparam name='mp2' type='MPARAM' io='input'.
  12260. // Second parameter
  12261. // :freturns.
  12262. // :fparam name='mresult' type='MRESULT' io='return'.
  12263. // Return code of a PM message.
  12264. // :efparams.
  12265. // :remarks.
  12266. // :epfunction.
  12267. MRESULT EXPENTRY UCMDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  12268. {
  12269.    PUCMDLGINFO pUCMDlgInfo = (PUCMDLGINFO)WinQueryWindowULong( hwnd, QWL_USER );
  12270.  
  12271.    if ( !pUCMDlgInfo && ( msg != WM_INITDLG ) ) {
  12272.      return( WinDefDlgProc( hwnd, msg, mp1, mp2 ) );
  12273.    } /* endif */
  12274.  
  12275.    switch ( msg ) {
  12276.    case WM_INITDLG:
  12277.      {
  12278.        PVOID    pCurUCMTemplate;
  12279.        ULONG    ulBufLen;
  12280.        SWP      swpBuffetDesc, swpCurrentDesc, swpText, swp;
  12281.        HWND     hwndBuffet, hwndCurrent, hwndTmp;
  12282.        UCMINFO  UCMInfo;
  12283.        HAB      hab = WinQueryAnchorBlock( hwnd );
  12284.  
  12285.        pUCMDlgInfo = (PUCMDLGINFO)mp2;
  12286.        if ( !pUCMDlgInfo ) {
  12287.          return (MRESULT)FALSE;
  12288.        } /* endif */
  12289.  
  12290.        WinSetWindowULong( hwnd, QWL_USER, (ULONG)pUCMDlgInfo );
  12291.  
  12292.        // Query the desc positions
  12293.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENTDESC ), &swpCurrentDesc );
  12294.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFETDESC ),  &swpBuffetDesc  );
  12295.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_TEXT ),  &swpText  );
  12296.        WinQueryWindowPos( hwnd, &swp );
  12297.  
  12298.        // Query the current toolbar
  12299.        pCurUCMTemplate = UCMenuMakeTemplate( pUCMDlgInfo->hwndUCMenu, &ulBufLen );
  12300.  
  12301.        // Query Its UCMINFO structure
  12302.        memset( &UCMInfo, '\0', sizeof UCMInfo );
  12303.        WinSendMsg( pUCMDlgInfo->hwndUCMenu, UCMENU_QUERYUCMINFO, MPFROMP( & UCMInfo ), (MPARAM)0 );
  12304.  
  12305.        WinCheckButton( hwnd, IDD_UCMDLG_TEXT, ( UCMInfo.Style & UCS_NOTEXT )? FALSE : TRUE );
  12306.  
  12307.        UCMInfo.cb     =  sizeof( UCMINFO );
  12308.        UCMInfo.Style &= UCS_FORCESIZE             |
  12309.                         UCS_FRAMED                |
  12310.                         UCS_NOTEXT                |
  12311.                         UCS_SHRINK_BLEND          |
  12312.                         UCS_SHRINK_OR             |
  12313.                         UCS_CHNGBMPBG             |
  12314.                         UCS_NO_CM_SEPARATOR       |
  12315.                         UCS_NO_CM_MENU_STYLE      |
  12316.                         UCS_NO_CM_MENU_IMPORT     |
  12317.                         UCS_NO_CM_MENU_EXPORT     |
  12318.                         UCS_NO_CM_MENU_DEFAULT    |
  12319.                         UCS_NO_CM_ITEM_EDIT       |
  12320.                         UCS_NO_CM_ITEM_CREATE     |
  12321.                         UCS_NO_CM_ITEM_DELETE     |
  12322.                         UCS_NO_CM                 |
  12323.                         UCS_NODEFAULTACTION;
  12324.  
  12325.        // Create its copy
  12326.        hwndCurrent = UCMenuCreateFromTemplate(
  12327.                                  hab,
  12328.                                  hwnd,
  12329.                                  hwnd,
  12330.                                  CMS_HORZ,
  12331.                                  0,
  12332.                                  0,
  12333.                                  swp.cx - swpCurrentDesc.x -14,
  12334.                                  0,
  12335.                                  HWND_TOP,
  12336.                                  IDD_UCMDLG_CURRENT,  // ID of the ucmenu, could be different from the menu id
  12337.                                  pCurUCMTemplate,     // module of the menu resource
  12338.                                  (PVOID)&UCMInfo,
  12339.                                  &hwndTmp );
  12340.        if ( pCurUCMTemplate ) {
  12341.          MyFree( pCurUCMTemplate );
  12342.        } /* endif */
  12343.  
  12344.        // Create the buffet toolbar
  12345.        UCMInfo.Style &= UCS_FORCESIZE |
  12346.                         UCS_FRAMED |
  12347.                         UCS_NOTEXT |
  12348.                         UCS_SHRINK_BLEND |
  12349.                         UCS_SHRINK_OR |
  12350.                         UCS_CHNGBMPBG;
  12351.        UCMInfo.Style |=  UCS_NO_CM | UCS_NOITEMSMODIF;
  12352.        UCMInfo.Style &= ~UCS_NO_DM_C_TO_OTHER;
  12353.        if ( pUCMDlgInfo->bFromTemplate ){
  12354.           hwndBuffet = UCMenuCreateFromTemplate(
  12355.                                     hab,
  12356.                                     hwnd,
  12357.                                     hwnd,
  12358.                                     CMS_HORZ,
  12359.                                     0,
  12360.                                     0,
  12361.                                     swp.cx - swpBuffetDesc.x -14,
  12362.                                     0,
  12363.                                     HWND_TOP,
  12364.                                     IDD_UCMDLG_BUFFET,  // ID of the ucmenu, could be different from the menu id
  12365.                                     pUCMDlgInfo->pTemplate,
  12366.                                     (PVOID)&UCMInfo,
  12367.                                     &hwndTmp );
  12368.        } else {
  12369.           hwndBuffet = UCMenuCreateFromResource(
  12370.                                     hab,
  12371.                                     hwnd,
  12372.                                     hwnd,
  12373.                                     CMS_HORZ,
  12374.                                     0,
  12375.                                     0,
  12376.                                     swp.cx - swpBuffetDesc.x -14,
  12377.                                     0,
  12378.                                     HWND_TOP,
  12379.                                     IDD_UCMDLG_BUFFET,  // ID of the ucmenu, could be different from the menu id
  12380.                                     pUCMDlgInfo->hmodBuffetMenu,
  12381.                                     pUCMDlgInfo->ulBuffetMenuID,
  12382.                                     (PVOID)&UCMInfo,
  12383.                                     &hwndTmp );
  12384.        } // endif
  12385.  
  12386.        // Subclass the icon to destroy items dropped over it
  12387.        WinSetWindowULong( WinWindowFromID( hwnd, IDD_UCMDLG_SHREDDER ), QWL_USER, (ULONG)pUCMDlgInfo );
  12388.        pUCMDlgInfo->OldShredderWndProc = WinSubclassWindow( WinWindowFromID( hwnd, IDD_UCMDLG_SHREDDER ), ShredderWndProc );
  12389.  
  12390.        WinSendMsg( hwnd, WM_SIZE, (MPARAM)0, (MPARAM)0 );
  12391.  
  12392.        // Ask for the list of actions and descriptions
  12393.        WinSendMsg( WinQueryWindow( pUCMDlgInfo->hwndUCMenu, QW_OWNER ),
  12394.                    WM_CONTROL,
  12395.                    MPFROM2SHORT( WinQueryWindowUShort( pUCMDlgInfo->hwndUCMenu, QWS_ID ), UCN_QRYACTIONLIST ),
  12396.                    MPFROMP( hwnd ) );
  12397.  
  12398.  
  12399.        // Cleanup
  12400.        if ( UCMInfo.pszBitmapSearchPath ) {
  12401.          MyFree( UCMInfo.pszBitmapSearchPath );
  12402.        } /* endif */
  12403.        if ( UCMInfo.pszDefaultBitmap ) {
  12404.          MyFree( UCMInfo.pszDefaultBitmap );
  12405.        } /* endif */
  12406.        if ( UCMInfo.pszFontNameSize ) {
  12407.          MyFree( UCMInfo.pszFontNameSize );
  12408.        } /* endif */
  12409.  
  12410.        return (MRESULT)FALSE;
  12411.      }
  12412.  
  12413.    case UCMENU_INSERTACTION:
  12414.       {
  12415.          WinSendDlgItemMsg( hwnd,
  12416.                             IDD_UCMDLG_ACTIONS,
  12417.                             LM_INSERTITEM,
  12418.                             (MPARAM)LIT_END,
  12419.                             mp1 );
  12420.          WinSendDlgItemMsg( hwnd,
  12421.                             IDD_UCMDLG_DESCR,
  12422.                             LM_INSERTITEM,
  12423.                             (MPARAM)LIT_END,
  12424.                             mp2 );
  12425.          return (MRESULT)0;
  12426.       }
  12427.  
  12428.    case WM_CONTROL:
  12429.      if ( ( SHORT1FROMMP( mp1 ) == IDD_UCMDLG_CURRENT || SHORT1FROMMP( mp1 ) == IDD_UCMDLG_BUFFET ) &&
  12430.           ( SHORT2FROMMP( mp1 ) == UCN_ITEMSELECTED ) ){
  12431.         PUCMITEM pucmi = (PUCMITEM)mp2;
  12432.         SHORT  sIndex;
  12433.         PSZ    pszTxt;
  12434.         CHAR   pszDesc[MAXDESCLEN];
  12435.  
  12436.         if ( pucmi && pucmi->pszAction ){
  12437.            pszTxt = pucmi->pszAction;
  12438.         } else {
  12439.            return (MRESULT)FALSE;
  12440.         } /* endif */
  12441.         sIndex = (USHORT)WinSendDlgItemMsg( hwnd,
  12442.                                             IDD_UCMDLG_ACTIONS,
  12443.                                             LM_SEARCHSTRING,
  12444.                                             MPFROM2SHORT( LSS_CASESENSITIVE, LIT_FIRST ),
  12445.                                             MPFROMP( pszTxt ) );
  12446.         if ( sIndex != LIT_NONE && sIndex != LIT_ERROR ){
  12447.            WinSendDlgItemMsg( hwnd,
  12448.                               IDD_UCMDLG_DESCR,
  12449.                               LM_QUERYITEMTEXT,
  12450.                               MPFROM2SHORT( sIndex, MAXDESCLEN ),
  12451.                               MPFROMP( pszDesc ) );
  12452.            WinMessageBox( HWND_DESKTOP, hwnd,
  12453.                           pszDesc,
  12454.                           nlsgetmessage( WinQueryAnchorBlock( hwnd ),
  12455.                                          pUCMDlgInfo->UCMData->hModUCM,
  12456.                                          NLS_ITEMDESCR, 0 ),
  12457.                           0, MB_CANCEL | MB_INFORMATION | MB_APPLMODAL | MB_MOVEABLE );
  12458.         } // endif
  12459.         return (MRESULT)FALSE;
  12460.      } /* endif */
  12461.      switch ( SHORT1FROMMP( mp1 ) ) {
  12462.      case IDD_UCMDLG_TEXT:
  12463.         switch ( SHORT2FROMMP( mp1 ) ){
  12464.         case BN_CLICKED:
  12465.           {
  12466.             ULONG  ulStyle1, ulStyle2, ulCx1, ulCy1, ulCx2, ulCy2;
  12467.             USHORT usText;
  12468.             WinSendMsg( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFET ),
  12469.                         UCMENU_QUERYSTYLE,
  12470.                         MPFROMP( &ulStyle1 ),
  12471.                         (MPARAM)0 );
  12472.             WinSendMsg( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT ),
  12473.                         UCMENU_QUERYSTYLE,
  12474.                         MPFROMP( &ulStyle2 ),
  12475.                         (MPARAM)0 );
  12476.             WinSendMsg( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFET ),
  12477.                         UCMENU_QUERYFORCEDSIZE,
  12478.                         MPFROMP( &ulCx1 ),
  12479.                         MPFROMP( &ulCy1 ) );
  12480.             WinSendMsg( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT ),
  12481.                         UCMENU_QUERYFORCEDSIZE,
  12482.                         MPFROMP( &ulCx2 ),
  12483.                         MPFROMP( &ulCy2 ) );
  12484.             usText = WinQueryButtonCheckstate( hwnd, IDD_UCMDLG_TEXT );
  12485.             if ( usText ) {
  12486.                ulStyle1 &= ~UCS_NOTEXT;
  12487.                ulStyle2 &= ~UCS_NOTEXT;
  12488.             } else {
  12489.                ulStyle1 |= UCS_NOTEXT;
  12490.                ulStyle2 |= UCS_NOTEXT;
  12491.             } /* endif */
  12492.             WinPostMsg( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFET ),
  12493.                         UCMENU_SETSTYLE,
  12494.                         (MPARAM)ulStyle1,
  12495.                         MPFROM2SHORT( (USHORT)ulCx1, (USHORT)ulCy1 ) );
  12496.             WinPostMsg( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT ),
  12497.                         UCMENU_SETSTYLE,
  12498.                         (MPARAM)ulStyle2,
  12499.                         MPFROM2SHORT( (USHORT)ulCx2, (USHORT)ulCy2 ) );
  12500.             WinPostMsg( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFET ),
  12501.                         UCMENU_UPDATE,
  12502.                         (MPARAM)0,
  12503.                         (MPARAM)0 );
  12504.             WinPostMsg( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT ),
  12505.                         UCMENU_UPDATE,
  12506.                         (MPARAM)0,
  12507.                         (MPARAM)0 );
  12508.  
  12509.           }
  12510.           break;
  12511.         default:
  12512.           break;
  12513.         } /* endswitch */
  12514.  
  12515.      case IDD_UCMDLG_CURRENT:
  12516.         switch ( SHORT2FROMMP( mp1 ) ){
  12517.         case UCN_SIZE:
  12518.            WinSendMsg( hwnd, WM_SIZE, (MPARAM)0, (MPARAM)0 );
  12519.            break;
  12520.         case UCN_QRYDEFTEMPLATEID:
  12521.         case UCN_QRYTEMPLATEMODULE:
  12522.         case UCN_QRYDEFTEMPLATE:
  12523.         case UCN_QRYACTIONLIST:
  12524.         case UCN_QRYRESBMP:
  12525.            mp1 = MPFROM2SHORT( WinQueryWindowUShort( pUCMDlgInfo->hwndUCMenu, QWS_ID ), SHORT2FROMMP( mp1 ) );
  12526.            return WinSendMsg( WinQueryWindow( pUCMDlgInfo->hwndUCMenu, QW_OWNER ),
  12527.                               msg, mp1, mp2 );
  12528.  
  12529.         default:
  12530.           break;
  12531.         } /* endswitch */
  12532.  
  12533.      default:
  12534.        break;
  12535.      } /* endswitch */
  12536.  
  12537.   case WM_COMMAND:
  12538.      switch ( (USHORT)mp1 ) {
  12539.      case IDD_UCMDLG_OK:
  12540.        { PVOID  pNewTemplate;
  12541.          ULONG  ulLen;
  12542.          pNewTemplate =
  12543.            UCMenuMakeTemplate( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT ), &ulLen );
  12544.          UCMenuNew( pUCMDlgInfo->hwndUCMenu, pNewTemplate );
  12545.          MyFree( pNewTemplate );
  12546.          WinDismissDlg( hwnd, 1 );
  12547.  
  12548.          // process the text checkmark
  12549. #if 0
  12550.          WinSendMsg( pUCMDlgInfo->hwndUCMenu,
  12551.                      UCMENU_QUERYSTYLE,
  12552.                      MPFROMP( &ulStyle ),
  12553.                      (MPARAM)0 );
  12554.          WinSendMsg( pUCMDlgInfo->hwndUCMenu,
  12555.                      UCMENU_QUERYFORCEDSIZE,
  12556.                      MPFROMP( &ulCx ),
  12557.                      MPFROMP( &ulCy ) );
  12558.          usText = WinQueryButtonCheckstate( hwnd, IDD_UCMDLG_TEXT );
  12559.          if ( usText ) {
  12560.             elQtyle &= ~UCS_NOTEXT;
  12561.          } else {
  12562.             ulStyle |= UCS_NOTEXT;
  12563.          } /* endif */
  12564.          WinPostMsg( pUCMDlgInfo->hwndUCMenu,
  12565.                     UCMENU_SETSTYLE,
  12566.                      (MPARAM) ulStyle,
  12567.                      MPFROM2SHORT( (USHORT)ulCx, (USHORT)ulCy ) );
  12568.          WinPostMsg( pUCMDlgInfo->hwndUCMenu,
  12569.                      UCMENU_UPDATE,
  12570.                      (MPARAM)0,
  12571.                      (MPARAM)0 );
  12572. #endif
  12573.        }
  12574.        break;
  12575.      case DID_CANCEL:
  12576.      case IDD_UCMDLG_CANCEL:
  12577.        WinDismissDlg( hwnd, 0 );
  12578.        break;
  12579.      case IDD_UCMDLG_DEFAULT:
  12580.        UCMenuLoadDefault( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT ) );
  12581.        break;
  12582.     case IDD_UCMDLG_HELP:
  12583.        UCMenuDisplayHelp( pUCMDlgInfo->UCMData,
  12584.                           (USHORT)PANEL_BUFFET,
  12585.                           (USHORT)UCN_HLP_BUFFET );
  12586.        break;
  12587.      default:
  12588.        break;
  12589.      } /* endswitch */
  12590.      break;
  12591.   case WM_SIZE:
  12592.      {
  12593.        SWP   swpCurrentDesc, swpBuffetDesc, swpText, swp;
  12594.        HWND  hwndCurrent, hwndBuffet;
  12595.        ULONG ulCxBuf, ulCyBuf, ulCxCur, ulCyCur;
  12596.  
  12597.        hwndCurrent = WinWindowFromID( hwnd, IDD_UCMDLG_CURRENT );
  12598.        hwndBuffet  = WinWindowFromID( hwnd, IDD_UCMDLG_BUFFET );
  12599.  
  12600.        // Query the desc positions
  12601.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENTDESC ), &swpCurrentDesc );
  12602.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFETDESC ),  &swpBuffetDesc  );
  12603.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_TEXT ),  &swpText  );
  12604.        WinQueryWindowPos( hwnd, &swp );
  12605.  
  12606.        // query its height, set its position and show it
  12607.        WinSendMsg( hwndCurrent, UCMENU_QUERYSIZE, MPFROMP(&ulCxCur), MPFROMP(&ulCyCur) );
  12608.        WinSetWindowPos( hwndCurrent,
  12609.                         HWND_TOP,
  12610.                         swpCurrentDesc.x + 6,
  12611.                         swpText.y + swpText.cy + 10,
  12612.                         0,
  12613.                         0,
  12614.                         SWP_MOVE | SWP_SHOW );
  12615.        WinSetWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENTDESC ),
  12616.                         HWND_TOP,
  12617.                         swpCurrentDesc.x,
  12618.                         swpText.y + swpText.cy + ulCyCur + 15,
  12619.                         0,
  12620.                         0,
  12621.                         SWP_MOVE | SWP_SHOW );
  12622.        WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_CURRENTDESC ), &swpCurrentDesc );
  12623.  
  12624.        // query its height, set its position and show it
  12625.        WinSendMsg( hwndBuffet, UCMENU_QUERYSIZE, MPFROMP(&ulCxBuf), MPFROMP(&ulCyBuf) );
  12626.        WinSetWindowPos( hwndBuffet,
  12627.                         HWND_TOP,
  12628.                         swpBuffetDesc.x + 6,
  12629.                         swpCurrentDesc.y + swpCurrentDesc.cy + 10,
  12630.                         0,
  12631.                         0,
  12632.                         SWP_MOVE | SWP_SHOW );
  12633.        WinSetWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_BUFFETDESC ),
  12634.                         HWND_TOP,
  12635.                         swpBuffetDesc.x,
  12636.                         swpCurrentDesc.y + swpCurrentDesc.cy + ulCyBuf + 15,
  12637.                         0,
  12638.                         0,
  12639.                         SWP_MOVE | SWP_SHOW );
  12640.        WinSetWindowPos( hwnd,
  12641.                         HWND_TOP,
  12642.                         0,
  12643.                         0,
  12644.                         swp.cx,
  12645.                         swpCurrentDesc.y + swpCurrentDesc.cy + ulCyBuf + swpBuffetDesc.cy + 20
  12646.                          + WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) + WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME ),
  12647.                         SWP_SIZE | SWP_SHOW );
  12648.         return (MRESULT)0;
  12649.      }
  12650.      break;
  12651. //case WM_PAINT:
  12652. //   {
  12653. //      RECTL rcl;
  12654. //      SWP   swp;
  12655. //      HPS   hps;
  12656. //
  12657. //      WinDefDlgProc( hwnd, msg, mp1, mp2 );
  12658. //
  12659. //      WinQueryWindowPos( WinWindowFromID( hwnd, IDD_UCMDLG_SHREDDER ), &swp );
  12660. //      rcl.xLeft   = swp.x - 10;
  12661. //      rcl.xRight  = swp.x + swp.cx + 10;
  12662. //      rcl.yBottom = swp.y - 10;
  12663. //      rcl.yTop    = swp.y + swp.cy + 10;
  12664. //      hps = WinGetPS( hwnd );
  12665. //      UCMenu3DFrame( hps, &rcl, TRUE );
  12666. //      WinDrawBorder( hps, &rcl, 1, 1, CLR_BLACK, 0, DB_PATCOPY );
  12667. //      WinReleasePS( hps );
  12668. //   }
  12669. //   break;
  12670.   default:
  12671.       return( WinDefDlgProc( hwnd, msg, mp1, mp2 ) );
  12672.       break;
  12673.    } /* endswitch */
  12674.    return (MRESULT)FALSE;
  12675.  
  12676. }
  12677. #endif
  12678.  
  12679.  
  12680. #if defined(UCMUI)
  12681. //----------------------------------------------------------------------------
  12682. // ShredderWndProc
  12683. //----------------------------------------------------------------------------
  12684. // :pfunction res=&IDF_SHRDDRWNDPROC. name='ShredderWndProc' text='Subclassed wnd proc for the shredder icon'.
  12685. // This wndproc processes the drop of ucmenu items over the buffet dialog shredder.
  12686. // :syntax name='ShredderWndProc' params='hwnd, msg, mp1, mp2' return='mresult' .
  12687. // :fparams.
  12688. // :fparam name='hwnd' type='HWND' io='input' .
  12689. // Window handle
  12690. // :fparam name='msg' type='ULONG' io='input' .
  12691. // Message
  12692. // :fparam name='mp1' type='MPARAM' io='input'.
  12693. // First parameter
  12694. // :fparam name='mp2' type='MPARAM' io='input'.
  12695. // Second parameter
  12696. // :freturns.
  12697. // :fparam name='mresult' type='MRESULT' io='return'.
  12698. // Return code of a PM message.
  12699. // :efparams.
  12700. // :remarks.
  12701. // :epfunction.
  12702. MRESULT EXPENTRY ShredderWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  12703. {
  12704.    PUCMDLGINFO pUCMDlgInfo = (PUCMDLGINFO)WinQueryWindowULong( hwnd, QWL_USER );
  12705.  
  12706.    if ( !pUCMDlgInfo ) {
  12707.      return( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  12708.    } /* endif */
  12709.  
  12710.    switch ( msg ){
  12711.    case DM_DRAGLEAVE:
  12712.       {
  12713.          RECTL rcl;
  12714.          HPS hps = DrgGetPS( hwnd );
  12715.          WinQueryWindowRect( hwnd, &rcl );
  12716. //       rcl.xLeft   -=  5;
  12717. //       rcl.xRight  +=  5;
  12718. //       rcl.yBottom -=  5;
  12719. //       rcl.yTop    +=  5;
  12720.          WinDrawBorder( hps, &rcl, 1, 1, CLR_PALEGRAY, 0, DB_PATCOPY);
  12721.          DrgReleasePS( hps );
  12722.       }
  12723.       break;
  12724.    case DM_DRAGOVER:
  12725.       {
  12726.        PDRAGINFO  pDraginfo = (PDRAGINFO)mp1;
  12727.        USHORT     usOperation, usIndicator;
  12728.        PDRAGITEM  pditem;
  12729.        RECTL rcl;
  12730.        HPS hps = DrgGetPS( hwnd );
  12731.  
  12732.        WinQueryWindowRect( hwnd, &rcl );
  12733. //     rcl.xLeft   -=  5;
  12734. //     rcl.xRight  +=  5;
  12735. //     rcl.yBottom -=  5;
  12736. //     rcl.yTop    +=  5;
  12737.        WinDrawBorder( hps, &rcl, 1, 1, CLR_BLACK, 0, DB_PATCOPY);
  12738.        DrgReleasePS( hps );
  12739.  
  12740.        /* ---------------------------------------------------------------------- */
  12741.        /* Get access to the DRAGINFO structure.                                  */
  12742.        /* ---------------------------------------------------------------------- */
  12743.        DrgAccessDraginfo( pDraginfo );
  12744.        pditem = DrgQueryDragitemPtr( pDraginfo, 0 );
  12745.  
  12746.        if ( WinQueryWindowUShort( WinQueryWindow( pDraginfo->hwndSource, QW_OWNER ), QWS_ID )
  12747.             != IDD_UCMDLG_CURRENT ) {
  12748.           usIndicator = DOR_NEVERDROP;
  12749.           DrgFreeDraginfo (pDraginfo);
  12750.           return (MRFROM2SHORT(usIndicator, usOperation));
  12751.        } /* endif */
  12752.  
  12753.        /* ---------------------------------------------------------------------- */
  12754.        /* Determine if a drop can be accepted                                    */
  12755.        /* ---------------------------------------------------------------------- */
  12756.        usIndicator = DOR_DROP;
  12757.        usOperation = pDraginfo->usOperation;
  12758.        switch (pDraginfo->usOperation) {
  12759.          case DO_COPY:
  12760.            usIndicator = DOR_NODROPOP;
  12761.            break;
  12762.          case DO_MOVE:
  12763.            usOperation = DO_MOVE;
  12764.            break;
  12765.          case DO_DEFAULT:
  12766.            usOperation = DO_MOVE;
  12767.            break;
  12768.          case DO_UNKNOWN:
  12769.             usIndicator = DOR_NODROPOP;
  12770.             break;
  12771.         default:
  12772.            usIndicator = DOR_NODROP;
  12773.            usOperation = 0;
  12774.        } // endswitch
  12775.  
  12776.        if ( !DrgVerifyRMF( pditem, "DRM_UCMITEM",  "DRF_UNKNOWN" ) ){
  12777.           usIndicator = DOR_NEVERDROP;
  12778.        } // endif
  12779.  
  12780.  
  12781.        DrgFreeDraginfo( pDraginfo );
  12782.  
  12783.        return MRFROM2SHORT( usIndicator, usOperation );
  12784.       }
  12785.       break;
  12786.    case DM_DROP:
  12787.       {
  12788.          PDRAGINFO pDraginfo = (PDRAGINFO)mp1;
  12789.          PDRAGITEM pditem;
  12790.          RECTL rcl;
  12791.          HPS hps = DrgGetPS( hwnd );
  12792.          WinQueryWindowRect( hwnd, &rcl );
  12793. //       rcl.xLeft   -=  5;
  12794. //       rcl.xRight  +=  5;
  12795. //       rcl.yBottom -=  5;
  12796. //       rcl.yTop    +=  5;
  12797.          WinDrawBorder( hps, &rcl, 1, 1, CLR_PALEGRAY, 0, DB_PATCOPY);
  12798.          DrgReleasePS( hps );
  12799.  
  12800.          DrgAccessDraginfo( pDraginfo );
  12801.  
  12802.          pditem = DrgQueryDragitemPtr( pDraginfo, 0 );
  12803.  
  12804.          if ( pditem ){
  12805.               switch ( pDraginfo->usOperation ){
  12806.                 case DO_MOVE:
  12807.                    WinSendMsg( WinQueryWindow( pDraginfo->hwndSource, QW_OWNER ),
  12808.                                MM_DELETEITEM,
  12809.                                MPFROM2SHORT( (USHORT)(pditem->ulItemID), TRUE ),
  12810.                                (MPARAM)0 );
  12811.                    break;
  12812.                 default:
  12813.                   //-- invalid operation
  12814.                   break;
  12815.               } // endswitch
  12816.          } // endif  pditem
  12817.  
  12818.          // ----------------------------------------------------------------------
  12819.          // -- free the resource:
  12820.          // ----------------------------------------------------------------------
  12821.          DrgDeleteDraginfoStrHandles( pDraginfo );
  12822.          DrgFreeDraginfo( pDraginfo );
  12823.       }
  12824.       break;
  12825.    default:
  12826.       return pUCMDlgInfo->OldShredderWndProc( hwnd, msg, mp1, mp2 );
  12827.       break;
  12828.    } // endif
  12829.    return (MRESULT)0;
  12830. }
  12831. #endif
  12832.  
  12833. //----------------------------------------------------------------------------
  12834. // UCMenuResourceBuffetDlg
  12835. //----------------------------------------------------------------------------
  12836. // :function res=&IDF_RESBUFFETDLG. name='UCMenuResourceBuffetDlg' text='Toolbar customization dialog'.
  12837. // This dialog let the user pick items from a buffet toolbar coming from a resource..
  12838. // :syntax name='UCMenuResourceBuffetDlg' params='hParent, hUCMenu, ulBuffetID, hmodBuffet' return='-' .
  12839. // :fparams.
  12840. // :fparam name='hParent' type='HWND' io='input' .
  12841. // Parent of the dialog.
  12842. // :fparam name='hUCMenu' type='HWND' io='input' .
  12843. // Handle of the ucmenu to modify.
  12844. // :fparam name='ulBuffetID' type='ULONG' io='input' .
  12845. // ID of the buffet menu.
  12846. // :fparam name='hmodBuffet' type='HMODULE' io='input' .
  12847. // Module where the buffet menu is.
  12848. // :freturns.
  12849. // :fparam name='ulResult' type='ULONG' io='return'.
  12850. // result of WinDglBox
  12851. // :efparams.
  12852. // :remarks.
  12853. // :related.
  12854. // :efunction.
  12855. //----------------------------------------------------------------------------
  12856.  
  12857. ULONG APIENTRY UCMenuResourceBuffetDlg( HWND hParent, HWND hUCMenu, ULONG ulBuffetID, HMODULE hmodBuffet)
  12858. {
  12859.    #if defined(UCMUI)  // Only build this code if we support a user interface
  12860.    UCMDLGINFO UCMDlgInfo;
  12861.    ULONG      ulResult = 0;
  12862.    PUCMDATA   UCMData = (PUCMDATA)WinQueryWindowULong( hUCMenu, QWL_UCMDATA );
  12863.  
  12864.    if ( UCMData ){
  12865.       memset( &UCMDlgInfo, '\0', sizeof( UCMDLGINFO ) );
  12866.  
  12867.       UCMDlgInfo.ulSize         = sizeof( UCMDLGINFO );
  12868.       UCMDlgInfo.hwndUCMenu     = hUCMenu;
  12869.       UCMDlgInfo.UCMData        = UCMData;
  12870.       UCMDlgInfo.ulBuffetMenuID = ulBuffetID;
  12871.       UCMDlgInfo.hmodBuffetMenu = hmodBuffet;
  12872.       UCMDlgInfo.bFromTemplate  = FALSE;
  12873.       ulResult = WinDlgBox( hParent,
  12874.                   WinQueryWindow( hUCMenu, QW_OWNER ),
  12875.                   UCMDlgProc,
  12876.                   UCMData->hModUCM,
  12877.                   IDD_UCMDLG,
  12878.                   (PVOID)&UCMDlgInfo );
  12879.    } /* endif */
  12880.    return ulResult;
  12881.    #endif
  12882.    return DID_CANCEL;  // Return dummy value
  12883. }
  12884.  
  12885. #if defined(UCMUI)
  12886. //----------------------------------------------------------------------------
  12887. // UCMenuTemplateBuffetDlg
  12888. //----------------------------------------------------------------------------
  12889. // :function res=&IDF_TMPLBUFFETDLG. name='UCMenuTemplateBuffetDlg' text='Toolbar customization dialog'.
  12890. // This dialog let the user pick items from a buffet toolbar coming from a template..
  12891. // :syntax name='UCMenuTemplateBuffetDlg' params='hParent, hUCMenu, pTemplate' return='-' .
  12892. // :fparams.
  12893. // :fparam name='hParent' type='HWND' io='input' .
  12894. // Parent of the dialog.
  12895. // :fparam name='hUCMenu' type='HWND' io='input' .
  12896. // Handle of the ucmenu to modify.
  12897. // :fparam name='pTemplate' type='PVOID' io='input' .
  12898. // Template of the buffet menu
  12899. // :freturns.
  12900. // :fparam name='ulResult' type='ULONG' io='return'.
  12901. // result of WinDglBox
  12902. // :efparams.
  12903. // :remarks.
  12904. // :related.
  12905. // :efunction.
  12906. //----------------------------------------------------------------------------
  12907.  
  12908. ULONG APIENTRY UCMenuTemplateBuffetDlg( HWND hParent, HWND hUCMenu, PVOID pTemplate )
  12909. {
  12910.    #if defined(UCMUI)  // Only build this code if we support a user interface
  12911.    UCMDLGINFO UCMDlgInfo;
  12912.    HWND       hBuffet;
  12913.    ULONG      ulResult = 0;
  12914.    PUCMDATA UCMData = (PUCMDATA)WinQueryWindowULong( hUCMenu, QWL_UCMDATA );
  12915.  
  12916.    if ( UCMData ){
  12917.       memset( &UCMDlgInfo, '\0', sizeof( UCMDLGINFO ) );
  12918.  
  12919.       UCMDlgInfo.ulSize         = sizeof( UCMDLGINFO );
  12920.       UCMDlgInfo.hwndUCMenu     = hUCMenu;
  12921.       UCMDlgInfo.hwndBuffet     = hBuffet;
  12922.       UCMDlgInfo.UCMData        = UCMData;
  12923.       UCMDlgInfo.pTemplate      = pTemplate;
  12924.       UCMDlgInfo.bFromTemplate  = TRUE;
  12925.       ulResult = WinDlgBox( hParent,
  12926.         WinQueryWindow( hUCMenu, QW_OWNER ),
  12927.         UCMDlgProc,
  12928.         UCMData->hModUCM,
  12929.         IDD_UCMDLG,
  12930.         (PVOID)&UCMDlgInfo );
  12931.    } /* endif */
  12932.    return ulResult;
  12933.    #endif
  12934.    return DID_CANCEL;  // Return dummy value
  12935. }
  12936. #endif // UCMUI
  12937.  
  12938. //----------------------------------------------------------------------------
  12939. // UCMenuGetVersion
  12940. //----------------------------------------------------------------------------
  12941. // :function res=&IDF_GETVER. name='UCMenuGetVersion' text='Get the version of the toolbar'.
  12942. // This function returns the version of the ucmenus code.
  12943. // :syntax name='UCMenuGetVersion' params='-' return='ulVersion' .
  12944. // :fparams.
  12945. // :freturns.
  12946. // :fparam name='ulVersion' type='ULONG' io='return'.
  12947. // version of the ucmenus.
  12948. // :efparams.
  12949. // :remarks.
  12950. // :related.
  12951. // :efunction.
  12952. //----------------------------------------------------------------------------
  12953.  
  12954. ULONG APIENTRY UCMenuGetVersion()
  12955. {
  12956.    return (ULONG) UCMENUS_VERSION;
  12957.  
  12958. }
  12959.  
  12960.  
  12961. #if defined(UCMUI)
  12962. //----------------------------------------------------------------------------
  12963. // UCMenuLoadResBmp
  12964. //----------------------------------------------------------------------------
  12965. // :pfunction res=&IDF_LOADRESBMP. name='UCMenuLoadResBmp' text='Load the built-in bitmaps'.
  12966. // This function loads the built-in bitmap in the resource bitmaps dialog toolbar
  12967. // It is started by ResBmpDlgProc in a second thread.
  12968. // :syntax name='UCMenuLoadResBmp' params='pArgs' return='-' .
  12969. // :fparams.
  12970. // :fparam name='pArgs' type='PVOID' io='input' .
  12971. // Points to &colon.
  12972. // :dl compact.
  12973. // :dt.hwnd
  12974. // :dd.HWND, handle of the calling dialog.
  12975. // :dt.pID
  12976. // :dd.PULONG, points to the bitmap ids, freed by UCMenuLoadResBmp
  12977. // :dt.ulNb
  12978. // :dd.ULONG, number of  bitmap ids.
  12979. // :dt.hwndMenu
  12980. // :dd.HWND, handle of the toolbar menu
  12981. // Freed by UCMenuLoadResBmp
  12982. // :freturns.
  12983. // :fparam name='-' type='VOID' io='-'.
  12984. // Nothing
  12985. // :efparams.
  12986. // :remarks.
  12987. // The calling convention must be _System because this function
  12988. // is used in a DosCreateThread.
  12989. // :related.
  12990. // :epfunction.
  12991. //----------------------------------------------------------------------------
  12992. VOID _System UCMenuLoadResBmp( PVOID pArgs )
  12993. {
  12994.    if ( pArgs ){
  12995.       int      i;
  12996.       ULONG    ulNbId, ulH, ulW;
  12997.       PULONG   pId;
  12998.       MENUITEM mi;
  12999.       HWND     hwnd, hwndText, hwndButton, hwndUCM, hwndMenu;
  13000.       PUCMDATA UCMData;
  13001.       HAB      hab;
  13002.       HMQ      hmq;
  13003.       SWP      swp, swp2;
  13004.  
  13005.       hab = WinInitialize(0);
  13006.      hmq = WinCreateMsgQueue( hab, 0 );
  13007.  
  13008.       // Get hwnd
  13009.       hwnd = *( (HWND*)pArgs );
  13010.       // Get pId
  13011.       pId = *( (PULONG*)( (PBYTE)pArgs + sizeof( HWND ) ) );
  13012.       // Get ulNbId;
  13013.       ulNbId = *( (PULONG)( (PBYTE)pArgs + sizeof( HWND ) + sizeof( PULONG ) ) );
  13014.       // Get hwndMenu
  13015.       hwndMenu = *( (PHWND)( (PBYTE)pArgs + sizeof( HWND ) + sizeof( PULONG ) + sizeof( ULONG ) ) );
  13016.  
  13017.       UCMData = (PUCMDATA)WinQueryWindowULong( hwnd, QWL_USER );
  13018.  
  13019.       hwndUCM  = WinWindowFromID( hwnd, 7 ); // 7 is the magic bitmaps ucmenu ID
  13020.  
  13021.       for ( i = 0; i < ulNbId; i++ ){
  13022.          memset( &mi, '\0', sizeof mi );
  13023.          mi.iPosition = MIT_END;
  13024.          mi.afStyle   = MIS_OWNERDRAW;
  13025.          mi.id = UCMenuGetNewID( hwndMenu, MIT_NONE, (PUCMDATA)WinQueryWindowULong( hwndMenu, QWL_USER ) ) + 1;
  13026.          mi.hItem = (LONG)MyMalloc( sizeof( UCMITEM ) );
  13027.          if ( mi.hItem ){
  13028.             CHAR szId[22];
  13029.             sprintf( szId, "%i", pId[i] );
  13030.             memset( (PVOID)mi.hItem, 0, sizeof( UCMITEM ) );
  13031.             ITEM( &mi, pszBmp ) = MyMalloc( strlen( szId ) + 1 );
  13032.             strcpy( ITEM( &mi, pszBmp ), szId );
  13033.             WinSendMsg( hwndUCM, MM_INSERTITEM, MPFROMP( &mi ), MPFROMP( "" ) );
  13034.          } // endif
  13035.       } // endfor
  13036.       MyFree( pId );
  13037.  
  13038.       // query ucmenu size
  13039.       WinSendMsg( hwndUCM, UCMENU_QUERYSIZE, MPFROMP( &ulW ), MPFROMP( &ulH ) );
  13040.  
  13041.       // query dialog size
  13042.       WinQueryWindowPos( hwnd, &swp );
  13043.       hwndText   = WinWindowFromID( hwnd, IDC_RESBMPTEXT );
  13044.       hwndButton = WinWindowFromID( hwnd, IDB_RESBMPCANCEL );
  13045.       WinQueryWindowPos( hwndButton, &swp2 );
  13046.  
  13047.       // size window
  13048.       WinSetWindowPos( hwnd, HWND_TOP, 0, 0, swp.cx, ulH + swp2.y + swp2.cy + 50,  SWP_SIZE );
  13049.  
  13050.       // position static text
  13051.       WinSetWindowPos( hwndText, HWND_TOP,
  13052.                        5, swp2.y, swp2.x - 10, swp2.cy, SWP_MOVE | SWP_SHOW | SWP_SIZE );
  13053.  
  13054.       // position, size and show ucm
  13055.       WinSetWindowPos( hwndUCM, HWND_TOP, 10, swp2.y + swp2.cy + 10, swp.cx - 20, ulH, SWP_MOVE | SWP_SHOW | SWP_SIZE );
  13056.  
  13057.       // show window
  13058.       WinSetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOW  );
  13059.  
  13060.       // Set text
  13061.       WinSetDlgItemText( hwnd, IDC_RESBMPTEXT, nlsgetmessage( WinQueryAnchorBlock( hwnd ), UCMData->hModUCM, NLS_BMPLOADED, 0 ) );
  13062.  
  13063.       MyFree( pArgs );
  13064.  
  13065.       WinDestroyMsgQueue( hmq );
  13066.       WinTerminate( hab );
  13067.    } // endif pArgs
  13068. }
  13069. #endif // UCMUI
  13070.  
  13071. //----------------------------------------------------------------------------
  13072. // SubMemStrdup
  13073. //----------------------------------------------------------------------------
  13074. // :pfunction res=&IDF_SUBMEMSTRDUP. name='SubMemStrdup' text='strdup in a memory pool'.
  13075. // Does a strdup in a memory pool.
  13076. // :syntax name='SubMemStrdup' params='pSubMem, pszSource' return='pszTarget' .
  13077. // :fparams.
  13078. // :fparam name='pSubMem' type='PVOID' io='input' .
  13079. // Pointer to the memory pool.
  13080. // :fparam name='pszSource' type='PSZ' io='input' .
  13081. // String to be duplicated.
  13082. // :freturns.
  13083. // :fparam name='pszTarget' type='PSZ' io='return'.
  13084. // Duplicated string or 0 if failure.
  13085. // :efparams.
  13086. // :remarks.
  13087. // :epfunction.
  13088. //----------------------------------------------------------------------------
  13089. PSZ   _Optlink SubMemStrdup(PVOID pSubMem, PSZ pszSource)
  13090. {
  13091.    if (pszSource) {
  13092.       ULONG ul=0;
  13093.       PSZ pszDest=0;
  13094.       ul = strlen(pszSource);
  13095.       if ( !DosSubAllocMem( pSubMem, (PVOID)&pszDest, ul+1 ) ){
  13096.          strcpy(pszDest,pszSource);
  13097.          return pszDest;
  13098.       } // endif
  13099.    } // endif
  13100.    return NULL;
  13101. }
  13102.  
  13103.  
  13104. //----------------------------------------------------------------------------
  13105. // UCMenuAlloc
  13106. //----------------------------------------------------------------------------
  13107. // :function res=&IDF_UCMALLOC. name='UCMenuAlloc' text='Malloc used by the ucmenus'.
  13108. // External entry point to the allocation routine used by the ucmenus.
  13109. // :syntax name='UCMenuAlloc' params='size' return='PVOID' .
  13110. // :fparams.
  13111. // :fparam name='size' type='size_t' io='input' .
  13112. // Size to allocate.
  13113. // :freturns.
  13114. // :fparam name='pMem' type='PVOID' io='return'.
  13115. // Pointer to the allocated memory or 0 if failure.
  13116. // :efparams.
  13117. // :remarks.
  13118. // :related.
  13119. // :efunction.
  13120. //----------------------------------------------------------------------------
  13121. PVOID APIENTRY UCMenuAlloc(size_t size)
  13122. {
  13123.    return MyMalloc( size );
  13124. }
  13125.  
  13126. //----------------------------------------------------------------------------
  13127. // UCMenuStrdup
  13128. //----------------------------------------------------------------------------
  13129. PSZ  APIENTRY UCMenuStrdup(const char *Src)
  13130. {
  13131.  
  13132.    return MyStrdup(Src);
  13133. }
  13134.  
  13135.  
  13136. //----------------------------------------------------------------------------
  13137. // UCMenuItemFree
  13138. //----------------------------------------------------------------------------
  13139. // Complement to UCMenuItemDup() function
  13140. //----------------------------------------------------------------------------
  13141. VOID APIENTRY UCMenuItemFree(UCMITEM *Source)
  13142. {
  13143.   if (Source != NULL) {
  13144.     /* Free strings */
  13145.     if (Source->pszBmp != NULL)
  13146.       MyFree(Source->pszBmp);
  13147.     if (Source->pszText != NULL)
  13148.       MyFree(Source->pszText);
  13149.     if (Source->pszAction != NULL)
  13150.       MyFree(Source->pszAction);
  13151.     if (Source->pszParameters != NULL)
  13152.       MyFree(Source->pszParameters);
  13153.     if (Source->pszData != NULL)
  13154.       MyFree(Source->pszData);
  13155.  
  13156.     /* Free structure */
  13157.     MyFree(Source);
  13158.   }
  13159. }
  13160.  
  13161. //----------------------------------------------------------------------------
  13162. // UCMenuItemDup
  13163. //----------------------------------------------------------------------------
  13164. UCMITEM * APIENTRY UCMenuItemDup(UCMITEM *Source)
  13165. {
  13166. UCMITEM *NewItem;
  13167.  
  13168.   NewItem=MyMalloc(sizeof(UCMITEM));
  13169.   if (NewItem != NULL) {
  13170.     memset(NewItem, 0x00, sizeof(UCMITEM));
  13171.     /* Dup strings */
  13172.     if (Source->pszBmp != NULL)
  13173.       NewItem->pszBmp = MyStrdup(Source->pszBmp);
  13174.     if (Source->pszText != NULL)
  13175.       NewItem->pszText = MyStrdup(Source->pszText);
  13176.     if (Source->pszAction != NULL)
  13177.       NewItem->pszAction = MyStrdup(Source->pszAction);
  13178.     if (Source->pszParameters != NULL)
  13179.       NewItem->pszParameters = MyStrdup(Source->pszParameters);
  13180.     if (Source->pszData != NULL)
  13181.       NewItem->pszData = MyStrdup(Source->pszData);
  13182.  
  13183.     /* Copy selected parts of the structure.  We do not */
  13184.     /* copy hBmp.                                       */
  13185.     NewItem->usId    = Source->usId;
  13186.     NewItem->ulFlags = Source->ulFlags;
  13187.   }
  13188.  
  13189.   return NewItem;
  13190. }
  13191.  
  13192. //----------------------------------------------------------------------------
  13193. // UCMenuFree
  13194. //----------------------------------------------------------------------------
  13195. // :function res=&IDF_UCMFREE. name='UCMenuFree' text='Free used by the ucmenus'.
  13196. // External entry point to the freeing routine used by the ucmenus.
  13197. // :syntax name='UCMenuFree' params='pMem' return='-' .
  13198. // :fparams.
  13199. // :fparam name='pMem' type='PVOID' io='input' .
  13200. // Pointer to free.
  13201. // :freturns.
  13202. // :fparam name='-' type='VOID' io='-'.
  13203. // Nothing.
  13204. // :efparams.
  13205. // :remarks.
  13206. // :related.
  13207. // :efunction.
  13208. //----------------------------------------------------------------------------
  13209.  
  13210. VOID  APIENTRY UCMenuFree(VOID * p)
  13211. {
  13212.    MyFree( p );
  13213. }
  13214.  
  13215.  
  13216.  
  13217. #ifdef UCMENUS_DEBUG
  13218.  
  13219.    #ifdef MYMALLOC_RIGHT_BOUNDARY
  13220.  
  13221.       #define MYPAGESIZE 4096lu
  13222.  
  13223.       VOID *   MyMalloc(size_t size)
  13224.       {
  13225.          // --------------------------------------------------------------
  13226.          // -- In case size+sizeof(ULONG) is on a page boundary, this code
  13227.          // -- will allocate one unnecessary supplemental page...
  13228.          // --------------------------------------------------------------
  13229.  
  13230.          PVOID p;
  13231.          ULONG ulSizeAllocated;
  13232.  
  13233.          ulSizeAllocated = (size+sizeof(ULONG)) - (size+sizeof(ULONG))%MYPAGESIZE + MYPAGESIZE;
  13234.  
  13235.          if (  DosAllocMem( &p, ulSizeAllocated, PAG_COMMIT | PAG_READ | PAG_WRITE) ) {
  13236.             return 0;
  13237.          }
  13238.          p =  ( PVOID ) ( ((PBYTE)p) + ulSizeAllocated  - size );
  13239.          *( ((PULONG)p)-1 ) = (ULONG)size;
  13240.          return p;
  13241.       }
  13242.  
  13243.       VOID  MyFree(VOID * p)
  13244.       {
  13245.          if (p) {
  13246.             ULONG ulSizeAllocated;
  13247.             ULONG ulSize = *( (PULONG)(p) -1 );
  13248.  
  13249.             ulSizeAllocated = (ulSize+sizeof(ULONG)) - (ulSize+sizeof(ULONG))%MYPAGESIZE + MYPAGESIZE;
  13250.             DosFreeMem( (PVOID) ( ((PBYTE)p) - ulSizeAllocated + ulSize ) );
  13251.          } // endif
  13252.       }
  13253.   #else
  13254.       VOID *   MyMalloc(size_t size)
  13255.       {
  13256.          PVOID p;
  13257.  
  13258.          if (DosAllocMem( &p, (ULONG) ( size ), PAG_COMMIT | PAG_READ | PAG_WRITE)) {
  13259.             return 0;
  13260.          }
  13261.          return p;
  13262.       }
  13263.  
  13264.  
  13265.       VOID  MyFree(VOID * p)
  13266.       {
  13267.          if (p) {DosFreeMem( (PVOID) ( p ));}
  13268.       }
  13269.   #endif // MY_MALLOC_RIGHT_BOUNDARY
  13270.  
  13271.    char * MyStrdup( const char * string)
  13272.    {
  13273.       if (string) {
  13274.          ULONG ul=0;
  13275.          char * stringDest = 0;
  13276.          ul = strlen(string);
  13277.          stringDest = MyMalloc(ul+1);
  13278.          if (stringDest) {
  13279.             strcpy(stringDest,string);
  13280.             return stringDest;
  13281.          } // endif
  13282.       } // endif
  13283.       return NULL;
  13284.    }
  13285. #else
  13286.    char * MyStrdup( const char * string)
  13287.    {
  13288.       if (string) {
  13289.          return strdup( string );
  13290.       } // endif
  13291.       return NULL;
  13292.    }
  13293.  
  13294. #endif // ifdef UCMENUS_DEBUG
  13295.  
  13296. //----------------------------------------------------------------------------
  13297. // nlsgetmessage
  13298. //----------------------------------------------------------------------------
  13299. // :pfunction res=&IDF_NLSGETMSG. name='nlsgetmessage' text='get a string from the string table'.
  13300. // Returns a string from the string table in a static buffer.
  13301. // :syntax name='nlsgetmessage' params='Hab, HModule, msg, buffnum' return='buffer' .
  13302. // :fparams.
  13303. // :fparam name='Hab' type='HAB' io='input' .
  13304. // Anchor block of the application.
  13305. // :fparam name='HModule' type='HMODULE' io='input' .
  13306. // Handle of the module where the string table is.
  13307. // :fparam name='msg' type='SHORT' io='input' .
  13308. // ID of the message to retrieve.
  13309. // :fparam name='buffnum' type='SHORT' io='input'.
  13310. //  Number of the buffer to use. (0-3)
  13311. // :freturns.
  13312. // :fparam name='buffer' type='PSZ' io='return'.
  13313. //  Pointer to the static buffer where the string is.
  13314. // :efparams.
  13315. // :remarks.
  13316. // Currently the indexes 0-2 are used for thread 1 and 3 for thread 2.
  13317. // :related.
  13318. // :epfunction.
  13319. //----------------------------------------------------------------------------
  13320. #define NLSSTRINGLEN   256
  13321. #define MAXNLSBUF 6
  13322. PSZ _Optlink nlsgetmessage(HAB Hab, HMODULE HModule, SHORT msg, SHORT buffnum )
  13323. {
  13324.    static UCHAR buffer[MAXNLSBUF][NLSSTRINGLEN];
  13325.  
  13326.    WinLoadString( Hab,
  13327.                   HModule,
  13328.                   msg,
  13329.                   NLSSTRINGLEN,
  13330.                   buffer[buffnum] );
  13331.  
  13332.    return buffer[buffnum];
  13333. }
  13334.  
  13335. /****************************************************************************/
  13336. LONG  _Optlink UCMString2Int(char *lpString, BOOL *lpTranslated)
  13337. /****************************************************************************/
  13338. /* Translate a string to binary value.  String may contain leading and      */
  13339. /* trailing blanks and optional minus sign.  An error occures if string     */
  13340. /* contains any non-numeric character other than leading/trailing blanks.   */
  13341. /* If an error occures, zero is returned and lpTranslated is set to FALSE   */
  13342. /* if supplied.  (If lpTranslated is a NULL pointer, zero is returned and   */
  13343. /* caller cannot know if an error occured).                                 */
  13344. /*                                                                          */
  13345. /****************************************************************************/
  13346. {
  13347.   char  *Buff = lpString;
  13348.   int    i    = 0;
  13349.   int    sign = 1;
  13350.   LONG   lReturn = 0L;
  13351.  
  13352.   /*-------------------------------------------------------------------------*/
  13353.   /*  check the buffer pointer                                               */
  13354.   /*-------------------------------------------------------------------------*/
  13355.   if (!lpString)                                
  13356.   {                                             
  13357.     if ( lpTranslated ) *lpTranslated = FALSE;  
  13358.     return 0L;
  13359.   }
  13360.  
  13361.   /*-------------------------------------------------------------------------*/
  13362.   /*  striping any extra spaces.                                             */
  13363.   /*-------------------------------------------------------------------------*/
  13364.   while ( Buff[i] == ' ' ) i++;
  13365.   if ( Buff[i] == '\0' )
  13366.   {
  13367.     if ( lpTranslated ) *lpTranslated = FALSE;
  13368.     return 0L;
  13369.   }
  13370.  
  13371.   /*-------------------------------------------------------------------------*/
  13372.   /*  check sign flag.                                                       */
  13373.   /*-------------------------------------------------------------------------*/
  13374.   if ( Buff[i] == '-' )
  13375.   {
  13376.     sign = -1;
  13377.     i++;
  13378.   }
  13379.  
  13380.   /*-------------------------------------------------------------------------*/
  13381.   /*  walk the number calculating as we go                                   */
  13382.   /*-------------------------------------------------------------------------*/
  13383.   while ( Buff[i]>='0' && Buff[i]<='9')
  13384.   {
  13385.     lReturn = (lReturn*10) + ((int)Buff[i] - (int)'0');
  13386.     i++;
  13387.   }
  13388.   while ( Buff[i] == ' ' ) i++;  // Ignore trailing blanks
  13389.   if ( Buff[i] != '\0' )         // Error if any more chars in string
  13390.   {
  13391.     if ( lpTranslated ) *lpTranslated = FALSE;
  13392.     return 0L;
  13393.   }
  13394.  
  13395.   /*-------------------------------------------------------------------------*/
  13396.   /*  return results                                                         */
  13397.   /*-------------------------------------------------------------------------*/
  13398.  
  13399.   if ( lpTranslated ) *lpTranslated = TRUE;
  13400.   return (sign * lReturn);
  13401. }
  13402.  
  13403.