{********************************************************************} { } { Developer Express Visual Component Library } { ExpressSkins Library } { } { Copyright (c) 2006-2008 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 EXPRESSSKINS 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 dxSkinsForm; interface {$I cxVer.inc} uses Types, Windows, Classes, SysUtils, Messages, Forms, Graphics, Controls, cxScrollBar, MultiMon, cxDWMAPI, ShellApi, cxLookAndFeelPainters, cxClasses, StdCtrls, cxGraphics, cxControls, cxGeometry, dxSkinsLookAndFeelPainter, dxSkinsCore, Math, ExtCtrls, FlatSB, cxLookAndFeels, dxUxTheme, dxSkinInfo; const dxSkinFormTextOffset = 5; dxSkinIconSpacing = 2; WM_POSTREDRAW: Cardinal = WM_DX + 1; WM_CHILDCHANGED: Cardinal = WM_DX + 2; WM_POSTCREATE: Cardinal = WM_DX + 3; WM_POSTCHECKRGN: Cardinal = WM_DX + 4; IsDesigning: Boolean = False; type TdxSkinFormPainter = class; TdxSkinFormNonClientAreaInfo = class; TdxSkinFormCorner = (sfcLeftTop, sfcRightTop, sfcLeftBottom, sfcRightBottom); TdxScrollAreaElement = (saeHorzScroll, saeVertScroll, saeSizeGrip); TdxScrollAreaElements = set of TdxScrollAreaElement; TdxSkinFormScrollBar = saeHorzScroll..saeVertScroll; TdxSkinFormEvent = procedure(Sender: TObject; AForm: TCustomForm; var ASkinName: string; var UseSkin: Boolean) of object; TdxSkinControlEvent = procedure(Sender: TObject; AControl: TWinControl; var UseSkin: Boolean) of object; { TdxSkinController } TdxSkinController = class(TcxLookAndFeelController) private FOnSkinControl: TdxSkinControlEvent; FOnSkinForm: TdxSkinFormEvent; function GetUseSkins: Boolean; procedure SetUseSkins(Value: Boolean); protected procedure Changed; function DoSkinControl(AControl: TWinControl): Boolean; virtual; function DoSkinForm(AForm: TCustomForm): TdxSkinLookAndFeelPainterClass; virtual; function DoSkinFormEx(AForm: TCustomForm; var ASkinName: string; var AUseSkin: Boolean): TdxSkinLookAndFeelPainterClass; virtual; procedure Loaded; override; procedure MasterLookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); override; procedure MasterLookAndFeelDestroying(Sender: TcxLookAndFeel); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Refresh; class function GetFormSkin(AForm: TCustomForm; var ASkinName: string): Boolean; published property Kind; property NativeStyle; property SkinName; property UseSkins: Boolean read GetUseSkins write SetUseSkins default True; property OnSkinForm: TdxSkinFormEvent read FOnSkinForm write FOnSkinForm; property OnSkinControl: TdxSkinControlEvent read FOnSkinControl write FOnSkinControl; end; { TdxSkinWinController } TdxSkinWinController = class(TcxIUnknownObject, IcxMouseTrackingCaller) private FHandle: HWND; FLookAndFeelPainter: TdxSkinLookAndFeelPainterClass; FMaster: TdxSkinWinController; FProcInstance: Pointer; FSavedWndProc: TWndMethod; FSavedWndProcPtr: Pointer; FWinControl: TWinControl; function GetHasVirtualChilds: Boolean; function GetIsHooked: Boolean; function GetIsMDIClient: Boolean; function GetLookAndFeelPainter: TdxSkinLookAndFeelPainterClass; procedure SetHandle(AHandle: HWND); protected function GetIsSkinUsed: Boolean; virtual; function GetMaster(AHandle: HWND): TdxSkinWinController; virtual; function GetUseSkinForControl: Boolean; virtual; procedure DefWndProc(var AMessage); procedure HookWndProc; virtual; procedure InitializePainter; virtual; procedure RedrawWindow(AUpdateNow: Boolean); procedure UnHookWndProc; virtual; procedure WndProc(var AMessage: TMessage); virtual; { IcxMouseTrackingCaller } procedure MouseLeave; virtual; public constructor Create(AHandle: HWND); virtual; destructor Destroy; override; class function IsMDIChildWindow(AHandle: HWND): Boolean; virtual; class function IsMDIClientWindow(AHandle: HWND): Boolean; virtual; class function IsMessageDlgWindow(AHandle: HWND): Boolean; virtual; class function IsSkinActive(AHandle: HWND): Boolean; class procedure FinalizeEngine(AHandle: HWND); class procedure InitializeEngine(AHandle: HWND); function GetSkinName(var ASkinName: string): Boolean; procedure Refresh; virtual; procedure Update; virtual; property Handle: HWND read FHandle write SetHandle; property HasVirtualChilds: Boolean read GetHasVirtualChilds; property IsHooked: Boolean read GetIsHooked; property IsMDIClient: Boolean read GetIsMDIClient; property IsSkinUsed: Boolean read GetIsSkinUsed; property LookAndFeelPainter: TdxSkinLookAndFeelPainterClass read GetLookAndFeelPainter; property Master: TdxSkinWinController read FMaster; property ProcInstance: Pointer read FProcInstance; property WinControl: TWinControl read FWinControl; end; TdxSkinWinControllerClass = class of TdxSkinWinController; TdxSkinGetControllerClassForWindowProc = function (AWnd: HWND): TdxSkinWinControllerClass; { TdxSkinFormController } TdxSkinFormController = class(TdxSkinWinController) private FForceRedraw: Boolean; FHasRegion: Boolean; FLockRedrawCount: Integer; FMaster: TdxSkinFormController; FPainter: TdxSkinFormPainter; FSizingInProcess: Boolean; FViewInfo: TdxSkinFormNonClientAreaInfo; function GetForm: TCustomForm; function GetIsMDIMain: Boolean; protected function GetIsSkinUsed: Boolean; override; function NeedForceRgnUpdate(ASizeType: Integer): Boolean; procedure CalculateViewInfo; virtual; procedure CheckWindowRgn(AForceRgn: Boolean); procedure DrawWindowBackground(DC: HDC); virtual; procedure DrawWindowBorder; virtual; procedure InitializeMessageForm; virtual; procedure InitializePainter; override; function HandleWindowMessage(var AMessage: TMessage): Boolean; virtual; procedure LockRedraw; procedure MouseLeave; override; function RefreshOnMouseEvent(AForceRefresh: Boolean = False): Boolean; procedure UnlockRedraw; procedure UpdateMDIClientEdge; procedure UpdateScrollTrackPos(AKind: TdxSkinFormScrollBar; APos: Integer); procedure WMDestroy(var Message: TWMDestroy); virtual; procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); virtual; procedure WMNCActivate(var Message: TWMNCActivate); virtual; procedure WMNCButtonDown(var Message: TWMNCHitMessage); virtual; procedure WMNCCalcSize(var Message: TWMNCCALCSIZE); virtual; procedure WMNCHitTest(var Message: TWMNCHitTest); virtual; procedure WMNCLButtonUp(var Message: TWMNCHitMessage); virtual; procedure WMNCMouseMove(var Message: TWMNCHitMessage); procedure WMNCPaint(var Message: TWMNCPaint); virtual; procedure WMScroll(var Message: TWMScroll); virtual; procedure WMSetText(var Message: TWMSetText); virtual; procedure WMSize(var Message: TWMSize); virtual; procedure WMSizing(var Message: TWMSize); virtual; procedure WMSysCommand(var Message: TWMSysCommand); virtual; procedure WndProc(var AMessage: TMessage); override; public constructor Create(AHandle: HWND); override; destructor Destroy; override; procedure Update; override; property ForceRedraw: Boolean read FForceRedraw write FForceRedraw; property Form: TCustomForm read GetForm; property HasRegion: Boolean read FHasRegion write FHasRegion; property IsMDIMain: Boolean read GetIsMDIMain; property Painter: TdxSkinFormPainter read FPainter; property SizingInProcess: Boolean read FSizingInProcess write FSizingInProcess; property ViewInfo: TdxSkinFormNonClientAreaInfo read FViewInfo; end; { TdxSkinFormNonClientAreaInfo } TdxSkinFormNonClientAreaInfo = class private FController: TdxSkinFormController; FThemeActive: Boolean; FThemeActiveAssigned: Boolean; function GetBorderBounds(ASide: TcxBorder): TRect; function GetButtonPressed: Boolean; function GetCaptionBounds: TRect; function GetCaptionButtonRect(const ACaptionRect: TRect): TRect; function GetCaptionContentOffset: TRect; function GetCaptionIconSize: Integer; function GetCaptionTextColor: TColor; function GetClientRect: TRect; function GetClientRectOnClient: TRect; function GetExStyle: Integer; function GetHandle: HWND; function GetHasBorder: Boolean; function GetHasCaption: Boolean; function GetHasMenu: Boolean; function GetIconBounds(AIcon: TdxSkinFormIcon): TRect; function GetIconState(AIcon: TdxSkinFormIcon): TdxSkinElementState; function GetIsAlphaBlendUsed: Boolean; function GetIsDialog: Boolean; function GetIsIconic: Boolean; function GetIsSizeBox: Boolean; function GetIsZoomed: Boolean; function GetNativeBorderWidth: Boolean; function GetNeedCheckNonClientSize: Boolean; function GetScrollAreaBounds(AItem: TdxScrollAreaElement): TRect; function GetScrollBarInfo(AScrollBar: TdxSkinFormScrollBar): TScrollBarInfo; function GetScrollBarPartBounds(AScrollBar: TdxSkinFormScrollBar; APart: TcxScrollBarPart): TRect; function GetScrollBarPartState(AScrollBar: TdxSkinFormScrollBar; APart: TcxScrollBarPart): TcxButtonState; function GetSizeArea(ASide: TcxBorder): TRect; function GetSizeCorners(ACorner: TdxSkinFormCorner): TRect; function GetSkinBorderWidth(ASide: TcxBorder): Integer; function GetStyle: Integer; function GetThemeActive: Boolean; function GetToolWindow: Boolean; function GetWindowRect: TRect; procedure SetActive(AActive: Boolean); procedure SetUpdateRgn(ARgn: HRGN); procedure SetWindowRgn(ARgn: HRGN); protected FActive: Boolean; FBorderBounds: array[TcxBorder] of TRect; FBorderWidths: TRect; FBoundsNoBorders: TRect; FCaption: string; FCaptionBounds: TRect; FCaptionFont: TFont; FCaptionSufix: string; FCaptionTextColor: array[Boolean] of TColor; FCaptionTextShadowColor: TColor; FHasMenu: Boolean; FIconBounds: array[TdxSkinFormIcon] of TRect; FIconPressed: TdxSkinFormIcon; FIcons: TdxSkinFormIcons; FIconState: array[TdxSkinFormIcon] of TdxSkinElementState; FIsMDIClient: Boolean; FIsSimpleForm: Boolean; FMenuBounds: TRect; FPainter: TcxCustomLookAndFeelPainterClass; FPainterInfo: TdxSkinLookAndFeelPainterInfo; FScrollAreaBounds: array[TdxScrollAreaElement] of TRect; FScrollAreaElements: TdxScrollAreaElements; FScrollBarPartBounds: array[TdxSkinFormScrollBar, TcxScrollBarPart] of TRect; FScrollBarPartState: array[TdxSkinFormScrollBar, TcxScrollBarPart] of TcxButtonState; FScrollBarsInfo: array[TdxSkinFormScrollBar] of TScrollBarInfo; FSizeFrame: TSize; FSysMenuIcon: HICON; FTrackedScrollBar: TdxScrollAreaElement; FTrackIcon: TdxSkinFormIcon; FUpdateRgn: HRGN; FWindowBounds: TRect; FWindowRgn: HRGN; WindowInfo: TWindowInfo; procedure CalculateBordersInfo; virtual; procedure CalculateBorderWidths; virtual; procedure CalculateCaptionIconsInfo; virtual; procedure CalculateFontInfo; procedure CalculateScrollArea; virtual; procedure CalculateScrollBarPartInfo(AScrollBar: TdxSkinFormScrollBar; Pos1, Pos2: Integer; APart: TcxScrollBarPart); procedure CalculateScrollBarPartsInfo; virtual; function GetActiveMDIChild: TCustomForm; function GetBorderRect(ASide: TcxBorder; const ABounds, AWidths: TRect): TRect; function GetCaption: string; function GetIcons: TdxSkinFormIcons; virtual; function GetMaximizedMDIChild: TCustomForm; function GetSysMenuIcon: HICON; virtual; function GetSystemSizeFrame: TSize; function IsMDIMainAlphaBlendUsed: Boolean; procedure UpdateCaption(const ANewText: string); function UpdateCaptionIconStates: Boolean; function UpdateCaptionSufix: Boolean; function UpdateIconPressed(AReset: Boolean = False): TdxSkinFormIcon; property ThemeActiveAssigned: Boolean read FThemeActiveAssigned write FThemeActiveAssigned; public constructor Create(AController: TdxSkinFormController); virtual; destructor Destroy; override; procedure Calculate(AUpdateRgn: HRGN); virtual; function ClientToScreen(const P: TPoint): TPoint; overload; function ClientToScreen(const R: TRect): TRect; overload; function CreateDrawRgn: HRGN; virtual; function GetHitTest(AHitPoint: TPoint; AHitTest: Integer = 0): Integer; function GetIconHitTest: TdxSkinFormIcon; function GetIconHitTestFromHitTest(AHitTest: Integer): TdxSkinFormIcon; function GetScrollBarHitTest(var AScrollBar: TdxSkinFormScrollBar; var APart: TcxScrollBarPart): Boolean; function ScreenToClient(const P: TSmallPoint): TPoint; overload; function ScreenToClient(const P: TPoint): TPoint; overload; function ScreenToClient(const R: TRect): TRect; overload; property Active: Boolean read FActive write SetActive; property BorderBounds[ASide: TcxBorder]: TRect read GetBorderBounds; property BorderWidths: TRect read FBorderWidths; property BoundsNoBorders: TRect read FBoundsNoBorders; property ButtonPressed: Boolean read GetButtonPressed; property Caption: string read GetCaption; property CaptionBounds: TRect read FCaptionBounds; property CaptionFont: TFont read FCaptionFont; property CaptionTextColor: TColor read GetCaptionTextColor; property CaptionTextShadowColor: TColor read FCaptionTextShadowColor write FCaptionTextShadowColor; property ClientRect: TRect read GetClientRect; property ClientRectOnClient: TRect read GetClientRectOnClient; property Controller: TdxSkinFormController read FController; property ExStyle: Integer read GetExStyle; property Handle: HWND read GetHandle; property HasBorder: Boolean read GetHasBorder; property HasCaption: Boolean read GetHasCaption; property HasMenu: Boolean read GetHasMenu; property IconBounds[AIcon: TdxSkinFormIcon]: TRect read GetIconBounds; property IconPressed: TdxSkinFormIcon read FIconPressed write FIconPressed; property Icons: TdxSkinFormIcons read FIcons; property IconState[AIcon: TdxSkinFormIcon]: TdxSkinElementState read GetIconState; property IsAlphaBlendUsed: Boolean read GetIsAlphaBlendUsed; property IsDialog: Boolean read GetIsDialog; property IsIconic: Boolean read GetIsIconic; property IsMDIClient: Boolean read FIsMDIClient; property IsSizebox: Boolean read GetIsSizeBox; property IsZoomed: Boolean read GetIsZoomed; property MenuBounds: TRect read FMenuBounds; property NativeBorderWidth: Boolean read GetNativeBorderWidth; property NeedCheckNonClientSize: Boolean read GetNeedCheckNonClientSize; property Painter: TcxCustomLookAndFeelPainterClass read FPainter; property PainterInfo: TdxSkinLookAndFeelPainterInfo read FPainterInfo; property ScrollAreaBounds[AItem: TdxScrollAreaElement]: TRect read GetScrollAreaBounds; property ScrollAreaElements: TdxScrollAreaElements read FScrollAreaElements; property ScrollBarInfo[AScrollBar: TdxSkinFormScrollBar]: TScrollBarInfo read GetScrollBarInfo; property ScrollBarPartBounds[AScrollBar: TdxSkinFormScrollBar; APart: TcxScrollBarPart]: TRect read GetScrollBarPartBounds; property ScrollBarPartState[AScrollBar: TdxSkinFormScrollBar; APart: TcxScrollBarPart]: TcxButtonState read GetScrollBarPartState; property SimpleForm: Boolean read FIsSimpleForm; property SizeArea[ASide: TcxBorder]: TRect read GetSizeArea; property SizeCorners[ACorner: TdxSkinFormCorner]: TRect read GetSizeCorners; property SizeFrame: TSize read FSizeFrame; property SkinBorderWidth[ASide: TcxBorder]: Integer read GetSkinBorderWidth; property Style: Integer read GetStyle; property SysMenuIcon: HICON read FSysMenuIcon; property SystemSizeFrame: TSize read GetSystemSizeFrame; property ThemeActive: Boolean read GetThemeActive; property ToolWindow: Boolean read GetToolWindow; property TrackedScrollBar: TdxScrollAreaElement read FTrackedScrollBar write FTrackedScrollBar; property TrackIcon: TdxSkinFormIcon read FTrackIcon write FTrackIcon; property UpdateRgn: HRGN read FUpdateRgn write SetUpdateRgn; property WindowBounds: TRect read FWindowBounds; property WindowRect: TRect read GetWindowRect; property WindowRgn: HRGN read FWindowRgn write SetWindowRgn; end; { TdxSkinFormPainter } TdxSkinFormPainter = class private FBaseCanvas: TCanvas; FBordersCache: array[TcxBorder] of TdxSkinElementCache; FCanvas: TcxCanvas; FDC: HDC; FIconsCache: array[TdxSkinFormIcon] of TdxSkinElementCache; FNeedRelease: Boolean; FPainter: TcxCustomLookAndFeelPainterClass; FPainterInfo: TdxSkinLookAndFeelPainterInfo; FViewInfo: TdxSkinFormNonClientAreaInfo; function GetActive: Boolean; function GetIconElement(AIcon: TdxSkinFormIcon): TdxSkinElement; function GetIsBordersThin: Boolean; protected procedure CreateCacheInfos; procedure DrawBackground(DC: HDC; const R: TRect); virtual; procedure DrawScrollAreaElements(DC: HDC); virtual; procedure DrawScrollBar(DC: HDC; AScrollBar: TdxSkinFormScrollBar; const R: TRect); virtual; procedure DrawSizeGrip(DC: HDC; const R: TRect); procedure DrawWindowCaption(DC: HDC; const R: TRect; AElement: TdxSkinElement); virtual; procedure DrawWindowIcon(DC: HDC; const R: TRect; AIcon: TdxSkinFormIcon; AElement: TdxSkinElement); virtual; procedure FreeCacheInfos; procedure InternalDrawBorder(const R: TRect; ASide: TcxBorder; AFillBackground: Boolean); procedure InternalDrawBorders; procedure InternalDrawCaption(const R: TRect; AElement: TdxSkinElement); procedure InternalDrawThinBorders; public constructor Create(AViewInfo: TdxSkinFormNonClientAreaInfo); virtual; destructor Destroy; override; procedure BeginPaint(ADestDC: HDC = 0); procedure DrawWindowBackground; virtual; procedure DrawWindowBorder; virtual; procedure EndPaint; function IsRectVisible(const R: TRect): Boolean; function SelectDC(DC: HDC): Integer; property Active: Boolean read GetActive; property Canvas: TcxCanvas read FCanvas; property IconElements[AIcon: TdxSkinFormIcon]: TdxSkinElement read GetIconElement; property IsBordersThin: Boolean read GetIsBordersThin; property Painter: TcxCustomLookAndFeelPainterClass read FPainter; property PainterInfo: TdxSkinLookAndFeelPainterInfo read FPainterInfo; property ViewInfo: TdxSkinFormNonClientAreaInfo read FViewInfo; end; { TdxSkinCustomControlViewInfo } TdxSkinCustomControlViewInfo = class private FController: TdxSkinWinController; function GetClientRect: TRect; function GetIsEnabled: Boolean; function GetIsFocused: Boolean; function GetIsMouseAtControl: Boolean; public constructor Create(AController: TdxSkinWinController); virtual; property ClientRect: TRect read GetClientRect; property Controller: TdxSkinWinController read FController; property IsEnabled: Boolean read GetIsEnabled; property IsFocused: Boolean read GetIsFocused; property IsMouseAtControl: Boolean read GetIsMouseAtControl; end; TdxSkinCustomControlViewInfoClass = class of TdxSkinCustomControlViewInfo; { TdxSkinButtonViewInfo } TdxSkinButtonViewInfo = class(TdxSkinCustomControlViewInfo) private FCaption: string; FPressed: Boolean; FState: TcxButtonState; procedure SetState(AState: TcxButtonState); protected procedure UpdateEnabledState; public constructor Create(AController: TdxSkinWinController); override; property Caption: string read FCaption; procedure MouseClickEvent(ADown: Boolean); virtual; procedure MouseHoverEvent(AEnter: Boolean); virtual; property Pressed: Boolean read FPressed; property State: TcxButtonState read FState write SetState; end; { TdxSkinCustomPainter } TdxSkinCustomControlPainter = class(TObject) private FCanvas: TCanvas; FcxCanvas: TcxCanvas; FDC: HDC; FNeedRelease: Boolean; FViewInfo: TdxSkinCustomControlViewInfo; function GetController: TdxSkinWinController; function GetPainter: TcxCustomLookAndFeelPainterClass; protected procedure BeginPaint(DC: HDC = 0); procedure EndPaint; property NeedRelease: Boolean read FNeedRelease; public constructor Create(AViewInfo: TdxSkinCustomControlViewInfo); destructor Destroy; override; procedure DrawBackground; procedure DrawButton(const ACaption: string; const R: TRect; AState: TcxButtonState); procedure DrawFocus(const R: TRect); property Canvas: TcxCanvas read FcxCanvas; property Controller: TdxSkinWinController read GetController; property Painter: TcxCustomLookAndFeelPainterClass read GetPainter; property ViewInfo: TdxSkinCustomControlViewInfo read FViewInfo; end; { TdxSkinCustomController } TdxSkinCustomController = class(TdxSkinWinController) private FPainter: TdxSkinCustomControlPainter; FViewInfo: TdxSkinCustomControlViewInfo; protected class function GetViewInfoClass: TdxSkinCustomControlViewInfoClass; virtual; function GetMaster(AHandle: HWND): TdxSkinWinController; override; procedure InitializePainter; override; procedure WndProc(var AMessage: TMessage); override; // Messages function WMEraseBk(var AMessage: TWMEraseBkgnd): Boolean; virtual; function WMPaint(var AMessage: TWMPaint): Boolean; virtual; public constructor Create(AHandle: HWND); override; destructor Destroy; override; procedure DrawBackground(DC: HDC = 0); procedure DrawContent(DC: HDC = 0); virtual; property Painter: TdxSkinCustomControlPainter read FPainter; property ViewInfo: TdxSkinCustomControlViewInfo read FViewInfo; end; { TdxSkinButtonController } TdxSkinButtonController = class(TdxSkinCustomController) protected function GetViewInfo: TdxSkinButtonViewInfo; class function GetViewInfoClass: TdxSkinCustomControlViewInfoClass; override; procedure MouseLeave; override; procedure WndProc(var AMessage: TMessage); override; public procedure DrawContent(DC: HDC = 0); override; property ViewInfo: TdxSkinButtonViewInfo read GetViewInfo; end; { TdxSkinPanelController } TdxSkinPanelController = class(TdxSkinCustomController) private FPainting: Boolean; protected function WMEraseBk(var AMessage: TWMEraseBkgnd): Boolean; override; function WMPaint(var AMessage: TWMPaint): Boolean; override; procedure InternalDrawBackground(APanel: TCustomPanel; const R: TRect); procedure WndProc(var AMessage: TMessage); override; public procedure DrawContent(DC: HDC = 0); override; end; { TdxSkinFrameController } TdxSkinFrameController = class(TdxSkinCustomController) protected function WMPrintClient(var AMessage: TWMPrintClient): Boolean; procedure WndProc(var AMessage: TMessage); override; public procedure DrawContent(DC: HDC = 0); override; end; var dxSkinControllersList: TList; dxSkinGetControllerClassForWindowProc: TdxSkinGetControllerClassForWindowProc; function dxSkinGetControllerClassForWindow(AWnd: HWND): TdxSkinWinControllerClass; implementation const SC_TITLEDBLCLICK = 61490; {$IFNDEF DELPHI7} ICON_SMALL2 = 2; WM_NCMOUSELEAVE = $02A2; WM_NCMOUSEHOVER = $02A0; {$ENDIF} WM_NCUAHDRAWCAPTION = $00AE; WM_NCUAHDRAWFRAME = $00AF; WM_SYNCPAINT = $0088; // hittests CornerHitTests: array[TdxSkinFormCorner] of DWORD = (HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT); ResizeHitTests: array[TcxBorder] of DWORD = (HTLEFT, HTTOP, HTRIGHT, HTBOTTOM); IconsHitTest: array[TdxSkinFormIcon] of DWORD = (HTSYSMENU, HTHELP, HTMINBUTTON, HTMAXBUTTON, HTMAXBUTTON, HTCLOSE); IconCommand: array[TdxSkinFormIcon] of Integer = (SC_DEFAULT, SC_CONTEXTHELP, SC_MINIMIZE, SC_MAXIMIZE, SC_RESTORE, SC_CLOSE); sdxMDICaptionFormat = '%s - [%s]'; const CaptionFlags = DT_VCENTER or DT_SINGLELINE or DT_EDITCONTROL or DT_END_ELLIPSIS or DT_NOPREFIX; FrameStates: array[Boolean] of TdxSkinElementState = (esActiveDisabled, esActive); type { TdxSkinWinControllerHelper } TdxSkinWinControllerHelper = class(TObject) private FHandle: HWND; protected procedure InternalInitializeEngine(AHandle: HWND); procedure WndProc(var AMsg: TMessage); public constructor Create; destructor Destroy; override; procedure ChildChanged(AHandle: HWND); procedure FinalizeEngine(AHandle: HWND); procedure InitializeEngine(AHandle: HWND); property Handle: HWND read FHandle; end; var FormControllers: TcxObjectList; SkinHelper: TdxSkinWinControllerHelper; WndProcHookHandle: HHOOK; type TCustomFormAccess = class(TCustomForm); TCustomFrameAccess = class(TCustomFrame); TCustomLabelAccess = class(TCustomLabel); TCustomPanelAccess = class(TCustomPanel); TcxLookAndFeelAccess = class(TcxLookAndFeel); function GetControllerByControl(AControl: TWinControl): TdxSkinWinController; var I: Integer; begin Result := nil; if AControl = nil then Exit; for I := 0 to FormControllers.Count - 1 do if TdxSkinWinController(FormControllers.Items[I]).WinControl = AControl then begin Result := TdxSkinWinController(FormControllers.Items[I]); Break; end; end; function GetControllerByHandle(AHandle: HWND): TdxSkinWinController; var I: Integer; begin Result := nil; for I := 0 to FormControllers.Count - 1 do if TdxSkinWinController(FormControllers.Items[I]).Handle = AHandle then begin Result := TdxSkinWinController(FormControllers.Items[I]); Break; end; end; function GetWindowCaption(AWnd: HWND): string; var L: Integer; begin L := SendMessage(AWnd, WM_GETTEXTLENGTH, 0, 0); SetLength(Result, L); if L > 0 then SendMessage(AWnd, WM_GETTEXT, L + 1, Integer(@Result[1])); end; function GetWindowClass(AWnd: HWND): string; var AClassName: array[Byte] of Char; begin if GetClassName(AWnd, @AClassName[0], 256) > 0 then Result := AClassName else Result := ''; end; procedure RefreshController(AController: TdxSkinFormController); var AIndex: Integer; ASkinController: TdxSkinController; ASkinName: string; AUseSkin: Boolean; begin with AController do for AIndex := dxSkinControllersList.Count - 1 downto 0 do begin ASkinController := TdxSkinController(dxSkinControllersList[AIndex]); if (csDestroying in ASkinController.ComponentState) then Continue; if FLookAndFeelPainter = nil then FLookAndFeelPainter := ASkinController.DoSkinForm(Form) else begin AUseSkin := SendMessage(Form.Handle, dxWMGetSkinnedMessage, 0, 0) <> 1; if AUseSkin then begin AUseSkin := GetSkinName(ASkinName); FLookAndFeelPainter := ASkinController.DoSkinFormEx(Form, ASkinName, AUseSkin); end else FLookAndFeelPainter := nil; end; end; end; procedure RefreshControllers; var AIndex: Integer; begin for AIndex := 0 to FormControllers.Count - 1 do with TdxSkinWinController(FormControllers[AIndex]) do begin FLookAndFeelPainter := nil; if IsMDIClient then Continue; if FormControllers[AIndex] is TdxSkinFormController then RefreshController(TdxSkinFormController(FormControllers[AIndex])); end; for AIndex := 0 to FormControllers.Count - 1 do TdxSkinWinController(FormControllers[AIndex]).Update; end; { TdxSkinWinController } constructor TdxSkinWinController.Create(AHandle: HWND); begin FProcInstance := Classes.MakeObjectInstance(WndProc); Handle := AHandle; end; destructor TdxSkinWinController.Destroy; begin EndMouseTracking(Self); Handle := 0; {$IFDEF DELPHI6}Classes.{$ENDIF}FreeObjectInstance(FProcInstance); inherited Destroy; end; class procedure TdxSkinWinController.InitializeEngine(AHandle: HWND); var ANewController: TdxSkinWinController; begin ANewController := GetControllerByHandle(AHandle); if ANewController = nil then begin ANewController := GetControllerByControl(FindControl(AHandle)); if ANewController = nil then begin ANewController := Self.Create(AHandle); ANewController.FMaster := ANewController.GetMaster(AHandle); FormControllers.Add(ANewController); end else ANewController.Handle := AHandle; ANewController.InitializePainter; ANewController.Update; end; end; class procedure TdxSkinWinController.FinalizeEngine(AHandle: HWND); var AController: TdxSkinWinController; begin AController := GetControllerByHandle(AHandle); if Assigned(AController) then begin FormControllers.Remove(AController); AController.Free; end; end; class function TdxSkinWinController.IsMDIChildWindow(AHandle: HWND): Boolean; var AControl: TWinControl; begin AControl := FindControl(AHandle); Result := (AControl is TCustomForm) and (TCustomFormAccess(AControl).FormStyle = fsMDIChild); end; class function TdxSkinWinController.IsMDIClientWindow(AHandle: HWND): Boolean; begin Result := AnsiSameText(GetWindowClass(AHandle), 'MDICLIENT'); end; class function TdxSkinWinController.IsSkinActive(AHandle: HWND): Boolean; var AController: TdxSkinWinController; begin AController := GetControllerByHandle(AHandle); Result := Assigned(AController) and AController.IsSkinUsed; end; class function TdxSkinWinController.IsMessageDlgWindow(AHandle: HWND): Boolean; begin Result := AnsiSameText(GetWindowClass(AHandle), 'TMessageForm'); end; function TdxSkinWinController.GetHasVirtualChilds: Boolean; var AControl: TWinControl; I: Integer; begin AControl := WinControl; Result := False; if Assigned(AControl) then for I := 0 to AControl.ControlCount - 1 do begin Result := not (AControl.Controls[I] is TWinControl); if Result then Break; end; end; function TdxSkinWinController.GetIsHooked: Boolean; begin Result := (Handle <> 0) and ((FSavedWndProcPtr <> nil) or Assigned(FSavedWndProc)); end; function TdxSkinWinController.GetIsMDIClient: Boolean; begin Result := Assigned(FMaster); end; function TdxSkinWinController.GetLookAndFeelPainter: TdxSkinLookAndFeelPainterClass; begin Result := FLookAndFeelPainter; if Master <> nil then Result := Master.LookAndFeelPainter; end; procedure TdxSkinWinController.SetHandle(AHandle: HWND); begin UnHookWndProc; FHandle := AHandle; FWinControl := FindControl(Handle); Update; end; function TdxSkinWinController.GetIsSkinUsed: Boolean; begin Result := LookAndFeelPainter <> nil; end; function TdxSkinWinController.GetMaster(AHandle: HWND): TdxSkinWinController; begin Result := nil; if IsMDIClientWindow(AHandle) then Result := GetControllerByHandle(GetParent(AHandle)); end; function TdxSkinWinController.GetUseSkinForControl: Boolean; var AControl: TWinControl; AIndex: Integer; ASkinController: TdxSkinController; AUseSkin: Boolean; begin AControl := WinControl; AUseSkin := cxUseSkins and (AControl <> nil); if Assigned(AControl) then for AIndex := dxSkinControllersList.Count - 1 downto 0 do begin ASkinController := TdxSkinController(dxSkinControllersList[AIndex]); if (csDestroying in ASkinController.ComponentState) then Continue; AUseSkin := ASkinController.DoSkinControl(AControl); if AUseSkin then Break; end; Result := AUseSkin; end; procedure TdxSkinWinController.DefWndProc(var AMessage); begin if FSavedWndProcPtr <> nil then with TMessage(AMessage) do Result := CallWindowProc(FSavedWndProcPtr, Handle, Msg, wParam, lParam) else if Assigned(FSavedWndProc) then FSavedWndProc(TMessage(AMessage)); end; procedure TdxSkinWinController.HookWndProc; begin if Handle = 0 then Exit; UnHookWndProc; if WinControl <> nil then begin FSavedWndProc := WinControl.WindowProc; WinControl.WindowProc := WndProc; end else begin FSavedWndProcPtr := Pointer(GetWindowLong(Handle, GWL_WNDPROC)); SetWindowLong(Handle, GWL_WNDPROC, Integer(FProcInstance)); end; end; procedure TdxSkinWinController.InitializePainter; begin // nothing todo end; procedure TdxSkinWinController.RedrawWindow(AUpdateNow: Boolean); var AFlags: Integer; const DefaultFlags = RDW_ERASE or RDW_INVALIDATE or RDW_FRAME or RDW_ALLCHILDREN; begin if Handle = 0 then Exit; AFlags := DefaultFlags; if AUpdateNow then AFlags := AFlags or RDW_UPDATENOW; Windows.RedrawWindow(Handle, nil, 0, AFlags); end; procedure TdxSkinWinController.UnHookWndProc; begin if IsHooked then begin if WinControl <> nil then WinControl.WindowProc := FSavedWndProc else SetWindowLong(Handle, GWL_WNDPROC, Integer(FSavedWndProcPtr)); FSavedWndProcPtr := nil; FSavedWndProc := nil; end; end; function TdxSkinWinController.GetSkinName(var ASkinName: string): Boolean; begin Result := GetExtendedStylePainters.GetNameByPainter(FLookAndFeelPainter, ASkinName); end; procedure TdxSkinWinController.Refresh; const Flags = SWP_FRAMECHANGED or SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER; begin if Handle <> 0 then SetWindowPos(Handle, 0, 0, 0, 0, 0, Flags); end; procedure TdxSkinWinController.Update; begin HookWndProc; Refresh; RedrawWindow(HasVirtualChilds); end; procedure TdxSkinWinController.WndProc(var AMessage: TMessage); begin DefWndProc(AMessage); end; procedure TdxSkinWinController.MouseLeave; begin end; { TdxSkinController } constructor TdxSkinController.Create(AOwner: TComponent); begin inherited Create(AOwner); if dxSkinControllersList <> nil then dxSkinControllersList.Add(Self); Changed; end; destructor TdxSkinController.Destroy; begin Changed; if dxSkinControllersList <> nil then dxSkinControllersList.Remove(Self); inherited Destroy; end; procedure TdxSkinController.Refresh; begin Changed; end; class function TdxSkinController.GetFormSkin(AForm: TCustomForm; var ASkinName: string): Boolean; var AController: TdxSkinWinController; begin AController := GetControllerByHandle(AForm.Handle); Result := Assigned(AController) and AController.GetSkinName(ASkinName); end; procedure TdxSkinController.Changed; begin RefreshControllers; end; function TdxSkinController.DoSkinControl(AControl: TWinControl): Boolean; var AUseSkin: Boolean; begin Result := AControl <> nil; if Result then begin AUseSkin := True; if Assigned(OnSkinControl) then OnSkinControl(Self, AControl, AUseSkin); Result := AUseSkin end end; function TdxSkinController.DoSkinForm( AForm: TCustomForm): TdxSkinLookAndFeelPainterClass; var ASkinName: string; AUseSkin: Boolean; begin if (AForm <> nil) and (SendMessage(AForm.Handle, dxWMGetSkinnedMessage, 0, 0) = 1) then begin ASkinName := ''; AUseSkin := False; end else begin ASkinName := SkinName; AUseSkin := UseSkins; end; Result := DoSkinFormEx(AForm, ASkinName, AUseSkin); end; function TdxSkinController.DoSkinFormEx(AForm: TCustomForm; var ASkinName: string; var AUseSkin: Boolean): TdxSkinLookAndFeelPainterClass; var APainter: TcxCustomLookAndFeelPainterClass; begin Result := nil; if AForm = nil then Exit; if Assigned(OnSkinForm) then OnSkinForm(Self, AForm, ASkinName, AUseSkin); if AUseSkin and (ASkinName <> '') and GetExtendedStylePainters.GetPainterByName( ASkinName, APainter) and (APainter.InheritsFrom(TdxSkinLookAndFeelPainter)) then Result := TdxSkinLookAndFeelPainterClass(APainter); end; procedure TdxSkinController.Loaded; begin inherited Loaded; Changed; end; procedure TdxSkinController.MasterLookAndFeelChanged( Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); begin inherited MasterLookAndFeelChanged(Sender, AChangedValues); Changed; end; procedure TdxSkinController.MasterLookAndFeelDestroying( Sender: TcxLookAndFeel); begin inherited MasterLookAndFeelDestroying(Sender); Changed; end; function TdxSkinController.GetUseSkins: Boolean; begin Result := cxUseSkins; end; procedure TdxSkinController.SetUseSkins(Value: Boolean); begin if Value <> UseSkins then begin cxLookAndFeels.cxUseSkins := Value; TcxLookAndFeelAccess(RootLookAndFeel).Changed([lfvKind..lfvSkinName]); Changed; end; end; { TdxSkinFormController } constructor TdxSkinFormController.Create(AHandle: HWND); begin inherited Create(AHandle); FViewInfo := TdxSkinFormNonClientAreaInfo.Create(Self); FPainter := TdxSkinFormPainter.Create(FViewInfo); if IsMessageDlgWindow(AHandle) then InitializeMessageForm; end; destructor TdxSkinFormController.Destroy; var I: Integer; begin cxClearObjectLinks(Self); for I := 0 to dxSkinControllersList.Count - 1 do with TdxSkinFormController(dxSkinControllersList[I]) do if FMaster = Self then FMaster := nil; FreeAndNil(FPainter); FreeAndNil(FViewInfo); inherited Destroy; end; procedure TdxSkinFormController.Update; begin inherited Update; if (Handle <> 0) and HasRegion and not IsSkinUsed and (Form <> nil) then begin HasRegion := False; SetWindowRgn(Handle, 0, False); end; UpdateMDIClientEdge; end; procedure TdxSkinFormController.DrawWindowBackground(DC: HDC); begin Painter.BeginPaint(DC); try Painter.DrawWindowBackground; finally Painter.EndPaint; end; end; procedure TdxSkinFormController.DrawWindowBorder; begin Painter.BeginPaint; try Painter.DrawWindowBorder; finally Painter.EndPaint; end; end; procedure TdxSkinFormController.CalculateViewInfo; begin ViewInfo.Calculate(0); end; procedure TdxSkinFormController.CheckWindowRgn(AForceRgn: Boolean); var R: TRect; begin if AForceRgn then begin HasRegion := True; GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top); SetWindowRgn(Handle, CreateRectRgnIndirect(R), True); end else if IsZoomed(Handle) and HasRegion then begin HasRegion := False; LockRedraw; SetWindowRgn(Handle, 0, False); UnlockRedraw; PostMessage(Handle, WM_POSTREDRAW, 0, 0); end; end; procedure TdxSkinFormController.InitializeMessageForm; var I: Integer; AForm: TCustomForm; begin AForm := Form; for I := AForm.ControlCount - 1 downto 0 do begin if AForm.Controls[I] is TCustomLabel then TCustomLabelAccess(AForm.Controls[I]).Transparent := True; end; end; procedure TdxSkinFormController.InitializePainter; var ASkinName: string; AUseSkin: Boolean; I: Integer; begin if Form <> nil then for I := 0 to dxSkinControllersList.Count - 1 do with TdxSkinController(dxSkinControllersList[I]) do begin if I = 0 then begin FLookAndFeelPainter := DoSkinForm(Form); AUseSkin := FLookAndFeelPainter <> nil; end else begin AUseSkin := GetFormSkin(Form, ASkinName); FLookAndFeelPainter := DoSkinFormEx(Form, ASkinName, AUseSkin); end; if FLookAndFeelPainter <> nil then Break; end; end; function TdxSkinFormController.HandleWindowMessage( var AMessage: TMessage): Boolean; const WindowState: array[Boolean] of Integer = (0, SIZE_MAXIMIZED); begin Result := IsSkinUsed; if not Result then Exit; CheckWindowRgn(False); if ForceRedraw then begin DrawWindowBorder; ForceRedraw := False; end; case AMessage.Msg of $3F: UpdateMDIClientEdge; WM_DESTROY, WM_MDIDESTROY: if AMessage.WParam = 0 then WMDestroy(TWMDestroy(AMessage)) else DefWndProc(AMessage); WM_NCCALCSIZE: WMNCCalcSize(TWMNCCalcSize(AMessage)); WM_NCMOUSEMOVE: WMNCMouseMove(TWMNCHitMessage(AMessage)); WM_NCACTIVATE: WMNCActivate(TWMNCActivate(AMessage)); WM_ACTIVATE: begin DefWndProc(AMessage); DrawWindowBorder; end; WM_NCUAHDRAWFRAME, WM_NCUAHDRAWCAPTION, WM_SYNCPAINT: DrawWindowBorder; WM_NCLBUTTONDOWN, WM_NCLBUTTONDBLCLK: WMNCButtonDown(TWMNCHitMessage(AMessage)); WM_NCLBUTTONUP: WMNCLButtonUp(TWMNCHitMessage(AMessage)); WM_NCPAINT: WMNCPaint(TWMNCPaint(AMessage)); WM_NCHITTEST: WMNCHitTest(TWMNCHitTest(AMessage)); WM_ERASEBKGND: WMEraseBkgnd(TWMEraseBkgnd(AMessage)); WM_SIZING: WMSizing(TWMSize(AMessage)); WM_SIZE: WMSize(TWMSize(AMessage)); WM_SYSCOMMAND: WMSysCommand(TWMSysCommand(AMessage)); WM_VSCROLL, WM_HSCROLL: WMScroll(TWMScroll(AMessage)); WM_THEMECHANGED: begin ViewInfo.ThemeActiveAssigned := False; Result := False; end; else if AMessage.Msg = WM_CHILDCHANGED then begin if ViewInfo.UpdateCaptionSufix then DrawWindowBorder; end else if (dxWMSetSkinnedMessage > 0) and (AMessage.Msg = dxWMSetSkinnedMessage) then RefreshController(ViewInfo.Controller) else if AMessage.Msg = WM_POSTREDRAW then RedrawWindow(False) else if AMessage.Msg = WM_POSTCHECKRGN then CheckWindowRgn(NeedForceRgnUpdate(WindowState[IsZoomed(Handle)])) else Result := False; end; end; procedure TdxSkinFormController.LockRedraw; begin Inc(FLockRedrawCount); if FLockRedrawCount = 1 then DefWindowProc(Handle, WM_SETREDRAW, 0, 0); end; procedure TdxSkinFormController.UpdateMDIClientEdge; var AStyle: Integer; begin if IsMDIClient then begin AStyle := GetWindowLong(Handle, GWL_EXSTYLE); if AStyle and WS_EX_CLIENTEDGE <> 0 then AStyle := AStyle and not WS_EX_CLIENTEDGE else Exit; SetWindowLong(Handle, GWL_EXSTYLE, AStyle); Refresh; end; end; function TdxSkinFormController.RefreshOnMouseEvent( AForceRefresh: Boolean = False): Boolean; var APart: TcxScrollBarPart; AScrollBar: TdxSkinFormScrollBar; begin with ViewInfo do begin Result := UpdateCaptionIconStates; if TrackIcon <> sfiMenu then BeginMouseTracking(nil, ClientToScreen(IconBounds[TrackIcon]), Self) else if GetScrollBarHitTest(AScrollBar, APart) then begin Result := not IsMouseTracking(Self); BeginMouseTracking(nil, ClientToScreen(ScrollBarPartBounds[AScrollBar, APart]), Self) end else begin Result := Result or IsMouseTracking(Self); EndMouseTracking(Self); end; end; if Result or AForceRefresh then Refresh; end; procedure TdxSkinFormController.UnlockRedraw; begin Dec(FLockRedrawCount); if FLockRedrawCount = 0 then DefWindowProc(Handle, WM_SETREDRAW, 1, 0); end; procedure TdxSkinFormController.UpdateScrollTrackPos( AKind: TdxSkinFormScrollBar; APos: Integer); var Info: TScrollInfo; begin Info.cbSize := SizeOf(TScrollInfo); Info.fMask := SIF_TRACKPOS; if FlatSB_GetScrollInfo(Handle, Byte(AKind), Info) then APos := Info.nTrackPos; FlatSB_SetScrollPos(Handle, Byte(AKind), APos, False); end; procedure TdxSkinFormController.WMDestroy(var Message: TWMDestroy); begin FLookAndFeelPainter := nil; DefWndProc(Message); UnHookWndProc; end; procedure TdxSkinFormController.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin DrawWindowBackground(Message.DC); Message.Result := 1; end; procedure TdxSkinFormController.WMNCActivate(var Message: TWMNCActivate); var AFlags: DWORD; AMDIChild: TCustomForm; begin ViewInfo.Active := Message.Active; AMDIChild := ViewInfo.GetActiveMDIChild; if Assigned(AMDIChild) then AMDIChild.Perform(WM_NCACTIVATE, TMessage(Message).WParam, 0); if IsMDIChildWindow(Handle) then begin AFlags := GetWindowLong(Handle, GWL_STYLE); SetWindowLong(Handle, GWL_STYLE, AFlags and not WS_VISIBLE); Message.Result := DefWindowProc(Handle, WM_NCACTIVATE, TMessage(Message).WParam, 0); SetWindowLong(Handle, GWL_STYLE, AFlags); end else Message.Result := 1; DrawWindowBorder; end; procedure TdxSkinFormController.WMNCButtonDown(var Message: TWMNCHitMessage); var ALink: TcxObjectLink; ALocked: Boolean; begin ALink := cxAddObjectLink(Self); try ForceRedraw := True; ViewInfo.UpdateIconPressed; ViewInfo.UpdateCaptionIconStates; ALocked := Message.HitTest in [HTHSCROLL, HTVSCROLL]; if ALocked then LockRedraw; if ViewInfo.GetIconHitTest in [sfiMenu, sfiHelp] then DefWndProc(Message); if Assigned(ALink.Ref) then begin if ALocked then UnlockRedraw; RefreshOnMouseEvent(True); DrawWindowBorder; end; finally cxRemoveObjectLink(ALink); end; Message.Result := 0; end; procedure TdxSkinFormController.WMNCCalcSize(var Message: TWMNCCalcSize); var R, Margins: TRect; begin R := Message.CalcSize_Params^.rgrc[0]; DefWndProc(Message); CalculateViewInfo; if Message.CalcValidRects and ViewInfo.NeedCheckNonClientSize then begin Margins := ViewInfo.BorderWidths; if saeVertScroll in ViewInfo.ScrollAreaElements then Inc(Margins.Right, GetSystemMetrics(SM_CXVSCROLL)); if saeHorzScroll in ViewInfo.ScrollAreaElements then Inc(Margins.Bottom, GetSystemMetrics(SM_CYHSCROLL)); with ViewInfo do if IsZoomed and IsSizebox then begin Inc(Margins.Left, SystemSizeFrame.cx - SizeFrame.cx); Inc(Margins.Right, SystemSizeFrame.cx - SizeFrame.cx); Inc(Margins.Top, SystemSizeFrame.cy - SizeFrame.cy); if saeVertScroll in ScrollAreaElements then Inc(Margins.Right, SizeFrame.cx - BorderWidths.Right); if saeHorzScroll in ScrollAreaElements then Inc(Margins.Bottom, SizeFrame.cy - BorderWidths.Bottom); end; Message.CalcSize_Params^.rgrc[0] := cxRectContent(R, Margins); end; end; procedure TdxSkinFormController.WMNCHitTest(var Message: TWMNCHitTest); begin with Message do Result := ViewInfo.GetHitTest(SmallPointToPoint(Pos), Result); if (Message.Result = HTNOWHERE) or (Message.Result = HTSYSMENU) then DefWndProc(Message); end; procedure TdxSkinFormController.WMNCLButtonUp(var Message: TWMNCHitMessage); var ADefaultCall: Boolean; ADownIcon: TdxSkinFormIcon; begin ADownIcon := ViewInfo.UpdateIconPressed(True); ADefaultCall := ADownIcon in [sfiMenu, sfiHelp]; if ADefaultCall then DefWndProc(Message); RefreshOnMouseEvent(True); if not ADefaultCall then SendMessage(Handle, WM_SYSCOMMAND, IconCommand[ADownIcon], 0); end; procedure TdxSkinFormController.WMNCMouseMove(var Message: TWMNCHitMessage); begin if not RefreshOnMouseEvent then begin Message.HitTest := 0; DefWndProc(Message); DrawWindowBorder; end; end; procedure TdxSkinFormController.WMNCPaint(var Message: TWMNCPaint); var AFrameRgn, AWindowRgn: HRgn; begin CalculateViewInfo; DrawWindowBorder; AFrameRgn := ViewInfo.CreateDrawRgn; AWindowRgn := CreateRectRgnIndirect(ViewInfo.WindowRect); CombineRgn(AWindowRgn, AWindowRgn, AFrameRgn, RGN_XOR); DeleteObject(AFrameRgn); if ViewInfo.HasMenu or IsMDIClientWindow(Handle) then begin if Message.RGN <> 1 then begin CombineRgn(AWindowRgn, AWindowRgn, Message.RGN, RGN_AND); DeleteObject(Message.RGN); end; Message.RGN := AWindowRgn; DefWndProc(Message); end; DeleteObject(AWindowRgn); Message.RGN := 1; Message.Result := 0; end; procedure TdxSkinFormController.WMScroll(var Message: TWMScroll); begin ViewInfo.TrackedScrollBar := TdxScrollAreaElement(Message.Msg - WM_HSCROLL); if TWMScroll(Message).ScrollCode = SB_THUMBTRACK then UpdateScrollTrackPos(ViewInfo.TrackedScrollBar, TWMScroll(Message).Pos) else ViewInfo.TrackedScrollBar := saeSizeGrip; LockRedraw; DefWndProc(Message); UnlockRedraw; UnlockRedraw; try RedrawWindow(True); finally LockRedraw; end; end; procedure TdxSkinFormController.WMSetText(var Message: TWMSetText); begin DefWndProc(Message); ViewInfo.UpdateCaption(Message.Text); Refresh; end; procedure TdxSkinFormController.WMSizing(var Message: TWMSize); begin FSizingInProcess := True; DefWndProc(Message); end; procedure TdxSkinFormController.WMSize(var Message: TWMSize); begin FSizingInProcess := False; DefWndProc(Message); CheckWindowRgn(NeedForceRgnUpdate(Message.SizeType)); end; procedure TdxSkinFormController.WMSysCommand(var Message: TWMSysCommand); var ALink: TcxObjectLink; begin ALink := cxAddObjectLink(Self); try DefWndProc(Message); if Assigned(ALink.Ref) then DrawWindowBorder; finally cxRemoveObjectLink(ALink); end; end; procedure TdxSkinFormController.MouseLeave; begin UnlockRedraw; RefreshOnMouseEvent(True); UpdateWindow(Handle); LockRedraw; end; function TdxSkinFormController.GetForm: TCustomForm; var AControl: TWinControl; begin AControl := FindControl(Handle); if AControl is TCustomForm then Result := AControl as TCustomForm else Result := nil; end; function TdxSkinFormController.GetIsMDIMain: Boolean; begin Result := (Form <> nil) and (TCustomFormAccess(Form).FormStyle = fsMDIForm); end; function TdxSkinFormController.GetIsSkinUsed: Boolean; begin Result := inherited GetIsSkinUsed and (ViewInfo <> nil); end; function TdxSkinFormController.NeedForceRgnUpdate(ASizeType: Integer): Boolean; var AForm: TCustomForm; begin AForm := Form; if Assigned(AForm) then begin Result := AForm.BorderStyle <> bsNone; if Result then Result := (ASizeType <> SIZE_MAXIMIZED) or Assigned(AForm.Parent) end else Result := ASizeType <> SIZE_MAXIMIZED; end; procedure TdxSkinFormController.WndProc(var AMessage: TMessage); begin if AMessage.Msg = WM_SETTEXT then WMSetText(TWMSetText(AMessage)) else if not (IsSkinUsed and HandleWindowMessage(AMessage)) then DefWndProc(AMessage); end; { TdxSkinFormNonClientAreaInfo } constructor TdxSkinFormNonClientAreaInfo.Create(AController: TdxSkinFormController); begin FController := AController; FCaptionFont := TFont.Create; FTrackedScrollBar := saeSizeGrip; FCaption := GetWindowCaption(Handle); FActive := True; end; destructor TdxSkinFormNonClientAreaInfo.Destroy; begin UpdateRgn := 0; WindowRgn := 0; FreeAndNil(FCaptionFont); inherited Destroy; end; procedure TdxSkinFormNonClientAreaInfo.Calculate( AUpdateRgn: HRGN); begin FHasMenu := IsMenu(GetMenu(Handle)) and not TdxSkinFormController.IsMDIChildWindow(Handle); FIsMDIClient := TdxSkinFormController.IsMDIClientWindow(Handle); FIsSimpleForm := (Controller.Form <> nil) and not (TCustomFormAccess(Controller.Form).FormStyle in [fsMDIChild, fsMDIForm]); FPainter := Controller.LookAndFeelPainter; GetExtendedStylePainters.GetPainterData(Painter, FPainterInfo); WindowInfo.cbSize := SizeOf(WindowInfo); GetWindowInfo(Handle, WindowInfo); if NativeBorderWidth then FSizeFrame := GetSystemSizeFrame else FSizeFrame := Size(4, 4); FWindowBounds := cxRectOffset(WindowRect, -WindowRect.Left, -WindowRect.Top); FBoundsNOBorders := cxRectOffset(ClientRect, cxPointInvert(WindowRect.TopLeft)); WindowRgn := CreateRectRgnIndirect(WindowBounds); FIcons := GetIcons; FSysMenuIcon := GetSysMenuIcon; CalculateFontInfo; CalculateBorderWidths; FMenuBounds := cxRectSetBottom(FBoundsNOBorders, FBoundsNOBorders.Top, FBoundsNOBorders.Top - BorderWidths.Top); CalculateBordersInfo; CalculateCaptionIconsInfo; CalculateScrollArea; end; function TdxSkinFormNonClientAreaInfo.ClientToScreen(const P: TPoint): TPoint; begin Result := cxPointOffset(P, WindowRect.TopLeft); end; function TdxSkinFormNonClientAreaInfo.ClientToScreen(const R: TRect): TRect; begin Result := cxRectOffset(R, WindowRect.TopLeft); end; function TdxSkinFormNonClientAreaInfo.CreateDrawRgn: HRGN; var ARgn: HRgn; ASide: TcxBorder; AItem: TdxScrollAreaElement; begin Result := CreateRectRgnIndirect(cxNullRect); for ASide := bLeft to bBottom do begin if cxRectIsEmpty(BorderBounds[ASide]) then Continue; ARgn := CreateRectRgnIndirect( ClientToScreen(BorderBounds[ASide])); CombineRgn(Result, Result, ARgn, RGN_OR); DeleteObject(ARgn); end; if HasMenu then begin ARgn := CreateRectRgnIndirect(ClientToScreen( cxRectSetBottom(MenuBounds, MenuBounds.Bottom, 1))); CombineRgn(Result, Result, ARgn, RGN_OR); DeleteObject(ARgn); end; for AItem := saeHorzScroll to saeSizeGrip do if AItem in FScrollAreaElements then begin ARgn := CreateRectRgnIndirect(ClientToScreen(ScrollAreaBounds[AItem])); CombineRgn(Result, Result, ARgn, RGN_OR); DeleteObject(ARgn); end; end; function TdxSkinFormNonClientAreaInfo.GetHitTest(AHitPoint: TPoint; AHitTest: Integer = 0): Integer; var ASide: TcxBorder; AIcon: TdxSkinFormIcon; ACorner: TdxSkinFormCorner; begin Result := AHitTest; AHitPoint := ScreenToClient(AHitPoint); if IsSizebox and not IsZoomed then begin for ACorner := sfcLeftTop to sfcRightBottom do if (Result = HTNOWHERE) and PtInRect(SizeCorners[ACorner], AHitPoint) then Result := CornerHitTests[ACorner]; for ASide := bLeft to bBottom do if (Result = HTNOWHERE) and PtInRect(SizeArea[ASide], AHitPoint) then Result := ResizeHitTests[ASide]; end; if (Result = HTNOWHERE) and PtInRect(BorderBounds[bTop], AHitPoint) then begin Result := HTCAPTION; // correct 'restore' hittest IconsHitTest[sfiRestore] := HTMAXBUTTON; if IsIconic then IconsHitTest[sfiRestore] := HTMINBUTTON; // for AIcon := sfiMenu to sfiClose do begin if PtInRect(IconBounds[AIcon], AHitPoint) then Result := IconsHitTest[AIcon]; end; end; end; function TdxSkinFormNonClientAreaInfo.GetIconHitTest: TdxSkinFormIcon; begin Result := GetIconHitTestFromHitTest(GetHitTest(GetMouseCursorPos)); end; function TdxSkinFormNonClientAreaInfo.GetIconHitTestFromHitTest( AHitTest: Integer): TdxSkinFormIcon; begin Result := sfiMenu; case AHitTest of HTHELP: Result := sfiHelp; HTMINBUTTON: if IsIconic then Result := sfiRestore else Result := sfiMinimize; HTMAXBUTTON: if IsZoomed then Result := sfiRestore else Result := sfiMaximize; HTCLOSE: Result := sfiClose; end; end; function TdxSkinFormNonClientAreaInfo.GetScrollBarHitTest( var AScrollBar: TdxSkinFormScrollBar; var APart: TcxScrollBarPart): Boolean; var APoint: TPoint; AItem: TdxSkinFormScrollBar; APartItem: TcxScrollBarPart; begin Result := False; APoint := ScreenToClient(GetMouseCursorPos); for AItem := saeHorzScroll to saeVertScroll do begin if not (AItem in ScrollAreaElements) or not PtInRect(ScrollAreaBounds[AItem], APoint) then Continue; AScrollBar := AItem; for APartItem := sbpLineUp to sbpPageDown do begin Result := (ScrollBarPartState[AItem, APartItem] <> cxbsDefault) and PtInRect(ScrollBarPartBounds[AItem, APartItem], APoint); if Result then begin APart := APartItem; Exit; end; end; end; end; function TdxSkinFormNonClientAreaInfo.ScreenToClient(const P: TSmallPoint): TPoint; begin Result := ScreenToClient(SmallPointToPoint(P)); end; function TdxSkinFormNonClientAreaInfo.ScreenToClient(const P: TPoint): TPoint; begin Result := cxPointOffset(P, cxPointInvert(WindowRect.TopLeft)); end; function TdxSkinFormNonClientAreaInfo.ScreenToClient(const R: TRect): TRect; begin Result := cxRectOffset(R, cxPointInvert(WindowRect.TopLeft)); end; procedure TdxSkinFormNonClientAreaInfo.UpdateCaption(const ANewText: string); begin FCaption := ANewText; UpdateCaptionSufix; end; procedure TdxSkinFormNonClientAreaInfo.CalculateBordersInfo; var ASide: TcxBorder; begin for ASide := bLeft to bBottom do FBorderBounds[ASide] := GetBorderRect(ASide, WindowBounds, BorderWidths); if IsZoomed and not NativeBorderWidth and IsSizeBox then OffsetRect(FBorderBounds[bTop], 0, SystemSizeFrame.cy - SizeFrame.cy); end; procedure TdxSkinFormNonClientAreaInfo.CalculateBorderWidths; const CaptionMetric: array[Boolean] of Integer = (SM_CYCAPTION, SM_CYSMCAPTION); begin FBorderWidths := cxNullRect; if not NativeBorderWidth and HasBorder then begin FBorderWidths := PainterInfo.FormBorderWidths[not ToolWindow]; if ToolWindow then Inc(FBorderWidths.Top, SizeFrame.cy); end; if HasCaption then if NativeBorderWidth or ToolWindow then Inc(FBorderWidths.Top, GetSystemMetrics(CaptionMetric[ToolWindow])) else Inc(FBorderWidths.Top, SizeFrame.cy + 2 * GetSystemMetrics(SM_CYEDGE) + Max(GetSystemMetrics(SM_CYSMICON), cxScreenCanvas.FontHeight(FCaptionFont))); if NativeBorderWidth and HasBorder then begin Inc(FBorderWidths.Left, WindowInfo.cxWindowBorders); Inc(FBorderWidths.Right, WindowInfo.cxWindowBorders); Inc(FBorderWidths.Top, WindowInfo.cyWindowBorders); Inc(FBorderWidths.Bottom, WindowInfo.cyWindowBorders); end; end; function TdxSkinFormNonClientAreaInfo.GetCaptionButtonRect( const ACaptionRect: TRect): TRect; begin Result := BorderBounds[bTop]; with GetCaptionContentOffset do begin if NativeBorderWidth and IsSizeBox then Inc(Result.Top, SystemSizeFrame.cy) else Inc(Result.Top, Top); Dec(Result.Bottom, Bottom); Result.Right := ACaptionRect.Right; Result.Left := Result.Right - (Result.Bottom - Result.Top); end; end; procedure TdxSkinFormNonClientAreaInfo.CalculateCaptionIconsInfo; const RestoreAndMaximize = [sfiRestore, sfiMaximize]; var AIcon: TdxSkinFormIcon; AIconSize: Integer; ARealIcons: TdxSkinFormIcons; R: TRect; begin FillChar(FIconBounds, SizeOf(FIconBounds), 0); AIconSize := GetCaptionIconSize; FCaptionBounds := GetCaptionBounds; R := FCaptionBounds; R.Top := (R.Top + R.Bottom - AIconSize) div 2; R.Bottom := R.Top + AIconSize; if sfiMenu in Icons then begin FIconBounds[sfiMenu] := cxRectCenter(cxRectSetWidth(R, AIconSize), AIconSize, AIconSize); FCaptionBounds.Left := FIconBounds[sfiMenu].Right + dxSkinFormTextOffset; end else FCaptionBounds.Left := cxTextOffset + dxSkinFormTextOffset; R := GetCaptionButtonRect(FCaptionBounds); ARealIcons := Icons; if RestoreAndMaximize * Icons = RestoreAndMaximize then ARealIcons := ARealIcons - [sfiRestore] + [sfiMinimize]; for AIcon := sfiClose downto sfiHelp do begin if not (AIcon in ARealIcons) then Continue; FIconBounds[AIcon] := R; OffsetRect(R, -(R.Right - R.Left + dxSkinIconSpacing), 0); FCaptionBounds.Right := FIconBounds[AIcon].Left - dxSkinFormTextOffset; end; if RestoreAndMaximize * Icons = RestoreAndMaximize then FIconBounds[sfiRestore] := FIconBounds[sfiMinimize]; UpdateCaptionIconStates; end; procedure TdxSkinFormNonClientAreaInfo.CalculateFontInfo; var AMetrics: TNonClientMetrics; begin AMetrics.cbSize := SizeOf(AMetrics); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @AMetrics, 0); if ToolWindow then FCaptionFont.Handle := CreateFontIndirect(AMetrics.lfSmCaptionFont) else begin FCaptionFont.Handle := CreateFontIndirect(AMetrics.lfCaptionFont); if PainterInfo <> nil then FCaptionFont.Size := FCaptionFont.Size + (PainterInfo.FormCaptionDelta - 1); end; FCaptionTextShadowColor := clBtnShadow; FCaptionTextColor[True] := GetSysColor(COLOR_CAPTIONTEXT); FCaptionTextColor[False] := GetSysColor(COLOR_INACTIVECAPTIONTEXT); if PainterInfo <> nil then begin FCaptionTextColor[True] := PainterInfo.FormFrames[True, bTop].TextColor; if PainterInfo.FormInactiveColor <> nil then FCaptionTextColor[False] := PainterInfo.FormInactiveColor.Value; if PainterInfo.FormTextShadowColor <> nil then FCaptionTextShadowColor := PainterInfo.FormTextShadowColor.Value; end; end; procedure TdxSkinFormNonClientAreaInfo.CalculateScrollArea; const BothScrollBars = [saeHorzScroll, saeVertScroll]; begin FScrollAreaElements := []; FillChar(FScrollAreaBounds, SizeOf(FScrollAreaBounds), 0); FillChar(FScrollBarsInfo[saeHorzScroll], SizeOf(TScrollBarInfo), 0); FScrollBarsInfo[saeHorzScroll].cbSize := SizeOf(TScrollBarInfo); FScrollBarsInfo[saeVertScroll] := FScrollBarsInfo[saeHorzScroll]; Windows.GetScrollBarInfo(Handle, Integer(OBJID_VSCROLL), FScrollBarsInfo[saeVertScroll]); Windows.GetScrollBarInfo(Handle, Integer(OBJID_HSCROLL), FScrollBarsInfo[saeHorzScroll]); if Style and WS_HSCROLL = WS_HSCROLL then begin Include(FScrollAreaElements, saeHorzScroll); FScrollAreaBounds[saeHorzScroll] := cxRectSetTop(BoundsNOBorders, BoundsNOBorders.Bottom, GetSystemMetrics(SM_CYHSCROLL)); end; if Style and WS_VSCROLL = WS_VSCROLL then begin Include(FScrollAreaElements, saeVertScroll); FScrollAreaBounds[saeVertScroll] := cxRectSetLeft(BoundsNOBorders, BoundsNOBorders.Right, GetSystemMetrics(SM_CXVSCROLL)); end; if BothScrollBars * ScrollAreaElements = BothScrollBars then begin Include(FScrollAreaElements, saeSizeGrip); FScrollAreaBounds[saeHorzScroll].Right := FScrollAreaBounds[saeVertScroll].Left; FScrollAreaBounds[saeVertScroll].Bottom := FScrollAreaBounds[saeHorzScroll].Top; FScrollAreaBounds[saeSizeGrip] := cxRect(BoundsNOBorders.BottomRight, Point(FScrollAreaBounds[saeVertScroll].Right, FScrollAreaBounds[saeHorzScroll].Bottom)); end; CalculateScrollBarPartsInfo; end; procedure TdxSkinFormNonClientAreaInfo.CalculateScrollBarPartInfo( AScrollBar: TdxSkinFormScrollBar; Pos1, Pos2: Integer; APart: TcxScrollBarPart); var P: TPoint; AState: Integer; const Part2StateIndex: array[TcxScrollBarPart] of Integer = (0, 1, 5, 3, 2, 4); begin AState := ScrollBarInfo[AScrollBar].rgState[Part2StateIndex[APart]]; FScrollBarPartState[AScrollBar, APart] := cxbsDefault; if AState and STATE_SYSTEM_INVISIBLE = STATE_SYSTEM_INVISIBLE then Exit; FScrollBarPartState[AScrollBar, APart] := cxbsNormal; FScrollBarPartBounds[AScrollBar, APart] := ScrollAreaBounds[AScrollBar]; P := ScreenToClient(GetMouseCursorPos); if (Pos1 <> Pos2) and (Pos1 <> -1) then begin if AScrollBar = saeHorzScroll then FScrollBarPartBounds[AScrollBar, APart] := cxRectSetXPos(FScrollBarPartBounds[AScrollBar, APart], Pos1, Pos2) else FScrollBarPartBounds[AScrollBar, APart] := cxRectSetYPos(FScrollBarPartBounds[AScrollBar, APart], Pos1, Pos2); end; if ((APart = sbpThumbnail) and (AScrollBar = TrackedScrollBar)) or (AState and STATE_SYSTEM_PRESSED = STATE_SYSTEM_PRESSED) then FScrollBarPartState[AScrollBar, APart] := cxbsPressed else if AState and STATE_SYSTEM_UNAVAILABLE = STATE_SYSTEM_UNAVAILABLE then FScrollBarPartState[AScrollBar, APart] := cxbsDisabled else if (AState and STATE_SYSTEM_HOTTRACKED = STATE_SYSTEM_HOTTRACKED) or PtInRect(FScrollBarPartBounds[AScrollBar, APart], P) then begin FScrollBarPartState[AScrollBar, APart] := cxbsHot; if ButtonPressed and PtInRect(FScrollBarPartBounds[AScrollBar, APart], P) then FScrollBarPartState[AScrollBar, APart] := cxbsPressed; end; end; procedure TdxSkinFormNonClientAreaInfo.CalculateScrollBarPartsInfo; var R: TRect; AScrollBar: TdxSkinFormScrollBar; begin for AScrollBar := saeHorzScroll to saeVertScroll do begin if not (AScrollBar in ScrollAreaElements) then Continue; R := ScrollAreaBounds[AScrollBar]; if AScrollBar = saeVertScroll then R := cxRectSetXPos(R, R.Top, R.Bottom); with ScrollBarInfo[AScrollBar] do begin CalculateScrollBarPartInfo(AScrollBar, R.Left, R.Left + dxyLineButton, sbpLineUp); CalculateScrollBarPartInfo(AScrollBar, R.Right - dxyLineButton, R.Right, sbpLineDown); CalculateScrollBarPartInfo(AScrollBar, R.Left + xyThumbTop, R.Left + xyThumbBottom, sbpThumbnail); CalculateScrollBarPartInfo(AScrollBar, R.Left + dxyLineButton, R.Left + xyThumbTop, sbpPageUp); CalculateScrollBarPartInfo(AScrollBar, R.Left + xyThumbBottom, R.Right - dxyLineButton, sbpPageDown); end end; end; function TdxSkinFormNonClientAreaInfo.GetActiveMDIChild: TCustomForm; var AActiveChild: TCustomForm; begin Result := nil; if Assigned(Controller.Form) then if TCustomFormAccess(Controller.Form).FormStyle = fsMDIForm then begin AActiveChild := TCustomFormAccess(Controller.Form).ActiveMDIChild; if Assigned(AActiveChild) then Result := AActiveChild; end; end; function TdxSkinFormNonClientAreaInfo.GetBorderRect( ASide: TcxBorder; const ABounds, AWidths: TRect): TRect; begin Result := ABounds; case ASide of bLeft: Result.Right := Result.Left + AWidths.Left; bTop: Result.Bottom := Result.Top + AWidths.Top; bRight: Result.Left := Result.Right - AWidths.Right; bBottom: Result.Top := Result.Bottom - AWidths.Bottom; end; end; function TdxSkinFormNonClientAreaInfo.GetCaption: string; begin if FCaptionSufix = '' then Result := FCaption else Result := Format(sdxMDICaptionFormat, [FCaption, FCaptionSufix]); end; function TdxSkinFormNonClientAreaInfo.GetIcons: TdxSkinFormIcons; const SysMenuIcons: array[Boolean] of TdxSkinFormIcons = ([sfiMenu, sfiClose], [sfiClose]); begin Result := []; if Style and WS_SYSMENU = WS_SYSMENU then Result := SysMenuIcons[ToolWindow or IsDialog]; if Style and WS_MINIMIZEBOX = WS_MINIMIZEBOX then begin if IsIconic then Include(Result, sfiRestore) else Include(Result, sfiMinimize); end; if Style and WS_MAXIMIZEBOX = WS_MAXIMIZEBOX then begin if IsZoomed then Include(Result, sfiRestore) else Include(Result, sfiMaximize); end; if ExStyle and WS_EX_CONTEXTHELP = WS_EX_CONTEXTHELP then Include(Result, sfiHelp); end; function TdxSkinFormNonClientAreaInfo.GetMaximizedMDIChild: TCustomForm; var AActiveMDI: TCustomForm; begin AActiveMDI := GetActiveMDIChild; if Assigned(AActiveMDI) and Windows.IsZoomed(AActiveMDI.Handle) then Result := AActiveMDI else Result := nil; end; function TdxSkinFormNonClientAreaInfo.GetSysMenuIcon: HIcon; var wParam: Integer; begin wParam := Byte(not ToolWindow); if IsWinXP then wParam := ICON_SMALL2; Result := DefWindowProc(Handle, WM_GETICON, wParam, 0); end; function TdxSkinFormNonClientAreaInfo.GetSystemSizeFrame: TSize; begin Result := Size(GetSystemMetrics(SM_CXSIZEFRAME), GetSystemMetrics(SM_CYSIZEFRAME)); end; function TdxSkinFormNonClientAreaInfo.IsMDIMainAlphaBlendUsed: Boolean; var AMainForm: TWinControl; begin AMainForm := FindControl(GetParent(GetParent(Handle))); Result := (AMainForm <> nil) and (AMainForm is TCustomForm) and TCustomFormAccess(AMainForm).AlphaBlend; end; function TdxSkinFormNonClientAreaInfo.UpdateCaptionIconStates: Boolean; var AHitTest, AIcon: TdxSkinFormIcon; APrevStates: array[TdxSkinFormIcon] of TdxSkinElementState; begin Result := False; Move(FIconState, APrevStates, SizeOf(FIconState)); FillChar(FIconState, SizeOf(FIconState), 0); AHitTest := GetIconHitTest; TrackIcon := IconPressed; for AIcon := sfiMenu to sfiClose do begin if not Active then FIconState[AIcon] := esActiveDisabled else if ((AIcon = sfiMinimize) and (Style and WS_MINIMIZEBOX <> WS_MINIMIZEBOX)) or ((AIcon = sfiMaximize) and (Style and WS_MAXIMIZEBOX <> WS_MAXIMIZEBOX)) then FIconState[AIcon] := esDisabled; if (AHitTest <> AIcon) or (FIconState[AIcon] = esDisabled) then Continue; if ButtonPressed and (IconPressed = AIcon) then FIconState[AIcon] := esPressed else if IconPressed = sfiMenu then begin FIconState[AIcon] := esHot; TrackIcon := AIcon; end; end; for AIcon := sfiMenu to sfiClose do Result := Result or (FIconState[AIcon] <> APrevStates[AIcon]); end; function TdxSkinFormNonClientAreaInfo.UpdateIconPressed( AReset: Boolean = False): TdxSkinFormIcon; begin Result := FIconPressed; FIconPressed := GetIconHitTest; if AReset then begin if Result <> FIconPressed then Result := sfiMenu; FIconPressed := sfiMenu; end; end; function TdxSkinFormNonClientAreaInfo.UpdateCaptionSufix: Boolean; var AMDIChild: TCustomForm; ATempSufix: string; begin AMDIChild := GetMaximizedMDIChild; if Assigned(AMDIChild) then ATempSufix := AMDIChild.Caption else ATempSufix := ''; Result := ATempSufix <> FCaptionSufix; if Result then FCaptionSufix := ATempSufix; end; function TdxSkinFormNonClientAreaInfo.GetBorderBounds(ASide: TcxBorder): TRect; begin Result := FBorderBounds[ASide]; end; function TdxSkinFormNonClientAreaInfo.GetButtonPressed: Boolean; begin Result := GetMouseKeys and MK_LBUTTON = MK_LBUTTON; end; function TdxSkinFormNonClientAreaInfo.GetCaptionBounds: TRect; var AFrame: TSize; begin AFrame := Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); Result := BorderBounds[bTop]; Inc(Result.Top, Byte(ToolWindow) + 1); if IsSizeBox and not NativeBorderWidth and IsZoomed then InflateRect(Result, -SystemSizeFrame.cx, -AFrame.cy) else InflateRect(Result, -SizeFrame.cx, -AFrame.cy); if IsSizeBox then begin if IsZoomed then Inc(Result.Top, SizeFrame.cy) else if NativeBorderWidth then Inc(Result.Top, SystemSizeFrame.cy - 4); end; end; function TdxSkinFormNonClientAreaInfo.GetCaptionContentOffset: TRect; begin if PainterInfo.FormFrames[not ToolWindow, bTop] <> nil then Result := PainterInfo.FormFrames[not ToolWindow, bTop].ContentOffset.Rect else Result := cxNullRect; end; function TdxSkinFormNonClientAreaInfo.GetCaptionIconSize: Integer; begin if ToolWindow then Result := GetSystemMetrics(SM_CYSMCAPTION) - 2 * GetSystemMetrics(SM_CYEDGE) else Result := GetSystemMetrics(SM_CYSMICON); end; function TdxSkinFormNonClientAreaInfo.GetCaptionTextColor: TColor; begin Result := FCaptionTextColor[Active]; end; function TdxSkinFormNonClientAreaInfo.GetClientRect: TRect; begin Result := WindowInfo.rcClient; end; function TdxSkinFormNonClientAreaInfo.GetExStyle: Integer; begin Result := WindowInfo.dwExStyle; end; function TdxSkinFormNonClientAreaInfo.GetHandle: HWND; begin Result := Controller.Handle; end; function TdxSkinFormNonClientAreaInfo.GetClientRectOnClient: TRect; begin Result := cxRectOffset(ClientRect, cxPointInvert(ClientRect.TopLeft)); end; function TdxSkinFormNonClientAreaInfo.GetHasBorder: Boolean; begin Result := GetWindowLong(Handle, GWL_STYLE) and WS_BORDER = WS_BORDER; end; function TdxSkinFormNonClientAreaInfo.GetHasCaption: Boolean; begin Result := GetWindowLong(Handle, GWL_STYLE) and WS_CAPTION = WS_CAPTION; end; function TdxSkinFormNonClientAreaInfo.GetHasMenu: Boolean; begin Result := FHasMenu; end; function TdxSkinFormNonClientAreaInfo.GetIconBounds( AIcon: TdxSkinFormIcon): TRect; begin Result := FIconBounds[AIcon]; end; function TdxSkinFormNonClientAreaInfo.GetIconState( AIcon: TdxSkinFormIcon): TdxSkinElementState; begin Result := FIconState[AIcon]; end; function TdxSkinFormNonClientAreaInfo.GetIsAlphaBlendUsed: Boolean; begin Result := Controller.Form <> nil; if Result then with TCustomFormAccess(Controller.Form) do Result := AlphaBlend or (FormStyle = fsMDIChild) and IsMDIMainAlphaBlendUsed; end; function TdxSkinFormNonClientAreaInfo.GetIsDialog: Boolean; begin Result := WindowInfo.dwExStyle and WS_EX_DLGMODALFRAME = WS_EX_DLGMODALFRAME; end; function TdxSkinFormNonClientAreaInfo.GetIsIconic: Boolean; begin Result := WindowInfo.dwStyle and WS_ICONIC = WS_ICONIC; end; function TdxSkinFormNonClientAreaInfo.GetIsSizeBox: Boolean; begin Result := WindowInfo.dwStyle and WS_SIZEBOX = WS_SIZEBOX; end; function TdxSkinFormNonClientAreaInfo.GetIsZoomed: Boolean; begin Result := WindowInfo.dwStyle and WS_MAXIMIZE = WS_MAXIMIZE; end; function TdxSkinFormNonClientAreaInfo.GetNativeBorderWidth: Boolean; begin Result := FHasMenu or FIsMDIClient or not ThemeActive; end; function TdxSkinFormNonClientAreaInfo.GetNeedCheckNonClientSize: Boolean; begin Result := HasBorder and not (NativeBorderWidth or IsZoomed and TdxSkinFormController.IsMDIChildWindow(Handle)); end; function TdxSkinFormNonClientAreaInfo.GetScrollAreaBounds( AItem: TdxScrollAreaElement): TRect; begin Result := FScrollAreaBounds[AItem]; end; function TdxSkinFormNonClientAreaInfo.GetScrollBarInfo( AScrollBar: TdxSkinFormScrollBar): TScrollBarInfo; begin Result := FScrollBarsInfo[AScrollBar]; end; function TdxSkinFormNonClientAreaInfo.GetScrollBarPartBounds( AScrollBar: TdxSkinFormScrollBar; APart: TcxScrollBarPart): TRect; begin Result := FScrollBarPartBounds[AScrollBar, APart]; end; function TdxSkinFormNonClientAreaInfo.GetScrollBarPartState( AScrollBar: TdxSkinFormScrollBar; APart: TcxScrollBarPart): TcxButtonState; begin Result := FScrollBarPartState[AScrollBar, APart]; end; function TdxSkinFormNonClientAreaInfo.GetSizeArea( ASide: TcxBorder): TRect; begin Result := WindowBounds; if ASide in [bLeft, bRight] then Inc(Result.Top, BorderWidths.Top); if NativeBorderWidth then with SizeFrame do Result := GetBorderRect(ASide, Result, Rect(cx, cy, cx, cy)) else Result := GetBorderRect(ASide, Result, Rect(2, 2, 2, 2)) end; function TdxSkinFormNonClientAreaInfo.GetSizeCorners( ACorner: TdxSkinFormCorner): TRect; var ASize: TSize; begin Result := WindowBounds; ASize := SizeFrame; if not NativeBorderWidth then ASize := Size(2, 2); if ACorner in [sfcLeftTop, sfcLeftBottom] then Result.Right := Result.Left + ASize.cx else Result.Left := Result.Right - ASize.cx; if ACorner in [sfcLeftTop, sfcRightTop] then Result.Bottom := Result.Top + BorderWidths.Top else Result.Top := Result.Bottom - ASize.cy; end; function TdxSkinFormNonClientAreaInfo.GetSkinBorderWidth(ASide: TcxBorder): Integer; var AElement: TdxSkinElement; begin Result := 0; AElement := PainterInfo.FormFrames[not ToolWindow, ASide]; if Assigned(AElement) then begin if ASide in [bLeft, bRight] then Result := AElement.Size.cx else Result := AElement.Size.cy; end; end; function TdxSkinFormNonClientAreaInfo.GetStyle: Integer; begin Result := WindowInfo.dwStyle; end; function TdxSkinFormNonClientAreaInfo.GetThemeActive: Boolean; begin if not ThemeActiveAssigned then begin FThemeActive := IsThemeActive; ThemeActiveAssigned := True; end; Result := FThemeActive; end; function TdxSkinFormNonClientAreaInfo.GetToolWindow: Boolean; begin Result := WindowInfo.dwExStyle and WS_EX_TOOLWINDOW = WS_EX_TOOLWINDOW; end; function TdxSkinFormNonClientAreaInfo.GetWindowRect: TRect; begin Result := WindowInfo.rcWindow; end; procedure TdxSkinFormNonClientAreaInfo.SetActive(AActive: Boolean); begin if FActive <> AActive then begin FActive := AActive; UpdateCaptionIconStates; end; end; procedure TdxSkinFormNonClientAreaInfo.SetUpdateRgn(ARgn: HRGN); begin if FUpdateRgn <> 0 then DeleteObject(FUpdateRgn); FUpdateRgn := ARgn; if FUpdateRgn <> 0 then OffsetRgn(FUpdateRgn, -WindowRect.Left, -WindowRect.Top); end; procedure TdxSkinFormNonClientAreaInfo.SetWindowRgn(ARgn: HRGN); begin if FWindowRgn <> 0 then DeleteObject(FWindowRgn); FWindowRgn := ARgn; end; { TdxSkinFormPainter } constructor TdxSkinFormPainter.Create(AViewInfo: TdxSkinFormNonClientAreaInfo); begin FViewInfo := AViewInfo; FBaseCanvas := TCanvas.Create; FCanvas := TcxCanvas.Create(FBaseCanvas); CreateCacheInfos; end; destructor TdxSkinFormPainter.Destroy; begin FreeCacheInfos; FCanvas.Free; FBaseCanvas.Free; inherited Destroy; end; procedure TdxSkinFormPainter.CreateCacheInfos; var AIcon: TdxSkinFormIcon; ASide: TcxBorder; begin for ASide := Low(TcxBorder) to High(TcxBorder) do FBordersCache[ASide] := TdxSkinElementCache.Create; for AIcon := Low(TdxSkinFormIcon) to High(TdxSkinFormIcon) do FIconsCache[AIcon] := TdxSkinElementCache.Create; end; procedure TdxSkinFormPainter.FreeCacheInfos; var AIcon: TdxSkinFormIcon; ASide: TcxBorder; begin for ASide := Low(TcxBorder) to High(TcxBorder) do FBordersCache[ASide].Free; for AIcon := Low(TdxSkinFormIcon) to High(TdxSkinFormIcon) do FIconsCache[AIcon].Free; end; procedure TdxSkinFormPainter.BeginPaint(ADestDC: HDC = 0); const Flags = DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE; begin FPainter := ViewInfo.Painter; FPainterInfo := ViewInfo.PainterInfo; FDC := ADestDC; FNeedRelease := ADestDC = 0; if FNeedRelease then FDC := GetDCEx(ViewInfo.Handle, 0, Flags); FBaseCanvas.Handle := FDC; end; procedure TdxSkinFormPainter.DrawWindowBackground; begin if PainterInfo <> nil then dxSkinCheckSkinElement(PainterInfo.FormContent).Draw(Canvas.Handle, ViewInfo.ClientRectOnClient); end; procedure TdxSkinFormPainter.DrawWindowBorder; begin InternalDrawCaption(ViewInfo.BorderBounds[bTop], PainterInfo.FormFrames[not ViewInfo.ToolWindow, bTop]); if IsBordersThin then InternalDrawThinBorders else InternalDrawBorders; // Draw menu separator if ViewInfo.HasMenu then FillRect(Canvas.Handle, cxRectSetBottom(ViewInfo.MenuBounds, ViewInfo.MenuBounds.Bottom, 1), GetSysColorBrush(COLOR_MENU)); if (ViewInfo.ScrollAreaElements <> []) and not ViewInfo.IsIconic then DrawScrollAreaElements(Canvas.Handle); end; procedure TdxSkinFormPainter.EndPaint; begin if FNeedRelease then ReleaseDC(ViewInfo.Handle, FDC); FBaseCanvas.Handle := 0; end; procedure TdxSkinFormPainter.DrawBackground(DC: HDC; const R: TRect); begin dxSkinCheckSkinElement(PainterInfo.FormContent).Draw(DC, R); end; procedure TdxSkinFormPainter.DrawScrollAreaElements(DC: HDC); var AElement: TdxScrollAreaElement; CDC: HDC; MemBMP: HBitmap; begin for AElement := saeHorzScroll to saeSizeGrip do with ViewInfo do begin if not (AElement in ViewInfo.ScrollAreaElements) then Continue; if AElement = saeSizeGrip then DrawSizeGrip(DC, ScrollAreaBounds[AElement]) else begin CDC := CreateCompatibleDC(0); with ScrollAreaBounds[AElement] do begin MemBMP := CreateCompatibleBitmap(DC, Right - Left, Bottom - Top); SetWindowOrgEx(CDC, Left, Top, nil); end; MemBMP := SelectObject(CDC, MemBmp); DrawBackground(CDC, ScrollAreaBounds[AElement]); DrawScrollBar(CDC, AElement, ScrollAreaBounds[AElement]); SetWindowOrgEx(CDC, 0, 0, nil); with ScrollAreaBounds[AElement] do BitBlt(DC, Left, Top, Right - Left, Bottom - Top, CDC, 0, 0, SRCCOPY); MemBMP := SelectObject(CDC, MemBmp); DeleteObject(MemBMP); DeleteDC(CDC); end; end; end; procedure TdxSkinFormPainter.DrawScrollBar( DC: HDC; AScrollBar: TdxSkinFormScrollBar; const R: TRect); var APart: TcxScrollBarPart; begin DrawBackground(DC, R); DC := SelectDC(DC); for APart := sbpLineUp to sbpPageDown do with ViewInfo do begin if ScrollBarPartState[AScrollBar, APart] = cxbsDefault then Continue; Painter.DrawScrollBarPart(Canvas, AScrollBar = saeHorzScroll, ScrollBarPartBounds[AScrollBar, APart], APart, ScrollBarPartState[AScrollBar, APart]); end; SelectDC(DC); end; procedure TdxSkinFormPainter.DrawSizeGrip(DC: HDC; const R: TRect); begin // FillRect(DC, R, CreateSolidBrush(clRed)); DrawBackground(DC, R); Painter.DrawSizeGrip(Canvas, R, clNone); end; procedure TdxSkinFormPainter.DrawWindowCaption(DC: HDC; const R: TRect; AElement: TdxSkinElement); var CR: TRect; AIcon: TdxSkinFormIcon; APrevFont: HFONT; APrevColor: TColor; APrevTransparent: Integer; begin FBordersCache[bTop].CheckCacheState(dxSkinCheckSkinElement(AElement), R, FrameStates[ViewInfo.Active], 0); FBordersCache[bTop].Draw(DC, R); for AIcon := Low(TdxSkinFormIcon) to High(TdxSkinFormIcon) do if AIcon in ViewInfo.Icons then begin DrawWindowIcon(DC, ViewInfo.IconBounds[AIcon], AIcon, PainterInfo.FormIcons[not ViewInfo.ToolWindow, AIcon]); end; if Length(ViewInfo.Caption) > 0 then begin APrevFont := SelectObject(DC, ViewInfo.CaptionFont.Handle); APrevTransparent := SetBkMode(DC, Transparent); CR := ViewInfo.CaptionBounds; if ViewInfo.Active and not ViewInfo.ToolWindow then begin APrevColor := SetTextColor(DC, ViewInfo.CaptionTextShadowColor); if ViewInfo.CaptionTextShadowColor <> clDefault then cxDrawText(DC, ViewInfo.Caption, CR, CaptionFlags); SetTextColor(DC, APrevColor); end; OffsetRect(CR, -1, -1); APrevColor := SetTextColor(DC, ViewInfo.CaptionTextColor); cxDrawText(DC, ViewInfo.Caption, CR, CaptionFlags); SetBkMode(DC, APrevTransparent); SelectObject(DC, APrevFont); SetTextColor(DC, APrevColor); end; end; procedure TdxSkinFormPainter.DrawWindowIcon(DC: HDC; const R: TRect; AIcon: TdxSkinFormIcon; AElement: TdxSkinElement); begin if ((AIcon = sfiMenu) and (ViewInfo.SysMenuIcon = 0)) or ((AIcon <> sfiMenu) and (AElement = nil)) then Exit; if RectVisible(DC, R) then begin if AElement = nil then DrawIconEx(DC, R.Left, R.Top, ViewInfo.SysMenuIcon, R.Right - R.Left, R.Bottom - R.Top, 0, 0, DI_NORMAL) else begin FIconsCache[AIcon].CheckCacheState(AElement, R, ViewInfo.IconState[AIcon], 0); FIconsCache[AIcon].Draw(DC, R); end; end; end; procedure TdxSkinFormPainter.InternalDrawBorder(const R: TRect; ASide: TcxBorder; AFillBackground: Boolean); var ACachedDC: HDC; AElement: TdxSkinElement; AMemBmp: HBitmap; R1: TRect; begin AElement := PainterInfo.FormFrames[not ViewInfo.ToolWindow, ASide]; FBordersCache[ASide].CheckCacheState(AElement, R, FrameStates[Active]); if AFillBackground then begin R1 := R; OffsetRect(R1, -R1.Left, -R1.Top); ACachedDC := CreateCompatibleDC(Canvas.Handle); AMemBmp := CreateCompatibleBitmap(Canvas.Handle, R1.Right, R1.Bottom); AMemBmp := SelectObject(ACachedDC, AMemBmp); dxSkinCheckSkinElement(PainterInfo.FormContent).Draw(ACachedDC, R1, 0, FrameStates[Active]); FBordersCache[ASide].Draw(ACachedDC, R1); BitBlt(Canvas.Handle, R.Left, R.Top, R1.Right, R1.Bottom, ACachedDC, 0, 0, SRCCOPY); AMemBMP := SelectObject(ACachedDC, AMemBmp); DeleteObject(AMemBmp); DeleteDC(ACachedDC); end else FBordersCache[ASide].Draw(Canvas.Handle, R); end; procedure TdxSkinFormPainter.InternalDrawBorders; var AIsAlphaBlendUsed: Boolean; ASide: TcxBorder; R: TRect; begin AIsAlphaBlendUsed := ViewInfo.IsAlphaBlendUsed; for ASide := Low(TcxBorder) to High(TcxBorder) do begin R := ViewInfo.BorderBounds[ASide]; if (ASide <> bTop) and IsRectVisible(R) and not cxRectIsEmpty(R) then begin if ASide in [bLeft, bRight] then begin R.Top := ViewInfo.BorderBounds[bTop].Bottom; R.Bottom := ViewInfo.BorderBounds[bBottom].Top; end; InternalDrawBorder(R, ASide, AIsAlphaBlendUsed); end; end; end; procedure TdxSkinFormPainter.InternalDrawCaption(const R: TRect; AElement: TdxSkinElement); var ACachedDC: HDC; AMemBmp: HBitmap; begin ACachedDC := CreateCompatibleDC(Canvas.Handle); AMemBmp := CreateCompatibleBitmap(Canvas.Handle, R.Right, R.Bottom); AMemBmp := SelectObject(ACachedDC, AMemBmp); DrawWindowCaption(ACachedDC, R, AElement); BitBlt(Canvas.Handle, 0, 0, R.Right, R.Bottom, ACachedDC, 0, 0, SRCCOPY); AMemBMP := SelectObject(ACachedDC, AMemBmp); DeleteObject(AMemBmp); DeleteDC(ACachedDC); end; procedure TdxSkinFormPainter.InternalDrawThinBorders; var ASide: TcxBorder; R: TRect; begin InternalDrawBorder(ViewInfo.BorderBounds[bBottom], bBottom, True); for ASide := Low(TcxBorder) to High(TcxBorder) do if ASide in [bLeft, bRight] then begin R := ViewInfo.BorderBounds[ASide]; if IsRectVisible(R) and not cxRectIsEmpty(R) then begin R.Top := ViewInfo.BorderBounds[bTop].Bottom; R.Bottom := ViewInfo.WindowBounds.Bottom - ViewInfo.SkinBorderWidth[bBottom]; InternalDrawBorder(R, ASide, True); end; end; end; function TdxSkinFormPainter.IsRectVisible(const R: TRect): Boolean; begin with FViewInfo do Result := (FUpdateRgn = 0) or RectInRegion(FUpdateRgn, R); if Result then Result := Canvas.RectVisible(R); end; function TdxSkinFormPainter.SelectDC(DC: HDC): Integer; begin Result := Canvas.Handle; Canvas.Canvas.Handle := DC; end; function TdxSkinFormPainter.GetActive: Boolean; begin Result := ViewInfo.Active; end; function TdxSkinFormPainter.GetIconElement( AIcon: TdxSkinFormIcon): TdxSkinElement; begin Result := FPainterInfo.FormIcons[ViewInfo.ToolWindow, AIcon]; end; function TdxSkinFormPainter.GetIsBordersThin: Boolean; begin Result := (ViewInfo.SkinBorderWidth[bLeft] < ViewInfo.BorderWidths.Left) or (ViewInfo.SkinBorderWidth[bRight] < ViewInfo.BorderWidths.Right) or (ViewInfo.SkinBorderWidth[bBottom] < ViewInfo.BorderWidths.Bottom); end; { TdxSkinButtonPainter } constructor TdxSkinCustomControlPainter.Create(AViewInfo: TdxSkinCustomControlViewInfo); begin FViewInfo := AViewInfo; FCanvas := TCanvas.Create; FcxCanvas := TcxCanvas.Create(FCanvas); end; destructor TdxSkinCustomControlPainter.Destroy; begin FViewInfo := nil; FcxCanvas.Free; FCanvas.Free; inherited Destroy; end; function TdxSkinCustomControlPainter.GetController: TdxSkinWinController; begin Result := ViewInfo.Controller; end; function TdxSkinCustomControlPainter.GetPainter: TcxCustomLookAndFeelPainterClass; begin Result := Controller.LookAndFeelPainter; end; procedure TdxSkinCustomControlPainter.BeginPaint(DC: HDC = 0); const Flags = DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE; begin FNeedRelease := DC = 0; if NeedRelease then DC := GetDCEx(Controller.Handle, 0, Flags); FDC := DC; Canvas.Canvas.Handle := FDC; end; procedure TdxSkinCustomControlPainter.EndPaint; begin Canvas.Canvas.Handle := 0; if NeedRelease then ReleaseDC(Controller.Handle, FDC); end; procedure TdxSkinCustomControlPainter.DrawBackground; var AControl: TWinControl; begin AControl := Controller.WinControl; if AControl <> nil then cxDrawTransparentControlBackground(AControl, Canvas, ViewInfo.ClientRect); end; procedure TdxSkinCustomControlPainter.DrawButton(const ACaption: string; const R: TRect; AState: TcxButtonState); var AFlags: Integer; begin Painter.DrawButton(Canvas, R, '', AState, False, clDefault, clDefault, False); if Length(ACaption) > 0 then begin Canvas.Brush.Style := bsClear; AFlags := cxAlignVCenter or cxShowPrefix or cxAlignHCenter; if GetWindowLong(Controller.Handle, GWL_STYLE) and BS_MULTILINE <> 0 then AFlags := AFlags or cxWordBreak else AFlags := AFlags or cxSingleLine; if AState = cxbsDisabled then begin Canvas.Font.Color := clBtnHighlight; Canvas.DrawText(ACaption, cxRectOffset(R, 1, 1), AFlags, True); end; Canvas.Font.Color := Painter.ButtonSymbolColor(AState); Canvas.DrawText(ACaption, R, AFlags, True); end; end; procedure TdxSkinCustomControlPainter.DrawFocus(const R: TRect); begin DrawFocusRect(Canvas.Handle, R); end; { TdxSkinCustomControlViewInfo } constructor TdxSkinCustomControlViewInfo.Create(AController: TdxSkinWinController); begin FController := AController; end; function TdxSkinCustomControlViewInfo.GetClientRect: TRect; begin GetWindowRect(Controller.Handle, Result); OffsetRect(Result, -Result.Left, -Result.Top); end; function TdxSkinCustomControlViewInfo.GetIsEnabled: Boolean; begin Result := IsWindowEnabled(Controller.Handle); end; function TdxSkinCustomControlViewInfo.GetIsFocused: Boolean; begin Result := GetFocus = Controller.Handle; end; function TdxSkinCustomControlViewInfo.GetIsMouseAtControl: Boolean; begin Result := WindowFromPoint(Mouse.CursorPos) = FController.Handle; end; { TdxSkinButtonViewInfo } constructor TdxSkinButtonViewInfo.Create(AController: TdxSkinWinController); begin inherited Create(AController); FCaption := GetWindowCaption(Controller.Handle); UpdateEnabledState; end; procedure TdxSkinButtonViewInfo.MouseClickEvent(ADown: Boolean); const AStates: array[Boolean] of TcxButtonState = (cxbsNormal, cxbsPressed); begin State := AStates[ADown]; end; procedure TdxSkinButtonViewInfo.MouseHoverEvent(AEnter: Boolean); const AStates: array[Boolean, Boolean] of TcxButtonState = ((cxbsNormal, cxbsNormal), (cxbsHot, cxbsPressed)); begin State := AStates[AEnter, Pressed]; end; procedure TdxSkinButtonViewInfo.SetState(AState: TcxButtonState); var ANewState: TcxButtonState; begin if IsEnabled then ANewState := AState else ANewState := cxbsDisabled; if ANewState <> FState then begin FState := ANewState; FPressed := FState = cxbsPressed; Controller.RedrawWindow(True); end; end; procedure TdxSkinButtonViewInfo.UpdateEnabledState; const AStates: array[Boolean] of TcxButtonState = (cxbsDisabled, cxbsNormal); begin State := AStates[IsEnabled]; end; { TdxSkinButtonController } function TdxSkinButtonController.GetViewInfo: TdxSkinButtonViewInfo; begin Result := TdxSkinButtonViewInfo(inherited ViewInfo); end; class function TdxSkinButtonController.GetViewInfoClass: TdxSkinCustomControlViewInfoClass; begin Result := TdxSkinButtonViewInfo; end; procedure TdxSkinButtonController.DrawContent(DC: HDC = 0); begin Painter.BeginPaint(DC); try Painter.DrawBackground; with TdxSkinButtonViewInfo(ViewInfo) do begin Painter.DrawButton(Caption, ClientRect, State); if IsFocused then Painter.DrawFocus(cxRectInflate(ClientRect, -4, -4)); end; finally Painter.EndPaint; end; end; procedure TdxSkinButtonController.MouseLeave; begin inherited MouseLeave; ViewInfo.MouseHoverEvent(False) end; procedure TdxSkinButtonController.WndProc(var AMessage: TMessage); const AStates: array[Boolean] of TcxButtonState = (cxbsDisabled, cxbsNormal); begin if AMessage.Msg = WM_SETTEXT then ViewInfo.FCaption := TWMSetText(AMessage).Text; inherited WndProc(AMessage); if IsSkinUsed then case AMessage.Msg of WM_ENABLE: ViewInfo.UpdateEnabledState; WM_UPDATEUISTATE: if AMessage.WParamLo in [UIS_SET, UIS_CLEAR] then DrawContent; BM_SETSTATE: ViewInfo.MouseClickEvent(AMessage.WParam <> 0); WM_MOUSELEAVE, CM_MOUSELEAVE: ViewInfo.MouseHoverEvent(False); WM_MOUSEMOVE, WM_MOUSEHOVER: if ViewInfo.IsMouseAtControl then ViewInfo.MouseHoverEvent(True); end; end; { TdxSkinCustomController } constructor TdxSkinCustomController.Create(AHandle: HWND); begin inherited Create(AHandle); FViewInfo := GetViewInfoClass.Create(Self); FPainter := TdxSkinCustomControlPainter.Create(FViewInfo); end; destructor TdxSkinCustomController.Destroy; begin FViewInfo.Free; FPainter.Free; inherited Destroy; end; procedure TdxSkinCustomController.DrawBackground(DC: HDC = 0); begin Painter.BeginPaint(DC); try Painter.DrawBackground; finally Painter.EndPaint; end; end; procedure TdxSkinCustomController.DrawContent(DC: HDC = 0); begin end; class function TdxSkinCustomController.GetViewInfoClass: TdxSkinCustomControlViewInfoClass; begin Result := TdxSkinCustomControlViewInfo; end; function TdxSkinCustomController.GetMaster(AHandle: HWND): TdxSkinWinController; var AParent: TCustomForm; begin Result := nil; if Assigned(WinControl) then begin AParent := GetParentForm(WinControl); if Assigned(AParent) and GetUseSkinForControl then Result := GetControllerByHandle(AParent.Handle) end; end; procedure TdxSkinCustomController.InitializePainter; begin // nothing todo end; function TdxSkinCustomController.WMEraseBk(var AMessage: TWMEraseBkgnd): Boolean; begin AMessage.Result := 1; Result := True; end; function TdxSkinCustomController.WMPaint(var AMessage: TWMPaint): Boolean; var APaintStruct: TPaintStruct; ADC: HDC; begin Result := True; if AMessage.DC <> 0 then DrawContent(AMessage.DC) else begin ADC := BeginPaint(Handle, APaintStruct); try DrawContent(ADC); finally EndPaint(Handle, APaintStruct); end; end; end; procedure TdxSkinCustomController.WndProc(var AMessage: TMessage); var AHandled: Boolean; begin AHandled := False; if IsSkinUsed then case AMessage.Msg of WM_ERASEBKGND: AHandled := WMEraseBk(TWMEraseBkgnd(AMessage)); WM_PAINT: AHandled := WMPaint(TWMPaint(AMessage)); end; if not AHandled then inherited WndProc(AMessage); end; { TdxSkinPanelController } procedure TdxSkinPanelController.DrawContent(DC: HDC = 0); const Alignments: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER); var AControl: TControl; R: TRect; begin AControl := WinControl; if Assigned(AControl) and (AControl is TCustomPanel) then begin Painter.BeginPaint(DC); try R := ViewInfo.ClientRect; InternalDrawBackground(TCustomPanel(AControl), R); with TCustomPanelAccess(AControl) do begin Painter.Canvas.Brush.Style := bsClear; Painter.Canvas.Font := Font; DrawText(Painter.Canvas.Handle, PChar(Caption), -1, R, DrawTextBiDiModeFlags(DT_EXPANDTABS or DT_SINGLELINE or DT_VCENTER or Alignments[Alignment])); PaintControls(Painter.Canvas.Handle, nil); end; finally Painter.EndPaint; end; end; end; procedure TdxSkinPanelController.InternalDrawBackground(APanel: TCustomPanel; const R: TRect); begin with TCustomPanelAccess(APanel) do begin if csParentBackground in ControlStyle then cxDrawTransparentControlBackground(APanel, Painter.Canvas, R, False) else if Color = clBtnFace then Painter.Painter.DrawPanelContent(Painter.Canvas, R, False) else Painter.Painter.DrawPanelBackground(Painter.Canvas, APanel, R, Color); if (BevelOuter <> bvNone) or (BevelInner <> bvNone) then Painter.Painter.DrawPanelBorders(Painter.Canvas, R); end; end; function TdxSkinPanelController.WMEraseBk(var AMessage: TWMEraseBkgnd): Boolean; begin Result := False; // bug fix with ThemeParentBackground end; function TdxSkinPanelController.WMPaint(var AMessage: TWMPaint): Boolean; begin Result := False; if not FPainting then begin FPainting := True; try Result := inherited WMPaint(AMessage); finally FPainting := False; end; end; end; procedure TdxSkinPanelController.WndProc(var AMessage: TMessage); var AHandled: Boolean; begin AHandled := False; if (AMessage.Msg = WM_PRINTCLIENT) and IsSkinUsed then with TWMPrintClient(AMessage) do begin AHandled := (Result <> 1) and ((Flags and PRF_CHECKVISIBLE = 0) or IsWindowVisible(Handle)); if AHandled then WMPaint(TWMPaint(AMessage)); end; if not AHandled then inherited WndProc(AMessage); end; { TdxSkinFrameController } procedure TdxSkinFrameController.DrawContent(DC: HDC = 0); var AControl: TWinControl; begin Painter.BeginPaint(DC); try AControl := WinControl; if (AControl <> nil) and (AControl is TCustomFrame) then with TCustomFrameAccess(AControl) do begin if csParentBackground in ControlStyle then cxDrawTransparentControlBackground(AControl, Painter.Canvas, ViewInfo.ClientRect, False) else (Master as TdxSkinFormController).DrawWindowBackground(Painter.Canvas.Handle); PaintControls(Painter.Canvas.Handle, nil); end; finally Painter.EndPaint; end; end; function TdxSkinFrameController.WMPrintClient(var AMessage: TWMPrintClient): Boolean; begin Result := (AMessage.Result <> 1) and ((AMessage.Flags and PRF_CHECKVISIBLE = 0) or IsWindowVisible(Handle)); if Result then Result := WMPaint(TWMPaint(AMessage)); end; procedure TdxSkinFrameController.WndProc(var AMessage: TMessage); begin if not IsSkinUsed or (AMessage.Msg <> WM_PRINTCLIENT) or not WMPrintClient(TWMPrintClient(AMessage)) then inherited WndProc(AMessage); end; { TdxSkinWinControllerHelper } constructor TdxSkinWinControllerHelper.Create; begin FHandle := {$IFDEF DELPHI6}Classes.{$ENDIF}AllocateHWnd(WndProc); end; destructor TdxSkinWinControllerHelper.Destroy; begin {$IFDEF DELPHI6}Classes.{$ENDIF}DeallocateHWnd(FHandle); inherited Destroy; end; procedure TdxSkinWinControllerHelper.ChildChanged(AHandle: HWND); begin AHandle := GetParent(AHandle); if (AHandle <> 0) and AnsiSameText(GetWindowClass(AHandle), 'MDICLIENT') then begin AHandle := GetParent(AHandle); if AHandle <> 0 then SendMessage(AHandle, WM_CHILDCHANGED, 0, 0); end; end; procedure TdxSkinWinControllerHelper.FinalizeEngine(AHandle: HWND); begin TdxSkinWinController.FinalizeEngine(AHandle); SkinHelper.ChildChanged(AHandle); end; procedure TdxSkinWinControllerHelper.InitializeEngine(AHandle: HWND); begin if TdxSkinFormController.IsMDIClientWindow(AHandle) or IsWindowUnicode(AHandle) // todo: try to detect TntControls then PostMessage(SkinHelper.Handle, WM_POSTCREATE, 0, AHandle) else InternalInitializeEngine(AHandle); end; procedure TdxSkinWinControllerHelper.InternalInitializeEngine(AHandle: HWND); function IsAnotherApplicatonWindow(AWnd: HWND): Boolean; var AProcessId: Cardinal; begin GetWindowThreadProcessId(AWnd, @AProcessId); Result := (AWnd = 0) or (AProcessId <> GetCurrentProcessId); end; function GetSkinClassForWindow(AWnd: HWND): TdxSkinWinControllerClass; begin Result := nil; if not IsAnotherApplicatonWindow(AWnd) then Result := dxSkinGetControllerClassForWindowProc(AWnd); end; var ASkinClass: TdxSkinWinControllerClass; begin ASkinClass := GetSkinClassForWindow(AHandle); if ASkinClass <> nil then begin GetSystemMenu(AHandle, True); // W2k redrawing bug ASkinClass.InitializeEngine(AHandle); PostMessage(AHandle, WM_POSTCHECKRGN, 0, 0); end; end; procedure TdxSkinWinControllerHelper.WndProc(var AMsg: TMessage); begin if AMsg.Msg = WM_POSTCREATE then InternalInitializeEngine(AMsg.LParam) else AMsg.Result := DefWindowProc(Handle, AMsg.Msg, AMsg.WParam, AMsg.LParam); end; // function dxSkinGetControllerClassForWindow(AWnd: HWND): TdxSkinWinControllerClass; var AControl: TControl; begin Result := nil; if TdxSkinWinController.IsMDIClientWindow(AWnd) then Result := TdxSkinFormController else begin AControl := FindControl(AWnd); if AControl <> nil then begin if AControl is TCustomForm then Result := TdxSkinFormController; if AControl is TCustomFrame then Result := TdxSkinFrameController; if SameText(AControl.ClassName, 'TButton') then Result := TdxSkinButtonController; if SameText(AControl.ClassName, 'TPanel') then Result := TdxSkinPanelController; end; end; end; function dxSkinsWndProcHook(Code: Integer; wParam: WParam; lParam: LParam): LRESULT; stdcall; var AMsg: PCWPStruct; begin AMsg := PCWPStruct(lParam); Result := CallNextHookEx(WndProcHookHandle, Code, wParam, lParam); if IsDesigning then Exit; case AMsg.message of WM_CHILDACTIVATE, WM_MDIACTIVATE: SkinHelper.ChildChanged(AMsg.hwnd); WM_CREATE, WM_MDICREATE: SkinHelper.InitializeEngine(AMsg.hwnd); WM_DESTROY, WM_MDIDESTROY: if AMsg.wParam = 0 then SkinHelper.FinalizeEngine(AMsg.hwnd); end; end; var SetScrollInfo: function(hWnd: HWND; BarFlag: Integer; const ScrollInfo: TScrollInfo; Redraw: BOOL): Integer; stdcall; SetScrollPos: function (hWnd: HWND; nBar, nPos: Integer; bRedraw: BOOL): Integer stdcall; function My_SetScrollPos(hWnd: HWND; nBar, nPos: Integer; bRedraw: BOOL): Integer; stdcall; begin bRedraw := bRedraw and not TdxSkinFormController.IsSkinActive(hWnd); Result := SetScrollPos(hWnd, nBar, nPos, bRedraw); end; function My_SetScrollInfo(hWnd: HWND; BarFlag: Integer; const ScrollInfo: TScrollInfo; Redraw: BOOL): Integer; stdcall; begin Redraw := Redraw and not TdxSkinFormController.IsSkinActive(hWnd); Result := SetScrollInfo(hWnd, BarFlag, ScrollInfo, Redraw); end; procedure RegisterAssistants; begin SetScrollPos := FlatSB_SetScrollPos; SetScrollInfo := FlatSB_SetScrollInfo; FlatSB_SetScrollPos := My_SetScrollPos; FlatSB_SetScrollInfo := My_SetScrollInfo; dxSkinControllersList := TList.Create; SkinHelper := TdxSkinWinControllerHelper.Create; WndProcHookHandle := SetWindowsHookEx(WH_CALLWNDPROC, dxSkinsWndProcHook, 0, GetCurrentThreadId); WM_POSTREDRAW := RegisterWindowMessage('WM_POSTREDRAW'); WM_CHILDCHANGED := RegisterWindowMessage('WM_CHILDCHANGED'); WM_POSTCREATE := RegisterWindowMessage('WM_POSTCREATE'); WM_POSTCHECKRGN := RegisterWindowMessage('WM_POSTCHECKRGN'); FormControllers := TcxObjectList.Create; end; procedure UnregisterAssistants; begin FlatSB_SetScrollPos := SetScrollPos; FlatSB_SetScrollInfo := SetScrollInfo; UnhookWindowsHookEx(WndProcHookHandle); FormControllers.Clear; // destroy all active controllers dxSkinControllersList.Free; FormControllers.Free; SkinHelper.Free; end; initialization dxSkinGetControllerClassForWindowProc := dxSkinGetControllerClassForWindow; RegisterAssistants; finalization UnregisterAssistants; end.