SkinMenus.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:60k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************************}
  2. {                                                                   }
  3. {       Almediadev Visual Component Library                         }     
  4. {       DynamicSkinForm                                             }
  5. {       Version 4.98                                                }
  6. {                                                                   }
  7. {       Copyright (c) 2000-2002 Almediadev                          }
  8. {       ALL RIGHTS RESERVED                                         }
  9. {                                                                   }
  10. {       Home:  http://www.almdev.com                                }
  11. {       Support: support@almdev.com                                 }
  12. {                                                                   }
  13. {*******************************************************************}
  14. unit SkinMenus;
  15. {$P+,S-,W-,R-}
  16. {$WARNINGS OFF}
  17. {$HINTS OFF}
  18. interface
  19. uses
  20.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  21.   Menus, ExtCtrls, ImgList, SkinData, SPUtils, spEffBMp;
  22. type
  23.   TspSkinPopupWindow = class;
  24.   TspSkinMenuItem = class(TObject)
  25.   protected
  26.     Parent: TspSkinPopupWindow;
  27.     MI: TspDataSkinMenuItem;
  28.     ActivePicture: TBitMap;
  29.     FMorphKf: Double;
  30.     procedure SetMorphKf(Value: Double);
  31.     procedure Redraw;
  32.   public
  33.     MenuItem: TMenuItem;
  34.     ObjectRect: TRect;
  35.     Active: Boolean;
  36.     Down: Boolean;
  37.     FVisible: Boolean;
  38.     constructor Create(AParent: TspSkinPopupWindow; AMenuItem: TMenuItem;
  39.                        AData: TspDataSkinMenuItem);
  40.     procedure Draw(Cnvs: TCanvas);
  41.     procedure DefaultDraw(Cnvs: TCanvas);
  42.     function CanMorphing: Boolean; virtual;
  43.     procedure DoMorphing;
  44.     property MorphKf: Double read FMorphKf write SetMorphKf;
  45.     procedure MouseDown(X, Y: Integer);
  46.     procedure MouseEnter(Kb: Boolean);
  47.     procedure MouseLeave;
  48.   end;
  49.   TspSkinMenu = class;
  50.   TspSkinPopupWindow = class(TCustomControl)
  51.   private
  52.     DSMI: TspDataSkinMenuItem;
  53.     VisibleCount: Integer;
  54.     VisibleStartIndex: Integer;
  55.     Scroll: Boolean;
  56.     ScrollCode: Integer;
  57.     NewLTPoint, NewRTPoint,
  58.     NewLBPoint, NewRBPoint: TPoint;
  59.     NewItemsRect: TRect;
  60.     FRgn: HRGN;
  61.     ShowX, ShowY: Integer;
  62.     WT: TTimer;
  63.     OMX, OMY: Integer;
  64.     procedure WTProc(Sender: TObject);
  65.     procedure WMMouseActivate(var Message: TMessage); message WM_MOUSEACTIVATE;
  66.     procedure WMEraseBkGrnd(var Message: TMessage); message WM_ERASEBKGND;
  67.     procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
  68.     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  69.     procedure CreateMenu(Item: TMenuItem; StartIndex: Integer);
  70.     procedure CreateRealImage(B: TBitMap);
  71.     procedure SetMenuWindowRegion;
  72.     procedure DrawUpMarker(Cnvs: TCanvas);
  73.     procedure DrawDownMarker(Cnvs: TCanvas);
  74.     procedure StartScroll;
  75.     procedure StopScroll;
  76.   protected
  77.     ImgL: TCustomImageList;
  78.     GlyphWidth: Integer;
  79.     WindowPicture, MaskPicture: TBitMap;
  80.     OldActiveItem: Integer;
  81.     MouseTimer, MorphTimer: TTimer;
  82.     ParentMenu: TspSkinMenu;
  83.     SD: TspSkinData;
  84.     PW: TspDataSkinPopupWindow;
  85.     procedure WMTimer(var Message: TWMTimer); message WM_Timer;
  86.     function CanScroll(AScrollCode: Integer): Boolean;
  87.     procedure ScrollUp(Cycle: Boolean);
  88.     procedure ScrollDown(Cycle: Boolean);
  89.     function GetEndStartVisibleIndex: Integer;
  90.     procedure CalcItemRects;
  91.     procedure CreateParams(var Params: TCreateParams); override;
  92.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  93.       X, Y: Integer); override;
  94.     procedure TestMouse(Sender: TObject);
  95.     procedure TestActive(X, Y: Integer);
  96.     function InWindow(P: TPoint): Boolean;
  97.     procedure TestMorph(Sender: TObject);
  98.     procedure UpDatePW;
  99.     function GetActive(X, Y: Integer): Boolean;
  100.   public
  101.     Sc: TBitMap;
  102.     ESc: TspEffectBmp;
  103.     AlphaBlend: Boolean;
  104.     AlphaBlendValue: Byte;
  105.     AlphaBlendAnimation: Boolean;
  106.     ItemList: TList;
  107.     ActiveItem: Integer;
  108.     constructor CreateEx(AOwner: TComponent; AParentMenu: TspSkinMenu;
  109.                        AData: TspDataSkinPopupWindow);
  110.     destructor Destroy; override;
  111.      procedure Hide;
  112.     procedure Show(R: TRect; AItem: TMenuItem; StartIndex: Integer;
  113.                    PopupByItem: Boolean;  PopupUp: Boolean);
  114.     procedure PaintMenu(DC: HDC);
  115.     procedure PopupKeyDown(CharCode: Integer);
  116.   end;
  117.   TspSkinMenu = class(TComponent)
  118.   protected
  119.     { Protected declarations }
  120.     FFirst: Boolean;
  121.     FDefaultMenuItemHeight: Integer;
  122.     FDefaultMenuItemFont: TFont;
  123.     PopupCtrl: TControl;
  124.     FForm: TForm;
  125.     WaitTimer: TTimer;
  126.     WItem: TspSkinMenuItem;
  127.     WorkArea: TRect;
  128.     FVisible: Boolean;
  129.     SkinData: TspSkinData;
  130.     procedure SetDefaultMenuItemFont(Value: TFont);
  131.     function GetWorkArea: TRect;
  132.     function GetPWIndex(PW: TspSkinPopupWindow): Integer;
  133.     procedure CheckItem(PW: TspSkinPopupWindow; MI: TspSkinMenuItem; Down: Boolean; Kb: Boolean);
  134.     procedure CloseMenu(EndIndex: Integer);
  135.     procedure PopupSub(R: TRect; AItem: TMenuItem; StartIndex: Integer;
  136.                        PopupByItem, PopupUp: Boolean);
  137.     procedure WaitItem(Sender: TObject);
  138.   public
  139.     { Public declarations }
  140.     FPopupList: TList;
  141.     AlphaBlend: Boolean;
  142.     AlphaBlendValue: Byte;
  143.     AlphaBlendAnimation: Boolean;
  144.     property Visible: Boolean read FVisible;
  145.     constructor CreateEx(AOwner: TComponent; AForm: TForm);
  146.     destructor Destroy; override;
  147.     procedure Popup(APopupCtrl: TControl; ASkinData: TspSkinData; StartIndex: Integer;
  148.                     R: TRect; AItem: TMenuItem; PopupUp: Boolean);
  149.     procedure Hide;
  150.     property First: Boolean read FFirst;
  151.     property DefaultMenuItemFont: TFont
  152.       read FDefaultMenuItemFont write SetDefaultMenuItemFont;
  153.     property DefaultMenuItemHeight: Integer
  154.       read FDefaultMenuItemHeight write FDefaultMenuItemHeight;
  155.   published
  156.     { Published declarations }
  157.   end;
  158.   TspSkinPopupMenu = class(TPopupMenu)
  159.   protected
  160.     FSD: TspSkinData;
  161.     FComponentForm: TForm;
  162.     procedure Notification(AComponent: TComponent;
  163.       Operation: TOperation); override;
  164.   public
  165.     constructor Create(AOwner: TComponent); override;
  166.     procedure Popup(X, Y: Integer); override;
  167.     procedure PopupFromRect(R: TRect; APopupUp: Boolean);
  168.     procedure Popup2(ACtrl: TControl; X, Y: Integer);
  169.     procedure PopupFromRect2(ACtrl: TControl; R: TRect; APopupUp: Boolean);
  170.     property ComponentForm: TForm read FComponentForm write FComponentForm;
  171.   published
  172.     property SkinData: TspSkinData read FSD write FSD;
  173.   end;
  174.   function CanMenuClose(Msg: Cardinal): Boolean;
  175. const
  176.     WM_CLOSESKINMENU = WM_USER + 204;
  177. implementation
  178.    Uses DynamicSkinForm;
  179. const
  180.     MorphInc = 0.1;
  181.     MouseTimerInterval = 50;
  182.     MorphTimerInterval = 20;
  183.     WaitTimerInterval = 500;
  184.     MarkerItemHeight = 10;
  185.     ScrollTimerInterval = 100;
  186.     MI_MINNAME = 'DSF_MINITEM';
  187.     MI_MAXNAME = 'DSF_MAXITEM';
  188.     MI_CLOSENAME = 'DSF_CLOSE';
  189.     MI_RESTORENAME = 'DSF_RESTORE';
  190.     MI_MINTOTRAYNAME = 'DSF_MINTOTRAY';
  191.     MI_ROLLUPNAME = 'DSF_ROLLUP';
  192.     TMI_RESTORENAME = 'TRAY_DSF_RESTORE';
  193.     TMI_CLOSENAME = 'TRAY_DSF_CLOSE';
  194.     MI_MINCAPTION = 'Mi&nimize';
  195.     MI_MAXCAPTION = 'Ma&ximize';
  196.     MI_CLOSECAPTION = '&Close';
  197.     MI_RESTORECAPTION = '&Restore';
  198.     MI_MINTOTRAYCAPTION = 'Minimize to &Tray';
  199.     MI_ROLLUPCAPTION = 'Ro&llUp';
  200. procedure DrawCheckImage(Cnvs: TCanvas; X, Y: Integer; Color: TColor);
  201. var
  202.   i: Integer;
  203. begin
  204.   with Cnvs do
  205.   begin
  206.     Pen.Color := Color;
  207.     for i := 0 to 2 do
  208.     begin
  209.       MoveTo(X, Y + 5 - i);
  210.       LineTo(X + 2, Y + 7 - i);
  211.       LineTo(X + 7, Y + 2 - i);
  212.     end;
  213.   end;
  214. end;
  215. procedure DrawSubImage(Cnvs: TCanvas; X, Y: Integer; Color: TColor);
  216. var
  217.   i: Integer;
  218. begin
  219.   with Cnvs do
  220.   begin
  221.     Pen.Color := Color;
  222.     for i := 0 to 3 do
  223.     begin
  224.       MoveTo(X + i, Y + i);
  225.       LineTo(X + i, Y + 7 - i);
  226.     end;
  227.   end;
  228. end;
  229. procedure DrawRadioImage(Cnvs: TCanvas; X, Y: Integer; Color: TColor);
  230. begin
  231.   with Cnvs do
  232.   begin
  233.     Pen.Color := Color;
  234.     Brush.Color := Color;
  235.     Ellipse(X, Y, X + 6, Y + 6);
  236.   end;
  237. end;
  238. function RectWidth(R: TRect): Integer;
  239. begin
  240.   Result := R.Right - R.Left;
  241. end;
  242. function RectHeight(R: TRect): Integer;
  243. begin
  244.   Result := R.Bottom - R.Top;
  245. end;
  246. function CanMenuClose;
  247. begin
  248.   Result := False;
  249.   case Msg of
  250.     WM_MOUSEACTIVATE, WM_ACTIVATE,
  251.     WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN,
  252.     WM_NCLBUTTONDOWN, WM_NCMBUTTONDOWN, WM_NCRBUTTONDOWN,
  253.     WM_KILLFOCUS, WM_MOVE, WM_SIZE, WM_CANCELMODE, WM_PARENTNOTIFY:
  254.       Result := True;
  255.   end;
  256. end;
  257. //===============TspSkinMenuItem===================//
  258. constructor TspSkinMenuItem.Create;
  259. begin
  260.   Parent := AParent;
  261.   MenuItem := AMenuItem;
  262.   FVisible := True;
  263.   MI := AData;
  264.   if MI <> nil then 
  265.   with AData do
  266.   begin
  267.     if (ActivePictureIndex <> - 1) and
  268.        (ActivePictureIndex < Self.Parent.SD.FActivePictures.Count)
  269.     then
  270.       ActivePicture := Self.Parent.SD.FActivePictures.Items[ActivePictureIndex]
  271.     else
  272.       begin
  273.         ActivePicture := nil;
  274.         SkinRect := NullRect;
  275.         ActiveSkinRect := NullRect;
  276.       end;
  277.   end;
  278.   FMorphKf := 0;
  279. end;
  280. function TspSkinMenuItem.CanMorphing;
  281. var
  282.   AD: Boolean;
  283. begin
  284.   AD := Active or Down;
  285.   Result := FVisible and ((AD and (MorphKf < 1)) or
  286.                          (not AD and (MorphKf > 0)));
  287.   if not FVisible and (FMorphKf <> 0)
  288.   then
  289.     begin
  290.       Active := False;
  291.       Down := False;
  292.       FMorphKf := 0;
  293.     end;
  294. end;
  295. procedure TspSkinMenuItem.DoMorphing;
  296. begin
  297.   if Active or Down
  298.   then MorphKf := MorphKf + MorphInc
  299.   else MorphKf := MorphKf - MorphInc;
  300.   Draw(Parent.Canvas);
  301. end;
  302. procedure TspSkinMenuItem.SetMorphKf(Value: Double);
  303. begin
  304.   FMorphKf := Value;
  305.   if FMorphKf < 0 then FMorphKf := 0 else
  306.   if FMorphKf > 1 then FMorphKf := 1;
  307. end;
  308. procedure TspSkinMenuItem.ReDraw;
  309. begin
  310.   if (MI <> nil) and MI.Morphing
  311.   then Parent.MorphTimer.Enabled := True
  312.   else Draw(Parent.Canvas);
  313. end;
  314. procedure TspSkinMenuItem.MouseDown(X, Y: Integer);
  315. begin
  316.   if not Down and MenuItem.Enabled
  317.   then
  318.     Parent.ParentMenu.CheckItem(Parent, Self, True, False);
  319. end;
  320. procedure TspSkinMenuItem.MouseEnter;
  321. var
  322.   i: Integer;
  323. begin
  324.   Active := True;
  325.   for i := 0 to Parent.ItemList.Count - 1 do
  326.     if (TspSkinMenuItem(Parent.ItemList.Items[i]) <> Self)
  327.        and TspSkinMenuItem(Parent.ItemList.Items[i]).Down
  328.     then
  329.       with TspSkinMenuItem(Parent.ItemList.Items[i]) do
  330.       begin
  331.         Down := False;
  332.         ReDraw;
  333.       end;
  334.   if not Down
  335.   then
  336.     begin
  337.       ReDraw;
  338.       Parent.ParentMenu.CheckItem(Parent, Self, False, Kb);
  339.     end
  340.   else
  341.     with Parent.ParentMenu do
  342.     begin
  343.       i := GetPWIndex(Parent);
  344.       if i + 2 < FPopupList.Count
  345.       then
  346.         TspSkinPopupWindow(FPopupList.Items[i + 1]).UpDatePW;
  347.     end;
  348.     
  349. end;
  350. procedure TspSkinMenuItem.MouseLeave;
  351. begin
  352.   Active := False;
  353.   if not Down then ReDraw;
  354.   with Parent.ParentMenu do
  355.   begin
  356.     if (WItem <> nil) and (WItem = Self)
  357.     then
  358.       begin
  359.         WaitTimer.Enabled := False;
  360.         WItem := nil;
  361.       end;
  362.   end;
  363. end;
  364. procedure TspSkinMenuItem.DefaultDraw(Cnvs: TCanvas);
  365. var
  366.   MIShortCut: String;
  367.   B: TBitMap;
  368.   TextOffset: Integer;
  369.   R, TR, SR: TRect;
  370.   DrawGlyph: Boolean;
  371.   GX, GY, IX, IY: Integer;
  372.   EB1: TspEffectBmp;
  373.   kf: Double;
  374. begin
  375.   if MenuItem.ShortCut <> 0
  376.   then
  377.     MIShortCut := ShortCutToText(MenuItem.ShortCut)
  378.   else
  379.     MIShortCut := '';
  380.   B := TBitMap.Create;
  381.   B.Width := RectWidth(ObjectRect);
  382.   B.Height := RectHeight(ObjectRect);
  383.   if Parent.ImgL = nil
  384.   then TextOffset := 19
  385.   else TextOffset := Parent.GlyphWidth;
  386.   
  387.   with B.Canvas do
  388.   begin
  389.     R := Rect(0, 0, B.Width, B.Height);
  390.     Font.Assign(Parent.ParentMenu.FDefaultMenuItemFont);
  391.     if Active or Down
  392.     then
  393.       begin
  394.         Frame3D(B.Canvas, R, SP_XP_BTNFRAMECOLOR, SP_XP_BTNFRAMECOLOR, 1);
  395.         Brush.Color := SP_XP_BTNACTIVECOLOR;
  396.         Font.Color := clWindowText;
  397.         FillRect(R);
  398.       end
  399.     else
  400.       begin
  401.         R := Rect(0, 0, TextOffset, B.Height);
  402.         Brush.Color := clBtnFace;
  403.         FillRect(R);
  404.         R := Rect(TextOffset, 0, B.Width, B.Height);
  405.         Brush.Color := clWindow;
  406.         if MenuItem.Enabled
  407.         then
  408.           Font.Color := clWindowText
  409.         else
  410.           Font.Color := clBtnShadow;
  411.         FillRect(R);
  412.       end;
  413.   end;
  414.   if MenuItem.Caption = '-'
  415.   then
  416.     begin
  417.       R.Left := TextOffset;
  418.       R.Top := B.Height div 2;
  419.       R.Right := B.Width;
  420.       R.Bottom := B.Height div 2 + 1;
  421.       Frame3D(B.Canvas, R, clBtnShadow, clBtnShadow, 1);
  422.       if Parent.AlphaBlend and not CheckW2KWXP
  423.       then
  424.         begin
  425.           EB1 := TspEffectBmp.CreateFromhWnd(B.Handle);
  426.           kf := 1 - Parent.AlphaBlendValue / 255;
  427.           EB1.MorphRect(Parent.ESc, kf, Rect(0, 0, B.Width, B.Height),
  428.             ObjectRect.Left, ObjectRect.Top);
  429.           EB1.Draw(Cnvs.Handle, ObjectRect.Left, ObjectRect.Top);
  430.           EB1.Free;
  431.         end
  432.       else
  433.         Cnvs.Draw(ObjectRect.Left, ObjectRect.Top, B);
  434.       B.Free;
  435.       Exit;
  436.     end;
  437.   TR := Rect(2, 2, B.Width - 2, B.Height - 2);
  438.   // text
  439.   R := Rect(TR.Left + TextOffset, 0, TR.Right - 19, 0);
  440.   DrawText(B.Canvas.Handle, PChar(MenuItem.Caption), Length(MenuItem.Caption), R,
  441.              DT_CALCRECT);
  442.   OffsetRect(R, 0, TR.Top + RectHeight(TR) div 2 - R.Bottom div 2);
  443.   Inc(R.Right, 2);
  444.   DrawText(B.Canvas.Handle,
  445.            PChar(MenuItem.Caption), Length(MenuItem.Caption), R, DT_CENTER or DT_VCENTER);
  446.   // short cut
  447.   if MIShortCut <> ''
  448.   then
  449.     begin
  450.       SR := Rect(0, 0, 0, 0);
  451.       DrawText(B.Canvas.Handle, PChar(MIShortCut), Length(MIShortCut), SR,
  452.                DT_CALCRECT);
  453.       SR := Rect(TR.Right - SR.Right - 19, R.Top, TR.Right - 19, R.Bottom);
  454.       DrawText(B.Canvas.Handle,
  455.         PChar(MIShortCut), Length(MIShortCut), SR, DT_CENTER or DT_VCENTER);
  456.     end;
  457.   //
  458.   if MenuItem.Count <> 0
  459.   then
  460.     DrawSubImage(B.Canvas,
  461.                  TR.Right - 7, TR.Top + RectHeight(TR) div 2 - 4,
  462.                  B.Canvas.Font.Color);
  463.   //
  464.   DrawGlyph := (Parent.ImgL <> nil) and (MenuItem.ImageIndex > -1) and
  465.        (MenuItem.ImageIndex < Parent.ImgL.Count);
  466.   if DrawGlyph
  467.   then
  468.     begin
  469.       GX := TR.Left;
  470.       GY := TR.Top + RectHeight(TR) div 2 - Parent.ImgL.Height div 2;
  471.       if MenuItem.Checked
  472.       then
  473.         with B.Canvas do
  474.         begin
  475.           Brush.Style := bsClear;
  476.           Pen.Color := Font.Color;
  477.           Rectangle(GX - 1, GY - 1,
  478.                     GX + Parent.ImgL.Width + 1,
  479.                     GY + Parent.ImgL.Height + 1);
  480.         end;
  481.     end
  482.   else
  483.     begin
  484.       GX := 0; GY := 0;
  485.       IY := TR.Top + RectHeight(TR) div 2 - 4;
  486.       IX := TR.Left + 2;
  487.       if (MenuItem.Name = MI_CLOSENAME) or (MenuItem.Name = TMI_CLOSENAME)
  488.       then DrawCloseImage(B.Canvas, IX, IY, B.Canvas.Font.Color) else
  489.       if MenuItem.Name = MI_MINNAME
  490.       then DrawMinimizeImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  491.       else
  492.       if MenuItem.Name = MI_MAXNAME
  493.       then DrawMaximizeImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  494.       else
  495.       if (MenuItem.Name = MI_RESTORENAME) or (MenuItem.Name = TMI_RESTORENAME)
  496.       then DrawRestoreImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  497.       else
  498.       if MenuItem.Name = MI_ROLLUPNAME
  499.       then DrawRollUpImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  500.       else
  501.       if MenuItem.Name = MI_MINTOTRAYNAME
  502.       then DrawMTImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  503.       else
  504.       if MenuItem.Checked
  505.       then
  506.       if MenuItem.RadioItem
  507.       then
  508.         DrawRadioImage(B.Canvas,
  509.                        TR.Left + 3, TR.Top + RectHeight(TR) div 2 - 3,
  510.                        B.Canvas.Font.Color)
  511.       else
  512.         DrawCheckImage(B.Canvas,
  513.                        TR.Left + 3, TR.Top + RectHeight(TR) div 2 - 4,
  514.                        B.Canvas.Font.Color);
  515.     end;
  516.   //
  517.   if DrawGlyph
  518.   then
  519.     Parent.ImgL.Draw(B.Canvas, GX, GY, MenuItem.ImageIndex, MenuItem.Enabled);
  520.   if Parent.AlphaBlend and not CheckW2KWXP
  521.   then
  522.     begin
  523.       EB1 := TspEffectBmp.CreateFromhWnd(B.Handle);
  524.       kf := 1 - Parent.AlphaBlendValue / 255;
  525.       EB1.MorphRect(Parent.ESc, kf, Rect(0, 0, B.Width, B.Height),
  526.        ObjectRect.Left, ObjectRect.Top);
  527.       EB1.Draw(Cnvs.Handle, ObjectRect.Left, ObjectRect.Top);
  528.       EB1.Free;
  529.     end
  530.   else
  531.     Cnvs.Draw(ObjectRect.Left, ObjectRect.Top, B);
  532.   B.Free;
  533. end;
  534. procedure TspSkinMenuItem.Draw;
  535. var
  536.   GX, GY: Integer;
  537.   DrawGlyph: Boolean;
  538.   EB1: TspEffectBmp;
  539.   kf: Double;
  540. procedure CreateItemImage(B: TBitMap; AActive: Boolean);
  541. var
  542.   R, TR, SR, Rct: TRect;
  543.   TextOffset: Integer;
  544.   MIShortCut: String;
  545.   IX, IY: Integer;
  546. begin
  547.   if MenuItem.ShortCut <> 0
  548.   then
  549.     MIShortCut := ShortCutToText(MenuItem.ShortCut)
  550.   else
  551.     MIShortCut := '';
  552.   if AActive
  553.   then Rct := MI.ActiveSkinRect
  554.   else Rct := MI.SkinRect;
  555.   CreateHSkinImage(MI.ItemLO, MI.ItemRO,
  556.    B, ActivePicture, Rct,
  557.    RectWidth(ObjectRect), RectHeight(ObjectRect));
  558.   if Parent.ImgL = nil
  559.   then TextOffset := 16
  560.   else TextOffset := Parent.GlyphWidth;
  561.   TR := MI.TextRct;
  562.   TR.Right := B.Width - (RectWidth(MI.SkinRect) - MI.TextRct.Right);
  563.   with B.Canvas do
  564.   begin
  565.     Brush.Style := bsClear;
  566.     if AActive
  567.     then
  568.       Font.Color := MI.ActiveFontColor
  569.     else
  570.       if MenuItem.Enabled
  571.       then
  572.         Font.Color := MI.FontColor
  573.       else
  574.         Font.Color := MI.UnEnabledFontColor;
  575.     Font.Name := MI.FontName;
  576.     Font.Style := MI.FontStyle;
  577.     Font.Height := MI.FontHeight;
  578.     Font.CharSet := Self.Parent.ParentMenu.FDefaultMenuItemFont.Charset;
  579.     //
  580.     R := Rect(TR.Left + TextOffset, 0, TR.Right - 16, 0);
  581.     DrawText(B.Canvas.Handle, PChar(MenuItem.Caption), Length(MenuItem.Caption), R,
  582.              DT_CALCRECT);
  583.     OffsetRect(R, 0, TR.Top + RectHeight(TR) div 2 - R.Bottom div 2);
  584.     Inc(R.Right, 2);
  585.     DrawText(B.Canvas.Handle,
  586.              PChar(MenuItem.Caption), Length(MenuItem.Caption), R, DT_CENTER or DT_VCENTER);
  587.     // shortcut
  588.     if MIShortCut <> ''
  589.     then
  590.       begin
  591.         SR := Rect(0, 0, 0, 0);
  592.         DrawText(B.Canvas.Handle, PChar(MIShortCut), Length(MIShortCut), SR,
  593.                  DT_CALCRECT);
  594.         SR := Rect(TR.Right - SR.Right - 16, R.Top, TR.Right - 16, R.Bottom);
  595.         DrawText(B.Canvas.Handle,
  596.            PChar(MIShortCut), Length(MIShortCut), SR, DT_CENTER or DT_VCENTER);
  597.       end;
  598.     //
  599.     if MenuItem.Count <> 0
  600.     then
  601.       DrawSubImage(B.Canvas,
  602.                    TR.Right - 7, TR.Top + RectHeight(TR) div 2 - 4,
  603.                    B.Canvas.Font.Color);
  604.     //
  605.     DrawGlyph := (Parent.ImgL <> nil) and (MenuItem.ImageIndex > -1) and
  606.        (MenuItem.ImageIndex < Parent.ImgL.Count);
  607.     if DrawGlyph
  608.     then
  609.       begin
  610.         GX := TR.Left + 2;
  611.         GY := TR.Top + RectHeight(TR) div 2 - Parent.ImgL.Height div 2;
  612.         if MenuItem.Checked
  613.         then
  614.           begin
  615.             Brush.Style := bsClear;
  616.             Pen.Color := Font.Color;
  617.             Rectangle(GX - 1, GY - 1,
  618.                       GX + Parent.ImgL.Width + 1,
  619.                       GY + Parent.ImgL.Height + 1);
  620.           end;
  621.       end
  622.     else
  623.       begin
  624.         IY := TR.Top + RectHeight(TR) div 2 - 4;
  625.         IX := TR.Left + 2;
  626.         if (MenuItem.Name = MI_CLOSENAME) or (MenuItem.Name = TMI_CLOSENAME) 
  627.         then DrawCloseImage(B.Canvas, IX, IY, B.Canvas.Font.Color) else
  628.         if MenuItem.Name = MI_MINNAME
  629.         then DrawMinimizeImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  630.         else
  631.         if MenuItem.Name = MI_MAXNAME
  632.         then DrawMaximizeImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  633.         else
  634.         if (MenuItem.Name = MI_RESTORENAME) or (MenuItem.Name = TMI_RESTORENAME)
  635.         then DrawRestoreImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  636.         else
  637.         if MenuItem.Name = MI_ROLLUPNAME
  638.         then DrawRollUpImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  639.         else
  640.         if MenuItem.Name = MI_MINTOTRAYNAME
  641.         then DrawMTImage(B.Canvas, IX, IY, B.Canvas.Font.Color)
  642.         else
  643.         if MenuItem.Checked
  644.         then
  645.           if MenuItem.RadioItem
  646.           then
  647.             DrawRadioImage(B.Canvas,
  648.                            TR.Left + 2, TR.Top + RectHeight(TR) div 2 - 3,
  649.                            B.Canvas.Font.Color)
  650.           else
  651.             DrawCheckImage(B.Canvas,
  652.                            TR.Left + 2, TR.Top + RectHeight(TR) div 2 - 4,
  653.                            B.Canvas.Font.Color);
  654.       end;
  655.   end;
  656.   //
  657.   if DrawGlyph
  658.   then
  659.     Parent.ImgL.Draw(B.Canvas, GX, GY, MenuItem.ImageIndex, MenuItem.Enabled);
  660. end;
  661. var
  662.   B, AB: TBitMap;
  663.   EffB, EffAB: TspEffectBmp;
  664.   AD: Boolean;
  665. begin
  666.   if not FVisible then Exit;
  667.   if MI = nil
  668.   then
  669.     begin
  670.       DefaultDraw(Cnvs);
  671.       Exit;
  672.     end;
  673.   B := TBitMap.Create;
  674.   if MenuItem.Caption = '-'
  675.   then
  676.     begin
  677.       CreateHSkinImage(MI.DividerLO, MI.DividerRO,
  678.         B, ActivePicture, MI.DividerRect,
  679.         RectWidth(ObjectRect), RectHeight(ObjectRect));
  680.       if Parent.AlphaBlend and not CheckW2KWXP
  681.       then
  682.         begin
  683.           EB1 := TspEffectBmp.CreateFromhWnd(B.Handle);
  684.           kf := 1 - Parent.AlphaBlendValue / 255;
  685.           EB1.MorphRect(Parent.ESc, kf, Rect(0, 0, B.Width, B.Height),
  686.             ObjectRect.Left, ObjectRect.Top);
  687.           EB1.Draw(Cnvs.Handle, ObjectRect.Left, ObjectRect.Top);
  688.           EB1.Free;
  689.         end
  690.       else
  691.         Cnvs.Draw(ObjectRect.Left, ObjectRect.Top, B);
  692.      end
  693.   else
  694.     begin
  695.       AD := Active or Down;
  696.       if not MI.Morphing or
  697.       ((AD and (MorphKf = 1)) or (not AD and (MorphKf  = 0)))
  698.       then
  699.         begin
  700.           CreateItemImage(B, AD);
  701.           if Parent.AlphaBlend and not CheckW2KWXP
  702.           then
  703.             begin
  704.               EB1 := TspEffectBmp.CreateFromhWnd(B.Handle);
  705.               kf := 1 - Parent.AlphaBlendValue / 255;
  706.               EB1.MorphRect(Parent.ESc, kf, Rect(0, 0, B.Width, B.Height),
  707.                 ObjectRect.Left, ObjectRect.Top);
  708.               EB1.Draw(Cnvs.Handle, ObjectRect.Left, ObjectRect.Top);
  709.               EB1.Free;
  710.             end
  711.           else
  712.             Cnvs.Draw(ObjectRect.Left, ObjectRect.Top, B);
  713.         end
  714.       else
  715.         begin
  716.           CreateItemImage(B, False);
  717.           AB := TBitMap.Create;
  718.           CreateItemImage(AB, True);
  719.           EffB := TspEffectBmp.CreateFromhWnd(B.Handle);
  720.           EffAB := TspEffectBmp.CreateFromhWnd(AB.Handle);
  721.           case MI.MorphKind of
  722.             mkDefault: EffB.Morph(EffAB, MorphKf);
  723.             mkGradient: EffB.MorphGrad(EffAB, MorphKf);
  724.             mkLeftGradient: EffB.MorphLeftGrad(EffAB, MorphKf);
  725.             mkRightGradient: EffB.MorphRightGrad(EffAB, MorphKf);
  726.             mkLeftSlide: EffB.MorphLeftSlide(EffAB, MorphKf);
  727.             mkRightSlide: EffB.MorphRightSlide(EffAB, MorphKf);
  728.             mkPush: EffB.MorphPush(EffAB, MorphKf);
  729.           end;
  730.           if Parent.AlphaBlend and not CheckW2KWXP
  731.           then
  732.             begin
  733.               kf := 1 - Parent.AlphaBlendValue / 255;
  734.               EffB.MorphRect(Parent.ESc, kf, Rect(0, 0, B.Width, B.Height),
  735.                 ObjectRect.Left, ObjectRect.Top);
  736.             end;
  737.           EffB.Draw(Cnvs.Handle, ObjectRect.Left, ObjectRect.Top);
  738.           AB.Free;
  739.           EffB.Free;
  740.           EffAB.Free;
  741.         end;
  742.     end;
  743.   B.Free;
  744. end;
  745. //================TspSkinPopupWindow======================//
  746. constructor TspSkinPopupWindow.CreateEx;
  747. begin
  748.   inherited Create(AOwner);
  749.   ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable,
  750.                   csAcceptsControls];
  751.   ParentMenu := AParentMenu;
  752.   AlphaBlend := ParentMenu.AlphaBlend;
  753.   AlphaBlendValue := ParentMenu.AlphaBlendValue;
  754.   AlphaBlendAnimation := ParentMenu.AlphaBlendAnimation;
  755.   Ctl3D := False;
  756.   ParentCtl3D := False;
  757.   Visible := False;
  758.   ItemList := TList.Create;
  759.   MouseTimer := TTimer.Create(Self);
  760.   MouseTimer.Enabled := False;
  761.   MouseTimer.OnTimer := TestMouse;
  762.   MouseTimer.Interval := MouseTimerInterval;
  763.   MorphTimer := TTimer.Create(Self);
  764.   MorphTimer.Enabled := False;
  765.   MorphTimer.OnTimer := TestMorph;
  766.   MorphTimer.Interval := MorphTimerInterval;
  767.   FRgn := 0;
  768.   WindowPicture := nil;
  769.   MaskPicture := nil;
  770.   if (AData = nil) or (AData.WindowPictureIndex = -1)
  771.   then
  772.     begin
  773.       PW := nil;
  774.       SD := nil;
  775.     end
  776.   else
  777.     begin
  778.       PW := AData;
  779.       SD := ParentMenu.SkinData;
  780.       with PW do
  781.       begin
  782.         if (WindowPictureIndex <> - 1) and
  783.            (WindowPictureIndex < SD.FActivePictures.Count)
  784.         then
  785.           WindowPicture := SD.FActivePictures.Items[WindowPictureIndex];
  786.         if (MaskPictureIndex <> - 1) and
  787.            (MaskPictureIndex < SD.FActivePictures.Count)
  788.         then
  789.           MaskPicture := SD.FActivePictures.Items[MaskPictureIndex];
  790.       end;
  791.     end;
  792.   ActiveItem := -1;
  793.   OldActiveItem := -1;
  794.   OMX := -1;
  795.   OMY := -1;
  796.   Sc := TBitMap.Create;
  797.   Esc := nil;
  798.   WT := TTimer.Create(Self);
  799.   WT.Enabled := False;
  800.   WT.OnTimer := WTProc;
  801.   WT.Interval := 100;
  802.   DSMI := nil;
  803.   ScrollCode := 0;
  804. end;
  805. destructor TspSkinPopupWindow.Destroy;
  806. var
  807.   i: Integer;
  808. begin
  809.   for i := 0 to ItemList.Count - 1 do
  810.     TspSkinMenuItem(ItemList.Items[i]).Free;
  811.   ItemList.Clear;
  812.   ItemList.Free;
  813.   MouseTimer.Free;
  814.   MorphTimer.Free;
  815.   Sc.Free;
  816.   if Esc <> nil then Esc.Free;
  817.   inherited Destroy;
  818.   if FRgn <> 0 then DeleteObject(FRgn);
  819. end;
  820. function TspSkinPopupWindow.CanScroll;
  821. begin
  822.   Result := False;
  823.   case AScrollCode of
  824.     1: Result := VisibleStartIndex > 0;
  825.     2: Result := VisibleStartIndex + VisibleCount - 1 < ItemList.Count - 1;
  826.   end;
  827. end;
  828. procedure TspSkinPopupWindow.WMTimer;
  829. begin
  830.   inherited;
  831.   case ScrollCode of
  832.     1: if CanScroll(1) then ScrollUp(False) else StopScroll;
  833.     2: if CanScroll(2) then ScrollDown(False) else StopScroll;
  834.   end;
  835. end;
  836. procedure TspSkinPopupWindow.DrawUpMarker;
  837. var
  838.   R: TRect;
  839.   C: TColor;
  840. begin
  841.   if PW <> nil
  842.   then
  843.     begin
  844.       R := Rect(NewItemsRect.Left, NewItemsRect.Top,
  845.                 NewItemsRect.Right, NewItemsRect.Top + MarkerItemHeight);
  846.       if ScrollCode = 1
  847.       then C := PW.ScrollMarkerActiveColor
  848.       else C := PW.ScrollMarkerColor;
  849.     end
  850.   else
  851.     begin
  852.       R := Rect(3, 3, Width - 3, 3 + MarkerItemHeight);
  853.       if ScrollCode = 1
  854.       then C := clBtnText
  855.       else C := clBtnShadow;
  856.     end;  
  857.   DrawArrowImage(Cnvs, R, C, 3);
  858. end;
  859. procedure TspSkinPopupWindow.DrawDownMarker;
  860. var
  861.   R: TRect;
  862.   C: TColor;
  863. begin
  864.   if PW <> nil
  865.   then
  866.     begin
  867.       R := Rect(NewItemsRect.Left, NewItemsRect.Bottom - MarkerItemHeight,
  868.             NewItemsRect.Right, NewItemsRect.Bottom);
  869.       if ScrollCode = 2
  870.       then C := PW.ScrollMarkerActiveColor
  871.       else C := PW.ScrollMarkerColor;
  872.     end
  873.   else
  874.     begin
  875.       R := Rect(3, Height - MarkerItemHeight, Width - 3, Height - 3);
  876.       if ScrollCode = 2
  877.       then C := clBtnText
  878.       else C := clBtnShadow;
  879.     end;
  880.   DrawArrowImage(Cnvs, R, C, 4);
  881. end;
  882. procedure TspSkinPopupWindow.StartScroll;
  883. var
  884.   i: Integer;
  885. begin
  886.   i := ParentMenu.GetPWIndex(Self);
  887.   WT.Enabled := False;
  888.   ParentMenu.CloseMenu(i + 1);
  889.   KillTimer(Handle, 1);
  890.   SetTimer(Handle, 1, ScrollTimerInterval, nil);
  891. end;
  892. procedure TspSkinPopupWindow.StopScroll;
  893. begin
  894.   ScrollCode := 0;
  895.   DrawUpMarker(Canvas);
  896.   DrawDownMarker(Canvas);
  897.   KillTimer(Handle, 1);
  898. end;
  899. procedure TspSkinPopupWindow.ScrollUp;
  900. begin
  901.   if VisibleStartIndex > 0
  902.   then
  903.     begin
  904.       VisibleStartIndex := VisibleStartIndex - 1;
  905.       CalcItemRects;
  906.       RePaint;
  907.     end
  908.   else
  909.     if Cycle
  910.     then
  911.       begin
  912.         VisibleStartIndex := GetEndStartVisibleIndex;
  913.         CalcItemRects;
  914.         RePaint;
  915.       end;
  916. end;
  917. procedure TspSkinPopupWindow.ScrollDown(Cycle: Boolean);
  918. begin
  919.   if VisibleStartIndex + VisibleCount - 1 < ItemList.Count - 1
  920.   then
  921.     begin
  922.       VisibleStartIndex := VisibleStartIndex + 1;
  923.       CalcItemRects;
  924.       RePaint;
  925.     end
  926.   else
  927.     if Cycle
  928.     then
  929.       begin
  930.         VisibleStartIndex := 0;
  931.         CalcItemRects;
  932.         RePaint;
  933.       end;
  934. end;
  935. procedure TspSkinPopupWindow.PopupKeyDown(CharCode: Integer);
  936. var
  937.   PW: TspSkinPopupWindow;
  938.  procedure NextItem;
  939.  var
  940.    i, j: Integer;
  941.  begin
  942.    if Scroll and (ScrollCode = 0) and (ActiveItem = VisibleStartIndex + VisibleCount - 1)
  943.    then ScrollDown(True);
  944.    OldActiveItem := ActiveItem;
  945.    if ActiveItem < 0 then j := 0 else j := ActiveItem + 1;
  946.    if j = ItemList.Count then j := 0;
  947.    for i := j to ItemList.Count - 1 do
  948.      with TspSkinMenuItem(ItemList.Items[i]) do
  949.      begin
  950.        if MenuItem.Enabled and (MenuItem.Caption <> '-')
  951.        then
  952.          begin
  953.            ActiveItem := i;
  954.            Break;
  955.          end
  956.        else
  957.          begin
  958.            if Scroll and (ScrollCode = 0) and (i = VisibleStartIndex + VisibleCount - 1)
  959.            then ScrollDown(True);
  960.          end;
  961.      end;
  962.    if OldActiveItem <> ActiveItem
  963.    then
  964.      begin
  965.        if ActiveItem > -1 then
  966.        with TspSkinMenuItem(ItemList.Items[ActiveItem]) do
  967.        begin
  968.          MouseEnter(True);
  969.        end;
  970.        if OldActiveItem > -1 then
  971.        with TspSkinMenuItem(ItemList.Items[OldActiveItem]) do
  972.         begin
  973.           MouseLeave;
  974.         end;
  975.      end;
  976.  end;
  977.  procedure PriorItem;
  978.  var
  979.    i, j: Integer;
  980.  begin
  981.    if Scroll and (ScrollCode = 0) and (ActiveItem = VisibleStartIndex)
  982.    then ScrollUp(True);
  983.    OldActiveItem := ActiveItem;
  984.    if ActiveItem < 0 then j := ItemList.Count - 1 else j := ActiveItem - 1;
  985.    if (j = -1) then j := ItemList.Count - 1;
  986.    for i := j downto 0 do
  987.      with TspSkinMenuItem(ItemList.Items[i]) do
  988.      begin
  989.        if MenuItem.Enabled and (MenuItem.Caption <> '-')
  990.        then
  991.          begin
  992.            ActiveItem := i;
  993.            Break;
  994.          end
  995.        else
  996.          begin
  997.            if Scroll and (ScrollCode = 0) and  (i = VisibleStartIndex)
  998.            then ScrollUp(True);
  999.          end;
  1000.      end;
  1001.    if OldActiveItem <> ActiveItem
  1002.    then
  1003.      begin
  1004.        if ActiveItem > -1 then
  1005.        with TspSkinMenuItem(ItemList.Items[ActiveItem]) do
  1006.        begin
  1007.          MouseEnter(True);
  1008.        end;
  1009.        if OldActiveItem > -1 then
  1010.        with TspSkinMenuItem(ItemList.Items[OldActiveItem]) do
  1011.         begin
  1012.           MouseLeave;
  1013.         end;
  1014.      end;
  1015.  end;
  1016. function FindHotKeyItem: Boolean;
  1017. var
  1018.   i: Integer;
  1019. begin
  1020.   Result := False;
  1021.   for i := 0 to ItemList.Count - 1 do
  1022.       with TspSkinMenuItem(ItemList.Items[i]) do
  1023.       begin
  1024.         if Enabled and IsAccel(CharCode, MenuItem.Caption)
  1025.         then
  1026.           begin
  1027.             MouseEnter(False);
  1028.             OldActiveItem := ActiveItem;
  1029.             ActiveItem := i;
  1030.             if OldActiveItem <> -1
  1031.             then
  1032.               TspSkinMenuItem(ItemList.Items[OldActiveItem]).MouseLeave;
  1033.             MouseDown(0, 0);
  1034.             Result := True;
  1035.             Break;
  1036.           end;
  1037.       end
  1038. end;
  1039. begin
  1040.   if not Visible then Exit;
  1041.   if not FindHotKeyItem
  1042.   then 
  1043.   case CharCode of
  1044.     VK_DOWN:
  1045.       NextItem;
  1046.     VK_UP:
  1047.       PriorItem;
  1048.     VK_RIGHT:
  1049.       begin
  1050.         if ActiveItem <> -1
  1051.         then
  1052.           with TspSkinMenuItem(ItemList.Items[ActiveItem]) do
  1053.           begin
  1054.             if MenuItem.Count <> 0 then MouseDown(0, 0);
  1055.           end;
  1056.       end;
  1057.     VK_RETURN:
  1058.       begin
  1059.         if ActiveItem <> -1
  1060.         then
  1061.           with TspSkinMenuItem(ItemList.Items[ActiveItem]) do
  1062.           begin
  1063.             MouseDown(0, 0);
  1064.           end;
  1065.       end;
  1066.     VK_LEFT:
  1067.       begin
  1068.         if ParentMenu.FPopupList.Count > 1
  1069.         then
  1070.           begin
  1071.             ParentMenu.CloseMenu(ParentMenu.FPopupList.Count - 1);
  1072.             PW := TspSkinPopupWindow(ParentMenu.FPopupList.Items[ParentMenu.FPopupList.Count - 1]);
  1073.             if PW.ActiveItem <> -1
  1074.             then
  1075.               TspSkinMenuItem(PW.ItemList.Items[PW.ActiveItem]).Down := False;
  1076.           end
  1077.       end;
  1078.     VK_ESCAPE:
  1079.       begin
  1080.         ParentMenu.CloseMenu(ParentMenu.FPopupList.Count - 1);
  1081.         if ParentMenu.FPopupList.Count > 0
  1082.         then
  1083.           begin
  1084.             PW := TspSkinPopupWindow(ParentMenu.FPopupList.Items[ParentMenu.FPopupList.Count - 1]);
  1085.             if PW.ActiveItem <> -1
  1086.             then
  1087.               TspSkinMenuItem(PW.ItemList.Items[PW.ActiveItem]).Down := False;
  1088.           end;   
  1089.       end;
  1090.   end;
  1091. end;
  1092. procedure TspSkinPopupWindow.WTProc;
  1093. begin
  1094.   Sc.Width := Width + 1;
  1095.   Sc.Height := Height + 1;
  1096.   GetScreenImage(ShowX, ShowY, Sc);
  1097.   ESc := TspEffectBMP.CreateFromhWnd(Sc.Handle);
  1098.   //
  1099.   if (PW <> nil) and (PW.CursorIndex <> -1)
  1100.   then
  1101.     Cursor := SD.StartCursorIndex + PW.CursorIndex;
  1102.   //
  1103.   SetWindowPos(Handle, HWND_TOPMOST, ShowX, ShowY, 0, 0,
  1104.       SWP_NOACTIVATE or SWP_SHOWWINDOW or SWP_NOSIZE);
  1105.   Visible := True;
  1106.   MouseTimer.Enabled := True;
  1107.   if ItemList.Count > 0
  1108.   then
  1109.     begin
  1110.       ActiveItem := 0;
  1111.       TspSkinMenuItem(ItemList.Items[0]).MouseEnter(True);
  1112.     end;
  1113.   WT.Enabled := False;
  1114. end;
  1115. procedure TspSkinPopupWindow.UpDatePW;
  1116. var
  1117.   i: Integer;
  1118.   j: Integer;
  1119. begin
  1120.   j := ParentMenu.GetPWIndex(Self);
  1121.   if j + 1 < ParentMenu.FPopupList.Count
  1122.   then ParentMenu.CloseMenu(j + 1);
  1123.   for i := 0 to ItemList.Count - 1 do
  1124.     if TspSkinMenuItem(ItemList.Items[i]).Down
  1125.     then
  1126.       with TspSkinMenuItem(ItemList.Items[i]) do
  1127.       begin
  1128.         Down := False;
  1129.         ReDraw;
  1130.       end;
  1131. end;
  1132. procedure TspSkinPopupWindow.TestMorph;
  1133. var
  1134.   i: Integer;
  1135.   StopMorph: Boolean;
  1136. begin
  1137.   if PW = nil then Exit;
  1138.   StopMorph := True;
  1139.   for i := 0 to ItemList.Count  - 1 do
  1140.     with TspSkinMenuItem(ItemList.Items[i]) do
  1141.     begin
  1142.       if MI.Morphing and CanMorphing
  1143.       then
  1144.         begin
  1145.           DoMorphing;
  1146.           StopMorph := False;
  1147.         end;
  1148.     end;
  1149.   if StopMorph then MorphTimer.Enabled := False;
  1150. end;
  1151. procedure TspSkinPopupWindow.SetMenuWindowRegion;
  1152. var
  1153.   TempRgn: HRgn;
  1154. begin
  1155.   if PW = nil then Exit;
  1156.   TempRgn := FRgn;
  1157.   CreateSkinRegion
  1158.     (FRgn, PW.LTPoint, PW.RTPoint, PW.LBPoint, PW.RBPoint, PW.ItemsRect,
  1159.      NewLtPoint, NewRTPoint, NewLBPoint, NewRBPoint, NewItemsRect,
  1160.      MaskPicture, Width, Height);
  1161.   SetWindowRgn(Handle, FRgn, True);
  1162.   if TempRgn <> 0 then DeleteObject(TempRgn);
  1163. end;
  1164. procedure TspSkinPopupWindow.CreateRealImage;
  1165. var
  1166.   EB1: TspEffectBmp;
  1167.   Kf: Double;
  1168.   R: TRect;
  1169.   TextOffset: Integer;
  1170. begin
  1171.   if PW <> nil
  1172.   then
  1173.     CreateSkinImage(PW.LTPoint, PW.RTPoint, PW.LBPoint, PW.RBPoint,
  1174.       PW.ItemsRect, NewLTPoint, NewRTPoint, NewLBPoint, NewRBPoint,
  1175.       NewItemsRect, B, WindowPicture,
  1176.       Rect(0, 0, WindowPicture.Width, WindowPicture.Height),
  1177.       Width, Height, Scroll)
  1178.   else
  1179.     begin
  1180.       B.Width := Width;
  1181.       B.Height := Height;
  1182.       with B.Canvas do
  1183.       begin
  1184.         if ImgL = nil
  1185.         then TextOffset := 22
  1186.         else TextOffset := GlyphWidth + 3;
  1187.         R := Rect(0, 0, TextOffset, Height);
  1188.         Brush.Color := clBtnFace;
  1189.         FillRect(R);
  1190.         R := Rect(TextOffset, 0, Width, Height);
  1191.         Brush.Color := clWindow;
  1192.         FillRect(R);
  1193.       end;
  1194.       R := Rect(0, 0, Width, Height);
  1195.       Frame3D(B.Canvas, R, clBtnShadow, clBtnShadow, 1);
  1196.       Frame3D(B.Canvas, R, clWindow, clWindow, 1);
  1197.     end;
  1198.   if AlphaBlend and not CheckW2KWXP
  1199.   then
  1200.     begin
  1201.       EB1 := TspEffectBmp.CreateFromhWnd(B.Handle);
  1202.       kf := 1 - AlphaBlendValue / 255;
  1203.       EB1.MorphRect(ESc, kf, Rect(0, 0, B.Width, B.Height), 0, 0);
  1204.       EB1.Draw(B.Canvas.Handle, 0, 0);
  1205.       EB1.Free;
  1206.     end;
  1207. end;
  1208. procedure TspSkinPopupWindow.CreateMenu;
  1209. var
  1210.   sw, sh: Integer;
  1211.   i, j: Integer;
  1212.   Menu: TMenu;
  1213.   function CalcItemTextWidth(Item: TMenuItem): Integer;
  1214.   var
  1215.     R: TRect;
  1216.     MICaption: String;
  1217.   begin
  1218.    if Item.ShortCut <> 0
  1219.    then
  1220.      MICaption := Item.Caption + '  ' + ShortCutToText(Item.ShortCut)
  1221.    else
  1222.      MICaption := Item.Caption;
  1223.     R := Rect(0, 0, 0, 0);
  1224.     DrawText(Canvas.Handle, PChar(MICaption), Length(MICaption), R,
  1225.              DT_CALCRECT);
  1226.     Result := R.Right + 2;
  1227.   end;
  1228.   function GetMenuWindowHeight: Integer;
  1229.   var
  1230.     i, j, ih: integer;
  1231.   begin
  1232.     j := 0;
  1233.     for i := VisibleStartIndex to VisibleCount - 1 do
  1234.     with TspSkinMenuItem(ItemList.Items[i]) do
  1235.      begin
  1236.       if PW <> nil
  1237.       then
  1238.         begin
  1239.           if MenuItem.Caption = '-'
  1240.           then ih := RectHeight(DSMI.DividerRect)
  1241.           else ih := RectHeight(DSMI.SkinRect);
  1242.         end
  1243.       else
  1244.         begin
  1245.           if MenuItem.Caption = '-'
  1246.           then ih := 4
  1247.           else ih := ParentMenu.DefaultMenuItemHeight;
  1248.         end;
  1249.       inc(j, ih);
  1250.     end;
  1251.     if PW <> nil
  1252.     then
  1253.       Result := j + PW.ItemsRect.Top + (WindowPicture.Height - PW.ItemsRect.Bottom)
  1254.     else
  1255.       Result := j + 6;
  1256.   end;
  1257.   function GetMenuWindowWidth: Integer;
  1258.   var
  1259.     i, iw: Integer;
  1260.   begin
  1261.     iw := 0;
  1262.     for i := 0 to ItemList.Count - 1 do
  1263.     begin
  1264.       j := CalcItemTextWidth(TspSkinMenuItem(ItemList.Items[i]).MenuItem);
  1265.       if j > iw then iw := j;
  1266.     end;
  1267.     inc(iw, 16);
  1268.     if ImgL <> nil
  1269.     then
  1270.       GlyphWidth := ImgL.Width + 5
  1271.     else
  1272.       GlyphWidth := 16;
  1273.     Inc(iw, GlyphWidth);
  1274.     if PW <> nil
  1275.     then
  1276.       begin
  1277.         Inc(iw, DSMI.TextRct.Left);
  1278.         Inc(iw, RectWidth(DSMI.SkinRect) - DSMI.TextRct.Right);
  1279.         Result := iw + PW.ItemsRect.Left + (WindowPicture.Width - PW.ItemsRect.Right);
  1280.       end
  1281.     else
  1282.       Result := iw + 10;
  1283.   end;
  1284. procedure CalcSizes;
  1285. var
  1286.   W, H: Integer;
  1287. begin
  1288.   //
  1289.   VisibleStartIndex := 0;
  1290.   VisibleCount := ItemList.Count;
  1291.   W := GetMenuWindowWidth;
  1292.   H := GetMenuWindowHeight;
  1293.   Scroll := False;
  1294.   //
  1295.   if H > RectHeight(ParentMenu.WorkArea)
  1296.   then
  1297.     begin
  1298.       H := RectHeight(ParentMenu.WorkArea);
  1299.       Scroll := True;
  1300.     end;  
  1301.   //
  1302.   Width := W;
  1303.   Height := H;
  1304. end;
  1305. begin
  1306.   if SD <> nil
  1307.   then
  1308.     begin
  1309.       i := SD.GetIndex('MENUITEM');
  1310.       if i = -1 then i := SD.GetIndex('menuitem');
  1311.     end
  1312.   else
  1313.     i := -1;
  1314.   if (PW <> nil) and (i <> - 1)
  1315.   then
  1316.     begin
  1317.       // init menu
  1318.       DSMI := TspDataSkinMenuItem(SD.ObjectList.Items[i]);
  1319.       with Canvas.Font do
  1320.       begin
  1321.         Height := DSMI.FontHeight;
  1322.         Style := DSMI.FontStyle;
  1323.         Name := DSMI.FontName;
  1324.         CharSet := ParentMenu.FDefaultMenuItemFont.Charset;
  1325.       end;
  1326.     end
  1327.   else
  1328.     DSMI := nil;
  1329.   Menu := Item.GetParentMenu;
  1330.   ImgL := Menu.Images;
  1331.   j := Item.Count;
  1332.   for i := StartIndex to  j - 1 do
  1333.    if TMenuItem(Item.Items[i]).Visible
  1334.    then
  1335.     ItemList.Add(TspSkinMenuItem.Create(Self, TMenuItem(Item.Items[i]), DSMI));
  1336.   //
  1337.   CalcSizes;
  1338.   if PW <> nil
  1339.   then
  1340.     begin
  1341.       sw := WindowPicture.Width;
  1342.       sh := WindowPicture.Height;
  1343.       NewLTPoint := PW.LTPoint;
  1344.       NewRTPoint := Point(Width - (sw - PW.RTPoint.X), PW.RTPoint.Y);
  1345.       NewLBPoint := Point(PW.LBPoint.X, Height - (sh - PW.LBPoint.Y));
  1346.       NewRBPoint := Point(Width - (sw - PW.RBPoint.X),
  1347.                           Height - (sh - PW.RBPoint.Y));
  1348.       NewItemsRect := Rect(PW.ItemsRect.Left, PW.ItemsRect.Top,
  1349.                            Width - (sw - PW.ItemsRect.Right),
  1350.                            Height - (sh - PW.ItemsRect.Bottom));
  1351.     end
  1352.   else
  1353.     NewItemsRect := Rect(3, 3, Width - 3, Height - 3);
  1354.   CalcItemRects;
  1355.   if MaskPicture <> nil then SetMenuWindowRegion;
  1356. end;
  1357. function TspSkinPopupWindow.GetEndStartVisibleIndex: Integer;
  1358. var
  1359.   i, j, k, ih, H: Integer;
  1360. begin
  1361.   j := NewItemsRect.Bottom - MarkerItemHeight;
  1362.   H := MarkerItemHeight;
  1363.   k := 0;
  1364.   for i := ItemList.Count - 1 downto 0 do
  1365.   begin
  1366.     with TspSkinMenuItem(ItemList.Items[i]) do
  1367.      begin
  1368.        if DSMI <> nil
  1369.        then
  1370.          begin
  1371.            if MenuItem.Caption = '-'
  1372.            then ih := RectHeight(DSMI.DividerRect)
  1373.            else ih := RectHeight(DSMI.SkinRect);
  1374.          end
  1375.        else
  1376.          begin
  1377.            if MenuItem.Caption = '-'
  1378.            then ih := 4
  1379.            else ih := ParentMenu.DefaultMenuItemHeight;
  1380.          end;
  1381.        j := j - ih;
  1382.        if j >= H
  1383.        then
  1384.          inc(k)
  1385.        else
  1386.          Break;
  1387.      end;
  1388.   end;
  1389.   Result := ItemList.Count - k;
  1390. end;
  1391. procedure TspSkinPopupWindow.CalcItemRects;
  1392. var
  1393.   i, j, ih, H: Integer;
  1394. begin
  1395.   j := NewItemsRect.Top;
  1396.   H := NewItemsRect.Bottom;
  1397.   if Scroll
  1398.   then
  1399.     begin
  1400.       H := H - MarkerItemHeight;
  1401.       j := j + MarkerItemHeight;
  1402.     end;
  1403.   VisibleCount := 0;
  1404.   for i := VisibleStartIndex to ItemList.Count - 1 do
  1405.     with TspSkinMenuItem(ItemList.Items[i]) do
  1406.      begin
  1407.       if DSMI <> nil
  1408.       then
  1409.         begin
  1410.           if MenuItem.Caption = '-'
  1411.           then ih := RectHeight(DSMI.DividerRect)
  1412.           else ih := RectHeight(DSMI.SkinRect)
  1413.         end
  1414.       else
  1415.         begin
  1416.           if MenuItem.Caption = '-'
  1417.           then ih := 4
  1418.           else ih := ParentMenu.DefaultMenuItemHeight;
  1419.         end;
  1420.       ObjectRect.Left := NewItemsRect.Left;
  1421.       ObjectRect.Right := NewItemsRect.Right;
  1422.       ObjectRect.Top := j;
  1423.       ObjectRect.Bottom :=  j + ih;
  1424.       if ObjectRect.Bottom <= H
  1425.       then
  1426.         begin
  1427.           FVisible := True;
  1428.           Inc(VisibleCount)
  1429.         end
  1430.       else
  1431.         Break;
  1432.       inc(j, ih);
  1433.     end;
  1434.   if Scroll
  1435.   then
  1436.     begin
  1437.       if VisibleStartIndex > 0
  1438.       then
  1439.         for i := 0 to VisibleStartIndex - 1 do
  1440.           TspSkinMenuItem(ItemList.Items[i]).FVisible := False;
  1441.       if VisibleCount + VisibleStartIndex <= ItemList.Count - 1
  1442.       then
  1443.         for i := VisibleCount + VisibleStartIndex to ItemList.Count - 1 do
  1444.           TspSkinMenuItem(ItemList.Items[i]).FVisible := False;
  1445.     end;
  1446. end;
  1447. procedure TspSkinPopupWindow.CMMouseEnter;
  1448. begin
  1449.   inherited;
  1450. end;
  1451. procedure TspSkinPopupWindow.CMMouseLeave;
  1452. begin
  1453.   inherited;
  1454. end;
  1455. procedure TspSkinPopupWindow.CreateParams(var Params: TCreateParams);
  1456. begin
  1457.   inherited CreateParams(Params);
  1458.   with Params do
  1459.   begin
  1460.     Style := WS_POPUP;
  1461.     ExStyle := WS_EX_TOOLWINDOW;
  1462.     WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  1463.   end;
  1464. end;
  1465. procedure TspSkinPopupWindow.WMMouseActivate(var Message: TMessage);
  1466. begin
  1467.   Message.Result := MA_NOACTIVATE;
  1468. end;
  1469. procedure TspSkinPopupWindow.Hide;
  1470. begin
  1471.   SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
  1472.     SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  1473.   MouseTimer.Enabled := False;
  1474.   Visible := False;
  1475. end;
  1476. procedure TspSkinPopupWindow.Show;
  1477. procedure CalcMenuPos(var X, Y: Integer; R: TRect);
  1478. var
  1479.   WA: TRect;
  1480.   ChangeY: Boolean;
  1481.   function GetY: Integer;
  1482.   var
  1483.     Offset: Integer;
  1484.   begin
  1485.     if Scroll
  1486.     then
  1487.       Result := WA.Top
  1488.     else
  1489.       begin
  1490.         if PopupByItem
  1491.         then
  1492.           begin
  1493.             Offset := R.Top + Height - NewItemsRect.Top - WA.Bottom;
  1494.             if Offset > 0
  1495.             then
  1496.               begin
  1497.                 if R.Top < WA.Top + RectHeight(WA) div 2
  1498.                 then
  1499.                   Result := WA.Bottom - Height
  1500.                 else
  1501.                   begin
  1502.                     Result := R.Bottom - Height + NewItemsRect.Top;
  1503.                     if Result  < WA.Top then Result := WA.Top;
  1504.                   end
  1505.               end
  1506.             else
  1507.               Result := R.Top - NewItemsRect.Top;
  1508.           end
  1509.         else
  1510.           begin
  1511.             if PopupUp
  1512.             then
  1513.               begin
  1514.                 if R.Top - Height < WA.Top
  1515.                 then
  1516.                   begin
  1517.                     if R.Top < WA.Top + RectHeight(WA) div 2
  1518.                     then
  1519.                       begin
  1520.                         Result := R.Bottom;
  1521.                         Offset := Result + Height - WA.Bottom;
  1522.                         if Offset > 0
  1523.                         then
  1524.                           begin
  1525.                             Result  := Result - Offset;
  1526.                             ChangeY := True;
  1527.                           end;
  1528.                        end
  1529.                      else
  1530.                        begin
  1531.                          Result := WA.Top;
  1532.                          ChangeY := True;
  1533.                        end;
  1534.                   end
  1535.                 else
  1536.                   Result  := R.Top - Height;
  1537.               end
  1538.             else
  1539.               begin
  1540.                 Offset := R.Bottom + Height - WA.Bottom;
  1541.                 if Offset > 0
  1542.                 then
  1543.                   begin
  1544.                     if R.Top < WA.Top + RectHeight(WA) div 2
  1545.                     then
  1546.                       begin
  1547.                         Result := R.Bottom - Offset;
  1548.                         ChangeY := True
  1549.                       end
  1550.                     else
  1551.                       begin
  1552.                         if R.Top - Height < WA.Top
  1553.                         then
  1554.                           begin
  1555.                             Result := WA.Top;
  1556.                             ChangeY := True;
  1557.                           end
  1558.                         else
  1559.                           Result := R.Top - Height;
  1560.                       end
  1561.                   end
  1562.                 else
  1563.                   Result := R.Bottom;
  1564.               end;
  1565.           end;
  1566.       end;
  1567.   end;
  1568.   function GetX: Integer;
  1569.   begin
  1570.     if PopupByItem or Scroll or ChangeY
  1571.     then
  1572.       begin
  1573.         if R.Right + Width + 1 > WA.Right
  1574.         then Result := R.Left - Width - 1 else Result := R.Right + 1;
  1575.       end
  1576.     else
  1577.       begin
  1578.         if R.Left + Width > WA.Right
  1579.         then Result := WA.Right - Width else
  1580.         if R.Left < WA.Left then Result := WA.Left else Result := R.Left;
  1581.       end;
  1582.   end;
  1583. begin
  1584.   WA := ParentMenu.WorkArea;
  1585.   ChangeY := False;
  1586.   Y := GetY;
  1587.   X := GetX;
  1588. end;
  1589. const
  1590.   WS_EX_LAYERED = $80000;
  1591. var
  1592.   i: Integer;
  1593.   ABV: Byte;
  1594. begin
  1595.   if CheckW2KWXP and ParentMenu.AlphaBlend and ParentMenu.AlphaBlendAnimation and
  1596.      ParentMenu.First
  1597.   then
  1598.     Application.ProcessMessages;
  1599.   CreateMenu(AItem, StartIndex);
  1600.   CalcMenuPos(ShowX, ShowY, R);
  1601.   if AlphaBlend and not CheckW2KWXP
  1602.   then
  1603.     WT.Enabled := True
  1604.   else
  1605.     begin
  1606.       //
  1607.       if (PW <> nil) and (PW.CursorIndex <> -1)
  1608.       then
  1609.         Cursor := SD.StartCursorIndex + PW.CursorIndex;
  1610.       //
  1611.       if CheckW2KWXP and ParentMenu.AlphaBlend
  1612.       then
  1613.         begin
  1614.           SetWindowLong(Handle, GWL_EXSTYLE,
  1615.                         GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
  1616.           if ParentMenu.First and ParentMenu.AlphaBlendAnimation
  1617.           then SetAlphaBlendTransparent(Handle, 0)
  1618.           else SetAlphaBlendTransparent(Handle, ParentMenu.AlphaBlendValue);
  1619.         end;
  1620.       //
  1621.       SetWindowPos(Handle, HWND_TOPMOST, ShowX, ShowY, 0, 0,
  1622.       SWP_NOACTIVATE or SWP_SHOWWINDOW or SWP_NOSIZE);
  1623.       Visible := True;
  1624.       //
  1625.       if CheckW2KWXP and ParentMenu.AlphaBlend and ParentMenu.AlphaBlendAnimation and
  1626.          ParentMenu.First
  1627.       then
  1628.         begin
  1629.           i := 0;
  1630.           ABV := ParentMenu.AlphaBlendValue;
  1631.           repeat
  1632.             Inc(i, 2);
  1633.             if i > ABV then i := ABV;
  1634.             SetAlphaBlendTransparent(Handle, i);
  1635.           until i >= ABV;
  1636.         end;
  1637.       //
  1638.       MouseTimer.Enabled := True;
  1639.       ActiveItem := -1;
  1640.       if ItemList.Count > 0
  1641.       then
  1642.         for i := 0 to ItemList.Count - 1 do
  1643.         with TspSkinMenuItem(ItemList.Items[i]) do
  1644.         begin
  1645.           if MenuItem.Enabled
  1646.           then
  1647.             begin
  1648.               ActiveItem := i;
  1649.               MouseEnter(True);
  1650.               Break;
  1651.             end;
  1652.         end;
  1653.       //
  1654.     end;
  1655. end;
  1656. procedure TspSkinPopupWindow.PaintMenu;
  1657. var
  1658.   C: TCanvas;
  1659.   i: Integer;
  1660.   B: TBitMap;
  1661. begin
  1662.   C := TCanvas.Create;
  1663.   C.Handle := DC;
  1664.   B := TBitMap.Create;
  1665.   CreateRealImage(B);
  1666.   // Draw items
  1667.   for i := VisibleStartIndex to VisibleStartIndex + VisibleCount - 1 do
  1668.     TspSkinMenuItem(ItemList.Items[i]).Draw(B.Canvas);
  1669.   // markers
  1670.   if Scroll
  1671.   then
  1672.     begin
  1673.       DrawUpMarker(B.Canvas);
  1674.       DrawDownMarker(B.Canvas);
  1675.     end;
  1676.   C.Draw(0, 0, B);
  1677.   B.Free;
  1678.   C.Free;
  1679. end;
  1680. procedure TspSkinPopupWindow.WMEraseBkgrnd;
  1681. begin
  1682.   PaintMenu(Message.WParam);
  1683. end;
  1684. procedure TspSkinPopupWindow.MouseUp;
  1685. begin
  1686.   TestActive(X, Y);
  1687.   if (ActiveItem <> -1) and (Button = mbleft) and GetActive(X, Y)
  1688.   then
  1689.     with TspSkinMenuItem(ItemList.Items[ActiveItem]) do
  1690.      if MenuItem.Caption <> '-' then MouseDown(X, Y);
  1691. end;
  1692. procedure TspSkinPopupWindow.TestMouse;
  1693. var
  1694.   P, P1: TPoint;
  1695. begin
  1696.   GetCursorPos(P1);
  1697.   P := ScreenToClient(P1);
  1698.   if (OMX <> P.X) or (OMY <> P.Y)
  1699.   then 
  1700.     if InWindow(P1)
  1701.     then
  1702.       TestActive(P.X, P.Y)
  1703.     else
  1704.       if Scroll
  1705.       then
  1706.         begin
  1707.           ScrollCode := 0;
  1708.           DrawUpMarker(Canvas);
  1709.           DrawDownMarker(Canvas);
  1710.         end;
  1711.   OMX := P.X;
  1712.   OMY := P.Y;
  1713. end;
  1714. function TspSkinPopupWindow.GetActive;
  1715. var
  1716.   i: Integer;
  1717. begin
  1718.   i := -1;
  1719.   if ItemList.Count = 0
  1720.   then
  1721.     Result := False
  1722.   else
  1723.   repeat
  1724.     Inc(i);
  1725.     with TspSkinMenuItem(ItemList.Items[i]) do
  1726.       Result := FVisible and PtInRect(ObjectRect, Point(X, Y));
  1727.   until Result or (i = ItemList.Count - 1);
  1728. end;
  1729. procedure TspSkinPopupWindow.TestActive;
  1730. var
  1731.   i: Integer;
  1732.   B: Boolean;
  1733.   R1, R2: TRect;
  1734. begin
  1735.   if Scroll
  1736.   then
  1737.     begin
  1738.       R1 := Rect(NewItemsRect.Left, NewItemsRect.Top,
  1739.             NewItemsRect.Right, NewItemsRect.Top + MarkerItemHeight);
  1740.       R2 := Rect(NewItemsRect.Left, NewItemsRect.Bottom - MarkerItemHeight,
  1741.             NewItemsRect.Right, NewItemsRect.Bottom);
  1742.       if PtInRect(R1, Point(X, Y)) and (ScrollCode = 0) and CanScroll(1)
  1743.       then
  1744.         begin
  1745.           ScrollCode := 1;
  1746.           DrawUpMarker(Canvas);
  1747.           StartScroll;
  1748.         end
  1749.       else
  1750.       if PtInRect(R2, Point(X, Y)) and (ScrollCode = 0)  and CanScroll(2)
  1751.       then
  1752.         begin
  1753.           ScrollCode := 2;
  1754.           DrawDownMarker(Canvas);
  1755.           StartScroll;
  1756.         end
  1757.       else
  1758.         if (ScrollCode <> 0) and not PtInRect(R1, Point(X, Y)) and
  1759.                                  not PtInRect(R2, Point(X, Y))
  1760.         then
  1761.           StopScroll;
  1762.      end;
  1763.   if (ItemList.Count = 0) then Exit;
  1764.   OldActiveItem := ActiveItem;
  1765.   i := -1;
  1766.   repeat
  1767.     Inc(i);
  1768.     with TspSkinMenuItem(ItemList.Items[i]) do
  1769.     begin
  1770.       B := FVisible and PtInRect(ObjectRect, Point(X, Y));
  1771.     end;
  1772.   until B or (i = ItemList.Count - 1);
  1773.   if B then ActiveItem := i;
  1774.   if OldActiveItem >= ItemList.Count then OldActiveItem := -1;
  1775.   if ActiveItem >= ItemList.Count then ActiveItem := -1;
  1776.   if (OldActiveItem <> ActiveItem)
  1777.   then
  1778.     begin
  1779.       if OldActiveItem <> - 1
  1780.       then
  1781.         with TspSkinMenuItem(ItemList.Items[OldActiveItem]) do
  1782.         begin
  1783.           if MenuItem.Enabled and (MenuItem.Caption <> '-')
  1784.           then
  1785.             MouseLeave;
  1786.         end;
  1787.       if ActiveItem <> - 1
  1788.       then
  1789.         with TspSkinMenuItem(ItemList.Items[ActiveItem]) do
  1790.         begin
  1791.           if MenuItem.Enabled and (MenuItem.Caption <> '-')
  1792.           then
  1793.             MouseEnter(False);
  1794.         end;
  1795.     end;
  1796. end;
  1797. function TspSkinPopupWindow.InWindow;
  1798. var
  1799.   H: HWND;
  1800. begin
  1801.   H := WindowFromPoint(P);
  1802.   Result := H = Handle;
  1803. end;
  1804. //====================TspSkinMenu===================//
  1805. constructor TspSkinMenu.CreateEx;
  1806. begin
  1807.   inherited Create(AOwner);
  1808.   FPopupList := TList.Create;
  1809.   WaitTimer := TTimer.Create(Self);
  1810.   WaitTimer.Enabled := False;
  1811.   WaitTimer.OnTimer := WaitItem;
  1812.   WaitTimer.Interval := WaitTimerInterval;
  1813.   WItem := nil;
  1814.   FVisible := False;
  1815.   FForm := AForm;
  1816.   AlphaBlend := False;
  1817.   AlphaBlendValue := 200;
  1818.   PopupCtrl := nil;
  1819.   FDefaultMenuItemHeight := 20;
  1820.   FDefaultMenuItemFont := TFont.Create;
  1821.   with FDefaultMenuItemFont do
  1822.   begin
  1823.     Name := 'Arial';
  1824.     Style := [];
  1825.     Height := 14;
  1826.   end;
  1827. end;
  1828. destructor TspSkinMenu.Destroy;
  1829. begin
  1830.   CloseMenu(0);
  1831.   FPopupList.Free;
  1832.   WaitTimer.Free;
  1833.   FDefaultMenuItemFont.Free;
  1834.   inherited Destroy;
  1835. end;
  1836. procedure TspSkinMenu.SetDefaultMenuItemFont(Value: TFont);
  1837. begin
  1838.   FDefaultMenuItemFont.Assign(Value);
  1839. end;
  1840. function TspSkinMenu.GetWorkArea;
  1841. var
  1842.   R: TRect;
  1843. begin
  1844.   SystemParametersInfo(SPI_GETWORKAREA, 0, @R, 0);
  1845.   Result := R;
  1846. end;
  1847. procedure TspSkinMenu.WaitItem(Sender: TObject);
  1848. begin
  1849.   if WItem <> nil then CheckItem(WItem.Parent, WItem, True, False);
  1850.   WaitTimer.Enabled := False;
  1851. end;
  1852. function TspSkinMenu.GetPWIndex;
  1853. var
  1854.   i: Integer;
  1855. begin
  1856.   for i := 0 to FPopupList.Count - 1 do
  1857.     if PW = TspSkinPopupWindow(FPopupList.Items[i]) then Break;
  1858.   Result := i;
  1859. end;
  1860. procedure TspSkinMenu.CheckItem;
  1861. var
  1862.   Menu: TMenu;
  1863.   MenuI: TMenuItem;
  1864.   i: Integer;
  1865.   R: TRect;
  1866. begin
  1867.   if (MI.MenuItem.Count = 0) and not Down
  1868.   then
  1869.     begin
  1870.       WaitTimer.Enabled := False;
  1871.       WItem := nil;
  1872.       i := GetPWIndex(PW);
  1873.       if i < FPopupList.Count - 1 then CloseMenu(i + 1);
  1874.     end
  1875.   else
  1876.   if (MI.MenuItem.Count = 0) and Down
  1877.   then
  1878.     begin
  1879.       WaitTimer.Enabled := False;
  1880.       WItem := nil;
  1881.       MenuI := MI.MenuItem;
  1882.       Hide;
  1883.       Menu := MenuI.GetParentMenu;
  1884.       Menu.DispatchCommand(MenuI.Command);
  1885.     end
  1886.   else
  1887.   if (MI.MenuItem.Count <> 0) and not Down and not Kb
  1888.   then
  1889.     begin
  1890.       WaitTimer.Enabled := False;
  1891.       WItem := nil;
  1892.       i := GetPWIndex(PW);
  1893.       if i < FPopupList.Count - 1 then CloseMenu(i + 1);
  1894.       WItem := MI;
  1895.       WaitTimer.Enabled := True;
  1896.     end
  1897.   else
  1898.   if (MI.MenuItem.Count <> 0) and Down
  1899.   then
  1900.     begin
  1901.       //
  1902.       MenuI := MI.MenuItem;
  1903.       Menu := MenuI.GetParentMenu;
  1904.       Menu.DispatchCommand(MenuI.Command);
  1905.       //
  1906.       WaitTimer.Enabled := False;
  1907.       WItem := nil;
  1908.       MI.Down := True;
  1909.       R.Left := PW.Left + MI.ObjectRect.Left;
  1910.       R.Top := PW.Top + MI.ObjectRect.Top;
  1911.       R.Right := PW.Left + MI.ObjectRect.Right;
  1912.       R.Bottom := PW.Top + MI.ObjectRect.Bottom;
  1913.       PopupSub(R, MI.MenuItem, 0, True, False);
  1914.     end
  1915. end;
  1916. procedure TspSkinMenu.Popup;
  1917. begin
  1918.   FFirst := not FVisible;
  1919.   PopupCtrl := APopupCtrl;
  1920.   if FPopupList.Count <> 0 then CloseMenu(0);
  1921.   WorkArea := GetWorkArea;
  1922.   SkinData := ASkinData;
  1923.   if (AItem.Count = 0) then Exit;
  1924.   FVisible := True;
  1925.   PopupSub(R, AItem, StartIndex, False, PopupUp);
  1926.   FFirst := False;
  1927. end;
  1928. procedure TspSkinMenu.PopupSub;
  1929. begin
  1930.   if (SkinData = nil) or (SkinData.Empty)
  1931.   then
  1932.     FPopupList.Add(TspSkinPopupWindow.CreateEx(Self, Self, nil))
  1933.   else
  1934.     FPopupList.Add(TspSkinPopupWindow.CreateEx(Self, Self, SkinData.PopupWindow));
  1935.   with TspSkinPopupWindow(FPopupList.Items[FPopupList.Count - 1]) do
  1936.     Show(R, AItem, StartIndex, PopupByItem, PopupUp);
  1937. end;
  1938. procedure TspSkinMenu.CloseMenu;
  1939. var
  1940.   i: Integer;
  1941. begin
  1942.   for i := FPopupList.Count - 1 downto EndIndex do
  1943.   begin
  1944.     TspSkinPopupWindow(FPopupList.Items[i]).Free;
  1945.     FPopupList.Delete(i);
  1946.   end;
  1947.   if EndIndex = 0
  1948.   then
  1949.     begin
  1950.       WaitTimer.Enabled := False;
  1951.       FVisible := False;
  1952.       if PopupCtrl <> nil
  1953.       then
  1954.         begin
  1955.           if PopupCtrl is TWinControl
  1956.           then
  1957.             SendMessage(TWinControl(PopupCtrl).Handle, WM_CLOSESKINMENU, 0, 0)
  1958.           else
  1959.             PopupCtrl.Perform(WM_CLOSESKINMENU, 0, 0);
  1960.           PopupCtrl := nil;
  1961.         end;
  1962.     end;
  1963. end;
  1964. procedure TspSkinMenu.Hide;
  1965. begin
  1966.   CloseMenu(0);
  1967.   WaitTimer.Enabled := False;
  1968.   WItem := nil;
  1969.   if FForm <> nil then
  1970.   SendMessage(FForm.Handle, WM_CLOSESKINMENU, 0, 0);
  1971.   if PopupCtrl <> nil
  1972.   then
  1973.     begin
  1974.       if PopupCtrl is TWinControl
  1975.       then
  1976.         SendMessage(TWinControl(PopupCtrl).Handle, WM_CLOSESKINMENU, 0, 0)
  1977.        else
  1978.          PopupCtrl.Perform(WM_CLOSESKINMENU, 0, 0);
  1979.       PopupCtrl := nil;
  1980.     end;
  1981. end;
  1982. //============= TspSkinPopupMenu =============//
  1983. function FindDSFComponent(AForm: TForm): TSpDynamicSkinForm;
  1984. var
  1985.   i: Integer;
  1986. begin
  1987.   Result := nil;
  1988.   for i := 0 to AForm.ComponentCount - 1 do
  1989.    if AForm.Components[i] is TspDynamicSkinForm
  1990.    then
  1991.      begin
  1992.        Result := TspDynamicSkinForm(AForm.Components[i]);
  1993.        Break;
  1994.      end;
  1995. end;
  1996. constructor TspSkinPopupMenu.Create;
  1997. begin
  1998.   inherited Create(AOwner);
  1999.   FComponentForm := nil;
  2000.   FSD := nil;
  2001. end;
  2002. procedure TspSkinPopupMenu.Notification;
  2003. begin
  2004.   inherited Notification(AComponent, Operation);
  2005.   if (Operation = opRemove) and (AComponent = FSD) then FSD := nil;
  2006. end;
  2007. procedure TspSkinPopupMenu.PopupFromRect;
  2008. var
  2009.   DSF: TspDynamicSkinForm;
  2010. begin
  2011.   if Assigned(OnPopup) then OnPopup(Self);
  2012.   if FComponentForm = nil
  2013.   then
  2014.     begin
  2015.       //DSF := FindDSFComponent(TForm(Owner))
  2016.       if Owner.InheritsFrom(TForm) then
  2017.         DSF := FindDSFComponent(TForm(Owner)) else
  2018.          if Owner.Owner.InheritsFrom(TForm) then
  2019.          DSF := FindDSFComponent(TForm(Owner.Owner)) else
  2020.            DSF := nil;
  2021.     end
  2022.   else
  2023.     DSF := FindDSFComponent(FComponentForm);
  2024.   if (DSF <> nil) and (FSD = nil)
  2025.   then
  2026.     if DSF.MenusSkinData = nil
  2027.     then
  2028.       FSD := DSF.SkinData
  2029.     else
  2030.       FSD := DSF.MenusSkinData;
  2031.   if DSF <> nil
  2032.   then
  2033.     begin
  2034.       DSF.SkinMenuOpen;
  2035.       DSF.SkinMenu.Popup(nil, FSD, 0, R, Items, APopupUp);
  2036.     end;
  2037. end;
  2038. procedure TspSkinPopupMenu.Popup;
  2039. var
  2040.   DSF: TspDynamicSkinForm;
  2041. var
  2042.   R: TRect;
  2043. begin
  2044.   if Assigned(OnPopup) then OnPopup(Self);
  2045.   if FComponentForm = nil
  2046.   then
  2047.     begin
  2048.       //DSF := FindDSFComponent(TForm(Owner))
  2049.       if Owner.InheritsFrom(TForm) then
  2050.         DSF := FindDSFComponent(TForm(Owner)) else
  2051.          if Owner.Owner.InheritsFrom(TForm) then
  2052.          DSF := FindDSFComponent(TForm(Owner.Owner)) else
  2053.            DSF := nil;
  2054.     end
  2055.   else
  2056.     DSF := FindDSFComponent(FComponentForm);
  2057.   if (DSF <> nil) and (FSD = nil)
  2058.   then
  2059.     if DSF.MenusSkinData = nil
  2060.     then
  2061.       FSD := DSF.SkinData
  2062.     else
  2063.       FSD := DSF.MenusSkinData;
  2064.   if DSF <> nil
  2065.   then
  2066.     begin
  2067.       DSF.SkinMenuOpen;
  2068.       R := Rect(X, Y, X, Y);
  2069.       DSF.SkinMenu.Popup(nil, FSD, 0, R, Items, False);
  2070.     end;
  2071. end;
  2072. procedure TspSkinPopupMenu.PopupFromRect2;
  2073. var
  2074.   DSF: TspDynamicSkinForm;
  2075. begin
  2076.   if Assigned(OnPopup) then OnPopup(Self);
  2077.   if FComponentForm = nil
  2078.   then
  2079.     begin
  2080.       //DSF := FindDSFComponent(TForm(Owner))
  2081.       if Owner.InheritsFrom(TForm) then
  2082.         DSF := FindDSFComponent(TForm(Owner)) else
  2083.          if Owner.Owner.InheritsFrom(TForm) then
  2084.          DSF := FindDSFComponent(TForm(Owner.Owner)) else
  2085.            DSF := nil;
  2086.     end
  2087.   else
  2088.     DSF := FindDSFComponent(FComponentForm);
  2089.   if (DSF <> nil) and (FSD = nil)
  2090.   then
  2091.     if DSF.MenusSkinData = nil
  2092.     then
  2093.       FSD := DSF.SkinData
  2094.     else
  2095.       FSD := DSF.MenusSkinData;
  2096.   if DSF <> nil
  2097.   then
  2098.     begin
  2099.       DSF.SkinMenuOpen;
  2100.       DSF.SkinMenu.Popup(ACtrl, FSD, 0, R, Items, APopupUp);
  2101.     end;
  2102. end;
  2103. procedure TspSkinPopupMenu.Popup2;
  2104. var
  2105.   R: TRect;
  2106.   DSF: TspDynamicSkinForm;
  2107. begin
  2108.   if Assigned(OnPopup) then OnPopup(Self);
  2109.   if FComponentForm = nil
  2110.   then
  2111.     begin
  2112.       //DSF := FindDSFComponent(TForm(Owner))
  2113.       if Owner.InheritsFrom(TForm) then
  2114.         DSF := FindDSFComponent(TForm(Owner)) else
  2115.          if Owner.Owner.InheritsFrom(TForm) then
  2116.          DSF := FindDSFComponent(TForm(Owner.Owner)) else
  2117.            DSF := nil;
  2118.     end
  2119.   else
  2120.     DSF := FindDSFComponent(FComponentForm);
  2121.   if (DSF <> nil) and (FSD = nil)
  2122.   then
  2123.     if DSF.MenusSkinData = nil
  2124.     then
  2125.       FSD := DSF.SkinData
  2126.     else
  2127.       FSD := DSF.MenusSkinData;
  2128.   if (DSF <> nil) and (FSD <> nil)
  2129.   then
  2130.     begin
  2131.       DSF.SkinMenuOpen;
  2132.       R := Rect(X, Y, X, Y);
  2133.       DSF.SkinMenu.Popup(ACtrl, FSD, 0, R, Items, False);
  2134.     end;
  2135. end;
  2136. end.