kolmck/Addons/XPMenus.pas
dkolmck ec2ce65753 3.00F
git-svn-id: https://svn.code.sf.net/p/kolmck/code@76 91bb2d04-0c0c-4d2d-88a5-bbb6f4c1fa07
2010-10-09 13:35:54 +00:00

521 lines
16 KiB
ObjectPascal

{***********************************************************************}
{ Ęîěďîíĺíň KOL XPMenu }
{ Îďčńŕíčĺ: }
{ * Ďđčíčěŕĺň íŕ ńĺá˙ îňđčńîâęó ěĺíţ â ńňčëĺ OfficeXP. }
{ }
{ Âĺđńč˙ : 1.09 îň 22.10.2005 }
{ Ŕâňîđ : Řčđ˙ĺâ Ŕëĺęńŕíäđ }
{ E-mail : alex@diploms.com }
{ Âűďîëíĺí íŕ îńíîâĺ ęëŕńńŕ RyMenu Ŕëĺęńĺ˙ Đóě˙íöĺâŕ (skitl@mail.ru). }
{***********************************************************************}
{$DEFINE USE_AUTOFREE4CONTROLS}
unit XPMenus;
interface
uses
Windows, Types, Messages, KOL;
type
PXPControl=^TXPControl;
TXPControl=object(TControl)
end;
PXPMenu = ^TXPMenu;
TXPMenu = object(TMenu)
private
FFont: PGraphicTool;
FGutterColor: TColor;
FBackColor: TColor;
FSelectedColor: TColor;
FSelLightColor: TColor;
FCheckColor: TColor;
FMinWidth: Integer;
FMinHeight: Integer;
FIsPopup : boolean;
FBmpCheck: PBitmap;
procedure SetFont(Value: PGraphicTool);
procedure SetSelectedColor(const Value: TColor);
procedure InternalInitItems(Item: PMenu);
function TextExtent(const Text: string): TSize;
procedure InitCheckBmp;
protected
public
// destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
procedure DrawXPstyle;
function MeasureItem(Sender: PObj; Idx: Integer): Integer;
function DrawItem(Sender: PObj; DC: HDC; const Rect: TRect;
ItemIdx: Integer; DrawAction: TDrawAction; ItemState: TDrawState): Boolean;
public
property GutterColor: TColor read FGutterColor write FGutterColor;
property BackColor: TColor read FBackColor write FBackColor;
property SelectedColor: TColor read FSelectedColor write SetSelectedColor;
property CheckColor: TColor read FCheckColor write FCheckColor;
property Font: PGraphicTool read FFont write SetFont; {ěîćĺňĺ ďîěĺí˙ňü ôîíň ó ěĺíţ}
property ItemHeight: Integer read FMinHeight write FMinHeight;
property ItemWidth: Integer read FMinWidth write FMinWidth;
end;
TKOLXPMainMenu= PXPMenu;
TKOLXPPopupMenu= PXPMenu;
{procedure XPDrawItem(Sender: PObj; DC: HDC; ARect: TRect;
ItemState: TDrawState; TopLevel, IsLine: Boolean;
Bitmap:HBitmap;BitmapSize: tagBitmap; AFont: PGraphicTool;
const Caption: String; GutterWidth: Integer;
SelectedColor, GutterColor, MenuColor, SelLightColor, CheckColor: TColor);
}
function NewXPMenu( AParent : PControl; MaxCmdReserve: DWORD; const Template : array of PKOLChar;
aOnMenuItem: TOnMenuItem; isPopup:boolean ): PXPMenu;
implementation
type
TRGB = packed record
R, G, B: Byte;
end;
AGRBQuad = array [0..0] of RGBQuad;
PAGRBQuad = ^AGRBQuad;
PPoints = ^TPoints;
TPoints = array[0..0] of TPoint;
//Đŕńęëŕäűâŕĺň ęîëîđ íŕ ńîńňŕâíűĺ ÷ŕńňč
function GetRGB(const Color: TColor): TRGB;
var
iColor: TColor;
begin
iColor := Color2RGB(Color);
Result.R := GetRValue(iColor);
Result.G := GetGValue(iColor);
Result.B := GetBValue(iColor);
end;
//ďîëó÷ŕĺě áëĺäíűé öâĺň
function GetLightColor(Color: TColor; Light: Byte) : TColor;
var
fFrom: TRGB;
begin
FFrom := GetRGB(Color);
Result := RGB(
Round(FFrom.R + (255 - FFrom.R) * (Light / 100)),
Round(FFrom.G + (255 - FFrom.G) * (Light / 100)),
Round(FFrom.B + (255 - FFrom.B) * (Light / 100))
);
end;
function GetShadeColor(Color: TColor; Shade: Byte) : TColor;
var
fFrom: TRGB;
begin
FFrom := GetRGB(Color);
Result := RGB(
Max(0, FFrom.R - Shade),
Max(0, FFrom.G - Shade),
Max(0, FFrom.B - Shade)
);
end;
function BtnHighlight : TColor;
begin
Result := GetLightColor(clBtnFace, 50)
end;
function NewXPMenu( AParent : PControl; MaxCmdReserve: DWORD; const Template : array of PKOLChar;
aOnMenuItem: TOnMenuItem; isPopup:boolean): PXPMenu;
var M: PXPMenu;
{$IFDEF INITIALFORMSIZE_FIXMENU}
R: TRect;
{$ENDIF}
begin
New( Result, Create );
{+}{++}(*Result := PXPMenu.Create;*){--}
Result.FVisible := TRUE;
Result.FPopupFlags := TPM_LEFTALIGN or TPM_LEFTBUTTON;
Result.FMenuItems := NewList;
Result.FOnMenuItem := aOnMenuItem;
if (High(Template)>=0) and (Template[0] <> nil) then
begin
if (AParent <> nil) and (PXPControl( AParent).fMenuObj = nil) and not PXPControl( AParent).IsControl then
Result.FHandle := CreateMenu
else
Result.FHandle := CreatePopupMenu;
Result.FillMenuItems( Result.FHandle, 0, Template );
end;
if Assigned( AParent ) then
begin
Result.FControl :=PControl( AParent);
if Assigned(PXPControl( AParent).fMenuObj) then
begin
// add popup menu to the end of menu chain
M := PXPMenu( PXPControl( AParent).fMenuObj );
while Assigned(M.fNextMenu) do
M := PXPMenu(M.fNextMenu);
M.fNextMenu := Result;
end
else
begin
if not PXPControl( AParent).IsControl then
begin
{$IFDEF INITIALFORMSIZE_FIXMENU}
R := AParent.ClientRect;
{$ENDIF}
AParent.Menu := Result.FHandle;
{$IFDEF INITIALFORMSIZE_FIXMENU}
AParent.SetClientSize( R.Right, R.Bottom );
{$ENDIF}
end;
PXPControl( AParent).fMenuObj := Result;
AParent.AttachProc(WndProcMenu );
{$IFDEF USE_AUTOFREE4CONTROLS} //dufa
AParent.Add2AutoFree( Result );
{$ENDIF}
end;
end;
Result.FGutterColor := clBtnFace; //ńĺđŕ˙ ďîëîńęŕ
Result.FBackColor := GetLightColor(clBtnFace, 85);
Result.FSelectedColor := GetLightColor(clHighlight, 65); //âűäĺëĺííűé ďóíęň ěĺíţ
Result.FSelLightColor := GetLightColor(clHighlight, 75);
Result.FCheckColor :=clBlack;
Result.FMinWidth := 0;
Result.FMinHeight:=0;
Result.FIsPopup:=isPopup;
Result.FFont := NewFont;
Result.Add2AutoFree(Result.FFont);
end;
procedure TXPMenu.InitCheckBmp;
const ChkBMP: array[0..11] of word=(0,0,0,8,24,568,880,992,448,128,0,0);
var
i,j: Byte;
row: PAGRBQuad;
x:word;
begin
FBmpCheck := NewDIBBitmap(12,12,pf32bit);
Add2AutoFree(FBmpCheck);
with FBmpCheck^ do
begin
if FCheckColor=clWhite then Canvas.Brush.Color := clBlack else Canvas.Brush.Color := clWhite;
Canvas.FillRect(Rect(0, 0, Width, Height));
for j:=0 to Height-1 do begin
row:=ScanLine[j]; x:=ChkBMP[j];
for i:=0 to Width-1 do begin
if (x and 2048)=2048 then row[i]:=Color2RGBQuad(FCheckColor);
x:=x shl 1;
end;
end;
end
end;
function TXPMenu.TextExtent(const Text: string): TSize;
var
DC: HDC;
begin
DC := CreateCompatibleDC( 0 );
SelectObject(DC,FFont.Handle);
GetTextExtentPoint32( DC, PKOLChar(Text), Length(Text), Result);
DeleteDC(DC);
end;
{destructor TXPMenu.Destroy;
begin
FFont.Free;
if Assigned(FBmpCheck) then
Free_And_Nil(FBmpCheck);
inherited;
end;}
procedure TXPMenu.InternalInitItems(Item : PMenu);
//áĺćčň ďî âńĺě ďóíęňŕě, ďđč ńëó÷ŕĺ çŕăë˙äűâŕ˙ â ďîäďóíęňű
var
I: Integer;
begin
with Item^ do begin
OnMeasureItem := MeasureItem;
OnDrawItem := DrawItem;
OwnerDraw :=true;
for I := 0 to Count - 1 do
if Items[I].Count > 0 then InternalInitItems(Items[I]);
end;
end;
procedure TXPMenu.DrawXPstyle;
var i:integer;
begin
for i:=0 to Count -1 do
InternalInitItems(Items[i]);
end;
//ńîáńňâĺííî îňđčńîâęŕ-c
function TXPMenu.DrawItem(Sender: PObj; DC: HDC;
const Rect: TRect; ItemIdx: Integer; DrawAction: TDrawAction;
ItemState: TDrawState): Boolean;
var BitmapSize:tagBITMAP;
aBrush, aPen, aFont: PGraphicTool;
i:byte;
BMP,maskBMP{, grayBMP}:PBitmap;
{ oldBrush:HBrush;
oldPen:HPen;
oldFont:HFont;}
GutterWidth:Integer;
TopLevel:boolean;
ARect:TRect;
function GetGutterWidth(IsLine: Boolean): Integer;
begin
with PMenu(Sender)^ do
begin
if Pointer(Bitmap)<>nil then
begin
Result := Max(BitmapSize.bmWidth + 4,
Rect.Bottom - Rect.Top); //÷ĺňűđĺ ňî÷ęč äî ęŕđňčíęč + ęŕđňčíęŕ + ď˙ňü ďîńëĺ
if IsLine then
Result := Max(Result, TextExtent('W').cy + 4);
end else
if IsLine then
Result := TextExtent('W').cy + 4
else
Result := Rect.Bottom - Rect.Top; {řčđčíŕ = âűńîňĺ + 2 + 2 ňî÷ęč}
end;
Result := Max(Result, ItemHeight) + 1;
end;
procedure RGB2GrayScale(grayBMP:PBitmap);
var i,j:word;
fFrom: TRGB;
c:byte;
begin
with grayBMP^ do
for i:=0 to Width-1 do
for j:=0 to Height-1 do begin
FFrom := GetRGB(Pixels[i,j]);
with FFrom do c:=round(0.30*R+0.59*G+0.11*B);
Pixels[i,j]:=RGB(c,c,c) ;
end;
end;
procedure MyPolyline(DC: HDC;const Points: array of TPoint);
begin
Polyline(DC, PPoints(@Points)^, High(Points) + 1);
end;
const
//ňĺęńňîâűĺ ôëŕăč
_Flags: LongInt = DT_NOCLIP or DT_VCENTER or DT_END_ELLIPSIS or DT_SINGLELINE;
_FlagsTopLevel: array[Boolean] of Longint = (DT_LEFT, DT_CENTER);
_FlagsShortCut: Longint = (DT_RIGHT);
begin
with PMenu(Sender)^ do begin
if Pointer(Bitmap)<>nil then
GetObject(Bitmap , sizeof(tagBITMAP), @BitmapSize);
GutterWidth:=GetGutterWidth(IsSeparator);
TopLevel:=(TopParent.IndexOf( Parent )=-1) and not FIsPopup;
aBrush:=NewBrush;
aPen:=NewPen;
aFont:=NewFont;
aPen.Color := GetShadeColor(clHighlight, 50);
// oldPen:=SelectObject(DC,aPen.Handle);
// oldBrush:=SelectObject(DC,aBrush.Handle);
if (odsSelected in ItemState) then //ĺńëč ďóíęň ěĺíţ âűäĺëĺí
begin
if TopLevel then //ĺńëč ýňî ďîëîńęŕ îńíîâíîăî ěĺíţ
begin
aBrush.Color := BtnHighLight;
SelectObject(DC,aBrush.Handle);
FillRect(DC,Rect,aBrush.Handle);
aPen.Color := GetShadeColor(clBtnShadow, 50);
SelectObject(DC,aPen.Handle);
MyPolyline(DC,[
Point(Rect.Left, Rect.Bottom-1),
Point(Rect.Left, Rect.Top),
Point(Rect.Right-1, Rect.Top),
Point(Rect.Right-1, Rect.Bottom)
]);
end else
if not (odsDisabled in ItemState) then
begin
aBrush.Color := FSelectedColor;
SelectObject(DC,aBrush.Handle);
Rectangle(DC,Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);
end
end else
if TopLevel then //ĺńëč ýňî ďîëîńęŕ îńíîâíîăî ěĺíţ
begin
if (odsHotList in ItemState) then //ĺńëč ěűřü íŕä ďóíęňîě ěĺíţ
begin
aPen.Color := GetShadeColor(clHighlight, 50);
SelectObject(DC,aPen.Handle);
aBrush.Color := FSelectedColor;
SelectObject(DC,aBrush.Handle);
Rectangle(DC,Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);
end else
begin
aBrush.Color := clBtnFace;
FillRect(DC,Rect,aBrush.Handle);
end
end else
begin //íč÷ĺě íĺ ďđčěĺ÷ŕňĺëüíűé ďóíęň ěĺíţ
aBrush.Color := FGutterColor; //ďîëîńęŕ
FillRect(DC,Types.Rect(Rect.Left, Rect.Top, Rect.Left + GutterWidth, Rect.Bottom),aBrush.Handle );
aBrush.Color := FBackColor;
FillRect(DC,Types.Rect(Rect.Left + GutterWidth, Rect.Top, Rect.Right, Rect.Bottom),aBrush.Handle);
end;
if odsChecked in ItemState then
begin // ďîäńâĺ÷čâŕĺě ÷ĺęíóňűé ďóíęň ěĺíţ
aPen.Color := GetShadeColor(clHighlight, 50);
SelectObject(DC,aPen.Handle);
if (odsSelected in ItemState) then aBrush.Color := GetShadeColor(FSelLightColor, 40)
else aBrush.Color := FSelLightColor;
SelectObject(DC,aBrush.Handle);
Rectangle(DC,(Rect.Left + 1), (Rect.Top + 1),
(Rect.Left - 1 + GutterWidth - 1), (Rect.Bottom - 1) );
end;
if (Pointer(Bitmap)<>nil) and (not TopLevel) then begin
BMP:=NewBitmap(BitmapSize.bmWidth ,BitmapSize.bmHeight);
BMP.Handle:=CopyImage(Bitmap,IMAGE_BITMAP ,0,0,0);
maskBMP:=NewBitmap(BitmapSize.bmWidth ,BitmapSize.bmHeight);
maskBMP.Handle:=CopyImage(Bitmap,IMAGE_BITMAP ,0,0,0);
maskBMP.Convert2Mask(BMP.Pixels[0,0]);
if not (odsDisabled in ItemState) then begin //đčńóĺě öâĺňíóţ ęŕđňčíęó
if (odsSelected in ItemState) then begin
{grayBMP:=NewBitmap(BitmapSize.bmWidth ,BitmapSize.bmHeight);
grayBMP.Handle:=CopyImage(Bitmap,IMAGE_BITMAP ,0,0,0);
RGB2GrayScale(grayBMP);
grayBMP.DrawMasked(DC ,(ARect.Left + GutterWidth - 1 - BitmapSize.bmWidth ) shr 1+2,
(ARect.Top + ARect.Bottom - BitmapSize.bmHeight ) shr 1+2, maskBMP.Handle);
grayBMP.Free; }
end;
end else begin //đčńóĺě ďîăŕńřóţ ęŕđňčíęó
RGB2GrayScale(BMP);
end;
BMP.DrawMasked(DC ,(Rect.Left + GutterWidth - 1 - BitmapSize.bmWidth ) shr 1,
(Rect.Top + Rect.Bottom - BitmapSize.bmHeight ) shr 1, maskBMP.Handle);
maskBMP.Free; BMP.Free;
end else
if odsChecked in ItemState then begin
if not Assigned(FBmpCheck) then InitCheckBmp;
FBmpCheck.DrawTransparent(DC,(Rect.Left + GutterWidth - 1 - FBmpCheck.Width) shr 1,
(Rect.Top + Rect.Bottom - FBmpCheck.Height) shr 1,FBmpCheck.Pixels[0,0]);
end;
ARect:=Rect;
if not TopLevel then
Inc(ARect.Left, GutterWidth + 5); //îňńňóď äë˙ ňĺęńňŕ
aFont.Assign(Font);
with aFont^ do
begin
if (odsDefault in ItemState) then FontStyle := [fsBold];
if (odsDisabled in ItemState) then Color := clGray;
end;
// oldFont:=SelectObject(DC,aFont.Handle);
if IsSeparator then //ĺńëč đŕçäĺëčňĺëü
begin
aPen.Color := clBtnShadow;
SelectObject(DC,aPen.Handle);
MyPolyline(DC,[
Point(Rect.Left, ARect.Top + (ARect.Bottom - ARect.Top) shr 1),
Point(Rect.Right, ARect.Top + (ARect.Bottom - ARect.Top) shr 1)]);
end else
begin //ňĺęńň ěĺíţ
i:=1; while (i<=Length(Caption)) and (Caption[i]<>#9) do inc(i);
{ i:=Pos(#9, Caption);
if i=0 then i:=Length(Caption)+1;
} SetBkMode(DC, TRANSPARENT);
SetTextColor(DC, aFont.Color );
DrawText(DC, PKOLChar(copy(Caption,1,i-1)),i-1 ,ARect,
_Flags or _FlagsTopLevel[TopLevel]);
if i<Length(Caption) then //đŕçďŕëüöîâęŕ
begin
Dec(ARect.Right, 5);
DrawText(DC, PKOLChar(copy(Caption,i+1,Length(Caption)-i)),Length(Caption)-i,
ARect, _Flags or _FlagsShortCut);
end
end;
//DeleteObject(SelectObject(DC, oldFont));
//DeleteObject(SelectObject(DC, oldBrush));
//DeleteObject(SelectObject(DC, oldPen));
aFont.Free;
aBrush.Free;
aPen.Free;
end;
Result:=true;
end;
//đŕçěĺđű ěĺíţ
function TXPMenu.MeasureItem(Sender: PObj; Idx: Integer): Integer;
VAR Bound:integer;
bb:packed record
Height:word;
Width:word;
end absolute Bound;
BitmapSize:tagBitmap;
begin
with PMenu(Sender)^ do
if (TopParent.IndexOf( Parent )=-1) and not FIsPopup then
begin
bb.Width := TextExtent(Caption).cX;
bb.Height := TextExtent(Caption).cY;
end else begin
if Pointer(Bitmap)<>nil then
begin
GetObject(Bitmap , sizeof(tagBITMAP), @BitmapSize);
if IsSeparator then
if Max(ItemHeight, BitmapSize.bmHeight ) > 20 then //ďđč áîëüřĺě 20 óçęŕ˙ ďîëîńęŕ íĺęđŕńčâŕ
bb.Height := 11 else bb.Height := 5
else
begin
bb.Height := Max(ItemHeight,
Max(TextExtent('W').cy , BitmapSize.bmHeight ) + 4);
bb.Width := BitmapSize.bmWidth ;
if bb.Width < bb.Height then bb.Width := bb.Height else bb.Width := bb.Width + 5;
bb.Width := Max(ItemWidth,
bb.Width + TextExtent(Caption).cx + 15);
end
end else
begin
bb.Height := Max(TextExtent('W').cY + 4, ItemHeight);
bb.Width := Max(ItemWidth, bb.Height + TextExtent(Caption).cx + 15);
if IsSeparator then
if bb.Height > 20 then //ďđč áîëüřĺě 20 óçęŕ˙ ďîëîńęŕ íĺęđŕńčâŕ
bb.Height := 11 else bb.Height := 5;
end
end;
Result:=Bound;
end;
procedure TXPMenu.SetFont(Value: PGraphicTool);
begin
FFont.Assign(Value);
end;
procedure TXPMenu.SetSelectedColor(const Value: TColor);
begin
FSelectedColor := Value;
FSelLightColor := GetLightColor(Value, 75);
end;
end.