Componentes.Terceros.DevExp.../official/x.19/ExpressQuantumGrid 5/Sources/cxGridStdPopupMenu.pas
2007-09-09 11:27:22 +00:00

511 lines
17 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressQuantumGrid Utils }
{ }
{ Copyright (c) 1998-2006 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
{ LICENSED TO DISTRIBUTE THE EXPRESSQUANTUMGRID AND ALL }
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{********************************************************************}
unit cxGridStdPopupMenu;
{$I cxVer.inc}
interface
uses
{$IFNDEF DELPHI5}
cxClasses,
{$ENDIF}
Windows, Classes, Menus, cxGridMenuOperations, cxGridCustomPopupMenu,
cxGridFooterPopupMenuItems, cxGridHeaderPopupMenuItems, cxGridCustomView,
Graphics, ImgList;
type
TPopupMenuClass = class of TPopupMenu;
{ TcxMenuItem }
TcxMenuItem = class(TMenuItem)
end;
TStdGridPopupMenu = class(TPopupMenu, IDoPopup)
private
procedure InitItems(AItems: TMenuItem);
protected
{$IFDEF DELPHI7} {$IFDEF VCL}
procedure AdvancedDrawItemD7(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; State: TOwnerDrawState); virtual;
{$ENDIF} {$ENDIF}
procedure ClearOperations;
procedure CreateMenuItems; virtual;
{$IFDEF DELPHI5}
procedure DoPopup(Sender: TObject); override;
{$ENDIF}
procedure GridMenuPopup(ASenderMenu: TComponent;
AHitTest: TcxCustomGridHitTest; X,Y: Integer); virtual;
function GetPopupHandler: TcxGridOnPopupProc; virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{$IFNDEF DELPHI5}
procedure Popup(X, Y: Integer); override;
{$ENDIF}
end;
TcxGridStdHeaderMenu = class(TStdGridPopupMenu);
TcxGridStdFooterMenu = class(TStdGridPopupMenu);
implementation
uses
Dialogs, SysUtils, cxGridTableView;
{ TStdGridPopupMenu }
constructor TStdGridPopupMenu.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Images := cxGridPopupMenuImages;
CreateMenuItems;
end;
destructor TStdGridPopupMenu.Destroy;
begin
ClearOperations;
{$IFDEF DELPHI5}
Items.Clear;
{$ELSE}
while Items.Count > 0 do
Items[0].Free;
{$ENDIF}
inherited;
end;
{$IFDEF DELPHI7}
procedure TStdGridPopupMenu.AdvancedDrawItemD7(Sender: TObject;
ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState);
const
Alignments: array[TPopupAlignment] of Word = (DT_LEFT, DT_RIGHT, DT_CENTER);
EdgeStyle: array[Boolean] of Longint = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
var
ImageList: TCustomImageList;
ParentMenu: TMenu;
Alignment: TPopupAlignment;
DrawImage, DrawGlyph: Boolean;
GlyphRect, SaveRect: TRect;
DrawStyle: Longint;
OldBrushColor: TColor;
Selected: Boolean;
procedure NormalDraw;
var
AMenuItem: TcxMenuItem;
begin
AMenuItem := TcxMenuItem(Sender);
with ACanvas do
begin
if (odSelected in State) or (odHotLight in State) then
begin
Brush.Color := {$IFDEF VCL}clMenuHighlight{$ELSE}clHighlight{$ENDIF};
Font.Color := clHighlightText;
end;
{ With XP, we need to always fill in the rect, even when selected }
FillRect(ARect);
if ParentMenu is TMenu then
Alignment := paLeft
else if ParentMenu is TPopupMenu then
Alignment := TPopupMenu(ParentMenu).Alignment
else
Alignment := paLeft;
GlyphRect.Left := ARect.Left + 1;
GlyphRect.Top := ARect.Top + 1;
if AMenuItem.Caption = cLineCaption then
begin
FillRect(ARect);
GlyphRect.Left := 0;
GlyphRect.Right := -4;
DrawGlyph := False;
end
else
begin
DrawImage := (ImageList <> nil) and ((AMenuItem.ImageIndex > -1) and
(AMenuItem.ImageIndex < ImageList.Count));
if DrawImage then
begin
DrawGlyph := True;
GlyphRect.Right := GlyphRect.Left + ImageList.Width;
GlyphRect.Bottom := GlyphRect.Top + ImageList.Height;
{ Draw background pattern brush if selected }
if AMenuItem.Checked then
begin
Inc(GlyphRect.Right);
Inc(GlyphRect.Bottom);
OldBrushColor := Brush.Color;
if not (odSelected in State) then
begin
OldBrushColor := Brush.Color;
Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
FillRect(GlyphRect);
end
else
begin
Brush.Color := clBtnFace;
FillRect(GlyphRect);
end;
Brush.Color := OldBrushColor;
Inc(GlyphRect.Left);
Inc(GlyphRect.Top);
end;
ImageList.Draw(ACanvas, GlyphRect.Left, GlyphRect.Top,
AMenuItem.ImageIndex, AMenuItem.Enabled);
if AMenuItem.Checked then
begin
Dec(GlyphRect.Right);
Dec(GlyphRect.Bottom);
end;
end
else
begin
if (ImageList <> nil) then
begin
GlyphRect.Right := GlyphRect.Left + ImageList.Width;
GlyphRect.Bottom := GlyphRect.Top + ImageList.Height;
end;
DrawGlyph := False;
end;
end;
with GlyphRect do
begin
Dec(Left);
Dec(Top);
Inc(Right, 2);
Inc(Bottom, 2);
end;
if AMenuItem.Checked and DrawGlyph then
DrawEdge(ACanvas.Handle, GlyphRect, EdgeStyle[AMenuItem.Checked], BF_RECT);
if Selected then
begin
if DrawGlyph then ARect.Left := GlyphRect.Right + 1;
Brush.Color := clHighlight;
FillRect(ARect);
end;
if not (Selected and DrawGlyph) then
ARect.Left := GlyphRect.Right + 1;
Inc(ARect.Left, 2);
Dec(ARect.Right, 1);
DrawStyle := DT_EXPANDTABS or DT_SINGLELINE or Alignments[Alignment];
{ Calculate vertical layout }
SaveRect := ARect;
if odDefault in State then
Font.Style := [fsBold];
AMenuItem.DoDrawText(ACanvas, AMenuItem.Caption, ARect,
Selected, DrawStyle or DT_CALCRECT or DT_NOCLIP);
OffsetRect(ARect, 0, ((SaveRect.Bottom - SaveRect.Top) - (ARect.Bottom - ARect.Top)) div 2);
AMenuItem.DoDrawText(ACanvas, AMenuItem.Caption, ARect, Selected, DrawStyle);
if AMenuItem.ShortCut <> 0 then
begin
ARect.Left := ARect.Right;
ARect.Right := SaveRect.Right - 10;
AMenuItem.DoDrawText(ACanvas, ShortCutToText(AMenuItem.ShortCut), ARect, Selected, DT_RIGHT);
end;
end;
end;
procedure BiDiDraw;
var
AMenuItem: TcxMenuItem;
S: string;
begin
AMenuItem := TcxMenuItem(Sender);
with ACanvas do
begin
if (odSelected in State) or (odHotLight in State) then
begin
Brush.Color := clMenuHighlight;
Font.Color := clHighlightText;
end;
FillRect(ARect);
if ParentMenu is TMenu then
Alignment := paLeft
else if ParentMenu is TPopupMenu then
Alignment := TPopupMenu(ParentMenu).Alignment
else
Alignment := paLeft;
GlyphRect.Right := ARect.Right - 1;
GlyphRect.Top := ARect.Top + 1;
if AMenuItem.Caption = cLineCaption then
begin
FillRect(ARect);
GlyphRect.Left := GlyphRect.Right + 2;
GlyphRect.Right := 0;
DrawGlyph := False;
end
else
begin
DrawImage := (ImageList <> nil) and ((AMenuItem.ImageIndex > -1) and
(AMenuItem.ImageIndex < ImageList.Count));
if DrawImage then
begin
DrawGlyph := True;
GlyphRect.Left := GlyphRect.Right - ImageList.Width;
GlyphRect.Bottom := GlyphRect.Top + ImageList.Height;
{ Draw background pattern brush if selected }
if AMenuItem.Checked then
begin
Dec(GlyphRect.Left);
Inc(GlyphRect.Bottom);
OldBrushColor := Brush.Color;
if not (odSelected in State) then
begin
OldBrushColor := Brush.Color;
Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
FillRect(GlyphRect);
end
else
begin
Brush.Color := clBtnFace;
FillRect(GlyphRect);
end;
Brush.Color := OldBrushColor;
Dec(GlyphRect.Right);
Inc(GlyphRect.Top);
end;
ImageList.Draw(ACanvas, GlyphRect.Left, GlyphRect.Top,
AMenuItem.ImageIndex, AMenuItem.Enabled);
if AMenuItem.Checked then
begin
Dec(GlyphRect.Right);
Dec(GlyphRect.Bottom);
end;
end
else
begin
if (ImageList <> nil) then
begin
GlyphRect.Left := GlyphRect.Right - ImageList.Width;
GlyphRect.Bottom := GlyphRect.Top + ImageList.Height;
end;
DrawGlyph := False;
end;
end;
with GlyphRect do
begin
Dec(Left);
Dec(Top);
Inc(Right, 2);
Inc(Bottom, 2);
end;
if AMenuItem.Checked and DrawGlyph then
DrawEdge(ACanvas.Handle, GlyphRect, EdgeStyle[AMenuItem.Checked], BF_RECT);
if Selected then
begin
if DrawGlyph then ARect.Right := GlyphRect.Left - 1;
Brush.Color := clHighlight;
FillRect(ARect);
end;
if not (Selected and DrawGlyph) then
ARect.Right := GlyphRect.Left - 1;
Inc(ARect.Left, 2);
Dec(ARect.Right, 1);
DrawStyle := DT_EXPANDTABS or DT_SINGLELINE or Alignments[Alignment];
{ Calculate vertical layout }
SaveRect := ARect;
if odDefault in State then
Font.Style := [fsBold];
AMenuItem.DoDrawText(ACanvas, AMenuItem.Caption, ARect, Selected,
DrawStyle or DT_CALCRECT or DT_NOCLIP);
{ the DT_CALCRECT does not take into account alignment }
ARect.Left := SaveRect.Left;
ARect.Right := SaveRect.Right;
OffsetRect(ARect, 0, ((SaveRect.Bottom - SaveRect.Top) - (ARect.Bottom - ARect.Top)) div 2);
AMenuItem.DoDrawText(ACanvas, AMenuItem.Caption, ARect, Selected, DrawStyle);
if AMenuItem.ShortCut <> 0 then
begin
S := ShortCutToText(AMenuItem.ShortCut);
ARect.Left := 10;
ARect.Right := ARect.Left + ACanvas.TextWidth(S);
AMenuItem.DoDrawText(ACanvas, S, ARect, Selected, DT_RIGHT);
end;
end;
end;
begin
ParentMenu := TMenuItem(Sender).GetParentMenu;
ImageList := ParentMenu.Images;
Selected := odSelected in State;
if (ParentMenu <> nil) and (not ParentMenu.IsRightToLeft) then
NormalDraw
else
BiDiDraw;
end;
{$ENDIF}
procedure TStdGridPopupMenu.ClearOperations;
procedure DoClearOperations(AItems: TMenuItem);
var
I: Integer;
AOperation: TcxGridPopupMenuOperation;
begin
for I := 0 to AItems.Count - 1 do
begin
AOperation := TcxGridPopupMenuOperation(AItems[I].Tag);
FreeAndNil(AOperation);
DoClearOperations(AItems[I]);
end;
end;
begin
DoClearOperations(Items);
end;
procedure TStdGridPopupMenu.CreateMenuItems;
procedure InsertNewGroup(AItems: TMenuItem);
var
AItem: TcxMenuItem;
begin
AItem := TcxMenuItem.Create(Self);
AItem.Caption := '-';
AItems.Add(AItem);
end;
function GetMenuItemByOperationClass(const AItems: TMenuItem;
AClass: TcxGridPopupMenuOperationClass): TMenuItem;
var
I: Integer;
begin
Result := nil;
for I := 0 to AItems.Count - 1 do
if (AItems[I].Caption <> '-') and
Assigned(TcxGridPopupMenuOperation(AItems[I].Tag)) then
if (TcxGridPopupMenuOperation(AItems[I].Tag).ClassType = AClass) then
begin
Result := AItems[I];
Break;
end
else
begin
Result := GetMenuItemByOperationClass(AItems[I], AClass);
If Assigned(Result) then break;
end;
end;
var
I: Integer;
AMenuItem, ASubMenuItem: TMenuItem;
AOperation: TcxGridPopupMenuOperation;
AOperationHolder: Integer;
begin
if cxGridPopupMenuOperations = nil then exit;
for I := 0 to cxGridPopupMenuOperations.Count - 1 do
begin
if (cxGridPopupMenuOperations[I].OperationClass.GetPopupMenuClass =
Self.ClassType) or Self.ClassType.InheritsFrom(
cxGridPopupMenuOperations[I].OperationClass.GetPopupMenuClass) then
begin
AMenuItem := TcxMenuItem.Create(Self);
{$IFDEF DELPHI7}
if (Win32MajorVersion >= 5) and (Win32MinorVersion >= 1) then
AMenuItem.OnAdvancedDrawItem := AdvancedDrawItemD7
else
AMenuItem.OnAdvancedDrawItem := nil;
{$ENDIF}
AOperation := cxGridPopupMenuOperations[I].OperationClass.Create(AMenuItem);
AOperationHolder := Integer(AOperation);
AMenuItem.Tag := Variant(AOperationHolder);
if AOperation.BeginGroup then InsertNewGroup(Items);
if Assigned(AOperation.Handler) then
AMenuItem.OnClick := AOperation.DoExecute;
AMenuItem.ImageIndex := cxGridPopupMenuOperations[I].ImageIndex;
if AOperation.GetSubOperationClass <> nil then
begin
ASubMenuItem := GetMenuItemByOperationClass(Items, AOperation.GetSubOperationClass);
if Assigned(ASubMenuItem) then ASubMenuItem.Add(TMenuItem(AOperation.MenuItem));
end
else
Items.Add(TMenuItem(AOperation.MenuItem));
end;
end;
end;
procedure TStdGridPopupMenu.InitItems(AItems: TMenuItem);
var
I: Integer;
AOperation: TcxGridPopupMenuOperation;
begin
if AItems.Count > 0 then
for I := 0 to AItems.Count - 1 do
begin
if AItems[I].Count > 0 then InitItems(AItems[I]);
AOperation := TcxGridPopupMenuOperation(AItems[I].Tag);
if Assigned(AOperation) then
begin
AItems[I].Enabled := AOperation.Enabled;
AItems[I].Checked := AOperation.Down;
AItems[I].Visible := AOperation.Visible;
AItems[I].Caption := AOperation.Caption;
end;
end;
end;
{$IFDEF DELPHI5}
procedure TStdGridPopupMenu.DoPopup(Sender: TObject);
begin
InitItems(Items);
inherited DoPopup(Sender);
end;
{$ELSE}
procedure TStdGridPopupMenu.Popup(X, Y: Integer);
begin
InitItems(Items);
inherited Popup(X, Y);
end;
{$ENDIF}
function TStdGridPopupMenu.GetPopupHandler: TcxGridOnPopupProc;
begin
Result := GridMenuPopup;
end;
procedure TStdGridPopupMenu.GridMenuPopup(ASenderMenu: TComponent;
AHitTest: TcxCustomGridHitTest; X, Y: Integer);
begin
Popup(X, Y);
end;
initialization
RegisterPopupMenuClass(TcxGridStdHeaderMenu, [gvhtColumnHeader],
TcxGridTableView);
RegisterPopupMenuClass(TcxGridStdFooterMenu,
[gvhtFooterCell, gvhtGroupFooterCell], TcxGridTableView);
end.