851 lines
29 KiB
ObjectPascal
851 lines
29 KiB
ObjectPascal
|
|
{********************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressEditors }
|
|
{ }
|
|
{ Copyright (c) 1998-2009 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 EXPRESSEDITORS 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 cxEditUtils;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
{.$DEFINE NOFLICKER}
|
|
|
|
uses
|
|
Windows,
|
|
dxThemeManager,
|
|
{$IFDEF DELPHI6}
|
|
Variants,
|
|
{$ENDIF}
|
|
Classes, Controls, Forms, Graphics, ImgList, StdCtrls, SysUtils,
|
|
cxContainer, cxControls, cxEdit, cxEditPaintUtils,
|
|
cxGraphics, cxLookAndFeels, cxLookAndFeelPainters, cxScrollBar;
|
|
|
|
const
|
|
cxEditButtonMaxBorderWidth = 2;
|
|
cxEditMaxBorderWidth = cxContainerMaxBorderWidth;
|
|
cxEditMaxCheckBoxBorderWidth = 2;
|
|
cxEditShadowWidth = cxContainerShadowWidth;
|
|
|
|
type
|
|
TcxEditCanvasHandle = HDC;
|
|
|
|
function CalculateEditDefaultButtonWidth(ACanvas: TcxCanvas; AViewInfo: TcxEditButtonViewInfo): Integer;
|
|
function cxEditGetBorderWidthBySkinPainter(ABorderStyle: TcxEditBorderStyle;
|
|
ASkinPainter: TcxCustomLookAndFeelPainterClass): Integer;
|
|
procedure cxEditFillRect(ACanvas: TCanvas; const R: TRect; AColor: TColor); overload;
|
|
procedure cxEditFillRect(ACanvas: TcxCanvas; const R: TRect; AColor: TColor); overload;
|
|
procedure cxEditFillRect(ACanvasHandle: TcxEditCanvasHandle; const R: TRect;
|
|
ABrush: TBrushHandle); overload;
|
|
function cxIsDigitChar(C: Char): Boolean;
|
|
function cxOffsetRect(var ARect: TRect; AOffset: TPoint): Boolean;
|
|
function cxTextOutFlagsToDrawTextFlags(AFlags: DWORD): Integer;
|
|
procedure DrawArrow(ACanvas: TcxCanvas; AArrowSize: Integer; AContentRect: TRect;
|
|
AArrowDirection: TcxArrowDirection; AIsDoubleArrow: Boolean;
|
|
AOffsetContent: Boolean; AColor: TColor);
|
|
procedure DrawButtonBorder(ACanvas: TcxCanvas; var ARect: TRect;
|
|
ABorders: TcxBorders; AColor: TColor);
|
|
procedure DrawCustomEdit(ACanvas: TcxCanvas; AViewInfo: TcxCustomEditViewInfo;
|
|
ADrawBackground: Boolean; ABackgroundStyle: TcxEditBackgroundPaintingStyle);
|
|
function DrawTextFlagsTocxTextOutFlags(AFlags: DWORD): Integer;
|
|
procedure DrawGlyph(ACanvas: TCanvas; X, Y: Integer; AGlyph: TBitmap;
|
|
AEnabled: Boolean; ABrushColor: TColor = clNone; ABackgroundBitmap: TBitmap = nil); overload;
|
|
procedure DrawGlyph(ACanvas: TcxCanvas; X, Y: Integer; AGlyph: TBitmap;
|
|
AEnabled: Boolean; ABrushColor: TColor = clNone; ABackgroundBitmap: TBitmap = nil); overload;
|
|
procedure DrawGlyph(ACanvas: TcxCanvas; AImageList: TCustomImageList;
|
|
AImageIndex: TImageIndex;
|
|
const AGlyphRect: TRect; ABrushColor: TColor; AEnabled: Boolean;
|
|
ABackgroundBitmap: TBitmap = nil); overload;
|
|
function GetArrowSize(const AContentSize: TSize; AArrowDirection: TcxArrowDirection): TSize;
|
|
function GetEditButtonsContentVerticalOffset(ACanvas: TcxCanvas;
|
|
AButtonsStyle: TcxEditButtonStyle; ANativeStyle: Boolean): Integer;
|
|
function GetHotTrackColor: TColor;
|
|
function GetNativeInnerTextEditContentHeightCorrection(
|
|
AProperties: TcxCustomEditProperties; AIsInplace: Boolean): Integer;
|
|
function GetEditButtonRegion(ACanvas: TcxCanvas; AViewInfo: TcxEditButtonViewInfo): TcxRegion;
|
|
function GetEditBorderHighlightColor(AIsOffice11Style: Boolean): TColor;
|
|
function GetEditButtonHighlightColor(APressed: Boolean;
|
|
AIsOffice11Style: Boolean): TColor;
|
|
function GetPainterClass(ANativeStyle: Boolean;
|
|
ALookAndFeel: TcxLookAndFeelKind): TcxCustomLookAndFeelPainterClass;
|
|
procedure InternalFillRect(ACanvas: TcxCanvas; const AOuterRect, AInternalRect: TRect;
|
|
ABrush: TBrushHandle);
|
|
procedure InternalPolyLine(ACanvas: TcxCanvas; const Points: array of TPoint;
|
|
AColor: TColor; AOrtoDrawing: Boolean = False);
|
|
function IsShadowDrawingNeeded(AViewData: TcxCustomEditViewData): Boolean;
|
|
procedure RestoreCanvasFont(ACanvas: TcxCanvas; const ASavedLogFont: TLogFont);
|
|
procedure SaveCanvasFont(ACanvas: TcxCanvas; out ALogFont: TLogFont);
|
|
function VerifyBitmap(ABitmap: TBitmap): Boolean;
|
|
function VerifyImages(AImages: TCustomImageList): Boolean;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Messages, cxClasses, cxDrawTextUtils, dxOffice11, dxThemeConsts, dxUxTheme,
|
|
cxGeometry, cxDWMApi, dxCore;
|
|
|
|
const
|
|
cxEditButtonContentVerticalOffset: array [TcxEditButtonStyle] of Integer =
|
|
(0, 4, 2, 2, 2, 2, 2);
|
|
|
|
procedure DrawArrow(ACanvas: TcxCanvas; AArrowSize: Integer; AContentRect: TRect;
|
|
AArrowDirection: TcxArrowDirection; AIsDoubleArrow: Boolean;
|
|
AOffsetContent: Boolean; AColor: TColor);
|
|
var
|
|
AArrowBrush: TBrushHandle;
|
|
AArrowRect: TRect;
|
|
|
|
procedure InternalDrawArrow;
|
|
var
|
|
I: Integer;
|
|
R: TRect;
|
|
begin
|
|
case AArrowDirection of
|
|
adLeft:
|
|
begin
|
|
with AArrowRect do
|
|
R := Rect(Left, Top + AArrowSize - 1, Left + 1, Top + AArrowSize);
|
|
with R do
|
|
for I := 1 to AArrowSize do
|
|
begin
|
|
cxEditFillRect(ACanvas.Handle, R, AArrowBrush);
|
|
Inc(Left);
|
|
Dec(Top);
|
|
Inc(Right);
|
|
Inc(Bottom);
|
|
end;
|
|
Inc(AArrowRect.Left, AArrowSize);
|
|
end;
|
|
adRight:
|
|
begin
|
|
with AArrowRect do
|
|
R := Rect(Left, Top, Left + 1, Bottom);
|
|
with R do
|
|
for I := 1 to AArrowSize do
|
|
begin
|
|
cxEditFillRect(ACanvas.Handle, R, AArrowBrush);
|
|
Inc(Left);
|
|
Inc(Top);
|
|
Inc(Right);
|
|
Dec(Bottom);
|
|
end;
|
|
Inc(AArrowRect.Left, AArrowSize);
|
|
end;
|
|
adUp:
|
|
begin
|
|
with AArrowRect do
|
|
R := Rect(Left + AArrowSize - 1, Top, Left + AArrowSize, Top + 1);
|
|
with R do
|
|
for I := 1 to AArrowSize do
|
|
begin
|
|
cxEditFillRect(ACanvas.Handle, R, AArrowBrush);
|
|
Dec(Left);
|
|
Inc(Top);
|
|
Inc(Right);
|
|
Inc(Bottom);
|
|
end;
|
|
Inc(AArrowRect.Top, AArrowSize);
|
|
end;
|
|
adDown:
|
|
begin
|
|
with AArrowRect do
|
|
R := Rect(Left, Top, Right, Top + 1);
|
|
with R do
|
|
for I := 1 to AArrowSize do
|
|
begin
|
|
cxEditFillRect(ACanvas.Handle, R, AArrowBrush);
|
|
Inc(Left);
|
|
Inc(Top);
|
|
Dec(Right);
|
|
Inc(Bottom);
|
|
end;
|
|
Inc(AArrowRect.Top, AArrowSize);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
AArrowRectSize: TSize;
|
|
I: Integer;
|
|
begin
|
|
if AArrowDirection in [adLeft, adRight] then
|
|
begin
|
|
AArrowRectSize.cx := AArrowSize * (1 + Integer(AIsDoubleArrow));
|
|
AArrowRectSize.cy := AArrowSize * 2 - 1;
|
|
end
|
|
else
|
|
begin
|
|
AArrowRectSize.cx := AArrowSize * 2 - 1;
|
|
AArrowRectSize.cy := AArrowSize * (1 + Integer(AIsDoubleArrow));
|
|
end;
|
|
|
|
with AContentRect do
|
|
begin
|
|
AArrowRect.Left := Left + (Right - Left - AArrowRectSize.cx) div 2;
|
|
AArrowRect.Top := Top + (Bottom - Top - AArrowRectSize.cy) div 2;
|
|
if AOffsetContent then
|
|
begin
|
|
Inc(AArrowRect.Left);
|
|
Inc(AArrowRect.Top);
|
|
end;
|
|
AArrowRect.Right := AArrowRect.Left + AArrowRectSize.cx;
|
|
AArrowRect.Bottom := AArrowRect.Top + AArrowRectSize.cy;
|
|
end;
|
|
|
|
AArrowBrush := GetSolidBrush(ACanvas, AColor);
|
|
for I := 0 to Integer(AIsDoubleArrow) do
|
|
InternalDrawArrow;
|
|
end;
|
|
|
|
procedure DrawButtonBorder(ACanvas: TcxCanvas; var ARect: TRect;
|
|
ABorders: TcxBorders; AColor: TColor);
|
|
var
|
|
AWorkRect: TRect;
|
|
begin
|
|
AWorkRect := ARect;
|
|
Dec(AWorkRect.Bottom, 1);
|
|
Dec(AWorkRect.Right, 1);
|
|
ACanvas.Pen.Color := AColor;
|
|
|
|
if bLeft in ABorders then
|
|
begin
|
|
InternalPolyLine(ACanvas, [AWorkRect.TopLeft, Point(AWorkRect.Left, AWorkRect.Bottom)], AColor);
|
|
Inc(ARect.Left);
|
|
end;
|
|
if bRight in ABorders then
|
|
begin
|
|
InternalPolyLine(ACanvas, [Point(AWorkRect.Right, AWorkRect.Top), AWorkRect.BottomRight], AColor);
|
|
Dec(ARect.Right);
|
|
end;
|
|
if bTop in ABorders then
|
|
begin
|
|
InternalPolyLine(ACanvas, [AWorkRect.TopLeft, Point(AWorkRect.Right, AWorkRect.Top)], AColor);
|
|
Inc(ARect.Top);
|
|
end;
|
|
if bBottom in ABorders then
|
|
begin
|
|
InternalPolyLine(ACanvas, [Point(AWorkRect.Left, AWorkRect.Bottom), AWorkRect.BottomRight], AColor);
|
|
Dec(ARect.Bottom);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawGlyph(ACanvas: TCanvas; X, Y: Integer; AGlyph: TBitmap;
|
|
AEnabled: Boolean; ABrushColor: TColor = clNone; ABackgroundBitmap: TBitmap = nil);
|
|
|
|
procedure InternalDrawGlyphEnabled;
|
|
var
|
|
AGlyphDrawingBrush: TBrush;
|
|
APrevBrushStyle: TBrushStyle;
|
|
R: TRect;
|
|
begin
|
|
if ABackgroundBitmap = nil then
|
|
AGlyphDrawingBrush := ACanvas.Brush
|
|
else
|
|
AGlyphDrawingBrush := ABackgroundBitmap.Canvas.Brush;
|
|
APrevBrushStyle := AGlyphDrawingBrush.Style;
|
|
|
|
with ACanvas do
|
|
begin
|
|
if (ABackgroundBitmap <> nil) or (ABrushColor = clNone) then
|
|
AGlyphDrawingBrush.Style := bsClear
|
|
else
|
|
AGlyphDrawingBrush.Color := ABrushColor;
|
|
if ABackgroundBitmap = nil then
|
|
ACanvas.BrushCopy(Bounds(X, Y, AGlyph.Width, AGlyph.Height), AGlyph,
|
|
Rect(0, 0, AGlyph.Width, AGlyph.Height), AGlyph.TransparentColor)
|
|
else
|
|
begin
|
|
R := Rect(0, 0, AGlyph.Width, AGlyph.Height);
|
|
ABackgroundBitmap.Canvas.BrushCopy(R, AGlyph, R, AGlyph.TransparentColor);
|
|
ACanvas.Draw(X, Y, ABackgroundBitmap);
|
|
end;
|
|
end;
|
|
|
|
AGlyphDrawingBrush.Style := APrevBrushStyle;
|
|
end;
|
|
|
|
procedure InternalDrawGlyphDisabled;
|
|
var
|
|
ABitmap: TBitmap;
|
|
AImageList: TcxImageList;
|
|
begin
|
|
AImageList := TcxImageList.Create(nil);
|
|
try
|
|
AImageList.Width := AGlyph.Width;
|
|
AImageList.Height := AGlyph.Height;
|
|
ABitmap := nil;
|
|
try
|
|
if (ABackgroundBitmap = nil) and (ABrushColor <> clNone) then
|
|
begin
|
|
ABitmap := cxCreateBitmap(AImageList.Width, AImageList.Height, pfDevice);
|
|
cxEditFillRect(ABitmap.Canvas.Handle, Rect(0, 0, ABitmap.Width, ABitmap.Height),
|
|
GetSolidBrush(ABitmap.Canvas, ABrushColor));
|
|
end;
|
|
AImageList.AddMasked(AGlyph, AGlyph.TransparentColor);
|
|
if ABitmap <> nil then
|
|
begin
|
|
AImageList.Draw(ABitmap.Canvas, 0, 0, 0, AEnabled);
|
|
ACanvas.Draw(X, Y, ABitmap);
|
|
end
|
|
else
|
|
if ABackgroundBitmap = nil then
|
|
AImageList.Draw(ACanvas, X, Y, 0, AEnabled)
|
|
else
|
|
begin
|
|
AImageList.Draw(ABackgroundBitmap.Canvas, 0, 0, 0, AEnabled);
|
|
ACanvas.Draw(X, Y, ABackgroundBitmap);
|
|
end;
|
|
finally
|
|
ABitmap.Free;
|
|
end;
|
|
finally
|
|
AImageList.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if AEnabled then
|
|
InternalDrawGlyphEnabled
|
|
else
|
|
InternalDrawGlyphDisabled;
|
|
end;
|
|
|
|
procedure DrawGlyph(ACanvas: TcxCanvas; X, Y: Integer; AGlyph: TBitmap;
|
|
AEnabled: Boolean; ABrushColor: TColor = clNone; ABackgroundBitmap: TBitmap = nil);
|
|
begin
|
|
DrawGlyph(ACanvas.Canvas, X, Y, AGlyph, AEnabled, ABrushColor, ABackgroundBitmap);
|
|
end;
|
|
|
|
procedure DrawGlyph(ACanvas: TcxCanvas; AImageList: TCustomImageList;
|
|
AImageIndex: TImageIndex;
|
|
const AGlyphRect: TRect; ABrushColor: TColor; AEnabled: Boolean;
|
|
ABackgroundBitmap: TBitmap = nil);
|
|
var
|
|
ABitmap: TBitmap;
|
|
begin
|
|
ABitmap := nil;
|
|
try
|
|
if ABackgroundBitmap = nil then
|
|
begin
|
|
ABitmap := TBitmap.Create;
|
|
ABitmap.Width := AImageList.Width;
|
|
ABitmap.Height := AImageList.Height;
|
|
with ABitmap.Canvas do
|
|
cxEditFillRect(Handle, Rect(0, 0, ABitmap.Width, ABitmap.Height),
|
|
GetSolidBrush(ABitmap.Canvas, ABrushColor));
|
|
end;
|
|
if ABackgroundBitmap <> nil then
|
|
begin
|
|
AImageList.Draw(ABackgroundBitmap.Canvas, 0, 0, AImageIndex, AEnabled); // ??? itMask TODO
|
|
ACanvas.Draw(AGlyphRect.Left, AGlyphRect.Top, ABackgroundBitmap);
|
|
end else
|
|
begin
|
|
AImageList.Draw(ABitmap.Canvas, 0, 0, AImageIndex, AEnabled); // ??? itMask TODO
|
|
ACanvas.Draw(AGlyphRect.Left, AGlyphRect.Top, ABitmap);
|
|
end;
|
|
finally
|
|
if ABitmap <> nil then
|
|
ABitmap.Free;
|
|
end;
|
|
end;
|
|
|
|
function GetPainterClass(ANativeStyle: Boolean;
|
|
ALookAndFeel: TcxLookAndFeelKind): TcxCustomLookAndFeelPainterClass;
|
|
const
|
|
APainterMap: array[TcxLookAndFeelKind] of TcxCustomLookAndFeelPainterClass = (
|
|
TcxFlatLookAndFeelPainter, TcxStandardLookAndFeelPainter,
|
|
TcxUltraFlatLookAndFeelPainter, TcxOffice11LookAndFeelPainter
|
|
);
|
|
begin
|
|
if ANativeStyle and AreVisualStylesAvailable then
|
|
Result := TcxWinXPLookAndFeelPainter
|
|
else
|
|
Result := APainterMap[ALookAndFeel];
|
|
end;
|
|
|
|
procedure InternalPolyLine(ACanvas: TcxCanvas; const Points: array of TPoint;
|
|
AColor: TColor; AOrtoDrawing: Boolean = False);
|
|
var
|
|
I: Integer;
|
|
P1, P2: TPoint;
|
|
ABrush: TBrushHandle;
|
|
begin
|
|
with ACanvas do
|
|
if AOrtoDrawing then
|
|
begin
|
|
ABrush := GetSolidBrush(AColor);
|
|
for I := 0 to Length(Points) - 2 do
|
|
begin
|
|
P1 := Points[I];
|
|
P2 := Points[I + 1];
|
|
if P1.X = P2.X then
|
|
begin
|
|
Inc(P2.X);
|
|
if P1.Y > P2.Y then
|
|
begin
|
|
Inc(P1.Y);
|
|
Inc(P2.Y);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Inc(P2.Y);
|
|
if P1.X > P2.X then
|
|
begin
|
|
Inc(P1.X);
|
|
Inc(P2.X);
|
|
end;
|
|
end;
|
|
cxEditFillRect(ACanvas.Handle, Rect(P1.X, P1.Y, P2.X, P2.Y), ABrush);
|
|
end;
|
|
with Points[High(Points)] do
|
|
cxEditFillRect(ACanvas.Handle, Rect(X, Y, X + 1, Y + 1), ABrush);
|
|
end
|
|
else
|
|
begin
|
|
Pen.Color := AColor;
|
|
Polyline(Points);
|
|
with Points[High(Points)] do
|
|
Pixels[X, Y] := AColor;
|
|
end;
|
|
end;
|
|
|
|
function VerifyBitmap(ABitmap: TBitmap): Boolean;
|
|
begin
|
|
with ABitmap do
|
|
Result := (ABitmap <> nil) and (not Empty) and (Width > 0) and (Height > 0);
|
|
end;
|
|
|
|
function VerifyImages(AImages: TCustomImageList): Boolean;
|
|
begin
|
|
with AImages do
|
|
Result := (AImages <> nil) and (Width > 0) and (Height > 0);
|
|
end;
|
|
|
|
function CalculateEditDefaultButtonWidth(ACanvas: TcxCanvas; AViewInfo: TcxEditButtonViewInfo): Integer;
|
|
|
|
function GetEditButtonTotalBorderExtent: Integer;
|
|
var
|
|
ATheme: TdxTheme;
|
|
R, CR: TRect;
|
|
begin
|
|
with AViewInfo do
|
|
if Data.NativeStyle then
|
|
begin
|
|
R := Rect(0, 0, 100, 100);
|
|
if Data.ComboBoxStyle then
|
|
begin
|
|
ATheme := OpenTheme(totComboBox);
|
|
GetThemeBackgroundContentRect(ATheme, ACanvas.Handle, CP_DROPDOWNBUTTON,
|
|
CBXS_NORMAL, R, CR);
|
|
end else
|
|
begin
|
|
ATheme := OpenTheme(totButton);
|
|
GetThemeBackgroundContentRect(ATheme, ACanvas.Handle, BP_PUSHBUTTON,
|
|
PBS_NORMAL, R, CR);
|
|
end;
|
|
Result := CR.Left + (R.Right - R.Left - CR.Right);
|
|
end
|
|
else
|
|
Result := cxEditButtonMaxBorderWidth * 2;
|
|
end;
|
|
|
|
var
|
|
AButtonTotalBorderExtent: Integer;
|
|
ACaptionWidth: Integer;
|
|
begin
|
|
with AViewInfo do
|
|
begin
|
|
if Data.NativeStyle then
|
|
if Data.ComboBoxStyle then
|
|
Data.NativeStyle := AreVisualStylesMustBeUsed(Data.NativeStyle, totComboBox)
|
|
else
|
|
Data.NativeStyle := AreVisualStylesMustBeUsed(Data.NativeStyle, totButton);
|
|
AButtonTotalBorderExtent := GetEditButtonTotalBorderExtent;
|
|
if Width > 0 then
|
|
if Width < AButtonTotalBorderExtent then
|
|
Result := AButtonTotalBorderExtent
|
|
else
|
|
Result := Width
|
|
else
|
|
if (Data.Kind = bkGlyph) and VerifyBitmap(Glyph) then
|
|
Result := Glyph.Width + GetEditButtonTotalBorderExtent
|
|
else
|
|
begin
|
|
if Data.Kind = bkText then
|
|
ACaptionWidth := ACanvas.TextWidth(Data.VisibleCaption) + AButtonTotalBorderExtent + 2 + 1
|
|
else
|
|
ACaptionWidth := 0;
|
|
Result := GetSystemMetrics(SM_CYHSCROLL);
|
|
if ACaptionWidth > Result then
|
|
Result := ACaptionWidth;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function cxEditGetBorderWidthBySkinPainter(ABorderStyle: TcxEditBorderStyle;
|
|
ASkinPainter: TcxCustomLookAndFeelPainterClass): Integer;
|
|
const
|
|
SkinBordersWidth: array [Boolean] of Integer = (1, cxContainerMaxBorderWidth);
|
|
begin
|
|
if ASkinPainter = nil then
|
|
Result := GetContainerBorderWidth(TcxContainerBorderStyle(ABorderStyle))
|
|
else
|
|
Result := SkinBordersWidth[ABorderStyle = ebsThick];
|
|
end;
|
|
|
|
procedure cxEditFillRect(ACanvas: TCanvas; const R: TRect; AColor: TColor);
|
|
begin
|
|
Windows.FillRect(ACanvas.Handle, R, GetSolidBrush(AColor));
|
|
end;
|
|
|
|
procedure cxEditFillRect(ACanvas: TcxCanvas; const R: TRect; AColor: TColor);
|
|
begin
|
|
Windows.FillRect(ACanvas.Handle, R, GetSolidBrush(AColor));
|
|
end;
|
|
|
|
procedure cxEditFillRect(ACanvasHandle: TcxEditCanvasHandle; const R: TRect;
|
|
ABrush: TBrushHandle);
|
|
begin
|
|
Windows.FillRect(ACanvasHandle, R, ABrush);
|
|
end;
|
|
|
|
function cxIsDigitChar(C: Char): Boolean;
|
|
begin
|
|
Result := dxCharInSet(C, ['0'..'9']);
|
|
end;
|
|
|
|
function cxOffsetRect(var ARect: TRect; AOffset: TPoint): Boolean;
|
|
begin
|
|
Result := OffsetRect(ARect, AOffset.X, AOffset.Y);
|
|
end;
|
|
|
|
procedure ConvertFlag(AInputFlags: DWORD; var AOutputFlags: Integer;
|
|
AInputFlag: DWORD; AOutputFlag: Integer);
|
|
begin
|
|
if AInputFlags and AInputFlag <> 0 then
|
|
AOutputFlags := AOutputFlags or AOutputFlag;
|
|
end;
|
|
|
|
function cxTextOutFlagsToDrawTextFlags(AFlags: DWORD): Integer;
|
|
begin
|
|
Result := 0;
|
|
ConvertFlag(AFlags, Result, CXTO_LEFT, cxAlignLeft);
|
|
ConvertFlag(AFlags, Result, CXTO_CENTER_HORIZONTALLY, cxAlignHCenter);
|
|
ConvertFlag(AFlags, Result, CXTO_RIGHT, cxAlignRight);
|
|
ConvertFlag(AFlags, Result, CXTO_TOP, cxAlignTop);
|
|
ConvertFlag(AFlags, Result, CXTO_CENTER_VERTICALLY, cxAlignVCenter);
|
|
ConvertFlag(AFlags, Result, CXTO_BOTTOM, cxAlignBottom);
|
|
ConvertFlag(AFlags, Result, CXTO_SINGLELINE, cxSingleLine);
|
|
ConvertFlag(AFlags, Result, CXTO_WORDBREAK, cxWordBreak);
|
|
end;
|
|
|
|
function DrawTextFlagsTocxTextOutFlags(AFlags: DWORD): Integer;
|
|
begin
|
|
Result := 0;
|
|
ConvertFlag(AFlags, Result, cxAlignLeft, CXTO_LEFT);
|
|
ConvertFlag(AFlags, Result, cxAlignHCenter, CXTO_CENTER_HORIZONTALLY);
|
|
ConvertFlag(AFlags, Result, cxAlignRight, CXTO_RIGHT);
|
|
ConvertFlag(AFlags, Result, cxAlignTop, CXTO_TOP);
|
|
ConvertFlag(AFlags, Result, cxAlignVCenter, CXTO_CENTER_VERTICALLY);
|
|
ConvertFlag(AFlags, Result, cxAlignBottom, CXTO_BOTTOM);
|
|
ConvertFlag(AFlags, Result, cxSingleLine, CXTO_SINGLELINE);
|
|
ConvertFlag(AFlags, Result, cxWordBreak, CXTO_WORDBREAK);
|
|
end;
|
|
|
|
procedure InternalFillRect(ACanvas: TcxCanvas; const AOuterRect, AInternalRect: TRect;
|
|
ABrush: TBrushHandle);
|
|
begin
|
|
if IsRectEmpty(AOuterRect) or EqualRect(AOuterRect, AInternalRect) then
|
|
Exit;
|
|
if IsRectEmpty(AInternalRect) then
|
|
cxEditFillRect(ACanvas.Handle, AOuterRect, ABrush)
|
|
else
|
|
begin
|
|
cxEditFillRect(ACanvas.Handle, Rect(AOuterRect.Left, AOuterRect.Top,
|
|
AInternalRect.Left, AOuterRect.Bottom), ABrush);
|
|
cxEditFillRect(ACanvas.Handle, Rect(AInternalRect.Left, AOuterRect.Top,
|
|
AInternalRect.Right, AInternalRect.Top), ABrush);
|
|
cxEditFillRect(ACanvas.Handle, Rect(AInternalRect.Right, AOuterRect.Top,
|
|
AOuterRect.Right, AOuterRect.Bottom), ABrush);
|
|
cxEditFillRect(ACanvas.Handle, Rect(AInternalRect.Left, AInternalRect.Bottom,
|
|
AInternalRect.Right, AOuterRect.Bottom), ABrush);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawCustomEdit(ACanvas: TcxCanvas; AViewInfo: TcxCustomEditViewInfo;
|
|
ADrawBackground: Boolean; ABackgroundStyle: TcxEditBackgroundPaintingStyle);
|
|
|
|
procedure FillEditBorderRect(ABackgroundBrush: TBrushHandle);
|
|
begin
|
|
if not AViewInfo.Transparent then
|
|
cxEditFillRect(ACanvas.Handle, AViewInfo.BorderRect, ABackgroundBrush);
|
|
end;
|
|
|
|
procedure FillContentOffsetRegion(ABackgroundBrush: TBrushHandle);
|
|
begin
|
|
with AViewInfo do
|
|
begin
|
|
if Transparent or not AViewInfo.HasContentOffsets then
|
|
Exit;
|
|
cxEditFillRect(ACanvas.Handle, Rect(Bounds.Left, Bounds.Top, BorderRect.Left,
|
|
Bounds.Bottom), ABackgroundBrush);
|
|
cxEditFillRect(ACanvas.Handle, Rect(BorderRect.Left, Bounds.Top,
|
|
BorderRect.Right, BorderRect.Top), ABackgroundBrush);
|
|
cxEditFillRect(ACanvas.Handle, Rect(BorderRect.Left, BorderRect.Bottom,
|
|
BorderRect.Right, Bounds.Bottom), ABackgroundBrush);
|
|
cxEditFillRect(ACanvas.Handle, Rect(BorderRect.Right, Bounds.Top,
|
|
Bounds.Right, Bounds.Bottom), ABackgroundBrush);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawEditBordersBySkinPainter(const R1: TRect; ABorderWidth: Integer;
|
|
APainter: TcxCustomLookAndFeelPainterClass);
|
|
begin
|
|
with AViewInfo do
|
|
begin
|
|
if BorderStyle <> ebsNone then
|
|
ACanvas.FrameRect(R1, BorderColor, ABorderWidth);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawUsualEditBorders(const R: TRect; ABorderWidth: Integer);
|
|
var
|
|
R1: TRect;
|
|
begin
|
|
with AViewInfo do
|
|
begin
|
|
R1 := R;
|
|
if AViewInfo.Painter <> nil then
|
|
DrawEditBordersBySkinPainter(R, ABorderWidth, Painter)
|
|
else
|
|
case AViewInfo.BorderStyle of
|
|
ebsSingle, ebsThick:
|
|
ACanvas.FrameRect(R1, BorderColor, ABorderWidth);
|
|
ebsFlat:
|
|
begin
|
|
ACanvas.DrawEdge(R1, True, True, Edges);
|
|
InflateRect(R1, -1, -1);
|
|
ACanvas.FrameRect(R1, clBtnFace);
|
|
end;
|
|
ebs3D:
|
|
begin
|
|
ACanvas.DrawEdge(R1, True, True, Edges);
|
|
InflateRect(R1, -1, -1);
|
|
ACanvas.DrawComplexFrame(R1, cl3DDkShadow, cl3DLight, Edges);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DrawUsualEditBackground(ABackgroundBrush: TBrushHandle);
|
|
var
|
|
R: TRect;
|
|
ABorderWidth: Integer;
|
|
begin
|
|
with AViewInfo do
|
|
begin
|
|
R := BorderRect;
|
|
ABorderWidth := cxEditGetBorderWidthBySkinPainter(BorderStyle, Painter);
|
|
Dec(R.Left, ABorderWidth);
|
|
Dec(R.Top, ABorderWidth);
|
|
if bRight in Edges then Inc(R.Right, ABorderWidth);
|
|
if bBottom in Edges then Inc(R.Bottom, ABorderWidth);
|
|
if Shadow then
|
|
DrawContainerShadow(ACanvas, R);
|
|
if not(bRight in Edges) then Inc(R.Right, ABorderWidth);
|
|
if not(bBottom in Edges) then Inc(R.Bottom, ABorderWidth);
|
|
DrawUsualEditBorders(R, ABorderWidth);
|
|
if IsInplace then
|
|
begin
|
|
if not Transparent then
|
|
if ADrawBackground then
|
|
cxEditFillRect(ACanvas.Handle, Bounds, ABackgroundBrush)
|
|
else
|
|
FillContentOffsetRegion(ABackgroundBrush);
|
|
end
|
|
else
|
|
if ADrawBackground then
|
|
FillEditBorderRect(ABackgroundBrush);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawEditBackground(ABackgroundBrush: TBrushHandle);
|
|
begin
|
|
if not AViewInfo.DrawBackground(ACanvas) then
|
|
if AViewInfo.NativeStyle then
|
|
AViewInfo.DrawNativeStyleEditBackground(ACanvas, ADrawBackground,
|
|
ABackgroundStyle, ABackgroundBrush)
|
|
else
|
|
DrawUsualEditBackground(ABackgroundBrush);
|
|
end;
|
|
|
|
var
|
|
AVisibleButtonsCount: Integer;
|
|
I: Integer;
|
|
ASavedDC: Integer;
|
|
begin
|
|
AVisibleButtonsCount := Length(AViewInfo.ButtonsInfo);
|
|
ASavedDC := 0;
|
|
if (AVisibleButtonsCount > 0) and not AViewInfo.ButtonsInfo[0].Data.BackgroundPartiallyTransparent then
|
|
begin
|
|
ASavedDC := SaveDC(ACanvas.Handle);
|
|
for I := 0 to AVisibleButtonsCount - 1 do
|
|
ACanvas.ExcludeClipRect(AViewInfo.ButtonsInfo[I].VisibleBounds);
|
|
end;
|
|
DrawEditBackground(GetSolidBrush(ACanvas, AViewInfo.BackgroundColor));
|
|
|
|
if ASavedDC <> 0 then
|
|
RestoreDC(ACanvas.Handle, ASavedDC);
|
|
AViewInfo.DrawButtons(ACanvas);
|
|
end;
|
|
|
|
function GetArrowSize(const AContentSize: TSize; AArrowDirection: TcxArrowDirection): TSize;
|
|
var
|
|
AMinContentSize: Integer;
|
|
ATempVar: Longint;
|
|
begin
|
|
AMinContentSize := AContentSize.cx;
|
|
if AMinContentSize > AContentSize.cy then
|
|
AMinContentSize := AContentSize.cy;
|
|
|
|
Result.cx := (AMinContentSize - 1) div 2;
|
|
if not Odd(Result.cx) then
|
|
Result.cx := Result.cx + 1;
|
|
Result.cy := Result.cx div 2 + 1;
|
|
if AArrowDirection in [adLeft, adRight] then
|
|
begin
|
|
ATempVar := Result.cx;
|
|
Result.cx := Result.cy;
|
|
Result.cy := ATempVar;
|
|
end;
|
|
end;
|
|
|
|
function GetEditButtonsContentVerticalOffset(ACanvas: TcxCanvas;
|
|
AButtonsStyle: TcxEditButtonStyle; ANativeStyle: Boolean): Integer;
|
|
var
|
|
ATheme: TdxTheme;
|
|
CR, R: TRect;
|
|
begin
|
|
if ANativeStyle then
|
|
begin
|
|
R := Rect(0, 0, 100, 100);
|
|
ATheme := OpenTheme(totButton);
|
|
GetThemeBackgroundContentRect(ATheme, ACanvas.Handle, BP_PUSHBUTTON,
|
|
PBS_NORMAL, R, CR);
|
|
Result := CR.Top + R.Bottom - CR.Bottom;
|
|
end
|
|
else
|
|
Result := cxEditButtonContentVerticalOffset[AButtonsStyle];
|
|
end;
|
|
|
|
function GetHotTrackColor: TColor;
|
|
begin
|
|
Result := GetSysColor(COLOR_HOTLIGHT);
|
|
end;
|
|
|
|
function GetNativeInnerTextEditContentHeightCorrection(
|
|
AProperties: TcxCustomEditProperties; AIsInplace: Boolean): Integer;
|
|
begin
|
|
Result := Integer(AIsInplace and (AProperties.Buttons.Count > 0));
|
|
end;
|
|
|
|
function GetEditButtonRegion(ACanvas: TcxCanvas; AViewInfo: TcxEditButtonViewInfo): TcxRegion;
|
|
var
|
|
ATheme: TdxTheme;
|
|
ARgn1, ARgn2: HRGN;
|
|
begin
|
|
with AViewInfo do
|
|
if Data.NativeState <> TC_NONE then
|
|
begin
|
|
if Data.ComboBoxStyle then
|
|
begin
|
|
ATheme := OpenTheme(totComboBox);
|
|
GetThemeBackgroundRegion(ATheme, ACanvas.Handle, CP_DROPDOWNBUTTON,
|
|
Data.NativeState, @Bounds, ARgn1);
|
|
end else
|
|
begin
|
|
ATheme := OpenTheme(totButton);
|
|
GetThemeBackgroundRegion(ATheme, ACanvas.Handle, Data.NativePart,
|
|
Data.NativeState, @Bounds, ARgn1);
|
|
end;
|
|
ARgn2 := CreateRectRgnIndirect(Bounds);
|
|
CombineRgn(ARgn1, ARgn1, ARgn2, RGN_AND);
|
|
DeleteObject(ARgn2);
|
|
Result := TcxRegion.Create(ARgn1);
|
|
end
|
|
else
|
|
Result := TcxRegion.Create(Bounds);
|
|
end;
|
|
|
|
function GetEditBorderHighlightColor(
|
|
AIsOffice11Style: Boolean): TColor;
|
|
begin
|
|
if AIsOffice11Style then
|
|
Result := dxOffice11SelectedBorderColor
|
|
else
|
|
Result := clHighlight;
|
|
end;
|
|
|
|
function GetEditButtonHighlightColor(APressed: Boolean;
|
|
AIsOffice11Style: Boolean): TColor;
|
|
var
|
|
APainterClass: TcxCustomLookAndFeelPainterClass;
|
|
begin
|
|
if AIsOffice11Style then
|
|
APainterClass := TcxOffice11LookAndFeelPainter
|
|
else
|
|
APainterClass := TcxUltraFlatLookAndFeelPainter;
|
|
if APressed then
|
|
Result := APainterClass.ButtonColor(cxbsPressed)
|
|
else
|
|
Result := APainterClass.ButtonColor(cxbsHot);
|
|
end;
|
|
|
|
function IsShadowDrawingNeeded(AViewData: TcxCustomEditViewData): Boolean;
|
|
begin
|
|
Result := AViewData.Style.Shadow and not AViewData.IsNativeStyle(AViewData.Style.LookAndFeel);
|
|
end;
|
|
|
|
procedure RestoreCanvasFont(ACanvas: TcxCanvas; const ASavedLogFont: TLogFont);
|
|
begin
|
|
ACanvas.Font.Handle := CreateFontIndirect(ASavedLogFont);
|
|
end;
|
|
|
|
procedure SaveCanvasFont(ACanvas: TcxCanvas; out ALogFont: TLogFont);
|
|
begin
|
|
cxGetFontData(ACanvas.Font.Handle, ALogFont);
|
|
end;
|
|
|
|
end.
|