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

Delphi控件源码

开发平台:

C++ Builder

  1. {*******************************************************}
  2. {                                                       }
  3. {       AnimatedMenus/2000                              }
  4. {       TCustomPopupMenu2000 and TPopupMenu200Form      }
  5. {                                                       }
  6. {       Copyright (c) 1997-99 AnimatedMenus.com         }
  7. {       All rights reserved.                            }
  8. {                                                       }
  9. {*******************************************************}
  10. unit am2000popupmenu;
  11. {$I am2000.inc}
  12. interface
  13. uses
  14.   Windows, Messages, SysUtils, Classes, Graphics, Controls, StdCtrls, ExtCtrls,
  15.   Forms, Dialogs, Buttons, ComCtrls, Menus,
  16.   am2000options, am2000menuitem;
  17. type
  18.   // popup menu
  19.   TCustomPopupMenu2000 = class(T_AM2000_PopupMenu)
  20.   private
  21.     FEMI2000         : TEditableMenuItem2000; // layer for comptibility with Delphi and your apps
  22.     FSBPanelNo       : Integer;
  23.     FStatusBar       : TStatusBar;
  24.     FOnMenuCommand   : TNotifyEvent;
  25.     FOnMenuClose     : TNotifyEvent;
  26.     FFont            : TFont;
  27.     FParentFont      : Boolean;
  28.     FParentShowHint  : Boolean;
  29.     FShowHint        : Boolean;
  30.     FSystemFont      : Boolean;
  31.     FOnCloseQuery    : TCloseQueryEvent;
  32.     FRootItem        : TMenuItem2000;
  33.     FOptions         : T_AM2000_Options;
  34.     FCtl3D           : Boolean;
  35. {$IFNDEF Delphi4OrHigher}
  36.     FImages          : TImageList;
  37. {$ENDIF}
  38.     function IsFontStored: Boolean;
  39.     function IsShowHintStored: Boolean;
  40.     procedure SetFont(Value: TFont);
  41.     procedure SetParentFont(Value: Boolean);
  42.     procedure SetShowHint(Value: Boolean);
  43.     procedure SetParentShowHint(Value: Boolean);
  44.     procedure SetSystemFont(Value: Boolean);
  45.     procedure SetOptions(Value: T_AM2000_Options);
  46.   protected
  47.     property ParentShowHint  : Boolean
  48.       read FParentShowHint write SetParentShowHint default True;
  49.     property ParentFont      : Boolean
  50.       read FParentFont write SetParentFont default True;
  51.     procedure AssignMenuItems(var DestItems: TMenuItem; var DestHandle: HMenu); virtual;
  52.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  53.   public
  54.     Form             : TForm;
  55.     MenuItems        : TMenuItem;
  56.     MenuHandle       : HMenu;
  57.     property StatusBar       : TStatusBar
  58.       read FStatusBar write FStatusBar;
  59.     property StatusBarIndex  : Integer
  60.       read FSBPanelNo write FSBPanelNo;
  61.     property ShowHint        : Boolean
  62.       read FShowHint write SetShowHint stored IsShowHintStored;
  63.     property Options         : T_AM2000_Options
  64.       read FOptions write SetOptions;
  65.     property Font            : TFont
  66.       read FFont write SetFont stored IsFontStored;
  67.     property SystemFont      : Boolean
  68.       read FSystemFont write SetSystemFont default True;
  69.     property Ctl3D           : Boolean
  70.       read FCtl3D write FCtl3D default True;
  71.     property Items2000       : TMenuItem2000
  72.       read FRootItem stored True;
  73.     property OnMenuCommand   : TNotifyEvent
  74.       read FOnMenuCommand write FOnMenuCommand;
  75.     property OnMenuClose     : TNotifyEvent
  76.       read FOnMenuClose write FOnMenuClose;
  77.     property OnCloseQuery    : TCloseQueryEvent
  78.       read FOnCloseQuery write FOnCloseQuery;
  79. {$IFNDEF Delphi4OrHigher}
  80.     property Images : TImageList read FImages write FImages;
  81. {$ENDIF}
  82.     constructor Create(AOwner: TComponent); override;
  83.     destructor Destroy;                     override;
  84.     procedure Popup(X, Y: Integer);         override;
  85.     procedure SetSelectedIndex(First: Boolean);
  86.     procedure RemoveShowHiddenFlag;
  87.     function FormOnScreen: Boolean;
  88.     function GetTopMostForm: TForm;
  89.     procedure InitItems(AddEmpty: Boolean); virtual;
  90.     function IsShortCut(var Msg: TWMKey): Boolean;
  91. {$IFDEF Delphi4OrHigher}
  92.     override;
  93. {$ENDIF}
  94.   published
  95.     property Items   : TEditableMenuItem2000  read FEMI2000;
  96.   end;
  97.   // template
  98.   TCustomPopupMenu2000Form = class(TForm)
  99.   end;
  100. implementation
  101. uses
  102.   CommCtrl, MmSystem, ShellApi, 
  103.   am2000menubar, am2000title, am2000hintwindow, am2000utils,
  104.   am2000const;
  105. const
  106.   COLOR_GRADIENTACTIVECAPTION = 27;
  107.   COLOR_GRADIENTINACTIVECAPTION = 28;
  108.   clGradientActiveCaption = TColor(COLOR_GRADIENTACTIVECAPTION or $80000000);
  109.   clGradientInactiveCaption = TColor(COLOR_GRADIENTINACTIVECAPTION or $80000000);
  110. type
  111.   T_AM2000_PMFState = set of (fsSelectedChanged, fsMouseChanged, fsPaintMenu, fsFromBottomToTop,
  112.     fsFromRightToLeft, fsDrawDisabled, fsIgnoreMouseMove, fsBecomingDraggable, fsAnimated,
  113.     fsKillAnimate, fsDisabled, fsCtl3d, fsShowHidden, fsHiddenArrow, fsHiddenAsRegular,
  114.     fsNoDrawCanvas);
  115.   TByteArray = array [0..1024*1024] of Byte;
  116.   PByteArray = ^TByteArray;
  117.   TShortIntArray = array [0..1024*1024] of ShortInt;
  118.   PShortIntArray = ^TShortIntArray;
  119.   TPopupMenu2000Form = class(TCustomPopupMenu2000Form)
  120.   private
  121.     bi: TBitmapInfo;
  122.     bits, bits0, bits1: PByteArray;
  123.     dbits: PShortIntArray;
  124.     Buffer, Back: TBitmap;
  125.     FSelectedIndex, LastSelectedIndex, ItemWidth, ShortcutWidth,
  126.       ItemHeight, DX, DY, ParentMenuIndex, CurHiddenCount, BitsSize, CurStep: Integer;
  127.     Animation, CloseAnimation: T_AM2000_Animation;
  128.     PopupMenu: TCustomPopupMenu2000;
  129.     SubMenuForm, ParentMenuForm: TPopupMenu2000Form;
  130.     Timer, ASTimer: TTimer;
  131.     MenuHandle: HMenu;
  132.     Options: T_AM2000_Options;
  133.     MouseState: T_AM2000_MouseState;
  134.     NewLeft, NewTop, NewWidth, NewHeight, MX, MY, BL: Integer;
  135.     TimeStart: Integer;
  136.     State: T_AM2000_PMFState;
  137.     ToolTipWindow: T_AM2000_ToolTipWindow;
  138.     // items rects
  139.     FiLeft, FiWidth: Integer;
  140.     ItemRects: TList;
  141.     FocusItem: TMenuItem;
  142.     procedure wmKeyDown(var Msg: TWMKeyDown);      message wm_KeyDown;
  143.     procedure wmSysKeyDown(var Msg: TWMKeyDown);   message wm_SysKeyDown;
  144.     procedure wmChar(var Msg: TWMChar);            message wm_Char;
  145.     procedure cmMouseLeave(var Msg: TMessage);     message cm_MouseLeave;
  146.     procedure wmSetFocus(var Msg: TWMSetFocus);    message wm_SetFocus;
  147.     procedure wmActivate(var Msg: TWMActivate);    message wm_Activate;
  148.     procedure wmMouseActivate(var Msg: TWMMouseActivate); message wm_MouseActivate;
  149.     procedure cmShowingChanged(var Msg: TMessage); message cm_ShowingChanged;
  150.     procedure wmShowAnimated(var Msg: TMessage);   message wm_ShowAnimated;
  151.     procedure wmHideSilent(var Msg: TMessage);     message wm_HideSilent;
  152.     procedure wmKillAnimation(var Msg: TMessage);  message wm_KillAnimation;
  153.     procedure wmKillTimer(var Msg: TMessage);      message wm_KillTimer;
  154.     procedure wmInitState(var Msg: TMessage);      message wm_InitState;
  155.     procedure wmMouseMove(var Msg: TWMMouse);      message wm_MouseMove;
  156.     // utilities
  157.     procedure SetSelectedIndex(Value: Integer);
  158.     procedure PopupMenu2000FormTimer(Sender: TObject);
  159.     procedure SearchForOpenedMenuShortcut(var Msg: TWMKey);
  160.     procedure DestroySubMenuForm;
  161.     procedure CreateSubMenuForm(Menu: TPopupMenu; Handle: HMenu; Items: TMenuItem);
  162.     procedure RebuildToolTipWindow(Recreate: Boolean);
  163.     // bounds management
  164.     procedure RebuildBounds;
  165.     function GetItemRect(Index: Integer): TRect;
  166.     function GetMenuItemHeight(const M: TMenuItem): Integer;
  167.     function GetMenuItemHeightIndex(Index: Integer): Integer;
  168.     function GetRealHeight: Integer; virtual;
  169.     function GetRealWidth: Integer;  virtual;
  170.     procedure GetOptions(Items: TMenuItem; Popup: TObject;
  171.       var Options: T_AM2000_Options);
  172.     procedure TimerShow(Sender: TObject);
  173.     procedure AnimatedHide;
  174.   protected
  175.     procedure Paint; override;
  176.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  177.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  178.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  179.     procedure SetZOrder(TopMost : Boolean); override;
  180.   public
  181.     CurMenuItem, MenuItems: TMenuItem;
  182.     property SelectedIndex: Integer read FSelectedIndex write SetSelectedIndex;
  183.     constructor Create(AOwner: TComponent); override;
  184.     destructor Destroy; override;
  185.     function Animate: Boolean; virtual;
  186.     procedure SilentShow;
  187.     procedure SilentHide;
  188.     procedure Repaint; override;
  189.     procedure PopupSubMenuForm(SelectFirst: Boolean);
  190.     procedure BringMenuToFront;
  191.     function GetCurMenuItem(RaiseException: Boolean): TMenuItem;
  192.     function GetMenuItemIndex(Index: Integer; RaiseException: Boolean): TMenuItem;
  193.     // bounds management
  194.     function GetIndexAt(X, Y: Integer): Integer;
  195.   end;
  196.   // forgot about this
  197.   TFalseMenu = class(TComponent)
  198.   private
  199. {$IFDEF Delphi4OrHigher}
  200.     FBiDiMode: TBiDiMode;
  201. {$ENDIF}
  202.     FItems: TMenuItem;
  203.   end;
  204. { TCustomPopupMenu2000 }
  205. constructor TCustomPopupMenu2000.Create(AOwner: TComponent);
  206. begin
  207.   inherited;
  208.   FFont:= TFont.Create;
  209.   FParentFont:= False;
  210.   FSystemFont:= True;
  211.   FCtl3D:= True;
  212.   FRootItem:= TMenuItem2000.Create(Self);
  213.   FOptions:= T_AM2000_Options.Create;
  214.   // we don't need TMenuItem so we just destoy it
  215.   // and create TMenuItem2000 instead of.
  216.   TFalseMenu(Self).FItems.Free;
  217.   TFalseMenu(Self).FItems:= FRootItem;
  218. {$IFDEF Delphi4OrHigher}
  219.   TFalseMenu(Self).FBiDiMode:= BiDiMode;
  220. {$ENDIF}
  221.   FEMI2000:= TEditableMenuItem2000.Create(Self);
  222.   // this form will be automatically destroyed by the Owner
  223.   if not (csDesigning in ComponentState) then
  224.     Form:= TPopupMenu2000Form.Create(Owner);
  225. end;
  226. destructor TCustomPopupMenu2000.Destroy;
  227. begin
  228.   FFont.Free;
  229.   FOptions.Free;
  230.   if (csDesigning in ComponentState)
  231.   then SendMessage(GetMnuDsgnHandle, wm_Close, 0, 0);
  232.   inherited;
  233. end;
  234. procedure TCustomPopupMenu2000.Popup(X, Y: Integer);
  235. begin
  236.   KillActivePopupMenu2000(False, False);
  237.   ActivePopupMenu:= Self;
  238.   // event
  239.   if Assigned(OnPopup)
  240.   then OnPopup(Self);
  241.   // init items
  242.   InitItems(False);
  243.   // remove hidden items
  244.   if not (PopupComponent is TCustomMenuBar2000)
  245.   then RemoveShowHiddenFlag;
  246.   // bring menu to front
  247.   Forms.TForm(Owner).BringToFront;
  248.   with TPopupMenu2000Form(Form) do begin
  249.     ParentMenuForm:= nil;
  250.     AssignMenuItems(MenuItems, MenuHandle);
  251.     // set system font
  252.     if (PopupComponent is TCustomMenuBar2000)
  253.     then SystemFont:= TCustomMenuBar2000(PopupComponent).SystemFont
  254.     else SystemFont:= Self.SystemFont;
  255.     // set animation options
  256.     if MenuItems is TMenuItem2000
  257.     and (TMenuItem2000(MenuItems).Options is T_AM2000_Options)
  258.     then
  259.       with T_AM2000_Options(TMenuItem2000(MenuItems).Options) do begin
  260.         TPopupMenu2000Form(Form).Animation:= Animation;
  261.         TPopupMenu2000Form(Form).CloseAnimation:= CloseAnimation;
  262.       end;
  263.     PopupMenu:= Self;
  264.     Include(State, fsSelectedChanged);
  265.     // show menu
  266.     if (not IsWindowEnabled(Handle))
  267.     then EnableWindow(Handle, True);
  268.     SetBounds(X, Y, 0, 0);
  269.     BringMenuToFront;
  270.     // animation
  271.     try
  272.       if Animate then Exit;
  273.     except
  274.     end;
  275.     SilentHide;
  276.     if ActivePopupMenu = Self
  277.     then ActivePopupMenu:= nil;
  278.   end;
  279. end;
  280. procedure TCustomPopupMenu2000.AssignMenuItems(var DestItems: TMenuItem; var DestHandle: HMenu);
  281.   // assigns menu items to TCustomPopupMenu2000Form
  282. begin
  283.   if MenuItems <> nil
  284.   then DestItems:= Self.MenuItems
  285.   else DestItems:= Self.Items2000;
  286.   if MenuHandle <> 0
  287.   then DestHandle:= Self.MenuHandle
  288.   else DestHandle:= DestItems.Handle;
  289. end;
  290. function TCustomPopupMenu2000.FormOnScreen: Boolean;
  291. var
  292.   R: TRect;
  293. begin
  294.   Result:= (Form <> nil)
  295.     and (GetClientRect(Form.Handle, R))
  296.     and (R.Top <> R.Bottom)
  297.     and (R.Left <> R.Right);
  298. end;
  299. function TCustomPopupMenu2000.GetTopMostForm: TForm;
  300. begin
  301.   Result:= Form;
  302.   while Assigned(TPopupMenu2000Form(Result).SubMenuForm)
  303.   do Result:= TPopupMenu2000Form(Result).SubMenuForm;
  304. end;
  305. procedure TCustomPopupMenu2000.SetSelectedIndex(First: Boolean);
  306. begin
  307.   if Form <> nil
  308.   then
  309.     with TPopupMenu2000Form(Form) do begin
  310.       if First
  311.       then
  312.         FSelectedIndex:= 0
  313.       else
  314.         FSelectedIndex:= itNothing;
  315.         
  316.       if FormOnScreen then Paint;
  317.     end;
  318. end;
  319. function TCustomPopupMenu2000.IsFontStored: Boolean;
  320. begin
  321.   Result:= not (FParentFont or FSystemFont);
  322. end;
  323. function TCustomPopupMenu2000.IsShowHintStored: Boolean;
  324. begin
  325.   Result:= not FParentShowHint;
  326. end;
  327. procedure TCustomPopupMenu2000.SetFont(Value: TFont);
  328. begin
  329.   FFont.Assign(Value);
  330. end;
  331. procedure TCustomPopupMenu2000.SetParentFont(Value: Boolean);
  332. begin
  333.   FParentFont:= Value;
  334.   if Value then FSystemFont:= False;
  335. end;
  336. procedure TCustomPopupMenu2000.SetSystemFont(Value: Boolean);
  337. begin
  338.   FSystemFont:= Value;
  339.   if Value then FParentFont:= False;
  340. end;
  341. procedure TCustomPopupMenu2000.SetShowHint(Value: Boolean);
  342. begin
  343.   if FShowHint <> Value then begin
  344.     FShowHint:= Value;
  345.     FParentShowHint:= False;
  346.   end;
  347. end;
  348. procedure TCustomPopupMenu2000.SetParentShowHint(Value: Boolean);
  349. begin
  350.   if FParentShowHint <> Value then
  351.     FParentShowHint:= Value;
  352.   if FParentShowHint then
  353.     if Owner is TControl
  354.     then FShowHint:= TControl(Owner).ShowHint
  355.     else FShowHint:= False;
  356. end;
  357. procedure TCustomPopupMenu2000.SetOptions(Value: T_AM2000_Options);
  358. begin
  359.   FOptions.Assign(Value);
  360. end;
  361. procedure TCustomPopupMenu2000.Notification(AComponent: TComponent;
  362.   Operation: TOperation);
  363. begin
  364.   inherited;
  365.   if (Operation = opRemove) then begin
  366. {$IFNDEF Delphi4OrHigher}
  367.     if (AComponent = FImages) then FImages:= nil;
  368. {$ENDIF}
  369.     if (AComponent = FStatusBar) then FStatusBar:= nil;
  370.   end;
  371. end;
  372. procedure TCustomPopupMenu2000.InitItems(AddEmpty: Boolean);
  373. begin
  374.   if (Items.Count = 0)
  375.   and (MenuItems = nil)
  376.   and (MenuHandle = 0)
  377.   then Items.Add(NewItem('(Empty)', 0, False, False, nil, 0, ''));
  378. end;
  379. procedure TCustomPopupMenu2000.RemoveShowHiddenFlag;
  380. begin
  381.   with TPopupMenu2000Form(Form) do
  382.     if not (fsBecomingDraggable in State) then begin
  383.       Exclude(State, fsShowHidden);
  384.       Exclude(State, fsHiddenAsRegular);
  385.     end;
  386.   if not (mfHiddenAsRegular in Options.Flags)
  387.   then Options.Flags:= Options.Flags - [mfHiddenIsVisible];
  388. end;
  389. function TCustomPopupMenu2000.IsShortCut(var Msg: TWMKey): Boolean;
  390. begin
  391.   Result:= IsShortCutEx(Msg, Items2000, csDesigning in ComponentState);
  392. end;
  393. { TPopupMenu2000Form }
  394. constructor TPopupMenu2000Form.Create(AOwner: TComponent);
  395. begin
  396.   inherited CreateNew(AOwner {$IFDEF VER93}, 0{$ENDIF});
  397.   // own initializaton
  398.   FSelectedIndex:= itNothing;
  399.   CurHiddenCount:= 0;
  400.   LastSelectedIndex:= itNothing;
  401.   Animation:=  anVSlide;
  402.   CloseAnimation:= anVSlide;
  403.   BorderStyle:= bsNone;
  404.   FormStyle:= fsStayOnTop;
  405.   Position:= poDesigned;
  406.   // init timers
  407.   Timer:= TTimer.Create(Self);
  408.   Timer.Enabled:= False;
  409.   Timer.Interval:= 250;
  410.   Timer.OnTimer:= PopupMenu2000FormTimer;
  411.   ASTimer:= TTimer.Create(Self);
  412.   ASTimer.Enabled:= False;
  413.   ASTimer.Interval:= 2000;
  414.   ASTimer.OnTimer:= TimerShow;
  415.   Buffer:= TBitmap.Create;
  416.   Buffer.Canvas.Font.Assign(Font);
  417.   Back:= TBitmap.Create;
  418.   ItemRects:= TList.Create;
  419.   SetBounds(0, 0, 0, 0);
  420.   InstallGMHooks;
  421. end;
  422. destructor TPopupMenu2000Form.Destroy;
  423. begin
  424.   MenuItems:= nil;
  425.   Back.Free;
  426.   Buffer.Free;
  427.   Options.Free;
  428.   ItemRects.Free;
  429.   // free bits
  430.   if bits <> nil then Freemem(bits);
  431.   if bits0 <> nil then Freemem(bits0);
  432.   if bits1 <> nil then Freemem(bits1);
  433.   if dbits <> nil then Freemem(dbits);
  434.   ToolTipWindow.Free;
  435.   RemoveGMHooks;
  436.   // this checking is necessary when submenu going to be killed
  437.   // by MainForm (Owner property), not by ParenTCustomPopupMenu2000
  438.   if (ParentMenuForm <> nil)
  439.   and (ParentMenuForm.SubMenuForm = Self) then
  440.     ParentMenuForm.SubMenuForm:= nil;
  441.   if (SubMenuForm <> nil)
  442.   then SubMenuForm.Release;
  443.   inherited Destroy;
  444. end;
  445. { Properties }
  446. function TPopupMenu2000Form.GetRealHeight: Integer;
  447. begin
  448.   Result:= GetItemRect(ItemRects.Count -1).Bottom +
  449.     Options.Margins.Bottom;
  450.   // options
  451.   with Options do begin
  452.     if (BackgroundDisplay = bdExpand)
  453.     and (Result < Background.Height)
  454.     then Result:= Background.Height;
  455.   end;
  456.   // hidden arrow
  457.   if fsHiddenArrow in State
  458.   then Inc(Result, 19);
  459.   // ctl3d
  460.   if (BorderStyle = bsNone)
  461.   and (fsCtl3d in State)
  462.   then Inc(Result, 2*Options.Margins.Border);
  463. end;
  464. function TPopupMenu2000Form.GetRealWidth: Integer;
  465. begin
  466.   Result:= GetItemRect(0).Right;
  467.   // options
  468.   with Options do
  469.     if (BackgroundDisplay = bdExpand)
  470.     and (Result < Background.Width)
  471.     then Result:= Background.Width;
  472.   // ctl3d
  473.   if (BorderStyle = bsNone)
  474. //  and (fsCtl3d in State)
  475.   then Inc(Result, Options.Margins.Border * 2);
  476. end;
  477. function TPopupMenu2000Form.GetIndexAt(X, Y: Integer): Integer;
  478. var
  479.   I, H: Integer;
  480.   P: TPoint;
  481. begin
  482.   P:= Point(X, Y);
  483.   H:= Options.Margins.Top;
  484.   if (BorderStyle = bsNone)
  485.   then
  486.     if (fsCtl3D in State)
  487.     then Inc(H, Options.Margins.Border +2)
  488.     else Inc(H, Options.Margins.Border);
  489.   Result:= itNothing;
  490.   if (MenuHandle = 0)
  491.   or (Y <= H)
  492.   then Exit;
  493.   // is title visible?
  494.   with Options.Title do
  495.     if (ParentMenuForm = nil)
  496.     and Visible
  497.     and (((Align = atLeft) and (X <= Width))
  498.     or   ((Align = atRight) and (X >= Buffer.Width - Width)))
  499.     then Exit;
  500.   // is menu draggable?
  501.   if (Options.Draggable)
  502.   and (BorderStyle = bsNone)
  503.   and (Y <= 11)
  504.   then begin
  505.     Result:= itDragPane;
  506.     Exit;
  507.   end;
  508.   // count all menu items
  509.   for I:= 0 to ItemRects.Count -1 do
  510.     if PtInRect(GetItemRect(I), P)
  511.     then begin
  512.       Result:= I;
  513.       Exit;
  514.     end;
  515.   // hidden arrow?
  516.   if (fsHiddenArrow in State)
  517.   and PtInRect(Rect(3, Buffer.Height -16, Buffer.Width -3, Buffer.Height -3), P)
  518.   then Result:= itHiddenArrow;
  519. end;
  520. procedure TPopupMenu2000Form.SetSelectedIndex(Value: Integer);
  521. var
  522.   Direction: Integer;
  523.   M: TMenuItem;
  524. begin
  525.   if (Value <> SelectedIndex) then begin
  526.     if Value > FSelectedIndex then Direction:= 1
  527.                               else Direction:= -1;
  528.     LastSelectedIndex:= FSelectedIndex;
  529.     FSelectedIndex:= Value;
  530.     Include(State, fsSelectedChanged);
  531.     if MenuHandle = 0 then Exit;
  532.     mii.fMask:= miim_Type + miim_State;
  533.     repeat
  534.       // in case if LastSelectedItem = itNothing
  535.       if (FSelectedIndex = LastSelectedIndex) then Break;
  536.       if FSelectedIndex < 0 then FSelectedIndex:= ItemRects.Count -1;
  537.       if FSelectedIndex >= ItemRects.Count then begin
  538.         FSelectedIndex:= itNothing;
  539.         // show hidden menu items
  540.         if fsHiddenArrow in State then begin
  541.           ASTimer.Enabled:= False;
  542.           Include(State, fsShowHidden);
  543.           SilentHide;
  544.           Animate;
  545.           Exit;
  546.         end;
  547.       end;
  548.       // no enabled items available
  549.       if (FSelectedIndex = LastSelectedIndex)
  550.       then Break;
  551.       // try to find ordinal menu item
  552.       M:= GetMenuItemIndex(FSelectedIndex, False);
  553.       if (M <> nil)
  554.       and (M.Caption <> '-')
  555.       and ((M.Enabled) or (not (mfNoHighDisabled in Options.Flags)))
  556.       then Break;
  557.       // Win32 menu item
  558.       if (M = nil) then begin
  559.         mii.dwTypeData:= Z;
  560.         mii.cch:= SizeOf(Z) -1;
  561.         if GetMenuItemInfo(MenuHandle, FSelectedIndex, True, mii)
  562.         and (mii.fType and mft_Separator = 0)
  563.         and (mii.fState and (mfs_Grayed + mfs_Disabled) = 0)
  564.         then Break;
  565.       end;
  566.       Inc(FSelectedIndex, Direction);
  567.     until False;
  568.     Include(State, fsDrawDisabled);
  569.     Paint;
  570.     CheckShowHint(GetCurMenuItem(False), False, Self);
  571.     // set context
  572.     if (CurMenuItem <> nil)
  573.     then HelpContext:= CurMenuItem.HelpContext;
  574.   end;
  575. end;
  576. procedure TPopupMenu2000Form.GetOptions(Items: TMenuItem; Popup: TObject; var Options: T_AM2000_Options);
  577.   // returns options for the current submenu
  578. begin
  579.   Options.Free;
  580.   Options:= T_AM2000_Options.Create;
  581.   // assign parent options
  582.   if (Popup is TCustomPopupMenu2000)
  583.   then Options.Assign(TCustomPopupMenu2000(Popup).Options);
  584.   // title cannot be inherited
  585.   if ParentMenuForm <> nil
  586.   then Options.Title.Visible:= False;
  587.   // assign current options
  588.   if (Items is TMenuItem2000)
  589.   and (not TMenuItem2000(Items).Options.IsDefault)
  590.   then Options.Assign(TMenuItem2000(Items).Options);
  591. end;
  592. { Events }
  593. procedure TPopupMenu2000Form.WMActivate(var Msg: TWMActivate);
  594. var
  595.   F: Forms.TForm;
  596. begin
  597.   if (Msg.Active = wa_Active)
  598.   and (Owner is Forms.TForm)
  599.   then begin
  600.     F:= Forms.TForm(Owner);
  601.     while (F.FormStyle = fsMdiChild)
  602.     and (F.Owner is Forms.TForm)
  603.     do F:= Forms.TForm(F.Owner);
  604.     if (F is Forms.TForm)
  605.     and (F.Visible)
  606.     and not (csDestroying in F.ComponentState)
  607.     then SendMessage(F.Handle, wm_NCActivate, 1, 0);
  608.   end
  609.   else
  610.     inherited;
  611. end;
  612. // many thanks to Jordan Russell again!...
  613. procedure TPopupMenu2000Form.WMMouseActivate(var Msg: TWMMouseActivate);
  614. begin
  615.   Msg.Result:= ma_NoActivate;
  616.   if (Owner is Forms.TForm) then
  617.     SetActiveWindow(Forms.TForm(Owner).Handle);
  618. end;
  619. procedure TPopupMenu2000Form.CMMouseLeave(var Msg: TMessage);
  620. begin
  621.   inherited;
  622.   MouseState:= [];
  623.   if (fsAnimated in State)
  624.   or (fsDisabled in State)
  625.   then Exit;
  626.   // no menu or no submenu
  627.   if not HasSubMenu(GetCurMenuItem(False))
  628.   then begin
  629.     LastSelectedIndex:= FSelectedIndex;
  630.     FSelectedIndex:= itNothing;
  631.     Include(State, fsSelectedChanged);
  632.     Paint;
  633.   end;
  634.   // clear status bar
  635.   SetStatusBarText('');
  636. end;
  637. procedure TPopupMenu2000Form.WMSetFocus(var Msg: TWMSetFocus);
  638. begin
  639.   if (fsAnimated in State)
  640.   and (Owner is Forms.TForm)
  641.   and (Forms.TForm(Owner).Visible)
  642.   then Forms.TForm(Owner).SetFocus
  643.   else inherited;
  644. end;
  645. procedure TPopupMenu2000Form.CMShowingChanged(var Msg: TMessage);
  646. begin
  647.   // Skip Application.UpdateVisible
  648.   // that shows annoying 'application icon' on taskbar
  649.   if Showing
  650.   then begin
  651.     ShowWindow(Handle, sw_ShowNA);
  652.     SetWindowPos(Handle, hwnd_Top, Left, Top, Width, Height, FormFlags);
  653.   end
  654.   else
  655.     ShowWindow(Handle, sw_Hide);
  656. end;
  657. procedure TPopupMenu2000Form.MouseDown;
  658. var
  659.   I, MX, MY: Integer;
  660. begin
  661.   if ssLeft  in Shift then Include(MouseState, msLeftButton);
  662.   if ssRight in Shift then Include(MouseState, msRightButton);
  663.   Include(State, fsMouseChanged);
  664. //  BringMenuToFront;
  665.   // hide tooltip
  666.   if (ToolTipWindow <> nil)
  667.   then ToolTipWindow.Deactivate;
  668.   // click on dragpane
  669.   I:= GetIndexAt(X, Y);
  670.   if (Options.Draggable)
  671.   and (I = itDragPane)
  672.   and (Button = mbLeft)
  673.   then begin
  674.     Include(State, fsBecomingDraggable);
  675.     Include(State, fsShowHidden);
  676.     Include(State, fsHiddenAsRegular);
  677.     // Draggable pane clicked!
  678.     if Options.Caption <> ''
  679.     then Caption:= Options.Caption
  680.     else
  681.     if MenuItems.Caption <> ''
  682.     then Caption:= StripAmpersands(MenuItems.Caption)
  683.     else Caption:= 'AM/2000 Menu';
  684.     // set window properties
  685.     BorderStyle:= bsToolWindow;
  686.     // cancel ParentMenuForm
  687.     if ParentMenuForm <> nil then begin
  688.       ParentMenuForm.SubMenuForm:= nil;
  689.       ParentMenuForm:= nil;
  690.     end;
  691.     // hide previous floating menu
  692.     for I:= 0 to FloatingMenusList.Count -1 do
  693.       with TPopupMenu2000Form(FloatingMenusList[I]) do
  694.         if MenuItems = Self.MenuItems then begin
  695.           FloatingMenusList.Delete(I);
  696.           Close;
  697.           Break;
  698.         end;
  699.     FloatingMenusList.Add(Self);
  700.     // rebuild bounds
  701.     RebuildBounds;
  702.     MX:= GetRealWidth;
  703.     MY:= GetRealHeight;
  704.     if SystemParametersInfo(spi_GetNonClientMetrics, 0, @NonClientMetrics, 0)
  705.     then Inc(MY, Integer(NonClientMetrics.iCaptionHeight) +3);
  706.     SetBounds(Left, Top, MX, MY);
  707.     Buffer.Width:= MX;
  708.     Buffer.Height:= MY;
  709.     Buffer.FreeImage;
  710.     // paint menu
  711.     Paint;
  712.     Show;
  713.     Refresh;
  714.     // tooltip window
  715.     RebuildToolTipWindow(True);
  716.     // remove menu
  717.     KillActivePopupMenu2000(True, False);
  718.     SendMessage(Handle, WM_SysCommand, $F012, 0);  // system message
  719.     Exclude(State, fsBecomingDraggable);
  720.   end
  721.   else
  722.     Paint;
  723. end;
  724. procedure TPopupMenu2000Form.MouseUp;
  725. var
  726.   wID: Integer;
  727.   MI: TMenuItem;
  728.   CanClose: Boolean;
  729.   P: TPoint;
  730.   procedure CheckHiddenSeparator(Index, Delta: Integer);
  731.     // if a separator exists at this Index and it's hidden
  732.     // then show it 
  733.   var
  734.     M1: TMenuItem;
  735.     MS: TMenuItem2000;
  736.     F: Boolean;
  737.   begin
  738.     F:= fsShowHidden in State;
  739.     if not F then Include(State, fsShowHidden);
  740.     Inc(Index, Delta);
  741.     M1:= GetMenuItemIndex(Index + Delta, False);
  742.     if (M1 is TMenuItem2000)
  743.     and (M1.Caption = '-')
  744.     and (TMenuItem2000(M1).Hidden)
  745.     then begin
  746.       MS:= TMenuItem2000(M1);
  747.       // now check for the next not hidden menu item
  748.       // to prevent duplicating separators
  749.       repeat
  750.         Inc(Index, Delta);
  751.         M1:= GetMenuItemIndex(Index, False);
  752.         if ((not (M1 is TMenuItem2000))
  753.         or (not TMenuItem2000(M1).Hidden))
  754.         then begin
  755.           if (M1 <> nil)
  756.           and (M1.Caption = '-')
  757.           then MS:= nil;
  758.           Break;
  759.         end;
  760.       until M1 = nil;
  761.       if MS <> nil then MS.Hidden:= False;
  762.     end;
  763.     if not F then Exclude(State, fsShowHidden);
  764.   end;
  765. begin
  766.   if not (ssLeft  in Shift) then Exclude(MouseState, msLeftButton);
  767.   if not (ssRight in Shift) then Exclude(MouseState, msRightButton);
  768.   Include(State, fsMouseChanged);
  769.   if (fsAnimated in State) or (fsKillAnimate in State) then Exit;
  770.   // if hidden arrow is pressed
  771.   if SelectedIndex = itHiddenArrow then begin
  772.     ASTimer.Enabled:= False;
  773.     Include(State, fsShowHidden);
  774.     SilentHide;
  775.     Animate;
  776.     Exit;
  777.   end;
  778.   // nothing is selected
  779.   if SelectedIndex = itNothing then begin
  780.     Paint;
  781.     Exit;
  782.   end;
  783.   // popup context menu
  784.   MI:= GetCurMenuItem(False);
  785.   if (Button = mbRight)
  786.   and (MI <> nil)
  787.   and (MI is TMenuItem2000)
  788.   and (TMenuItem2000(MI).PopupMenu <> nil)
  789.   then
  790.     with TMenuItem2000(MI) do begin
  791.       Include(State, fsDisabled);
  792.       DestroySubMenuForm;
  793.       // on popup event
  794.       if Assigned(PopupMenu.OnPopup)
  795.       then PopupMenu.OnPopup(MI);
  796.       // create context menu as submenu
  797.       CreateSubMenuForm(PopupMenu, PopupMenu.Items.Handle, PopupMenu.Items);
  798.       PopupMenu.PopupComponent:= MI;
  799.       SubMenuForm.Animation:= Self.Options.Animation;
  800.       // show context menu
  801.       GetCursorPos(P);
  802.       SubMenuForm.SetBounds(P.X, P.Y, 0, 0);
  803.       SubMenuForm.Animate;
  804.       Exit;
  805.     end;
  806.   // clear status bar
  807.   SetStatusBarText('');
  808.   if Assigned(SubMenuForm) then begin
  809.     Exclude(State, fsDisabled);
  810.     PopupSubMenuForm(False);
  811.     Exit;
  812.   end;
  813.   CanClose:= True;
  814.   if (MI <> nil)
  815.   and (MenuItems.IndexOf(MI) <> -1)
  816.   then begin
  817.     // ordinary menu item
  818.     if HasSubmenu(MI) then begin
  819.       PopupSubMenuForm(False);
  820.       Exit;
  821.     end;
  822.     if (not MI.Enabled) or (MI.Caption = '-') then Exit;
  823.     // is editbox
  824.     if (MI is TMenuItem2000)
  825.     and (TMenuItem2000(MI).Control = ctlEditbox)
  826.     then begin
  827.       MI.Click;
  828.       Include(State, fsDisabled);
  829.       FocusItem:= MI;
  830.       TMenuItem2000(MI).AsEdit.BeginEdit(X, Y);
  831.       Exit;
  832.     end;
  833.     // other stuffs
  834.     Timer.Enabled:= False;
  835.     if Assigned(PopupMenu.OnCloseQuery)
  836.     then PopupMenu.OnCloseQuery(MI, CanClose);
  837.     if CanClose then begin
  838.       KillActivePopupMenu2000(True, True);
  839.       if ActiveMenuBar <> nil
  840.       then ActiveMenuBar.HideActiveItem;
  841.       FullShowCaret;
  842.       sndPlaySound(PChar(MenuCommandSound), snd_Async + snd_NoDefault + snd_NoStop);
  843.     end;
  844.     if (MI is TMenuItem2000)
  845.     and (TMenuItem2000(MI).Hidden)
  846.     and (not (mfNoChangeHidden in Options.Flags))
  847.     then begin
  848.       TMenuItem2000(MI).Hidden:= False;
  849.       // and show separators
  850.       CheckHiddenSeparator(LastSelectedIndex, -1);
  851.       CheckHiddenSeparator(LastSelectedIndex, 1);
  852.     end;
  853.     if Assigned(PopupMenu.OnMenuCommand)
  854.     then PopupMenu.OnMenuCommand(MI);
  855.     // set item index for button array
  856.     if (MI is TMenuItem2000)
  857.     and (TMenuItem2000(MI).Control = ctlButtonArray)
  858.     then
  859.       with TMenuItem2000(MI).AsButtonArray do
  860.         ItemIndex:= LastItemIndex;
  861.     // Click
  862.     MI.Click;
  863.   end
  864.   else begin
  865.     mii.fMask:= miim_Type + miim_ID + miim_Submenu;
  866.     mii.dwTypeData:= Z;
  867.     mii.cch:= SizeOf(Z) -1;
  868.     if (not GetMenuItemInfo(MenuHandle, SelectedIndex + CurHiddenCount, True, mii))
  869.     or (mii.fType and mft_Separator <> 0)
  870.     or (mii.fState and mfs_Disabled <> 0)
  871.     then Exit;
  872.     wID:= mii.wID;
  873.     Timer.Enabled:= False;
  874.     if Assigned(PopupMenu.OnCloseQuery)
  875.     then PopupMenu.OnCloseQuery(MI, CanClose);
  876.     if CanClose then begin
  877.       KillActivePopupMenu2000(True, True);
  878.       if ActiveMenuBar <> nil
  879.       then ActiveMenuBar.HideActiveItem;
  880.       SendMessage(Forms.TForm(Owner).Handle, wm_NCActivate, 1, 0);
  881.       FullShowCaret;
  882.       sndPlaySound(PChar(MenuCommandSound), snd_Async + snd_NoDefault + snd_NoStop);
  883.     end;
  884.     if Assigned(PopupMenu.OnMenuCommand)
  885.     then PopupMenu.OnMenuCommand(nil);
  886.     PostMessage(Forms.TForm(Owner).Handle, wm_Command, wID, 0);
  887.   end;
  888.   // show must go on
  889.   if (not CanClose)
  890.   then begin
  891.     Paint;
  892.     Timer.Enabled:= True;
  893.     if (ToolTipWindow <> nil)
  894.     then ToolTipWindow.Activate;
  895.   end;
  896. end;
  897. procedure TPopupMenu2000Form.wmMouseMove(var Msg: TWMMouse);
  898. begin
  899.   inherited;
  900.   // enable tooltip
  901.   if (ToolTipWindow <> nil) then begin
  902.     ToolTipWindow.Activate;
  903.     ToolTipWindow.RelayMouseMove(Msg.Pos);
  904.   end;
  905. end;
  906. procedure TPopupMenu2000Form.MouseMove(Shift: TShiftState; X, Y: Integer);
  907. const
  908.   LastX: Integer = 0;
  909.   LastY: Integer = 0;
  910. var
  911.   R: TRect;
  912.   I, L: Integer;
  913. begin
  914.   Include(MouseState, msMouseOver);
  915.   if ssLeft  in Shift
  916.   then Include(MouseState, msLeftButton)
  917.   else Exclude(MouseState, msLeftButton);
  918.   if ssRight in Shift
  919.   then Include(MouseState, msRightButton)
  920.   else Exclude(MouseState, msRightButton);
  921.   
  922.   // change mouse cursor
  923.   if (GetCurMenuItem(False) is TMenuItem2000)
  924.   and (TMenuItem2000(CurMenuItem).Control = ctlEditbox)
  925.   then begin
  926.     if (BorderStyle = bsNone)
  927.     then
  928.       if (fsCtl3D in State)
  929.       then L:= Options.Margins.Border +2
  930.       else L:= Options.Margins.Border
  931.     else
  932.       L:= 0;
  933.     Inc(L, AmpTextWidth(Buffer.Canvas, CurMenuItem.Caption) +5);
  934.     R:= GetItemRect(FSelectedIndex);
  935.     if R.Left < L then R.Left:= L;
  936.     InflateRect(R, 0, -2);
  937.     if PtInRect(R, Point(X, Y))
  938.     then
  939.       Cursor:= crIBeam
  940.     else
  941.       if Cursor <> crDefault
  942.       then Cursor:= crDefault;
  943.   end
  944.   else
  945.     if Cursor <> crDefault
  946.     then Cursor:= crDefault;
  947.   // ignore some little movements
  948.   if (fsAnimated in State)
  949.   or (fsKillAnimate in State)
  950.   or (fsDisabled in State)
  951. //  or ((Abs(X - LastX) <= 2)
  952. //  and (Abs(Y - LastY) <= 2))
  953.   then Exit;
  954.   LastX:= X;
  955.   LastY:= Y;
  956.   if fsIgnoreMouseMove in State then begin
  957.     Exclude(State, fsIgnoreMouseMove);
  958.     Exit;
  959.   end;
  960.   Timer.Enabled:= False;
  961.   // set parentmenuform highlight
  962.   if (ParentMenuForm <> nil)
  963.   and (not (fsDisabled in ParentMenuForm.State))
  964.   and (ParentMenuForm.FSelectedIndex <> ParentMenuIndex)
  965.   then
  966.     with ParentMenuForm do begin
  967.       LastSelectedIndex:= FSelectedIndex;
  968.       FSelectedIndex:= Self.ParentMenuIndex;
  969.       Include(State, fsSelectedChanged);
  970.       Exclude(State, fsDrawDisabled);
  971.       Paint;
  972.     end;
  973.   // set highlight
  974.   I:= GetIndexAt(X, Y);
  975.   if I <> SelectedIndex then begin
  976.     LastSelectedIndex:= FSelectedIndex;
  977.     FSelectedIndex:= I;
  978.     Include(State, fsSelectedChanged);
  979.     Exclude(State, fsDrawDisabled);
  980.     Paint;
  981.     // show menu item hint
  982.     SetStatusBarText('');
  983.     CheckShowHint(GetCurMenuItem(False), True, Self);
  984.     // is it hidden arrow?
  985.     if (SelectedIndex = itHiddenArrow) then begin
  986.       ASTimer.Enabled:= False;
  987.       ASTimer.Enabled:= True;
  988.     end;
  989.   end
  990.   else
  991.     if (GetCurMenuItem(False) <> nil)
  992.     and (CurMenuItem is TMenuItem2000)
  993.     and (TMenuItem2000(CurMenuItem).Control = ctlButtonArray)
  994.     then
  995.       with TMenuItem2000(CurMenuItem), AsButtonArray do
  996.         if GetIndexAt(X, Y) <> LastItemIndex
  997.         then begin
  998.           Paint;
  999.           CheckShowHint(GetCurMenuItem(False), True, Self);
  1000.         end;
  1001.   Timer.Enabled:= True;
  1002. end;
  1003. procedure TPopupMenu2000Form.SearchForOpenedMenuShortcut(var Msg: TWMKey);
  1004.   // just a symbol key - seeking for menu item
  1005. var
  1006.   I: Integer;
  1007.   M: TMenuItem;
  1008.   S: String;
  1009.   UseFirstLetter: Boolean;
  1010. begin
  1011.   UseFirstLetter:= True;
  1012.   repeat
  1013.     UseFirstLetter:= not UseFirstLetter;
  1014.     for I:= 0 to ItemRects.Count -1 do begin
  1015.       M:= GetMenuItemIndex(I, False);
  1016.       if (M = nil) then begin
  1017.         mii.fMask:= miim_ID + miim_Type + miim_State;
  1018.         mii.dwTypeData:= @Z;
  1019.         mii.cch:= SizeOf(Z) -1;
  1020.         if (not GetMenuItemInfo(MenuHandle, I, True, mii))
  1021.         or (mii.fType and mft_Separator <> 0)
  1022.         or (mii.fState and (mfs_Disabled + mfs_Grayed) <> 0)
  1023.         then Continue;
  1024.         S:= StrPas(Z);
  1025.       end
  1026.       else
  1027.         if (not (M.Visible and M.Enabled))
  1028.         or ((M is TMenuItem2000)
  1029.         and (TMenuItem2000(M).Hidden)
  1030.         and (not (fsShowHidden in State)))
  1031.         then Continue
  1032.         else S:= M.Caption;
  1033.       if IsAccelEx(Msg.CharCode, S, UseFirstLetter) then begin
  1034.         SelectedIndex:= I;
  1035.         Exclude(State, fsSelectedChanged);
  1036.         if ((M <> nil) and (M.Enabled))
  1037.         or ((M = nil) and (mii.fState and (mfs_Grayed + mfs_Disabled) = 0))
  1038.         then MouseUp(mbLeft, [], 0, 0)
  1039.         else MessageBeep(0);
  1040.         Msg.Result:= 1;
  1041.         Exit;
  1042.       end;
  1043.     end { for  };
  1044.   until UseFirstLetter { repeat };
  1045.   MessageBeep(0);
  1046. end;
  1047. procedure TPopupMenu2000Form.wmKeyDown(var Msg: TWMKeyDown);
  1048.   // keyboard events
  1049. var
  1050.   M: TMsg;
  1051.   Shift: TShiftState;
  1052. begin
  1053.   // handle focus item
  1054.   if (FocusItem <> nil)
  1055.   and (fsDisabled in State)
  1056.   and (FocusItem is TMenuItem2000)
  1057.   then begin
  1058.     // get shift state
  1059.     Shift:= [];
  1060.     if GetKeyState(vk_Shift) < 0    then Include(Shift, ssShift);
  1061.     if GetKeyState(vk_Control) < 0  then Include(Shift, ssCtrl);
  1062.     if Msg.KeyData and AltMask <> 0 then Include(Shift, ssAlt);
  1063.     // handle char
  1064.     case Msg.CharCode of
  1065.       vk_Escape, vk_Return:
  1066.         begin
  1067.           TMenuItem2000(FocusItem).AsEdit.CancelEdit(Msg.CharCode = vk_Return);
  1068.           Exclude(State, fsDisabled);
  1069.           FocusItem:= nil;
  1070.           Paint;
  1071.           Msg.Result:= 1;
  1072.         end;
  1073.       else
  1074.         // send char
  1075.         TMenuItem2000(FocusItem).ControlOptions.KeyDown(Msg.CharCode, Shift);
  1076.     end;
  1077.     // set result
  1078.     if Msg.CharCode = 0 then Msg.Result:= 1;
  1079.   end
  1080.   // other menu item
  1081.   else
  1082.   case Msg.CharCode of
  1083.     // click item
  1084.     vk_Return:
  1085.       begin
  1086.         MouseUp(mbLeft, [], 0, 0);
  1087.         Msg.Result:= 1;
  1088.       end;
  1089.     vk_Up:
  1090.       begin
  1091.         SelectedIndex:= SelectedIndex -1;
  1092.         Timer.Enabled:= False;
  1093.         Msg.Result:= 1;
  1094.       end;
  1095.     vk_Tab:
  1096.       begin
  1097.         if GetKeyState(vk_Shift) < 0
  1098.         then SelectedIndex:= SelectedIndex -1
  1099.         else SelectedIndex:= SelectedIndex +1;
  1100.         Timer.Enabled:= False;
  1101.         Msg.Result:= 1;
  1102.       end;
  1103.       
  1104.     vk_Down:
  1105.       begin
  1106.         if GetKeyState(vk_Control) < 0 then begin
  1107.           ASTimer.Enabled:= False;
  1108.           Include(State, fsShowHidden);
  1109.           SilentHide;
  1110.           Animate;
  1111.         end
  1112.         else begin
  1113.           SelectedIndex:= SelectedIndex +1;
  1114.           Timer.Enabled:= False;
  1115.         end;
  1116.         Msg.Result:= 1;
  1117.       end;
  1118.     vk_Left:
  1119.       if ParentMenuForm <> nil then begin;
  1120.         if not (fsAnimated in State)
  1121.         then SilentHide;
  1122.         Release;
  1123.         Msg.Result:= 1;
  1124.       end;
  1125.     vk_Right:
  1126.       if (GetCurMenuItem(False) <> nil)
  1127.       and (CurMenuItem.Enabled)
  1128.       and HasSubmenu(CurMenuItem)
  1129.       then begin
  1130.         PopupSubMenuForm(True);
  1131.         Msg.Result:= 1;
  1132.       end;
  1133.     vk_Escape:
  1134.       begin
  1135.         if not (fsAnimated in State)
  1136.         then SilentHide;
  1137.         if (ParentMenuForm <> nil)
  1138.         then begin
  1139.           Exclude(ParentMenuForm.State, fsDisabled);
  1140.           Release;
  1141.         end
  1142.         else KillActivePopupMenu2000(False, False);
  1143.         Msg.Result:= 1;
  1144.       end;
  1145.     vk_F1:
  1146.       if (Application.HelpFile <> '')
  1147.       and (GetCurMenuItem(False) <> nil)
  1148.       and (CurMenuItem.HelpContext <> 0)
  1149.       then begin
  1150.         KillActivePopupMenu2000(True, False);
  1151.         if (PopupMenu <> nil)
  1152.         and (PopupMenu.Owner is TForm)
  1153.         and (biHelp in TForm(PopupMenu.Owner).BorderIcons)
  1154.         then Application.HelpCommand(HELP_CONTEXTPOPUP, CurMenuItem.HelpContext)
  1155.         else Application.HelpCommand(HELP_CONTEXT, CurMenuItem.HelpContext);
  1156.         // We have to remove the next message that is in the queue.
  1157.         PeekMessage(M, 0, 0, 0, pm_Remove);
  1158.         Msg.Result:= 1;
  1159.       end;
  1160.     else
  1161.       if (Msg.CharCode <> vk_Shift) and (Msg.CharCode <> vk_Control)
  1162.       then begin
  1163.         SearchForOpenedMenuShortcut(Msg);
  1164.         Msg.Result:= 1;
  1165.       end;
  1166.   end;
  1167.   // hide tooltip
  1168.   if (ToolTipWindow <> nil)
  1169.   then ToolTipWindow.Deactivate;
  1170. end;
  1171. procedure TPopupMenu2000Form.wmChar(var Msg: TWMChar);
  1172. var
  1173.   C: Char;
  1174. begin
  1175.   // handle focus item
  1176.   if (FocusItem <> nil)
  1177.   and (fsDisabled in State)
  1178.   then begin
  1179.     // send char
  1180.     C:= Char(Msg.CharCode);
  1181.     if (FocusItem is TMenuItem2000)
  1182.     then TMenuItem2000(FocusItem).ControlOptions.KeyPress(C);
  1183.     // set result
  1184.     if C = #0 then Msg.Result:= 1;
  1185.   end;
  1186. end;
  1187. procedure TPopupMenu2000Form.wmSysKeyDown(var Msg: TWMKeyDown);
  1188. begin
  1189.   // hide active menu
  1190.   if (Msg.CharCode = vk_Menu) or (Msg.CharCode = vk_F10) then begin
  1191.     KillActivePopupMenu2000(True, False);
  1192.     if Assigned(ActiveMenuBar)
  1193.     then ActiveMenuBar.SetDisableAltKeyUp(True);
  1194.     FullShowCaret;
  1195.     Msg.Result:= 1;
  1196.     Exit;
  1197.   end;
  1198.   // handle as menu key
  1199.   wmKeyDown(Msg);
  1200. end;
  1201. // thanks for this routine to Stewart Creswell
  1202. procedure TPopupMenu2000Form.SetZOrder(TopMost : Boolean);
  1203. const
  1204.   NormalWindowPos: array[Boolean] of HWND = (HWND_BOTTOM, HWND_TOP);
  1205.   TopWindowPos: array[Boolean] of HWND = (HWND_NOTOPMOST, HWND_TOPMOST);
  1206. begin
  1207.   if Parent <> nil
  1208.   then
  1209.     inherited
  1210.   else
  1211.     if Handle <> 0 then
  1212.       if FormStyle = fsStayOnTop
  1213.       then SetWindowPos(Handle, TopWindowPos[TopMost], 0, 0, 0, 0, FormFlags)
  1214.       else SetWindowPos(Handle, NormalWindowPos[TopMost], 0, 0, 0, 0, FormFlags);
  1215. end;
  1216. procedure TPopupMenu2000Form.PopupMenu2000FormTimer(Sender: TObject);
  1217. var
  1218.   fw: HWND;
  1219.   C: TComponent;
  1220. begin
  1221.   if fsDisabled in State then Exit;
  1222.   Timer.Enabled:= False;
  1223.   if fsSelectedChanged in State then begin
  1224.     Exclude(State, fsSelectedChanged);
  1225.     GetCurMenuItem(False);
  1226.     // this is because DrawDisabled = True when selecton is moved by kbd
  1227.     // and = False when is moved by the mouse :)
  1228.     if not (fsDrawDisabled in State)
  1229.     then CheckShowHint(CurMenuItem, True, Self);
  1230.     // if submenu is not actual
  1231.     if (SubMenuForm = nil)
  1232.     or ((CurMenuItem <> SubMenuForm.MenuItems)
  1233.     and ((not (CurMenuItem is TMenuItem2000))
  1234.      or (TMenuItem2000(CurMenuItem).AttachMenu = nil)
  1235.      or (TMenuItem2000(CurMenuItem).AttachMenu.Items <> SubMenuForm.MenuItems)))
  1236.     then PopupSubMenuForm(False);
  1237.   end;
  1238.   // close menus when owner *and* menu windows (and ActiveMdiChild) is not active
  1239.   fw:= GetForegroundWindow;
  1240.   C:= FindControl(fw);
  1241.   if not ((fw = 0)
  1242.   or (C is Forms.TForm)
  1243.   or (fw = Application.Handle))
  1244.   then begin
  1245.     FullShowCaret;
  1246.     KillActivePopupMenu2000(True, False);
  1247.     Exit;
  1248.   end;
  1249.   if not (fsKillAnimate in State) then
  1250.     Timer.Enabled:= True;
  1251. end;
  1252. procedure TPopupMenu2000Form.TimerShow(Sender: TObject);
  1253. begin
  1254.   ASTimer.Enabled:= False;
  1255.   // check is mouse cursor still over the hidden arrow
  1256.   if SelectedIndex = itHiddenArrow then begin
  1257.     Include(State, fsShowHidden);
  1258.     Animate;
  1259.   end;
  1260. end;
  1261. procedure TPopupMenu2000Form.DestroySubMenuForm;
  1262. begin
  1263.   if Assigned(SubMenuForm) then begin
  1264.     SubMenuForm.SilentHide;
  1265.     SubMenuForm.Release;
  1266.     SubMenuForm:= nil;
  1267.   end;
  1268. end;
  1269. procedure TPopupMenu2000Form.CreateSubMenuForm(Menu: TPopupMenu; Handle: HMenu; Items: TMenuItem);
  1270. begin
  1271.   if (Menu is TCustomPopupMenu2000)
  1272.   or (Menu = nil)
  1273.   then
  1274.   try
  1275.     SubMenuForm:= TPopupMenu2000Form.Create(Owner);
  1276.     SubMenuForm.Font.Assign(Font);
  1277.     SubMenuForm.ParentMenuForm:= Self;
  1278.     SubMenuForm.MenuHandle:=     Handle;
  1279.     SubMenuForm.MenuItems:=      Items;
  1280.     SubMenuForm.ParentMenuIndex:=SelectedIndex;
  1281.     SubMenuForm.Animation:=      Animation;
  1282.     SubMenuForm.CloseAnimation:= CloseAnimation;
  1283.     if Menu = nil
  1284.     then SubMenuForm.PopupMenu:= PopupMenu
  1285.     else SubMenuForm.PopupMenu:= TCustomPopupMenu2000(Menu);
  1286.   except
  1287.     SubMenuForm:= nil
  1288.   end;
  1289. end;
  1290. procedure TPopupMenu2000Form.PopupSubMenuForm(SelectFirst: Boolean);
  1291. var
  1292.   X: Integer;
  1293.   hSubMenu: HMenu;
  1294.   Item: TMenuItem;
  1295.   Popup: TPopupMenu;
  1296. begin
  1297.   hSubMenu:= 0;
  1298.   Popup:= nil;
  1299.   // first try - use GetCurMenuItem
  1300.   Item:= GetCurMenuItem(False);
  1301.   // check if sub menu already open
  1302.   if ((SubMenuForm <> nil)
  1303.   and ((SubMenuForm.MenuItems = Item)
  1304.   or ((Item is TMenuItem2000)
  1305.     and (TMenuItem2000(Item).AttachMenu <> nil)
  1306.     and (SubMenuForm.MenuItems = TMenuItem2000(Item).AttachMenu.Items))))
  1307.   or (fsKillAnimate in State)
  1308.   then Exit;
  1309.   DestroySubmenuForm;
  1310.   // exit on disabled items
  1311.   if (Item <> nil) and (not Item.Enabled)
  1312.   then Exit;
  1313.   if Item <> nil then begin
  1314.     if (Item is TMenuItem2000)
  1315.     and (TMenuItem2000(Item).AttachMenu <> nil)
  1316.     then begin
  1317.       Popup:= TMenuItem2000(Item).AttachMenu;
  1318.       Popup.PopupComponent:= CurMenuItem;
  1319.       if Popup.Items.Count = 0
  1320.       then TCustomPopupMenu2000(Popup).InitItems(True);
  1321.       Item:= Popup.Items;
  1322.     end;
  1323.     // if disabled or empty or no menu attached then exit
  1324.     if (not Item.Enabled)
  1325.     or (Item.Count = 0)
  1326.     then Exit;
  1327.     hSubMenu:= Item.Handle;
  1328.   end
  1329.   // second try - use GetMenuItemInfo()
  1330.   else
  1331.   if FSelectedIndex >= 0 then begin
  1332.     mii.fMask:= miim_State + miim_SubMenu;
  1333.     GetMenuItemInfo(MenuHandle, FSelectedIndex, True, mii);
  1334.     hSubMenu:= mii.hSubMenu;
  1335.     // if disabled then exit
  1336.     if mii.fState and (mfs_Disabled + mfs_Grayed) <> 0 then Exit;
  1337.   end;
  1338.   
  1339.   // no submenu
  1340.   if (hSubMenu = 0) then Exit;
  1341.   // on click event
  1342.   if (Item <> nil)
  1343.   and Assigned(Item.OnClick)
  1344.   then Item.OnClick(CurMenuItem);
  1345.   // init popup menu
  1346.   if (Popup <> nil) then begin
  1347.     Popup.PopupComponent:= CurMenuItem;
  1348.     // on popup event
  1349.     if Assigned(Popup.OnPopup)
  1350.     then Popup.OnPopup(CurMenuItem);
  1351.   end;
  1352.   CreateSubMenuForm(Popup, hSubMenu, Item);
  1353.   // set alignment
  1354.   if Options.Alignment <> taRightToLeft
  1355.   then X:= Width -5
  1356.   else X:= 5;
  1357.   // set first selected
  1358.   if SelectFirst then SubMenuForm.FSelectedIndex:= 0;
  1359.   // convert point
  1360.   with ClientToScreen(Point(X, GetItemRect(FSelectedIndex).Top -5)) do
  1361.     SubMenuForm.SetBounds(X, Y, 0, 0);
  1362. {$IFDEF Delphi4OrHigher}
  1363.   SubMenuForm.DefaultMonitor:= dmActiveForm;
  1364. {$ENDIF}
  1365.   SubMenuForm.Animate;
  1366. end;
  1367. procedure TPopupMenu2000Form.BringMenuToFront;
  1368. var
  1369.   F: TPopupMenu2000Form;
  1370. begin
  1371.   if (fsKillAnimate in State) then Exit;
  1372.   // process all submenus
  1373.   F:= Self;
  1374.   while Assigned(F) do begin
  1375.     SetWindowPos(F.Handle, hwnd_TopMost, F.Left, F.Top, F.Width, F.Height, FormFlags);
  1376.     F:= F.SubMenuForm;
  1377.   end;
  1378. end;
  1379. function TPopupMenu2000Form.GetCurMenuItem(RaiseException: Boolean): Menus.TMenuItem;
  1380. begin
  1381.   Result:= GetMenuItemIndex(SelectedIndex, RaiseException);
  1382. end;
  1383. function TPopupMenu2000Form.GetMenuItemIndex(Index: Integer; RaiseException: Boolean): TMenuItem;
  1384. var
  1385.   I, C: Integer;
  1386.   M: TMenuItem;
  1387. begin
  1388.   Result:= nil;
  1389.   CurMenuItem:= nil;
  1390.   if (MenuItems = nil)
  1391.   or (Index >= MenuItems.Count)
  1392.   then Exit;
  1393.   CurHiddenCount:= 0;
  1394.   C:= -1;
  1395.   for I:= 0 to MenuItems.Count -1 do begin
  1396.     M:= MenuItems[I];
  1397.     // menu item is not visible
  1398.     if not M.Visible
  1399.     then Continue;
  1400.     // menu item is hidden
  1401.     if  (not (fsShowHidden in State))
  1402.     and (M is TMenuItem2000)
  1403.     and (TMenuItem2000(M).Hidden)
  1404.     then begin
  1405.       Inc(CurHiddenCount);
  1406.       Continue;
  1407.     end;
  1408.    // else
  1409.     Inc(C);
  1410.     if C = Index then begin
  1411.       CurMenuItem:= MenuItems[I];
  1412.       Result:= CurMenuItem;
  1413.       Exit;
  1414.     end;
  1415.   end;
  1416.   if RaiseException then
  1417.     raise Exception.Create('Menu item not found.');
  1418. end;
  1419. { Main Routines }
  1420. function TPopupMenu2000Form.Animate: Boolean;
  1421. var
  1422.   CurAnim: T_AM2000_Animation;
  1423.   abd: TAppBarData;
  1424.   SR: TRect; // original screen rect
  1425.   X: Integer;
  1426.   DDC: HDC;
  1427. begin
  1428.   Perform(wm_InitState, 0, 0);
  1429.   DX:= 1;
  1430.   DY:= 1;
  1431.   Result:= True;
  1432.   CurHiddenCount:= 0;
  1433.   FocusItem:= nil;
  1434.   Include(State, fsAnimated);
  1435.   Exclude(State, fsKillAnimate);
  1436.   // calculate real coords of Windows Desktop without TaskBar
  1437.   abd.cbSize:= sizeOf(abd);
  1438.   abd.hWnd:= Handle;
  1439.   SHAppBarMessage(abm_GetTaskBarPos, abd);
  1440.   SubtractRect(SR, Rect(0, 0, Screen.Width, Screen.Height), abd.rc);
  1441.   // calculate normal height and width.
  1442.   // mx and mx -- width and height of the full opened window
  1443.   RebuildBounds;
  1444.   MX:= GetRealWidth;
  1445.   MY:= GetRealHeight;
  1446.   Buffer.Width:= MX;
  1447.   Buffer.Height:= MY;
  1448.   Buffer.FreeImage;
  1449.   // code to arrange menu form
  1450.   BL:= 0;
  1451.   if Options.Alignment <> taRightToLeft then begin
  1452.     Exclude(State, fsFromRightToLeft);
  1453.     if (Left + MX) > SR.Right
  1454.     then
  1455.       if Assigned(ParentMenuForm)
  1456.       then begin
  1457.         if Animation = anVSlide
  1458.         then Left:= ParentMenuForm.Left - MX +6
  1459.         else Left:= ParentMenuForm.Left +6;
  1460.         Include(State, fsFromRightToLeft);
  1461.       end
  1462.       else Left:= SR.Right - MX;
  1463.     if Left <= 0 then Left:= 1;
  1464.   end
  1465.   else begin
  1466.     Include(State, fsFromRightToLeft);
  1467.     if Left > SR.Right then Left:= SR.Right;
  1468.   end;
  1469.   if (((Top + MY) < SR.Bottom) or (Top < MY)
  1470.   or (Animation = anHSlide))
  1471.   then Exclude(State, fsFromBottomToTop)
  1472.   else Include(State, fsFromBottomToTop);
  1473.   if (fsFromBottomToTop in State)
  1474.   then begin
  1475.     // menu shouldn't hide a menu button
  1476.     if (PopupMenu.PopupComponent is TCustomMenuBar2000)
  1477.     then
  1478.     with TCustomMenuBar2000(PopupMenu.PopupComponent) do
  1479.         if mbType = mbVertical then
  1480.              Self.Top:= SR.Bottom
  1481.         else Self.Top:= Self.Top - (aiRect.Bottom - aiRect.Top +2);
  1482.   end
  1483.   else
  1484.     if Top + MY > SR.Bottom
  1485.     then Top:= SR.Bottom - MY;
  1486.   if Top <= 0 then Top:= 1;
  1487.   if Options.Alignment <> taRightToLeft
  1488.   then NewLeft:= Left
  1489.   else NewLeft:= Left - MX;
  1490.   NewTop:= Top;
  1491.   NewWidth:= MX;
  1492.   NewHeight:= MY;
  1493.   // code for calculation animation steps
  1494.   CurAnim:= Animation;
  1495.   if CurAnim = anRandom then begin
  1496.     if Random(2) = 0 then CurAnim:= anHSlide
  1497.                      else CurAnim:= anVSlide;
  1498.   end;
  1499.   if CurAnim = anSmart then begin
  1500.     Animation:= anHSlide;
  1501.     CurAnim:= anVSlide;
  1502.   end;
  1503.   if CurAnim = anPopup then begin
  1504.     Animation:= anHSlide;
  1505.     CurAnim:= anUnfold;
  1506.   end;
  1507.   if CurAnim in [anHSlide, anUnfold] then DX:= MX div nSteps;
  1508.   if DX < 3 then DX:= 3;
  1509.   if CurAnim in [anVSlide, anUnfold] then DY:= MY div (2 * nSteps);
  1510.   if DY < 3 then DY:= 3;
  1511.   if DX < DY then DX:= DY;
  1512.   if CurAnim in [anVSlide, anUnfold] then begin
  1513.     NewHeight:= MY div 3 - DY;
  1514.     if (fsFromBottomToTop in State)
  1515.     then Top:= Top - NewHeight;
  1516.   end;
  1517.   if CurAnim in [anHSlide, anUnfold] then NewWidth:=  0;
  1518.   // check if mouse already moved
  1519.   ProcessMouseMoveMessages;
  1520.   if (fsKillAnimate in State) then begin
  1521.     Exclude(State, fsAnimated);
  1522.     Result:= False;
  1523.     Exit;
  1524.   end;
  1525.   // start
  1526.   Include(State, fsPaintMenu);
  1527.   Paint;
  1528.   // init fade in animation
  1529.   if CurAnim = anFadeIn then begin
  1530.     BitsSize:= (MX +1) * MY * SizeOf(TRgbTriple);
  1531.     // nado
  1532.     if bits1 <> nil then Freemem(bits1);
  1533.     GetMem(bits1, BitsSize);
  1534.     bi.bmiHeader.biSize:= SizeOf(bi.bmiHeader);
  1535.     bi.bmiHeader.biWidth:= MX;
  1536.     bi.bmiHeader.biHeight:= MY;
  1537.     bi.bmiHeader.biPlanes:= 1;
  1538.     bi.bmiHeader.biBitCount:= 24;
  1539.     bi.bmiHeader.biCompression:= bi_RGB;
  1540.     bi.bmiHeader.biSizeImage:= 0;
  1541.     GetDIBits(Buffer.Canvas.Handle, Buffer.Handle, 0, MY, bits1, bi, Dib_Rgb_Colors);
  1542.     // DDC
  1543.     DDC:= CreateDC('DISPLAY', nil, nil, nil);
  1544.     // est
  1545.     BitBlt(Buffer.Canvas.Handle, 0, 0, MX, MY, DDC, Left, Top, SrcCopy);
  1546.     DeleteDC(DDC);
  1547.     if bits0 <> nil then Freemem(bits0);
  1548.     GetMem(bits0, BitsSize);
  1549.     GetDIBits(Buffer.Canvas.Handle, Buffer.Handle, 0, MY, bits0, bi, Dib_Rgb_Colors);
  1550.     // temp
  1551.     if bits <> nil then Freemem(bits);
  1552.     GetMem(bits, BitsSize);
  1553.     // iterate
  1554.     if dbits <> nil then Freemem(dbits);
  1555.     GetMem(dbits, BitsSize);
  1556.     for X:= 0 to BitsSize -1 do
  1557.       dbits^[X]:= Integer((Integer(bits1^[X]) - Integer(bits0^[X]))) div (3*nSteps);
  1558.     CurStep:= 1;
  1559.     SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
  1560.     Perform(wm_SetRedraw, 0, 0);
  1561.     if Owner is TForm
  1562.     then TForm(Owner).Perform(wm_SetRedraw, 0, 0);
  1563.     SilentShow;
  1564.     BitBlt(Canvas.Handle, 0, 0, Buffer.Width, Buffer.Height, Buffer.Canvas.Handle, 0, 0, Canvas.CopyMode);
  1565.     Perform(wm_SetRedraw, 1, 0);
  1566.     if Owner is TForm
  1567.     then TForm(Owner).Perform(wm_SetRedraw, 1, 0);
  1568.     ProcessPaintMessages;
  1569.   end;
  1570.   if CurAnim <> anFadeIn then SilentShow;
  1571.   sndPlaySound(PChar(MenuPopupSound), snd_Async + snd_NoDefault + snd_NoStop);
  1572.   SendMessage(Handle, wm_ShowAnimated, GetCurrentTime, nTimeout);
  1573. end;
  1574. procedure TPopupMenu2000Form.wmKillAnimation(var Msg: TMessage);
  1575.   // cancels active animation
  1576. begin
  1577.   if fsBecomingDraggable in State then Exit;
  1578.   Include(State, fsKillAnimate);
  1579.   Exclude(State, fsAnimated);
  1580.   // process submenu
  1581.   if Assigned(SubMenuForm)
  1582.   then SubMenuForm.Perform(wm_KillAnimation, 0, 0);
  1583. end;
  1584. procedure TPopupMenu2000Form.wmShowAnimated(var Msg: TMessage);
  1585. var
  1586.   CT, X: Integer;
  1587. begin
  1588.   if (fsKillAnimate in State) then Exit;
  1589.   // delay
  1590.   CT:= Msg.LParam - (GetCurrentTime - Msg.WParam);
  1591.   if (CT > 0) and (CT < 1000) then Sleep(CT);
  1592.   Msg.LParam:= 0;
  1593.   if Animation = anFadeIn then begin
  1594.     if CurStep <= 3*nSteps then begin
  1595.       TimeStart:= GetCurrentTime;
  1596.       for X:= 0 to BitsSize -1 do
  1597.         bits^[X]:= bits0^[X] + dbits^[X] * CurStep;
  1598.       SetDIBits(Buffer.Canvas.Handle, Buffer.Handle, 0, MY, bits, bi, Dib_Rgb_Colors);
  1599.       BitBlt(Canvas.Handle, 0, 0, Buffer.Width, Buffer.Height, Buffer.Canvas.Handle, 0, 0, Canvas.CopyMode);
  1600.       ProcessMouseMoveMessages;
  1601. //      ProcessPaintMessages;
  1602.       Inc(CurStep);
  1603.       CT:= GetCurrentTime;
  1604.       PostMessage(Handle, wm_ShowAnimated, CT, nTimeout - (CT - TimeStart));
  1605.       Exit;
  1606.     end;
  1607.     Include(State, fsPaintMenu);
  1608.     
  1609.   end
  1610.   else begin
  1611.     // Animation!
  1612.     while (NewWidth < MX) or (NewHeight < MY) do begin
  1613.       // calculate the time wasted on drawing
  1614.       TimeStart:= GetCurrentTime;
  1615.       if NewWidth < MX then
  1616.         if (NewWidth + DX) >= MX then Break
  1617.         else begin
  1618.           NewWidth:= NewWidth + DX;
  1619.           if fsFromRightToLeft in State
  1620.           then NewLeft:= Left - DX;
  1621.         end;
  1622.       if NewHeight < MY then
  1623.         if (NewHeight + DY) >= MY then Break
  1624.         else begin
  1625.           NewHeight:= NewHeight + DY;
  1626.           if fsFromBottomToTop in State
  1627.           then NewTop:= Top - DY;
  1628.         end;
  1629.       SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
  1630.       Paint;
  1631.       ProcessMouseMoveMessages;
  1632.       ProcessPaintMessages;
  1633.       // it's necessary in case of menu already opened by another thread
  1634.       NewWidth:= Width;
  1635.       NewHeight:= Height;
  1636.       // adjust delay
  1637.       CT:= GetCurrentTime;
  1638.       PostMessage(Handle, wm_ShowAnimated, CT, nTimeout - (CT - TimeStart));
  1639.       Exit;
  1640.     end;
  1641.     // final setting bounds
  1642.     if fsFromBottomToTop in State then NewTop:= Top - (MY - Height) +1;
  1643.     if fsFromRightToLeft in State then NewLeft:= Left - (MX - Width);
  1644.   end;
  1645.   // finish
  1646.   SetBounds(NewLeft, NewTop, MX, MY);
  1647.   Paint;
  1648.   // finalization
  1649.   Exclude(State, fsAnimated);
  1650.   Exclude(State, fsKillAnimate);
  1651.   Timer.Enabled:= Assigned(PopupMenu);
  1652. end;
  1653. procedure TPopupMenu2000Form.SilentShow;
  1654. begin
  1655.   // special check for tray-icon menu
  1656.   FullHideCaret;
  1657.   RebuildToolTipWindow(False);
  1658.   Exclude(State, fsDisabled);
  1659.   ShowWindow(Handle, sw_ShowNA);
  1660.   if Assigned(Application.MainForm)
  1661.   and not Application.MainForm.Visible
  1662.   then SetForegroundWindow(Handle);
  1663.   SetWindowPos(Handle, hwnd_TopMost, Left, Top, Width, Height, FormFlags);
  1664. end;
  1665. procedure TPopupMenu2000Form.SilentHide;
  1666.   // hides the current window
  1667. begin
  1668.   Timer.Enabled:= False;
  1669.   if Assigned(SubMenuForm) then begin
  1670.     SubMenuForm.SilentHide;
  1671.     SubMenuForm.Release;
  1672.     SubMenuForm:= nil;
  1673.   end;
  1674.   if fsBecomingDraggable in State then begin
  1675.     Timer.Enabled:= True;
  1676.     Exit;
  1677.   end;
  1678.   ShowWindow(Handle, sw_Hide);
  1679.   SetBounds(Left, Top, 0, 0);
  1680.   FSelectedIndex:= itNothing;
  1681.   ProcessPaintMessages;
  1682.   // remove arrays
  1683.   if dbits <> nil then FreeMem(dbits); dbits:= nil;
  1684.   if bits <> nil then FreeMem(bits);  bits:= nil;
  1685.   if bits0 <> nil then FreeMem(bits0);  bits0:= nil;
  1686.   if bits1 <> nil then FreeMem(bits1); bits1:= nil;
  1687. end;
  1688. procedure TPopupMenu2000Form.AnimatedHide;
  1689.   // hides the current window
  1690. var
  1691.   I, X: Integer;
  1692. begin
  1693.   Timer.Enabled:= False;
  1694.   if Owner is TForm
  1695.   then TForm(Owner).Perform(wm_SetRedraw, 0, 0);
  1696.   if (SelectedIndex >= 0)
  1697.   and (SelectedIndex < ItemRects.Count)
  1698.   then begin
  1699.     // nado
  1700.     SetDIBits(Buffer.Canvas.Handle, Buffer.Handle, 0, MY, bits0, bi, Dib_Rgb_Colors);
  1701.     // est
  1702.     Paint;
  1703.     GetDIBits(Buffer.Canvas.Handle, Buffer.Handle, 0, MY, bits1, bi, Dib_Rgb_Colors);
  1704.     Move(bits1^, bits^, BitsSize);
  1705.     // temp
  1706.     for X:= 0 to BitsSize -1 do
  1707.       dbits^[X]:= Integer(Integer(bits1^[X]) - Integer(bits0^[X])) div (2*nSteps);
  1708.     // animation
  1709.     for I:= 2*nSteps -1 downto 0 do begin
  1710.       for X:= 0 to BitsSize -1 do
  1711.         if dbits^[X] <> 0
  1712.         then bits^[X]:= bits0^[X] + dbits^[X] * I;
  1713.       SetDIBits(Buffer.Canvas.Handle, Buffer.Handle, 0, MY, bits, bi, Dib_Rgb_Colors);
  1714.       BitBlt(Canvas.Handle, 0, 0, Buffer.Width, Buffer.Height, Buffer.Canvas.Handle, 0, 0, Canvas.CopyMode);
  1715.       Sleep(nTimeout);
  1716.     end;
  1717.   end;
  1718.   SilentHide;
  1719.   if Owner is TForm
  1720.   then TForm(Owner).Perform(wm_SetRedraw, 1, 0);
  1721.   
  1722. end;
  1723. procedure TPopupMenu2000Form.Repaint;
  1724. begin
  1725.   Include(State, fsPaintMenu);
  1726.   Paint;
  1727. end;
  1728. procedure TPopupMenu2000Form.WMKillTimer(var Msg: TMessage);
  1729. begin
  1730.   Timer.Enabled:= False;
  1731.   // process submenu
  1732.   if (SubMenuForm <> nil)
  1733.   then SubMenuForm.Perform(wm_KillTimer, 0, 0);
  1734. end;
  1735. procedure TPopupMenu2000Form.wmHideSilent(var Msg: TMessage);
  1736. begin
  1737.   if (Msg.LParam <> 0)
  1738.   and (Animation = anFadeIn)
  1739.   and (SubMenuForm = nil)
  1740.   then
  1741.     AnimatedHide
  1742.   else begin
  1743.     // process submenu first
  1744.     if (SubMenuForm <> nil)
  1745.     then SubMenuForm.Perform(wm_HideSilent, 0, Msg.LParam);
  1746.     SilentHide;
  1747.   end;
  1748. end;
  1749. { Get Routines }
  1750. function TPopupMenu2000Form.GetMenuItemHeight(const M: TMenuItem): Integer;
  1751. var
  1752.   Lines: Integer;
  1753. begin
  1754.   Result:= 0;
  1755.   if M = nil then Exit;
  1756.   if M.Caption = '-'
  1757.   then
  1758.     Result:= Options.SeparatorHeight
  1759.   else begin
  1760.     Lines:= GetNumLines(M.Caption);
  1761.     Inc(Result, ItemHeight * Lines);
  1762.     if (M is TMenuItem2000)
  1763.     then
  1764.       with TMenuItem2000(M) do
  1765.         if (Control <> ctlNone)
  1766.         then
  1767.           Result:= TMenuItem2000(M).GetHeight(ItemHeight)
  1768.         else
  1769.           if Hidden
  1770.           and not (fsHiddenAsRegular in State)
  1771.           then Inc(Result, 2);
  1772.   end;
  1773. end;
  1774. function TPopupMenu2000Form.GetMenuItemHeightIndex(Index: Integer): Integer;
  1775. begin
  1776.   with GetItemRect(Index) do Result:= Bottom - Top;
  1777. end;
  1778. procedure TPopupMenu2000Form.Paint;
  1779. var
  1780.   X, Y, I, Temp, CopyMode: Integer;
  1781.   R: TRect;
  1782.   OldPalette, op1: HPalette;
  1783.   M, M1, M0, M2: TMenuItem;
  1784.   P: TPoint;
  1785.   Y1, C1, C2, R1, G1, B1, I1, I2: Integer;
  1786.   DR, DG, DB, DH, F1, F2: Real;
  1787. begin
  1788.   if (fsAnimated in State)
  1789.   and (Animation = anFadeIn)
  1790.   and (not (fsPaintMenu in State))
  1791.   then Exit;
  1792.   // init DrawRect record
  1793.   DrawRect.State:= [];
  1794.   DrawRect.Canvas:= Buffer.Canvas;
  1795.   DrawRect.Handle:= MenuHandle;
  1796.   DrawRect.Options:= Options;
  1797.   DrawRect.MouseState:= MouseState;
  1798.   DrawRect.FullRepaint:= fsPaintMenu in State;
  1799.   if (PopupMenu <> nil)
  1800.   then DrawRect.Images:= TImageList(TCustomPopupMenu2000(PopupMenu).Images);
  1801.   // calculate bounds
  1802.   if (BorderStyle <> bsNone)
  1803.   then begin
  1804.     DrawRect.mir.Border:= 0;
  1805.     DrawRect.mir.LineRight:= ClientWidth;
  1806.   end
  1807.   else begin
  1808.     if (fsCtl3D in State)
  1809.     then DrawRect.mir.Border:= Options.Margins.Border +2
  1810.     else DrawRect.mir.Border:= Options.Margins.Border;
  1811.     DrawRect.mir.LineRight:= Buffer.Width - DrawRect.mir.Border;
  1812.   end;
  1813.   Y:= Options.Margins.Top + DrawRect.mir.Border;
  1814.   DrawRect.mir.LineLeft:= DrawRect.mir.Border;
  1815.   if (Options.Draggable)
  1816.   and (BorderStyle = bsNone)
  1817.   then Inc(Y, 10);
  1818.   DrawRect.mir.ItemWidth:= ItemWidth;
  1819.   DrawRect.mir.ShortcutWidth:= ShortcutWidth;
  1820.   if Options.Title.Visible then
  1821.     case Options.Title.Align of
  1822.       atLeft:  Inc(DrawRect.mir.LineLeft, Options.Title.Width);
  1823.       atRight: Dec(DrawRect.mir.LineRight,  Options.Title.Width);
  1824.     end;
  1825.   if Options.Alignment <> taRightToLeft
  1826.   then begin
  1827.     DrawRect.mir.ItemLeft:= DrawRect.mir.LineLeft + Options.Margins.Left;
  1828.     DrawRect.mir.ShortcutLeft:= DrawRect.mir.LineRight - Options.Margins.Right - DrawRect.mir.ShortcutWidth;
  1829.     DrawRect.mir.BitmapLeft:= DrawRect.mir.LineLeft;
  1830.     DrawRect.mir.TriangleWidth:= Options.Margins.Right -4;
  1831.     DrawRect.mir.TriangleLeft:= DrawRect.mir.LineRight - DrawRect.mir.TriangleWidth -2;
  1832.   end
  1833.   else begin
  1834.     DrawRect.mir.ShortcutLeft:= DrawRect.mir.LineLeft + Options.Margins.Left;
  1835.     DrawRect.mir.ItemLeft:= DrawRect.mir.LineRight - Options.Margins.Right - DrawRect.mir.itemWidth;
  1836.     DrawRect.mir.BitmapLeft:= DrawRect.mir.LineRight - Options.ItemHeight -1;
  1837.     DrawRect.mir.TriangleWidth:= Options.Margins.Left -4;
  1838.     DrawRect.mir.TriangleLeft:= DrawRect.mir.Border;
  1839.   end;
  1840.   if Options.Alignment <> taRightToLeft
  1841.   then DrawRect.mir.BitmapWidth:= DrawRect.mir.LineLeft + Options.Margins.Left - DrawRect.mir.BitmapLeft -3
  1842.   else DrawRect.mir.BitmapWidth:= DrawRect.mir.LineRight - DrawRect.mir.BitmapLeft -2;
  1843.   // select background's palette (if any)
  1844.   OldPalette:= 0;
  1845.   if (not Options.Background.Empty) then begin
  1846.     if (Options.Background.Palette <> 0) then begin
  1847.       OldPalette:= SelectPalette(Buffer.Canvas.Handle, Options.Background.Palette, True);
  1848.       RealizePalette(Buffer.Canvas.Handle);
  1849.     end;
  1850.     Include(DrawRect.State, isGraphBack);
  1851.     // fit background to menu
  1852.     if fsPaintMenu in State then begin
  1853.       op1:= 0;
  1854.       Back.Width:= Buffer.Width;
  1855.       Back.Height:= Buffer.Height;
  1856.       Back.FreeImage;
  1857.       with Back.Canvas do begin
  1858.         Brush.Style:= bsSolid;
  1859.         Brush.Color:= Options.Colors.Menu;
  1860.         FillRect(ClipRect);
  1861.       end;
  1862.       if Options.Background.Palette <> 0 then begin
  1863.         op1:= SelectPalette(Back.Canvas.Handle, Options.Background.Palette, True);
  1864.         RealizePalette(Back.Canvas.Handle);
  1865.       end;
  1866.       case Options.BackgroundDisplay of
  1867.         bdDefault, bdExpand:
  1868.           BitBlt(Back.Canvas.Handle, 0, 0, Back.Width, Back.Height,
  1869.             Options.Background.Canvas.Handle, 0, 0, SrcCopy);
  1870.         bdCenter:
  1871.           with DrawRect.mir do begin
  1872.             R.Left:= LineLeft;
  1873.             R.Right:= R.Left + Options.Background.Width;
  1874.             R.Top:= Border;
  1875.             R.Bottom:= R.Top + Options.Background.Height;
  1876.             OffsetRect(R, ((LineRight - LineLeft) - Options.Background.Width) div 2 - Border,
  1877.               (Buffer.Height - Options.Background.Height) div 2 - Border);
  1878.             BitBlt(Back.Canvas.Handle, R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top,
  1879.               Options.Background.Canvas.Handle, 0, 0, SrcCopy);
  1880.           end;
  1881.         bdTile:
  1882.           with Back.Canvas do begin
  1883.             Brush.Bitmap:= Options.Background;
  1884.             FillRect(ClipRect);
  1885.           end;
  1886.         bdStretch:
  1887.           with DrawRect.mir, Options.Background do
  1888.             StretchBlt(Back.Canvas.Handle, 0, 0, LineRight, Buffer.Height,
  1889.               Canvas.Handle, 0, 0, Width, Height, SrcCopy);
  1890.       end;
  1891.       if op1 <> 0
  1892.       then SelectPalette(Back.Canvas.Handle, op1, True);
  1893.     end;
  1894.   end;
  1895.   // mouse position
  1896.   GetCursorPos(DrawRect.MousePos);
  1897.   DrawRect.MousePos:= ScreenToClient(DrawRect.MousePos);
  1898.   // paint CanTearOff plane
  1899.   if (Options.Draggable)
  1900.   and ((fsPaintMenu in State)
  1901.     or ((fsSelectedChanged in State) and ((SelectedIndex = itDragPane)
  1902.       or (LastSelectedIndex = itDragPane))))
  1903.   and (BorderStyle = bsNone)
  1904.   then
  1905.     with Buffer, Canvas do begin
  1906.       Brush.Style:= bsSolid;
  1907.       if SelectedIndex = itDragPane
  1908.       then begin C1:= ColorToRGB(clActiveCaption); C2:= ColorToRGB(clGradientActiveCaption); end
  1909.       else begin C1:= ColorToRGB(clInactiveCaption); C2:= ColorToRGB(clGradientInactiveCaption); end;
  1910.       // gradient!
  1911.       DH:= (DrawRect.mir.LineRight - DrawRect.mir.LineLeft)/256;
  1912.       R1:= GetRValue(C1);
  1913.       G1:= GetGValue(C1);
  1914.       B1:= GetBValue(C1);
  1915.       DR:= (GetRValue(C2) - R1 +1)/256;
  1916.       DG:= (GetGValue(C2) - G1 +1)/256;
  1917.       DB:= (GetBValue(C2) - B1 +1)/256;
  1918.       for Y1:= 0 to 255 do begin
  1919.         Brush.Color:= Rgb(R1 + Round(DR*Y1), G1 + Round(DG*Y1), B1 + Round(DB*Y1));
  1920.         F1:= Y1*DH;
  1921.         F2:= (Y1 +1)*DH;
  1922.         I1:= Round(F1);
  1923.         I2:= Round(F2);
  1924.         FillRect(Rect(DrawRect.mir.LineLeft + I1, DrawRect.mir.Border, DrawRect.mir.LineLeft + I2, DrawRect.mir.Border +7));
  1925.       end;
  1926.       // bottom line
  1927.       Brush.Color:= Options.Colors.Menu;
  1928.       FillRect(Rect(DrawRect.mir.LineLeft, DrawRect.mir.Border +7, DrawRect.mir.LineRight, DrawRect.mir.Border +10));
  1929.     end;
  1930.   M:= nil;
  1931.   M1:= GetMenuItemIndex(0, False);
  1932.   // repeat for each menu item
  1933.   for I:= 0 to ItemRects.Count -1 do begin
  1934.     M0:= M;
  1935.     M:= M1;
  1936.     M1:= GetMenuItemIndex(I +1, False);
  1937.     Temp:= GetMenuItemHeightIndex(I);
  1938.     DrawRect.mir.Top:= Y;
  1939.     DrawRect.mir.Height:= Temp;
  1940.     // init state
  1941.     SetState(DrawRect.State, isSelected, SelectedIndex = I);
  1942.     Exclude(DrawRect.State, isNoLeftSunken);
  1943.     Exclude(DrawRect.State, isNoRightSunken);
  1944.     if fsShowHidden in State then begin
  1945.       if not (fsHiddenAsRegular in State) then begin
  1946.         SetState(DrawRect.State, isHidden, (M is TMenuItem2000) and (TMenuItem2000(M).Hidden));
  1947.         SetState(DrawRect.State, isHiddenPrev, ((M0 is TMenuItem2000) and (TMenuItem2000(M0).Hidden))
  1948.           or ((M0 = nil) and (isHidden in DrawRect.State)));
  1949.         SetState(DrawRect.State, isHiddenSucc, ((M1 is TMenuItem2000) and (TMenuItem2000(M1).Hidden))
  1950.           or ((M1 = nil) and (isHidden in DrawRect.State)));
  1951.         if (isHidden in DrawRect.State) then begin
  1952.           // hide next separator
  1953.           if (not (isHiddenSucc in DrawRect.State))
  1954.           and (M1 <> nil)
  1955.           and (M1.Caption = '-') then begin
  1956.             M2:= GetMenuItemIndex(I +2, False);
  1957.             if (M2 is TMenuItem2000)
  1958.             and (TMenuItem2000(M2).Hidden)
  1959.             then SetState(DrawRect.State, isHiddenSucc, True);
  1960.           end;
  1961.           // hide prev separator
  1962.           if (not (isHiddenPrev in DrawRect.State))
  1963.           and (M0 <> nil)
  1964.           and (M0.Caption = '-') then begin
  1965.             M2:= GetMenuItemIndex(I -2, False);
  1966.             if (M2 is TMenuItem2000)
  1967.             and (TMenuItem2000(M2).Hidden)
  1968.             then SetState(DrawRect.State, isHiddenPrev, True);
  1969.           end;
  1970.           if Options.Title.Visible then begin
  1971.             SetState(DrawRect.State, isNoLeftSunken, Options.Title.Align = atLeft);
  1972.             SetState(DrawRect.State, isNoRightSunken, Options.Title.Align = atRight);
  1973.           end;
  1974.         end;
  1975.       end;
  1976.     end
  1977.     // ignore separator in Window menu
  1978.     else
  1979.       if (CurHiddenCount > 0)
  1980.       and (CurHiddenCount = MenuItems.Count)
  1981.       then Inc(CurHiddenCount);
  1982.     // handle focus item
  1983.     SetState(DrawRect.State, isActivated, (msLeftButton in MouseState) or ((FocusItem = M)
  1984.       and (fsDisabled in State)));
  1985.     DrawRect.Item:= M;
  1986.     DrawRect.Index:= I;
  1987.     // is menu item should be drawn?
  1988.     if (fsPaintMenu in State)
  1989.     or (((I = SelectedIndex) or (I = LastSelectedIndex))) then begin
  1990.       // draw background
  1991.       if not Back.Empty
  1992.       then begin
  1993.         if I = SelectedIndex
  1994.         then CopyMode:= NotSrcCopy
  1995.         else CopyMode:= Buffer.Canvas.CopyMode;
  1996.         with DrawRect.mir.LineRect do
  1997.           BitBlt(Buffer.Canvas.Handle, Left, Top, Right - Left, Bottom - Top,
  1998.             Back.Canvas.Handle, 0, Y, SrcCopy);
  1999.       end;
  2000.       // draw menu item
  2001.       // win32 menu item
  2002.       if M = nil
  2003.       then begin
  2004.         Inc(DrawRect.Index, CurHiddenCount);
  2005.         DrawMenuItemWin32(@DrawRect);
  2006.       end
  2007.       else
  2008.       // control
  2009.       if (M is TMenuItem2000) and (TMenuItem2000(M).Control <> ctlNone)
  2010.       then
  2011.         TMenuItem2000(M).ControlOptions.Draw(@DrawRect)
  2012.       else
  2013.       // ordinary menu item
  2014.         DrawMenuItem(@DrawRect);
  2015.     end;
  2016.     // increment Y
  2017.     Inc(Y, Temp);
  2018.     // fill interitem space
  2019.     if (fsPaintMenu in State)
  2020.     and (Options.Margins.Space > 0)
  2021.     and (I < ItemRects.Count -1)
  2022.     then
  2023.       if not Back.Empty
  2024.       then
  2025.         with DrawRect.mir do
  2026.           BitBlt(Buffer.Canvas.Handle, LineLeft, Y, LineRight - LineLeft,
  2027.             Options.Margins.Space, Back.Canvas.Handle, 0, Y, Buffer.Canvas.CopyMode)
  2028.       else
  2029.         with Buffer.Canvas, DrawRect.mir do begin
  2030.           if Brush.Style <> bsSolid
  2031.           then Brush.Style:= bsSolid;
  2032.           if Brush.Color <> Options.Colors.Menu
  2033.           then Brush.Color:= Options.Colors.Menu;
  2034.           Buffer.Canvas.FillRect(Rect(LineLeft, Y, LineRight,
  2035.             Y + Options.Margins.Space));
  2036.         end;
  2037.     // increment Y
  2038.     Inc(Y, Options.Margins.Space);
  2039.   end;
  2040.   Dec(Y, Options.Margins.Space);
  2041.   // final paintings
  2042.   if fsPaintMenu in State then
  2043.     with Buffer, Canvas, DrawRect.mir do begin
  2044.       if Brush.Style <> bsSolid
  2045.       then Brush.Style:= bsSolid;
  2046.       if Brush.Color <> Options.Colors.Menu
  2047.       then Brush.Color:= Options.Colors.Menu;
  2048.       // fill top rect
  2049.       R:= Rect(0, 0, Buffer.Width, Border + Options.Margins.Top);
  2050.       FillRect(R);
  2051.       // fill bottom rect
  2052.       R.Top:= Y;
  2053.       R.Bottom:= Buffer.Height +1;
  2054.       FillRect(R);
  2055.       // fill left border
  2056.       R:= Rect(0, 0, LineLeft, Buffer.Height);
  2057.       FillRect(R);
  2058.       // fill right border
  2059.       R.Left:= LineRight;
  2060.       R.Right:= Buffer.Width +1;
  2061.       FillRect(R);
  2062.       // draw bottom background's part
  2063.       if (Y < Buffer.Height) then begin
  2064.         // draw bottom background's part
  2065.         if not Options.Background.Empty then
  2066.           BitBlt(Handle, DrawRect.mir.LineLeft, Y,
  2067.             DrawRect.mir.LineRight - DrawRect.mir.LineLeft, Buffer.Height - Y,
  2068.             Options.Background.Canvas.Handle, 0, Y, Buffer.Canvas.CopyMode);
  2069.       end;
  2070.       // paint frame
  2071.       Font:= Self.Font;
  2072.       R:= ClipRect;
  2073.       if (BorderStyle = bsNone)
  2074.       and (fsCtl3D in State)
  2075.       then DrawEdge(Handle, R, bdr_RaisedInner + bdr_RaisedOuter, bf_Rect);
  2076.       // paint title
  2077.       if Options.Title.Visible
  2078.       then Options.Title.Paint(Buffer.Canvas);
  2079.     end;
  2080.   // draw hidden arrow
  2081.   if (fsHiddenArrow in State)
  2082.   and ((fsPaintMenu in State)
  2083.     or (((fsSelectedChanged in State)
  2084.         or (fsMouseChanged in State))
  2085.       and ((SelectedIndex = itHiddenArrow)
  2086.         or (LastSelectedIndex = itHiddenArrow))))
  2087.   then
  2088.     with Buffer, Canvas do begin
  2089.       R:= Rect(DrawRect.mir.LineLeft, Height - DrawRect.mir.Border -13,
  2090.         DrawRect.mir.LineRight, Height - DrawRect.mir.Border - Options.Margins.Bottom);
  2091.       if SelectedIndex = itHiddenArrow
  2092.       then begin
  2093.         DrawPatternBackground(Canvas, R);
  2094.         if msLeftButton in MouseState
  2095.         then DrawEdge(Canvas.Handle, R, bdr_SunkenOuter, bf_Rect)
  2096.         else DrawEdge(Canvas.Handle, R, bdr_RaisedInner, bf_Rect);
  2097.       end
  2098.       else begin
  2099.         Brush.Style:= bsSolid;
  2100.         Brush.Color:= Options.Colors.Menu;
  2101.         FillRect(R);
  2102.       end;
  2103.       // draw arrow
  2104.       X:= (R.Right + R.Left) div 2 -3;
  2105.       Y:= (R.Top + R.Bottom) div 2 -4;
  2106.       if (SelectedIndex = itHiddenArrow)
  2107.       and (msLeftButton in MouseState) then begin
  2108.         Inc(X); Inc(Y);
  2109.       end;
  2110.       Pen.Color:= Options.Colors.MenuText;
  2111.       PolyLine([Point(X, Y), Point(X +2, Y +2), Point(X +4, Y), Point(X +4, Y +1), Point(X +2, Y +3),
  2112.         Point(X -1, Y)]);
  2113.       Inc(Y, 4);
  2114.       PolyLine([Point(X, Y), Point(X +2, Y +2), Point(X +4, Y), Point(X +4, Y +1), Point(X +2, Y +3),
  2115.         Point(X -1, Y)]);
  2116.     end;
  2117.   // restore palette
  2118.   if OldPalette <> 0
  2119.   then SelectPalette(Buffer.Canvas.Handle, OldPalette, True);
  2120.   // determine buffer's position & draw the buffer
  2121.   if fsFromBottomToTop in State then Y:= 0 else Y:= Buffer.Height - Height;
  2122.   if fsFromRightToLeft in State then X:= 0 else X:= Buffer.Width - Width;
  2123.   if (BorderStyle <> bsNone) then Inc(Y, ClientOrigin.Y - Top -20);
  2124.   BitBlt(Canvas.Handle, 0, 0, Buffer.Width, Buffer.Height, Buffer.Canvas.Handle, X, Y, Canvas.CopyMode);
  2125.   Exclude(State, fsPaintMenu);
  2126.   Exclude(State, fsMouseChanged);
  2127.   LastSelectedIndex:= SelectedIndex;
  2128. end;
  2129. procedure TPopupMenu2000Form.RebuildToolTipWindow(Recreate: Boolean);
  2130.   // set tooltips
  2131. var
  2132.   R: TRect;
  2133.   M: TMenuItem;
  2134.   X, Y, H, I, iI, iJ, Index, BW, BH: Integer;
  2135. begin
  2136.   // we have to recreate tooltip window if it became
  2137.   // floating
  2138.   ToolTipWindow.Free;
  2139.   ToolTipWindow:= nil;
  2140.   if (not PopupMenu.ShowHint)
  2141.   or (PopupMenu.StatusBar <> nil)
  2142.   then Exit;
  2143.   ToolTipWindow:= T_AM2000_ToolTipWindow.Create(Self);
  2144.   // init X
  2145.   X:= 0;
  2146.   if Options.Title.Visible
  2147.   and (Options.Title.Align = atLeft)
  2148.   then Inc(X, Options.Title.Width);
  2149.   // init Y
  2150.   Y:= Options.Margins.Top;
  2151.   if (BorderStyle = bsNone)
  2152.   then
  2153.     if (fsCtl3D in State)
  2154.     then begin Inc(X, Options.Margins.Border +2); Inc(Y, Options.Margins.Border +2); end
  2155.     else begin Inc(X, Options.Margins.Border); Inc(Y, Options.Margins.Border); end;
  2156.   // is menu draggable?
  2157.   if (Options.Draggable)
  2158.   and (BorderStyle = bsNone)
  2159.   then begin
  2160.     ToolTipWindow.AddTool(Rect(2, Y, MX -2, Y+9), SDraggableMenuInfo);
  2161.     Inc(Y, 10);
  2162.   end;
  2163.   // add tools to the ToolTip control
  2164.   for I:= 0 to ItemRects.Count -1 do begin
  2165.     M:= GetMenuItemIndex(I, False);
  2166.     H:= GetMenuItemHeightIndex(I);
  2167.     if (M <> nil) then
  2168.       // is it a button array?
  2169.       if (M is TMenuItem2000)
  2170.       and (TMenuItem2000(M).Control = ctlButtonArray)
  2171.       then
  2172.         with TMenuItem2000(M).AsButtonArray do begin
  2173.           if Bitmap.Empty then Continue;
  2174.           // init loop
  2175.           iI:= 0;
  2176.           iJ:= 0;
  2177.           Index:= 0;
  2178.           BW:= Bitmap.Width div Columns;
  2179.           BH:= Bitmap.Height div Rows;
  2180.           // assign each hint to tooltip control
  2181.           while Index < Hints.Count do begin
  2182.             R:= Rect(iI * BW + X +2, iJ * BH + Y +1, 0, 0);
  2183.             R.Right:= R.Left + BW;
  2184.             R.Bottom:= R.Top + BH;
  2185.             if Hints[Index] <> ''
  2186.             then ToolTipWindow.AddTool(R, Hints[Index]);
  2187.             // next step
  2188.             Inc(Index);
  2189.             Inc(iI);
  2190.             if iI = Columns
  2191.             then begin Inc(iJ); iI:= 0; end;
  2192.           end;
  2193.         end
  2194.       else
  2195.       // is hint present?
  2196.       if (M.Hint <> '') and (M.Hint <> #1)
  2197.       then
  2198.         ToolTipWindow.AddTool(Rect(0, Y, MX, Y+H), M.Hint);
  2199.     Inc(Y, H + Options.Margins.Space);
  2200.   end;
  2201.   // hidden arrow
  2202.   if (fsHiddenArrow in State)
  2203.   then ToolTipWindow.AddTool(Rect(0, Y, MX, MY), SExpand);
  2204.   ToolTipWindow.Activate;
  2205. end;
  2206. procedure TPopupMenu2000Form.RebuildBounds;
  2207. var
  2208.   I, DI1, DI2, H, P, W1, W2, MIC, W11, P11: Integer;
  2209.   M: TMenuItem;
  2210.   L: LongRec;
  2211.   S: String;
  2212.   IncludeBold: Boolean;
  2213.   procedure SetDefault(D: Boolean);
  2214.   begin
  2215.     with Buffer.Canvas.Font do
  2216.       if D then begin
  2217.         if not (fsBold in Style) then begin
  2218.           IncludeBold:= True;
  2219.           Style:= Style + [fsBold];
  2220.         end;
  2221.       end
  2222.       else
  2223.         if IncludeBold then begin
  2224.           IncludeBold:= False;
  2225.           Style:= Style - [fsBold];
  2226.         end;
  2227.   end;
  2228. begin
  2229.   // initialize
  2230.   P:= 0;
  2231.   M:= nil;
  2232.   I:= 0;
  2233.   DI1:= 0; // for invisible items
  2234.   DI2:= 0; // for hidden items
  2235.   W2:= 0;
  2236.   ItemWidth:= 0;
  2237.   ShortcutWidth:= 0;
  2238.   IncludeBold:= False;
  2239.   FiLeft:= 0;
  2240.   FiWidth:= 0;
  2241.   Exclude(State, fsHiddenArrow);
  2242.   ItemRects.Clear;
  2243.   if (MenuHandle = 0) or (Options = nil)
  2244.   then Exit;
  2245.   MIC:= GetMenuItemCount(MenuHandle);
  2246.   // start
  2247.   // calc top margin
  2248.   H:= Options.Margins.Top + Options.Margins.Border;
  2249.   if (BorderStyle = bsNone) then begin
  2250.     if (fsCtl3D in State)
  2251.     then begin Inc(H, Options.Margins.Border +2); Inc(FiLeft, Options.Margins.Border +2); end
  2252.     else begin Inc(H, Options.Margins.Border); Inc(FiLeft, Options.Margins.Border); end;
  2253.     // is menu draggable?
  2254.     if (Options.Draggable)
  2255.     then Inc(H, 9);
  2256.   end
  2257.   else
  2258.     Inc(H, 1);
  2259.   // calc all menu items
  2260.   while MIC > I + DI2 do begin
  2261.     L.Lo:= H;
  2262.     L.Hi:= 0;
  2263.     // calc item's heigth
  2264.     // Delphi menu item
  2265.     while (MenuItems.Count > I + DI1 + DI2) do begin
  2266.       M:= MenuItems[I + DI1 + DI2];
  2267.       // invisible item
  2268.       if (not M.Visible)
  2269.       then
  2270.         Inc(DI1)
  2271.       else
  2272.       // hidden item
  2273.       if (M is TMenuItem2000)
  2274.       and (TMenuItem2000(M).Hidden)
  2275.       and (not (fsShowHidden in State))
  2276.       then
  2277.         Inc(DI2)
  2278.       else
  2279.       // visible item
  2280.       begin
  2281.         L.Hi:= GetMenuItemHeight(M);
  2282.         // create new font style
  2283.         SetDefault(M.Default);
  2284.         S:= M.Caption;
  2285.         Break;
  2286.       end;
  2287.     end;
  2288.     if (MenuItems.Count <= I + DI1 + DI2) then M:= nil;
  2289.     // WinAPI menu item
  2290.     if M = nil then begin
  2291.       mii.fMask:= miim_Type;
  2292.       mii.dwTypeData:= Z;
  2293.       mii.cch:= SizeOf(Z) -1;
  2294.       if GetMenuItemInfo(MenuHandle, I + DI2, True, mii)
  2295.       then
  2296.         if (I = 0)
  2297.         and (DI2 <> 0)
  2298.         and (mii.fType and mft_Separator <> 0)
  2299.         then begin
  2300.           Inc(I);
  2301.           Continue;
  2302.         end
  2303.         else begin
  2304.           if mii.fType and mft_Separator <> 0
  2305.           then L.Hi:= Options.SeparatorHeight
  2306.           else L.Hi:= Options.ItemHeight;
  2307.           SetDefault(mii.fState and mfs_Default <> 0);
  2308.           S:= StrPas(Z);
  2309.         end;
  2310.     end;
  2311.     // add item's top and botton
  2312.     if L.Hi <> 0 then begin
  2313.       ItemRects.Add(Pointer(L));
  2314.       Inc(H, L.Hi + Options.Margins.Space);
  2315.       Inc(I);
  2316.     end;
  2317.     // calc item's caption width
  2318.     W1:= 0;
  2319.     if (M <> nil)
  2320.     and (M is TMenuItem2000)
  2321.     then begin
  2322.       W1:= TMenuItem2000(M).GetWidth(Buffer.Canvas);
  2323.       if W1 > 0 then Dec(W1, Options.Margins.Left + Options.Margins.Right);
  2324.     end;
  2325.     if W1 = 0 then begin
  2326.       P:= Pos(#9, S);
  2327.       if P <> 0 then S:= Copy(S, 1, P -1);
  2328.       // calc menu item's width
  2329.       repeat
  2330.         P11:= Pos('n', S);
  2331.         if P11 = 0 then P11:= Pos(#13, S);
  2332.         if P11 = 0 then P11:= Length(S) +1;
  2333.         if (S = '') or (P11 = 0) then Break;
  2334.         W11:= AmpTextWidth(Buffer.Canvas, Copy(S, 1, P11 -1));
  2335.         if W11 > W1 then W1:= W11;
  2336.         if (P11 < Length(S))
  2337.         and (S[P11] = #13)
  2338.         then Delete(S, 1, P11)
  2339.         else Delete(S, 1, P11 +1);
  2340.       until S = '';
  2341.     end;
  2342.     if ItemWidth < W1 then ItemWidth:= W1;
  2343.     // end caption width
  2344.     // calc item's shortcut width
  2345.     if (M <> nil)
  2346.     then
  2347.       if (M is TMenuItem2000)
  2348.       then begin
  2349.         if TMenuItem2000(M).ShortCut <> ''
  2350.         then W2:= Buffer.Canvas.TextWidth(GetMainShortCut(TMenuItem2000(M).ShortCut))
  2351.       end
  2352.       else
  2353.       if M.ShortCut <> 0
  2354.       then
  2355.         W2:= Buffer.Canvas.TextWidth(ShortCutToText(M.ShortCut));
  2356.     if P <> 0
  2357.     then W2:= Buffer.Canvas.TextWidth(Copy(Z, P +1, MaxInt));
  2358.     if ShortcutWidth < W2
  2359.     then ShortcutWidth:= W2;
  2360.     // end shortcut width
  2361.     // merge max caption width and max shrtcut width
  2362.     // office-like align (align shortcuts to the left)
  2363.     if not (mfStandardAlign in Options.Flags) then begin
  2364.       if W2 > 0 then Inc(W2, 4);
  2365.       if (FiWidth < W1 + W2) then FiWidth:= W1 + W2;
  2366.     end;
  2367.     
  2368.   end { loop for each menu item };
  2369.   // restore default canvas settings
  2370.   SetDefault(False);
  2371.   // merge max caption width and max shortcut width
  2372.   // standard align (align shortcuts to the right)
  2373.   if (mfStandardAlign in Options.Flags) then begin
  2374.     FiWidth:= ItemWidth + ShortCutWidth;
  2375.     if ShortCutWidth > 0 then Inc(FiWidth, 4);
  2376.   end;
  2377.   // add margins
  2378.   Inc(FiWidth, Options.Margins.Left + Options.Margins.Right);
  2379.   // add title
  2380.   with Options.Title do
  2381.     if (ParentMenuForm = nil)
  2382.     and Visible
  2383.     and (Align = atLeft)
  2384.     then Inc(FiLeft, Width);
  2385.   // set flag for hidden menu items
  2386.   if DI2 > 0
  2387.   then Include(State, fsHiddenArrow);
  2388.   // check menu with hidden menu items
  2389.   // and without unhidden menu items
  2390.   if (I = 0) and (DI2 > 0) then begin
  2391.     Include(State, fsShowHidden);
  2392.     RebuildBounds;
  2393.   end;
  2394. end;
  2395. function TPopupMenu2000Form.GetItemRect(Index: Integer): TRect;
  2396. begin
  2397.   if (Index >= 0) and (Index < ItemRects.Count) then begin
  2398.     Result.Left:=   FiLeft;
  2399.     Result.Top:=    LongRec(ItemRects[Index]).Lo;
  2400.     Result.Right:=  Result.Left + FiWidth;
  2401.     Result.Bottom:= Result.Top + LongRec(ItemRects[Index]).Hi;
  2402.   end
  2403.   else
  2404.     FillChar(Result, SizeOf(TRect), 0);
  2405. end;
  2406. procedure TPopupMenu2000Form.wmInitState;
  2407. var
  2408.   HiddenIsVisible: Boolean;
  2409. begin
  2410.   FormStyle:= fsStayOnTop;
  2411.   BorderStyle:= bsNone;
  2412.   HiddenIsVisible:= (fsShowHidden in State);
  2413.   if (PopupMenu = nil) then Exit;
  2414.   
  2415.   if HiddenIsVisible
  2416.   then PopupMenu.Options.Flags:= PopupMenu.Options.Flags + [mfHiddenIsVisible];
  2417.   // set Ctl3D
  2418.   if (PopupMenu.Ctl3D)
  2419.   then State:= [fsCtl3d]
  2420.   else State:= [];
  2421.   // assign options property
  2422.   GetOptions(MenuItems, PopupMenu, Options);
  2423.   // for submenus these properties
  2424.   // already initialized in CreateSubMenuForm
  2425.   if ParentMenuForm = nil
  2426.   then Animation:= Options.Animation;
  2427.   // hidden
  2428.   if HiddenIsVisible
  2429.   or (mfHiddenIsVisible in Options.Flags)
  2430.   then Include(State, fsShowHidden);
  2431.   // reassign font handle
  2432.   if PopupMenu.ParentFont
  2433.   then Font:= TForm(PopupMenu.Owner).Font
  2434.   else
  2435.   if PopupMenu.SystemFont
  2436.   then Font.Handle:= GetMenuFontHandle
  2437.   else Font:= PopupMenu.Font;
  2438.   Canvas.Font.Assign(Font);
  2439.   Buffer.Canvas.Font.Assign(Font);
  2440.   // get menu item height
  2441.   if PopupMenu.SystemFont
  2442.   then ItemHeight:= Canvas.TextHeight('Hj') +5
  2443.   else ItemHeight:= Options.ItemHeight;
  2444. end;
  2445. end.