am2000utils.pas
上传用户:powellwoo
上传日期:2007-01-07
资源大小:109k
文件大小:26k
源码类别:

Delphi控件源码

开发平台:

C++ Builder

  1. {*******************************************************}
  2. {                                                       }
  3. {       AnimatedMenus/2000                              }
  4. {       Additional utilities                            }
  5. {                                                       }
  6. {       Copyright (c) 1997-99 AnimatedMenus.com         }
  7. {       All rights reserved.                            }
  8. {                                                       }
  9. {*******************************************************}
  10. unit am2000utils;
  11. {$I am2000.inc}
  12. interface
  13. uses
  14.   Windows, Messages, SysUtils, Classes, Graphics, Controls, StdCtrls, ExtCtrls,
  15.   Forms, Dialogs, Menus, Buttons, CommCtrl, ComCtrls;
  16. const
  17.   wm_ShowAnimated     = wm_User + $102;
  18.   wm_ShowSilent       = wm_User + $103;
  19.   wm_HideAnimated     = wm_User + $104;
  20.   wm_HideSilent       = wm_User + $105;
  21.   // messages for popup menu form
  22.   wm_KillAnimation    = wm_User + $101;
  23.   wm_KillTimer        = wm_User + $106;
  24.   wm_SetKeepSelected  = wm_User + $112; // wParam -> enable/disable keepselected
  25.   wm_UpdateMenuBar    = wm_User + $107; // wParam <> 0 -> rebound menu bar
  26.   wm_ActivateMenuBar  = wm_User + $108; // wParam <> 0 -> window is active
  27.   wm_InitState        = wm_User + $113; // clears all menu states
  28.   // messages for menu designer
  29.   wm_SelectComponent  = wm_User + $120; // select component in Object Inspector
  30.   wm_UpdateCaption    = wm_User + $121;
  31.   wm_UpdateBitmap     = wm_User + $122;
  32.   // GetItemAt(X,Y)
  33.   itNothing           = -1;
  34.   itDragPane          = -2;
  35.   itHiddenArrow       = -3;
  36.   upNothing           = 0;
  37.   upRepaint           = 0;
  38.   upForceRebound      = 1;
  39.   upChildChanged      = 2;
  40.   upForceRebuild      = 3;
  41.   // vk_Menu key
  42.   AltMask = $20000000;
  43.   FormFlags = swp_NoMove or swp_NoSize or swp_NoActivate;
  44.   dt_DrawTextFlags = dt_NoClip + dt_SingleLine + dt_VCenter;
  45.   nSteps = 10;  // number of steps in menu animation
  46.   nTimeout = 5; // cannot be more than 100
  47.   nFirstStage = 6; // size of first step
  48. const
  49.   Pattern : TBitmap  = nil;
  50.   // Custom Sounds - set your favorite
  51.   MenuPopupSound    : String = 'MenuPopup';      // or = 'c:laser.wav';
  52.   MenuCloseSound    : String = '';
  53.   MenuCommandSound  : String = 'MenuCommand';
  54.   ActivePopupMenu   : TPopupMenu     = nil;
  55. const
  56.   FloatingMenusList       : TList            = nil;
  57.   IgnoreNextMenuUp        : Boolean          = False; // ignore alt key up after alt key down
  58.   IgnoreRepaintFloating   : Boolean          = False;
  59.   bmpCheckMark            : HBitmap          = 0;
  60.   bmpRadioItem            : HBitmap          = 0;
  61. var
  62.   Z: array [0..256] of Char;
  63.   mii: TMenuItemInfo;
  64.   NonClientMetrics: TNonClientMetrics;
  65. { other routines }
  66. procedure HideWindowMenu(Owner: TComponent);
  67. function AssignedActivePopupMenu2000Form: Boolean;
  68. procedure KillActivePopupMenu2000(KillMenuBar, B: Boolean);
  69. procedure SetStatusBarText(HintText: String);
  70. function GetMessageHook(Code, wParam, lParam: Integer): Integer; stdcall;
  71. function GetCBTHook(Code: Integer; wParam: HWND; lParam: LPARAM): LRESULT; stdcall;
  72. function GetCallWndProcHook(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  73. procedure CheckShowHint(MenuItem: Menus.TMenuItem; ShowFloatingHint: Boolean; Form: TForm);
  74. procedure ProcessPaintMessages;
  75. procedure ProcessMouseMoveMessages;
  76. procedure NewDisabledBlt(Canvas: TCanvas; X, Y: Integer; clHigh, clShadow: TColor;
  77.   hBmp: HBitmap);
  78. procedure ImgDisabledBlt(Canvas: TCanvas; X, Y: Integer; Images: TImageList; Index: Integer;
  79.   clShadow, clHigh: TColor);
  80. procedure TransBlt(Canvas: TCanvas; X, Y, Glyph, NumGlyphs: Integer; hBmp: HBitmap);
  81. procedure PaintMenuIcon(Owner, AMC: Forms.TForm; DC: HDC; X, Y, W: Integer);
  82. procedure FullHideCaret;
  83. procedure FullShowCaret;
  84. function GetMenuFontHandle: HFont;
  85. function GetValidName(Caption: String): String;
  86. procedure RepaintFloatingMenus;
  87. procedure OffsetBitmap(Bitmap: TBitmap; Left, Top, Width, Height: Integer);
  88. function StripAmpersands(S: String): String;
  89. procedure ShowDoesntSupport(Feature: String);
  90. procedure InstallGMHooks;
  91. procedure RemoveGMHooks;
  92. procedure InstallCWHooks;
  93. procedure RemoveCWHooks;
  94. function IsAccelEx(VK: Word; const Str: String; UseFirstLetter: Boolean): Boolean;
  95. function HasSubmenu(Item: TMenuItem): Boolean;
  96. function AmpTextWidth(Canvas: TCanvas; S: String): Integer;
  97. function GetMnuDsgnHandle: HWND;
  98. procedure CopyToClipboard(S: String);
  99. function PasteFromClipboard: String;
  100. function IsShortCutEx(var Msg: TWMKey; Items: TMenuItem; DoAction: Boolean): Boolean;
  101. function GetNumLines(S: String): Integer;
  102. implementation
  103. uses
  104.   am2000menubar, am2000popupmenu, am2000mainmenu, am2000hintwindow,
  105.   am2000menuitem, am2000const;
  106. const
  107.   // directions for GetNextToolbarButton2000
  108.   drLeft  = -1;
  109.   drRight = 1;
  110.   vk_0 = Byte('0');
  111.   vk_Z = Byte('Z');
  112. const
  113.   CurCaretIndex : Integer = 0;
  114.   HGetMessageHook         : HHook            = 0;
  115.   HGetCBTHook             : HHook            = 0;
  116.   HGetCallWndProcHook     : HHook            = 0;
  117.   GMHooksCount            : Integer          = 0;
  118.   CWHooksCount            : Integer          = 0;
  119. { Routines }
  120. function AssignedActivePopupMenu2000Form: Boolean;
  121. begin
  122.   Result:= (ActivePopupMenu <> nil)
  123.     and TCustomPopupMenu2000(ActivePopupMenu).FormOnScreen;
  124. end;
  125. procedure HideWindowMenu(Owner: TComponent);
  126. begin
  127.   // hides only MDIForm's menu
  128.   if (Owner is Forms.TForm)
  129.   and (not (Owner.Owner is Forms.TForm))
  130.   and (Forms.TForm(Owner).Menu <> nil)
  131.   then begin
  132.     Forms.TForm(Owner).Menu:= nil;
  133.   end;
  134. end;
  135. procedure SetStatusBarText(HintText: String);
  136. var
  137.   I: Integer;
  138.   S: String;
  139. begin
  140.   S:= Trim(GetLongHint(HintText));
  141.   // remove '&#13;' symbols from status bar text
  142.   repeat
  143.     I:= Pos('&#', S);
  144.     if I = 0 then System.Break;
  145.     System.Delete(S, I, 5);
  146.     System.Insert(' ', S, I);
  147.   until False;
  148.   if Assigned(ActivePopupMenu)
  149.   and Assigned(TCustomPopupMenu2000(ActivePopupMenu).StatusBar)
  150.   then
  151.     with TCustomPopupMenu2000(ActivePopupMenu), StatusBar do begin
  152.       if SimplePanel
  153.       then SimpleText:= S
  154.       else
  155.         if StatusBarIndex < Panels.Count
  156.         then Panels[StatusBarIndex].Text:= S;
  157.       Exit;
  158.     end;
  159. {  if AssignedActiveMenuBar
  160.   and Assigned(ActiveMenuBar.StatusBar)
  161.   then
  162.     with ActiveMenu2000, StatusBar do
  163.       if SimplePanel
  164.       then SimpleText:= S
  165.       else
  166.         if StatusBarIndex < Panels.Count
  167.         then Panels[StatusBarIndex].Text:= S;
  168. }
  169. end;
  170. // processing mousemove and paint messages --
  171. // a bit faster than Application.ProcessMessages
  172. // thanks to Jordan Russell
  173. procedure ProcessPaintMessages;
  174. var
  175.   Msg: TMsg;
  176. begin
  177.   while PeekMessage(Msg, 0, wm_Paint, wm_Paint, pm_NoRemove) do begin
  178.     case Integer(GetMessage(Msg, 0, wm_Paint, wm_Paint)) of
  179.       -1: Exit;
  180.       0: begin PostQuitMessage(Msg.WParam); Exit; end;
  181.     end;
  182.     DispatchMessage(Msg);
  183.   end;
  184. end;
  185. procedure ProcessMouseMoveMessages;
  186. var
  187.   Msg: TMsg;
  188. begin
  189.   while PeekMessage(Msg, 0, wm_MouseMove, wm_MouseMove, pm_NoRemove) do begin
  190.     case Integer(GetMessage(Msg, 0, wm_MouseMove, wm_MouseMove)) of
  191.       -1: Exit;
  192.       0: begin PostQuitMessage(Msg.WParam); Exit; end;
  193.     end;
  194.     DispatchMessage(Msg);
  195.   end;
  196. end;
  197. procedure KillActivePopupMenu2000;
  198. begin
  199.   try
  200.     if AssignedActivePopupMenu2000Form then
  201.       with ActivePopupMenu, TCustomPopupMenu2000(ActivePopupMenu).Form do begin
  202.         SetStatusBarText('');
  203.         Perform(wm_KillTimer, 0, 0);
  204.         Perform(wm_KillAnimation, 0, 0);
  205.         Perform(wm_HideSilent, 0, LongInt(B));
  206.       end;
  207.     if KillMenuBar
  208.     and (ActiveMenuBar <> nil)
  209.     then ActiveMenuBar.HideActiveItem;
  210.   except
  211.   end;
  212.   ActivePopupMenu:= nil;
  213. end;
  214. { Hooks }
  215. function GetMessageHook(Code, wParam, lParam: Integer): Integer; stdcall;
  216. const
  217.   LastForm: TCustomPopupMenu2000Form = nil;
  218. var
  219.   M: TMsg;
  220.   Msg: Integer;
  221.   C: TControl;
  222.   P: TPoint;
  223.   procedure ClearMessage;
  224.   begin
  225.     FillChar(PMsg(lParam)^, SizeOf(TMsg), 0);
  226.   end;
  227.   function IsOkControl(C: TControl): Boolean;
  228.   begin
  229.     Result:=
  230.       ((C is TCustomPopupMenu2000Form) and (TForm(C).BorderStyle = bsNone))
  231.       or (C is TCustomMenuBar2000)
  232.       or (Assigned(C) and IsOkControl(C.Parent));
  233.   end;
  234.   function IsFloating: Boolean;
  235.   var
  236.     I: Integer;
  237.   begin
  238.     Result:= False;
  239.     for I:= 0 to FloatingMenusList.Count -1 do
  240.       if SendMessage(TForm(FloatingMenusList[I]).Handle, wm_NCHitTest, 0,
  241.         MakeLong(P.X, P.Y)) <> htError
  242.       then begin
  243.         Result:= True;
  244.         Exit;
  245.       end;
  246.   end;
  247.   function GetActiveMenuBar: Boolean;
  248.   var
  249.     F: TForm;
  250.     function SearchForActiveMenuBar(C: TComponent): Boolean;
  251.     var
  252.       I: Integer;
  253.     begin
  254.       Result:= False;
  255.       I:= 0;
  256.       while (I < C.ComponentCount) and (not Result) do begin
  257.         if C.Components[I] is TCustomMenuBar2000 then begin
  258.           ActiveMenuBar:= TCustomMenuBar2000(C.Components[I]);
  259.           Result:= True;
  260.           Exit;
  261.         end;
  262.         if C.Components[I].ComponentCount > 0 then
  263.           Result:= Result or SearchForActiveMenuBar(C.Components[I]);
  264.         Inc(I);
  265.       end;
  266.     end;
  267.   begin
  268.     F:= Screen.ActiveForm;
  269.     Result:= (F.Menu = nil)
  270.       and SearchForActiveMenuBar(F)
  271.       and (ActiveMenuBar <> nil);
  272.   end;
  273. begin
  274.   Result:= 0;
  275.   if (Code >= 0)
  276.   and Assigned(Application)
  277.   and Application.Active
  278.   and (not IsIconic(GetActiveWindow))
  279.   then begin
  280.     M:= PMsg(lParam)^;
  281.     Msg:= PMsg(lParam)^.Message;
  282.     // check for mouse messages
  283.     if ((Msg >= wm_LButtonDblClk) and (Msg <= wm_MButtonDblClk))
  284.     or ((Msg >= wm_NCRButtonDblClk) and (Msg <= wm_NCMButtonDblClk))
  285.     or (Msg = wm_LButtonDown)
  286.     or (Msg = wm_NCLButtonDown)
  287.     or (Msg = wm_NCRButtonDown)
  288.     then begin
  289.       // is it a mouse click on form's client area?
  290.       if (Msg > wm_MouseFirst) then begin
  291.         GetCursorPos(P);
  292.         C:= FindDragTarget(P, True);
  293.         if Assigned(C) and IsOkControl(C) then Exit;
  294.       end
  295.       else
  296.         if IsFloating then Exit;
  297.       // if not -- kil active menu
  298.       if AssignedActivePopupMenu2000Form then begin
  299.         if TCustomPopupMenu2000(ActivePopupMenu).Form.BorderStyle <> bsNone
  300.         then Exit;
  301.         KillActivePopupMenu2000(True, False);
  302.         IgnoreNextMenuUp:= False;
  303.       end;
  304.       if Assigned(ActiveMenuBar)
  305.       then ActiveMenuBar.KillActiveItem;
  306.       FullShowCaret;
  307.     end;
  308.     // another key?
  309.     if ((Msg = wm_KeyDown) or (Msg = wm_KeyUp) or (Msg = wm_SysKeyDown) or (Msg = wm_SysKeyUp))
  310.     then 
  311.       // trying to search receiver of the message in active popup menu
  312.       if ((ActivePopupMenu <> nil)
  313.         and (TCustomPopupMenu2000(ActivePopupMenu).GetTopMostForm.Perform(Msg, M.wParam, M.lParam) <> 0))
  314.       or
  315.       // .. or in active menu bar...
  316.         (GetActiveMenuBar
  317.         and (not (csDesigning in ActiveMenuBar.ComponentState))
  318.         and IsWindowEnabled(TForm(ActiveMenuBar.Owner).Handle)
  319.         and (ActiveMenuBar.Perform(Msg, M.wParam, M.lParam) <> 0))
  320.     then begin
  321.       ClearMessage;
  322.       Exit;
  323.     end { keyboard message } ;
  324.   end { main form is active } ;
  325.   Result:= CallNextHookEx(HGetMessageHook, Code, wParam, lParam);
  326. end;
  327. function GetCBTHook(Code: Integer; wParam: HWND; lParam: LPARAM): LRESULT; stdcall;
  328.   // updates menu bar on new mdi form
  329. begin
  330.   if ((Code = HCBT_MINMAX)
  331.   or (Code = HCBT_SETFOCUS))
  332.   and (Assigned(ActiveMenuBar)
  333.   and ActiveMenuBar.HandleAllocated)
  334.   then PostMessage(ActiveMenuBar.Handle, wm_UpdateMenuBar, upChildChanged, 0);
  335.   Result := CallNextHookEx(HGetCBTHook, Code, wParam, lParam);
  336. end;
  337. function GetCallWndProcHook(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  338.   // activate and deactivate application and main form
  339. var
  340.   IsActive: Boolean;
  341. begin
  342.   if (Code = HC_ACTION) then
  343.     with PCWPStruct(lParam)^ do
  344.       if ((Message = WM_ACTIVATE)
  345.       or (Message = WM_ACTIVATEAPP))
  346.       and (Assigned(ActiveMenuBar)
  347.       and ActiveMenuBar.HandleAllocated)
  348.       and ((hwnd = ActiveMenuBar.Handle) or (hwnd = TForm(ActiveMenuBar.Owner).Handle))
  349.       then begin
  350.         if (Message = WM_ACTIVATE)
  351.         then IsActive:= IsWindowEnabled(TForm(ActiveMenuBar.Owner).Handle)
  352.         else IsActive:= Boolean(WParam);
  353.         PostMessage(ActiveMenuBar.Handle, wm_ActivateMenuBar, DWord(IsActive), 0);
  354.       end;
  355.   Result:= CallNextHookEx(HGetCallWndProcHook, Code, wParam, lParam);
  356. end;
  357. { Other Routines }
  358. procedure CheckShowHint(MenuItem: TMenuItem; ShowFloatingHint: Boolean; Form: TForm);
  359. var
  360.   S: String;
  361. begin
  362.   if not Assigned(MenuItem) then Exit;
  363.   S:= '';
  364.   if (MenuItem is TMenuItem2000)
  365.   then
  366.     if (TMenuItem2000(MenuItem).Control = ctlButtonArray)
  367.     then
  368.       with TMenuItem2000(MenuItem), AsButtonArray do begin
  369.         if (LastItemIndex >= 0)
  370.         and (LastItemIndex < Hints.Count)
  371.         then S:= Hints[LastItemIndex]
  372.       end
  373.     else
  374.       S:= TMenuItem2000(MenuItem).Hint
  375.   else
  376.     S:= MenuItem.Hint;
  377.   // fire Application.OnHint
  378.   Application.Hint:= S;
  379.   Form.Hint:= S;
  380.   if (ActivePopupMenu <> nil)
  381.   and (TCustomPopupMenu2000(ActivePopupMenu).StatusBar <> nil)
  382.   then SetStatusBarText(S);
  383. end;
  384. // thanks to Brad Stowers for this routine
  385. procedure PaintMenuIcon(Owner, AMC: Forms.TForm; DC: HDC; X, Y, W: Integer);
  386. var
  387.   IconHandle, NewIcon: HIcon;
  388. begin
  389.   if Assigned(AMC) and (AMC.Icon.Handle <> 0)
  390.   then IconHandle := AMC.Icon.Handle
  391.   else
  392.   if Assigned(AMC) and (Owner.Icon.Handle <> 0)
  393.   then IconHandle:= Owner.Icon.Handle
  394.   else
  395.   if Application.Icon.Handle <> 0
  396.   then IconHandle:= Application.Icon.Handle
  397.   else IconHandle:= LoadIcon(0, IDI_APPLICATION);
  398.   NewIcon:= CopyImage(IconHandle, IMAGE_ICON, W, W, $4000);
  399.   DrawIconEx(DC, X, Y, NewIcon, 0, 0, 0, 0, DI_NORMAL);
  400.   DeleteObject(NewIcon);
  401. end;
  402. procedure TransBlt(Canvas: TCanvas; X, Y, Glyph, NumGlyphs: Integer; hBmp: HBitmap);
  403. var
  404.   BitmapDC: HDC;
  405.   X1, Y1, DX, XE, Cur, Trans: Integer;
  406.   BmpInfo: Windows.TBitmap;
  407.   oldh: HBitmap;
  408. begin
  409.   BmpInfo.bmHeight:= 16;
  410.   BmpInfo.bmWidth:= 16;
  411.   GetObject(hBmp, SizeOf(BmpInfo), @BmpInfo);
  412.   BitmapDC:= CreateCompatibleDC(Canvas.Handle);
  413.   oldh:= SelectObject(BitmapDC, hBmp);
  414.   if oldh <> 0 then begin
  415.     Trans:= GetPixel(BitmapDC, 0, BmpInfo.bmHeight -1);
  416.     if NumGlyphs > 1 then begin
  417.       XE:= BmpInfo.bmWidth div NumGlyphs;
  418.       DX:= Glyph * XE;
  419.     end
  420.     else begin
  421.       DX:= 0;
  422.       XE:= BmpInfo.bmWidth;
  423.     end;
  424.     for X1:= 0 to XE -1 do
  425.       for Y1:= 0 to BmpInfo.bmHeight -1 do begin
  426.         Cur:= GetPixel(BitmapDC, X1 + DX, Y1);
  427.         if (Cur <> Trans) then
  428.           SetPixel(Canvas.Handle, X + X1, Y + Y1, Cur);
  429.       end;
  430.     SelectObject(BitmapDC, oldh);
  431.   end;
  432.   DeleteDC(BitmapDC);
  433. end;
  434. procedure NewDisabledBlt(Canvas: TCanvas; X, Y: Integer; clHigh, clShadow: TColor;
  435.   hBmp: HBitmap);
  436. var
  437.   XOffset: Integer;
  438.   BitmapDC: HDC;
  439.   Trans: TColor;
  440.   BmpInfo: Windows.TBitmap;
  441.   oldh: HBitmap;
  442.   procedure PaintColor(Color: TColor; Offset: Integer);
  443.   var
  444.     X1, Y1, Cur: Integer;
  445.   begin
  446.     for X1:= XOffset to XOffset + BmpInfo.bmWidth -1 do
  447.       for Y1:= 0 to BmpInfo.bmHeight -1 do begin
  448.         Cur:= GetPixel(BitmapDC, X1, Y1);
  449.         if (Cur <> Trans)
  450.         and (Cur and $000000FF <= 132)
  451.         and (Cur and $0000FF00 shr 08 <= 128)
  452.         and (Cur and $00FF0000 shr 16 <= 132)
  453.         then
  454.           SetPixel(Canvas.Handle, X + X1 + Offset, Y + Y1 + Offset, Color);
  455.       end;
  456.   end;
  457. begin
  458.   if hBmp = 0 then Exit;
  459.   XOffset:= 0;
  460.   BmpInfo.bmHeight:= 16;
  461.   BmpInfo.bmWidth:= 16;
  462.   GetObject(hBmp, SizeOf(BmpInfo), @BmpInfo);
  463.   BitmapDC:= CreateCompatibleDC(Canvas.Handle);
  464.   oldh:= SelectObject(BitmapDC, hBmp);
  465.   if oldh <> 0 then begin
  466.     Trans:= GetPixel(BitmapDC, 0, BmpInfo.bmHeight -1);
  467.     PaintColor(ColorToRgb(clShadow), 1);
  468.     PaintColor(ColorToRgb(clHigh), 0);
  469.     SelectObject(BitmapDC, oldh);
  470.   end;
  471.   DeleteDC(BitmapDC);
  472. end;
  473. procedure ImgDisabledBlt(Canvas: TCanvas; X, Y: Integer; Images: TImageList; Index: Integer;
  474.   clShadow, clHigh: TColor);
  475. const
  476.   ROP_DSPDxax = $00E20746;
  477. var
  478.   R: TRect;
  479.   DestDC, SrcDC: HDC;
  480.   MonoBitmap: TBitmap;
  481. begin
  482.   MonoBitmap:= TBitmap.Create;
  483.   with MonoBitmap do begin
  484.     Monochrome:= True;
  485.     Width:= Images.Width;
  486.     Height:= Images.Height;
  487.   end;
  488.   // Store masked version of image temporarily in FBitmap
  489.   MonoBitmap.Canvas.Brush.Color:= clWhite;
  490.   MonoBitmap.Canvas.FillRect(Rect(0, 0, Images.Width, Images.Height));
  491.   ImageList_DrawEx(Images.Handle, Index, MonoBitmap.Canvas.Handle, 0, 0, 0, 0,
  492.     CLR_DEFAULT, 0, ILD_NORMAL);
  493.   R:= Rect(X, Y, X + Images.Width, Y + Images.Height);
  494.   SrcDC:= MonoBitmap.Canvas.Handle;
  495.   // Convert Black to clHigh
  496.   Canvas.Brush.Color:= clHigh;
  497.   DestDC := Canvas.Handle;
  498.   Windows.SetTextColor(DestDC, clWhite);
  499.   Windows.SetBkColor(DestDC, clBlack);
  500.   BitBlt(DestDC, X+1, Y+1, Images.Width, Images.Height, SrcDC, 0, 0, ROP_DSPDxax);
  501.   // Convert Black to clShadow
  502.   Canvas.Brush.Color:= clShadow;
  503.   DestDC:= Canvas.Handle;
  504.   SetTextColor(DestDC, clWhite);
  505.   SetBkColor(DestDC, clBlack);
  506.   BitBlt(DestDC, X, Y, Images.Width, Images.Height, SrcDC, 0, 0, ROP_DSPDxax);
  507. end;
  508. procedure FullHideCaret;
  509.   // hides the caret
  510. begin
  511.   HideCaret(0);
  512.   Inc(CurCaretIndex);
  513. end;
  514. procedure FullShowCaret;
  515.   // shows the caret
  516. var
  517.   I: Integer;
  518. begin
  519.   for I:= CurCaretIndex downto 1 do
  520.     ShowCaret(0);
  521.   CurCaretIndex:= 0;
  522. end;
  523. function GetMenuFontHandle: HFont;
  524.   // retrives default menu font
  525. begin
  526.   if SystemParametersInfo(spi_GetNonClientMetrics, 0, @NonClientMetrics, 0)
  527.   then Result:= CreateFontIndirect(NonClientMetrics.lfMenuFont)
  528.   else Result:= GetStockObject(SYSTEM_FONT);
  529. end;
  530. function GetValidName(Caption: String): String;
  531.   // creates valid menu item name from the given caption
  532. var
  533.   I: Integer;
  534. begin
  535.   Result:= '';
  536.   for I:= 1 to Length(Caption) do
  537.     if Caption[I] in ['0'..'9', 'A'..'Z', '_', 'a'..'z']
  538.     then AppendStr(Result, Caption[I]);
  539.   if Result = '' then Result:= 'N';
  540.   if Result[1] in ['0'..'9'] then Result:= 'N' + Result;
  541. end;
  542. procedure RepaintFloatingMenus;
  543. var
  544.   I: Integer;
  545. begin
  546.   if IgnoreRepaintFloating then Exit;
  547.   for I:= 0 to FloatingMenusList.Count -1 do
  548.     TForm(FloatingMenusList[I]).Repaint;
  549. end;
  550. procedure OffsetBitmap(Bitmap: TBitmap; Left, Top, Width, Height: Integer);
  551. var
  552.   TempBitmap: TBitmap;
  553. begin
  554.   TempBitmap:= TBitmap.Create;
  555.   TempBitmap.Width:= Width;
  556.   TempBitmap.Height:= Height;
  557.   BitBlt(TempBitmap.Canvas.Handle, 0, 0, Width, Height,
  558.     Bitmap.Canvas.Handle, Left, Top, Bitmap.Canvas.CopyMode);
  559.   BitBlt(Bitmap.Canvas.Handle, 0, 0, Width, Height,
  560.     TempBitmap.Canvas.Handle, 0, 0, Bitmap.Canvas.CopyMode);
  561.   TempBitmap.Free;
  562. end;
  563. procedure InstallGMHooks;
  564. begin
  565.   Inc(GMHooksCount);
  566.   if GMHooksCount <> 1 then Exit;
  567.   // setting the hook - many thanks to Victor Santos
  568.   // for help in solving the problems with hook
  569.   if HGetMessageHook = 0
  570.   then HGetMessageHook:= SetWindowsHookEx(wh_GetMessage, @GetMessageHook, 0, GetCurrentThreadID);
  571. end;
  572. procedure RemoveGMHooks;
  573. begin
  574.   Dec(GMHooksCount);
  575.   if GMHooksCount <> 0 then Exit;
  576.   // remove the 'get message' hook
  577.   if HGetMessageHook <> 0
  578.   then UnhookWindowsHookEx(HGetMessageHook);
  579.   HGetMessageHook:= 0;
  580. end;
  581. procedure InstallCWHooks;
  582. begin
  583.   Inc(CWHooksCount);
  584.   if CWHooksCount <> 1 then Exit;
  585.   // install the computer-based training hook for mdi child form
  586.   if (HGetCBTHook = 0)
  587.   then HGetCBTHook:= SetWindowsHookEx(WH_CBT, @GetCBTHook, 0, GetCurrentThreadID);
  588.   // install the call window procedure hook - for gray activated
  589.   if (HGetCallWndProcHook = 0)
  590.   then HGetCallWndProcHook:= SetWindowsHookEx(WH_CallWndProc, @GetCallWndProcHook, 0, GetCurrentThreadID);
  591. end;
  592. procedure RemoveCWHooks;
  593. begin
  594.   Dec(CWHooksCount);
  595.   if CWHooksCount <> 0 then Exit;
  596.   // remove the 'computer-based training' hook
  597.   if HGetCBTHook <> 0
  598.   then UnhookWindowsHookEx(HGetCBTHook);
  599.   // remove the 'call window procedure' hook
  600.   if HGetCallWndProcHook <> 0
  601.   then UnhookWindowsHookEx(HGetCallWndProcHook);
  602.   HGetCBTHook:= 0;
  603.   HGetCallWndProcHook:= 0;
  604. end;
  605. procedure ShowDoesntSupport(Feature: String);
  606. begin
  607.   KillActivePopupMenu2000(True, True);
  608.   Application.MessageBox(PChar(SDoesntSupportText1 + Feature + SDoesntSupportText2), SDoesntSupportTitle, mb_IconInformation);
  609. end;
  610. function StripAmpersands(S: String): String;
  611. var
  612.   P: Integer;
  613. begin
  614.   Result:= ' ';
  615.   P:= Pos('&', S);
  616.   while P > 0 do begin
  617.     if P > 1
  618.     then AppendStr(Result, Copy(S, 1, P -1));
  619.     Delete(S, 1, P);
  620.     if (S <> '') and (S[1] = '&')
  621.     then begin
  622.       AppendStr(Result, '&');
  623.       Delete(S, 1, 1);
  624.     end;
  625.     P:= Pos('&', S);
  626.   end;
  627.   AppendStr(Result, S);
  628. end;
  629. function IsAccelEx(VK: Word; const Str: String; UseFirstLetter: Boolean): Boolean;
  630. var
  631.   S: String;
  632. begin
  633.   Result:= (VK in [$30..$39,$41..$5a])
  634.     and Forms.IsAccel(VK, Str);
  635.   if (not Result)
  636.   and UseFirstLetter
  637.   and (Str <> '')
  638.   then begin
  639.     S:= StripAmpersands(Str);
  640.     Result:= (S <> '') and (VK = Byte(UpCase(S[1])));
  641.   end;
  642. end;
  643. function HasSubmenu(Item: TMenuItem): Boolean;
  644. begin
  645.   Result:= (Item <> nil)
  646.     and ((Item.Count > 0)
  647.     or ((Item is TMenuItem2000)
  648.     and (TMenuItem2000(Item).AttachMenu <> nil)));
  649. end;
  650. function AmpTextWidth(Canvas: TCanvas; S: String): Integer;
  651.   // returns text width without ampersands
  652. begin
  653.   Result:= Canvas.TextWidth(StripAmpersands(S));
  654. end;
  655. function GetMnuDsgnHandle: HWND;
  656. begin
  657.   Result:= FindWindow(nil, 'AM/2000 Menu Designer');
  658. end;
  659. procedure CopyToClipboard(S: String);
  660. var
  661.   L: Integer;
  662.   hglbCopy: HGLOBAL;
  663.   lptstrCopy: PChar;
  664. begin
  665.   L:= (Length(S) +1) * SizeOf(Char);
  666.   OpenClipboard(0);
  667.   EmptyClipboard;
  668.   hglbCopy:= GlobalAlloc(GMEM_DDESHARE, L);
  669.   lptstrCopy:= GlobalLock(hglbCopy);
  670.   Move(PChar(S)^, lptstrCopy^, L);
  671. //    lptstrCopy[cch] = (TCHAR) 0;    // null character
  672.   GlobalUnlock(hglbCopy);
  673.   // Place the handle on the clipboard.
  674.   SetClipboardData(cf_Text, hglbCopy);
  675.   CloseClipboard;
  676. end;
  677. function PasteFromClipboard: String;
  678. var
  679.   hglb: HGLOBAL;
  680.   lptstr: PChar;
  681. begin
  682.   Result:= '';
  683.   OpenClipboard(0);
  684.   hglb:= GetClipboardData(cf_Text);
  685.   lptstr:= GlobalLock(hglb);
  686.   if lptstr <> nil then Result:= StrPas(lptstr);
  687.   GlobalUnlock(hglb);
  688.   CloseClipboard;
  689. end;
  690. function IsShortCutEx(var Msg: TWMKey; Items: TMenuItem; DoAction: Boolean): Boolean;
  691. type
  692.   TClickResult = (crDisabled, crClicked, crShortCutMoved);
  693. var
  694.   ShortCut: TShortCut;
  695.   ShortCutStr: String;
  696.   ShortCutItem: TMenuItem;
  697.   function DoClick(Item: TMenuItem): TClickResult;
  698.     // thanks to Borland (Inprise) for this code
  699.   begin
  700.     Result:= crClicked;
  701.     if Item.Parent <> nil then Result:= DoClick(Item.Parent);
  702.     if Result = crClicked then
  703.       if Item.Enabled 
  704.       then begin
  705. {$IFDEF Delphi4OrHigher}
  706.         if DoAction then Item.InitiateAction;
  707. {$ENDIF}
  708.         Item.Click;
  709.       end
  710.       else Result:= crDisabled;
  711.   end;
  712.   function PosShortCut(const SC, SCList: String): Boolean;
  713.     // is shortcut delimited with semi-colons or string limits?
  714.   var
  715.     P, E: Integer;
  716.   begin
  717.     P:= Pos(SC, SCList);
  718.     E:= P + Length(SC);
  719.     Result:= (P <> 0)
  720.       and ((P = 1) or (SCList[P -1] = ';'))
  721.       and ((E > Length(SCList)) or (SCList[E] = ';'));
  722.   end;
  723.   function FindItemByShortCut(Items: TMenuItem): TMenuItem;
  724.   var
  725.     I: Integer;
  726.   begin
  727.     I:= 0;
  728.     Result:= nil;
  729.     while (I < Items.Count) and (Result = nil) do begin
  730.       if (Items[I].ShortCut = ShortCut)
  731.       or ((Items[I] is TMenuItem2000)
  732.       and (PosShortCut(ShortCutStr, TMenuItem2000(Items[I]).ShortCut)))
  733.       then begin
  734.         Result:= Items[I];
  735.         Exit;
  736.       end;
  737.       if Items[I].Count > 0 then
  738.         Result:= FindItemByShortCut(Items[I]);
  739.       Inc(I);
  740.     end;
  741.   end;
  742.   procedure SearchForItems(Items: TMenuItem);
  743.   var
  744.     ClickResult: TClickResult;
  745.   begin
  746.     if Items = nil then Exit;
  747.     repeat
  748.       ClickResult:= crDisabled;
  749.       ShortCutItem:= FindItemByShortCut(Items);
  750.       if ShortCutItem <> nil then begin
  751.         KillActivePopupMenu2000(True, False);
  752.         ClickResult:= DoClick(ShortCutItem);
  753.       end;
  754.     until ClickResult <> crShortCutMoved;
  755.     if ShortCutItem <> nil
  756.     then begin
  757.       Msg.Result:= 1;
  758.       Result:= True;
  759.     end;
  760.   end;
  761. begin
  762.   Result:= False;
  763.   // get short cut
  764.   ShortCut:= Msg.CharCode;
  765.   if GetKeyState(vk_Shift) < 0 then Inc(ShortCut, scShift);
  766.   if GetKeyState(vk_Control) < 0 then Inc(ShortCut, scCtrl);
  767.   if Msg.KeyData and AltMask <> 0 then Inc(ShortCut, scAlt);
  768.   // get text short cut
  769.   ShortCutStr:= ShortCutToText(ShortCut);
  770.   // search
  771.   if ShortCutStr <> ''
  772.   then SearchForItems(Items);
  773. end;
  774. function GetNumLines(S: String): Integer;
  775. var
  776.   P, PS: PChar;
  777. begin
  778.   Result:= 1;
  779.   PS:= PChar(S);
  780.   repeat
  781.     P:= StrPos(PS, 'n');
  782.     if P = nil then P:= StrPos(PS, #13);
  783.     if P = nil then Break;
  784.     Inc(Result);
  785.     PS:= @P[1];
  786.   until PS[0] = #0;
  787. end;
  788. initialization
  789.   // active menu2000 list for multiforms
  790.   FloatingMenusList:= TList.Create;
  791.   // structure for quering menus
  792.   mii.cbSize:= 44;
  793.   NonClientMetrics.cbSize := sizeof(NonClientMetrics);
  794.   // get system parameters info
  795.   SystemParametersInfo(spi_GetNonClientMetrics, 0, @NonClientMetrics, 0);
  796.   // load bitmaps
  797.   bmpCheckMark:=      LoadBitmap(HInstance, 'AM2000_SYSTEMCHECKMARK');
  798.   bmpRadioItem:=      LoadBitmap(HInstance, 'AM2000_SYSTEMRADIOITEM');
  799. finalization
  800.   FloatingMenusList.Free;
  801.   // delete bitmaps
  802.   DeleteObject(bmpCheckMark);
  803.   DeleteObject(bmpRadioItem);
  804. end.