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

Delphi控件源码

开发平台:

Delphi

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