{********************************************************************} { } { Developer Express Visual Component Library } { ExpressSkins Library } { } { Copyright (c) 2006-2007 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; const dxSkinIconSpacing = 2; WM_POSTREDRAW: Cardinal = WM_DX + 1; WM_CHILDCHANGED: Cardinal = WM_DX + 2; WM_POSTMDICREATE: Cardinal = WM_DX + 3; 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; { TdxSkinController } TdxSkinController = class(TcxLookAndFeelController) private FOnSkinForm: TdxSkinFormEvent; function GetUseSkins: Boolean; procedure SetUseSkins(Value: Boolean); protected procedure Changed; 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; end; { TdxSkinWinController } TdxSkinWinController = class(TObject, IUnknown, IcxMouseTrackingCaller) private FHandle: HWND; FLookAndFeelPainter: TdxSkinLookAndFeelPainterClass; FMaster: TdxSkinWinController; FProcInstance: Pointer; FSavedWndProc: TWndMethod; FSavedWndProcPtr: Pointer; function GetControl: 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; procedure DefWndProc(var AMessage); procedure HookWndProc; virtual; procedure InitializePainter; virtual; procedure RedrawWindow(AUpdateNow: Boolean); procedure UnHookWndProc; virtual; procedure WndProc(var AMessage: TMessage); virtual; { IUnknown } function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; { IcxMouseTrackingCaller } procedure MouseLeave; virtual; public constructor Create(AHandle: HWND); virtual; destructor Destroy; override; class function IsMDIChildWindow(AHandle: HWND): Boolean; class function IsMDIClientWindow(AHandle: HWND): Boolean; class function IsMessageDlgWindow(AHandle: HWND): Boolean; 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 GetControl; end; TdxSkinWinControllerClass = class of TdxSkinWinController; { 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; procedure CalculateViewInfo; procedure CheckWindowRgn(AForceRgn: Boolean); procedure DrawWindowBackground(DC: HDC); virtual; procedure DrawWindowBorder; virtual; procedure InitializeMessageForm; 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 WMSizing(var Message: TWMSize); virtual; procedure WMSize(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; function GetBorderBounds(ASide: TcxBorder): TRect; function GetButtonPressed: Boolean; function GetCaptionBounds: TRect; function GetCaptionButtonSize: Integer; function GetCaptionIconSize: Integer; 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 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 GetStyle: Integer; 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: 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 CalculateCaptionInfo; 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; procedure UpdateCaption(const ANewText: string); function UpdateCaptionIconStates: Boolean; function UpdateCaptionSufix: Boolean; function UpdateIconPressed(AReset: Boolean = False): TdxSkinFormIcon; 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 FCaptionTextColor write FCaptionTextColor; 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 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 SystemSizeFrame: TSize read GetSystemSizeFrame; property Style: Integer read GetStyle; property SysMenuIcon: HICON read FSysMenuIcon; 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; FCanvas: TcxCanvas; FDC: HDC; FNeedRelease: Boolean; FPainter: TcxCustomLookAndFeelPainterClass; FPainterInfo: TdxSkinLookAndFeelPainterInfo; FViewInfo: TdxSkinFormNonClientAreaInfo; function GetActive: Boolean; function GetIconElement(AIcon: TdxSkinFormIcon): TdxSkinElement; protected 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; 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 Painter: TcxCustomLookAndFeelPainterClass read FPainter; property PainterInfo: TdxSkinLookAndFeelPainterInfo read FPainterInfo; property ViewInfo: TdxSkinFormNonClientAreaInfo read FViewInfo; end; { TdxSkinButtonViewInfo } TdxSkinButtonViewInfo = class private FCaption: string; FController: TdxSkinWinController; FPressed: Boolean; FState: TcxButtonState; function GetClientRect: TRect; function GetIsEnabled: Boolean; function GetIsFocused: Boolean; function GetIsMouseAtControl: Boolean; procedure SetState(AState: TcxButtonState); public constructor Create(AController: TdxSkinWinController); virtual; procedure MouseClickEvent(ADown: Boolean); procedure MouseHoverEvent(AEnter: Boolean); property Caption: string read FCaption; 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; property Pressed: Boolean read FPressed; property State: TcxButtonState read FState write SetState; end; { TdxSkinButtonPainter } TdxSkinButtonPainter = class private FCanvas: TCanvas; FcxCanvas: TcxCanvas; FDC: HDC; FNeedRelease: Boolean; FViewInfo: TdxSkinButtonViewInfo; function GetController: TdxSkinWinController; function GetPainter: TcxCustomLookAndFeelPainterClass; protected procedure BeginPaint(DC: HDC = 0); procedure EndPaint; property NeedRelease: Boolean read FNeedRelease; public constructor Create(AViewInfo: TdxSkinButtonViewInfo); 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: TdxSkinButtonViewInfo read FViewInfo; end; { TdxSkinButtonController } TdxSkinButtonController = class(TdxSkinWinController) private FPainter: TdxSkinButtonPainter; FViewInfo: TdxSkinButtonViewInfo; protected function GetMaster(AHandle: HWND): TdxSkinWinController; override; procedure InitializePainter; override; procedure MouseLeave; override; procedure WndProc(var AMessage: TMessage); override; // Messages function WMEraseBk(var AMessage: TWMEraseBkgnd): Boolean; function WMPaint(var AMessage: TWMPaint): Boolean; public constructor Create(AHandle: HWND); override; destructor Destroy; override; procedure DrawBackground(DC: HDC = 0); procedure DrawContent(DC: HDC = 0); virtual; property Painter: TdxSkinButtonPainter read FPainter; property ViewInfo: TdxSkinButtonViewInfo read FViewInfo; end; { TdxSkinPanelController } TdxSkinPanelController = class(TdxSkinButtonController) protected procedure WndProc(var AMessage: TMessage); override; public procedure DrawContent(DC: HDC = 0); override; end; 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; FrameStates: array[Boolean] of TdxSkinElementState = (esActiveDisabled, esActive); var FormControllers: TcxObjectList; FormsList: TList; SkinControllersList: TList; WndProcHookHandle: HHOOK; type TCustomFormAccess = class(TCustomForm); TCustomLabelAccess = class(TCustomLabel); TcxLookAndFeelAccess = class(TcxLookAndFeel); TCustomPanelAccess = class(TCustomPanel); 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 := SkinControllersList.Count - 1 downto 0 do begin ASkinController := TdxSkinController(SkinControllersList[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; FormsList.Add(Pointer(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 if FormsList.IndexOf(Pointer(AHandle)) >= 0 then Exit; ANewController := Self.Create(AHandle); ANewController.FMaster := ANewController.GetMaster(AHandle); FormControllers.Add(ANewController); ANewController.InitializePainter; ANewController.Update; end; class procedure TdxSkinWinController.FinalizeEngine(AHandle: HWND); var AIndex: Integer; begin AIndex := FormsList.Remove(Pointer(AHandle)); if AIndex >=0 then begin FormControllers[AIndex].Free; FormControllers.Delete(AIndex); 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 AIndex: Integer; begin AIndex := FormsList.IndexOf(Pointer(AHandle)); Result := (AIndex >= 0) and TdxSkinWinController(FormControllers[AIndex]).IsSkinUsed; end; class function TdxSkinWinController.IsMessageDlgWindow(AHandle: HWND): Boolean; begin Result := AnsiSameText(GetWindowClass(AHandle), 'TMessageForm'); end; function TdxSkinWinController.GetControl: TWinControl; begin Result := FindControl(Handle); 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; Update; end; function TdxSkinWinController.GetIsSkinUsed: Boolean; begin Result := LookAndFeelPainter <> nil; end; function TdxSkinWinController.GetMaster(AHandle: HWND): TdxSkinWinController; var AParent: HWND; ID: Integer; begin Result := nil; if IsMDIClientWindow(AHandle) then begin AParent := GetParent(AHandle); ID := FormsList.IndexOf(Pointer(AParent)); if ID < 0 then Exit; Result := FormControllers[ID] as TdxSkinWinController; end; 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 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 not IsHooked then Exit; if WinControl <> nil then WinControl.WindowProc := FSavedWndProc else SetWindowLong(Handle, GWL_WNDPROC, Integer(FSavedWndProcPtr)); FSavedWndProcPtr := nil; FSavedWndProc := nil; 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; function TdxSkinWinController._AddRef: Integer; begin Result := -1; end; function TdxSkinWinController._Release: Integer; begin Result := -1; end; function TdxSkinWinController.QueryInterface(const IID: TGUID; out Obj): HResult; const E_NOINTERFACE = HResult($80004002); begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; procedure TdxSkinWinController.MouseLeave; begin end; { TdxSkinController } constructor TdxSkinController.Create(AOwner: TComponent); begin inherited Create(AOwner); if SkinControllersList <> nil then SkinControllersList.Add(Self); Changed; end; destructor TdxSkinController.Destroy; begin Changed; if SkinControllersList <> nil then SkinControllersList.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 := nil; if FormsList.IndexOf(Pointer(AForm.Handle)) >= 0 then AController := FormControllers[FormsList.IndexOf(Pointer(AForm.Handle))] as TdxSkinWinController; Result := Assigned(AController) and AController.GetSkinName(ASkinName); end; procedure TdxSkinController.Changed; begin RefreshControllers; 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(ViewInfo); if IsMessageDlgWindow(AHandle) then InitializeMessageForm; end; destructor TdxSkinFormController.Destroy; var I: Integer; begin for I := 0 to SkinControllersList.Count - 1 do with TdxSkinFormController(SkinControllersList[I]) do if FMaster = Self then FMaster := nil; FreeAndNil(FPainter); FreeAndNil(FViewInfo); inherited Destroy; end; procedure TdxSkinFormController.Update; begin inherited Update; if HasRegion and not IsSkinUsed and (Handle <> 0) 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), False); end else if IsZoomed(Handle) and HasRegion then begin HasRegion := False; LockRedraw; SetWindowRgn(Handle, 0, False); UnlockRedraw; end else Exit; PostMessage(Handle, WM_POSTREDRAW, 0, 0); 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 SkinControllersList.Count - 1 do with TdxSkinController(SkinControllersList[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; begin Result := IsSkinUsed; if not Result then Exit; CheckWindowRgn(False); if ForceRedraw then DrawWindowBorder; case AMessage.Msg of $3F: UpdateMDIClientEdge; WM_DESTROY, WM_MDIDESTROY: if AMessage.WParam <> 0 then DefWndProc(AMessage) else WMDestroy(TWMDestroy(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_SETTEXT: WMSetText(TWMSetText(AMessage)); WM_SIZING: WMSizing(TWMSize(AMessage)); WM_SIZE: WMSize(TWMSize(AMessage)); WM_SYSCOMMAND: WMSysCommand(TWMSysCommand(AMessage)); WM_VSCROLL, WM_HSCROLL: WMScroll(TWMScroll(AMessage)); else if AMessage.Msg = WM_CHILDCHANGED then begin if ViewInfo.UpdateCaptionSufix then DrawWindowBorder; end else if AMessage.Msg = WM_POSTREDRAW then RedrawWindow(False) else Result := False; end; ForceRedraw := False; 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 ALocked: Boolean; begin ForceRedraw := True; ViewInfo.UpdateIconPressed; ViewInfo.UpdateCaptionIconStates; ALocked := Message.HitTest in [HTHSCROLL, HTVSCROLL]; if ALocked then LockRedraw; if ViewInfo.GetIconHitTest = sfiMenu then DefWndProc(Message); if ALocked then UnlockRedraw; RefreshOnMouseEvent(True); DrawWindowBorder; 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 not ViewInfo.NativeBorderWidth and ViewInfo.HasBorder 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)); if ViewInfo.IsZoomed and ViewInfo.IsSizebox then begin with ViewInfo do begin Inc(Margins.Left, SystemSizeFrame.cx - SizeFrame.cx); Inc(Margins.Right, SystemSizeFrame.cx - SizeFrame.cx); Inc(Margins.Top, SystemSizeFrame.cy - SizeFrame.cy); end; if saeVertScroll in ViewInfo.ScrollAreaElements then Inc(Margins.Right, ViewInfo.SizeFrame.cx - ViewInfo.BorderWidths.Right); if saeHorzScroll in ViewInfo.ScrollAreaElements then Inc(Margins.Bottom, ViewInfo.SizeFrame.cy - ViewInfo.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 ADownIcon: TdxSkinFormIcon; begin ADownIcon := ViewInfo.UpdateIconPressed(True); if ADownIcon = sfiMenu then DefWndProc(Message); RefreshOnMouseEvent(True); if ADownIcon <> sfiMenu 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((Message.SizeType <> SIZE_MAXIMIZED) or (Form <> nil) and (Form.Parent <> nil)); DrawWindowBorder; end; procedure TdxSkinFormController.WMSysCommand(var Message: TWMSysCommand); begin DefWndProc(Message); DrawWindowBorder; 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; procedure TdxSkinFormController.WndProc(var AMessage: TMessage); begin if AMessage.Msg = WM_POSTMDICREATE then TdxSkinFormController.InitializeEngine(AMessage.LParam) else if not IsSkinUsed or not HandleWindowMessage(AMessage) then begin DefWndProc(AMessage); Exit; end; 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 := (GetMenu(Handle) <> 0) 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); 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; CalculateBorderWidths; FMenuBounds := cxRectSetBottom(FBoundsNOBorders, FBoundsNOBorders.Top, FBoundsNOBorders.Top - BorderWidths.Top); CalculateBordersInfo; CalculateCaptionInfo; 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 + GetSystemMetrics(SM_CYSMICON) + 2 * GetSystemMetrics(SM_CYEDGE)); 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; 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 + cxTextOffset; end else FCaptionBounds.Left := cxTextOffset * 2; AIconSize := GetCaptionButtonSize; R := FCaptionBounds; R.Top := (R.Top + R.Bottom - AIconSize) div 2; R.Bottom := R.Top + AIconSize; R.Left := R.Right - AIconSize; 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, -(AIconSize + dxSkinIconSpacing), 0); FCaptionBounds.Right := FIconBounds[AIcon].Left - cxTextOffset; end; if RestoreAndMaximize * Icons = RestoreAndMaximize then FIconBounds[sfiRestore] := FIconBounds[sfiMinimize]; UpdateCaptionIconStates; end; procedure TdxSkinFormNonClientAreaInfo.CalculateCaptionInfo; begin CalculateCaptionIconsInfo; CalculateFontInfo; end; procedure TdxSkinFormNonClientAreaInfo.CalculateFontInfo; var AMetrics: TNonClientMetrics; const SysColors: array[Boolean] of TColor = (COLOR_INACTIVECAPTIONTEXT, COLOR_CAPTIONTEXT); 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 := GetSysColor(SysColors[Active]); if PainterInfo <> nil then begin if Active then FCaptionTextColor := PainterInfo.FormFrames[True, bTop].TextColor else if PainterInfo.FormInactiveColor <> nil then FCaptionTextColor := 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.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 then begin if not NativeBorderWidth and IsZoomed then InflateRect(Result, -SystemSizeFrame.cx, -AFrame.cy) else InflateRect(Result, -SizeFrame.cx, -AFrame.cy); end else InflateRect(Result, -AFrame.cx, -AFrame.cy); if IsZoomed and IsSizeBox then Inc(Result.Top, SizeFrame.cy); end; function TdxSkinFormNonClientAreaInfo.GetCaptionButtonSize: Integer; const AMetrics: array[Boolean] of Integer = (SM_CYCAPTION, SM_CYSMCAPTION); begin if NativeBorderWidth then Result := GetSystemMetrics(AMetrics[ToolWindow]) - 2 * GetSystemMetrics(SM_CYEDGE) else Result := GetCaptionIconSize; 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.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) and TCustomFormAccess(Controller.Form).AlphaBlend; 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 IsThemeActive; 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.GetStyle: Integer; begin Result := WindowInfo.dwStyle; 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); end; destructor TdxSkinFormPainter.Destroy; begin FCanvas.Free; FBaseCanvas.Free; inherited Destroy; 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 dxSkinCheckSkinElement(PainterInfo.FormContent).Draw( Canvas.Handle, ViewInfo.ClientRectOnClient); end; procedure TdxSkinFormPainter.DrawWindowBorder; var AAlphaBlendUsed: Boolean; AElement: TdxSkinElement; ASide: TcxBorder; R: TRect; procedure BufferedDraw(const R: TRect; AIsCaption: Boolean; AElement: TdxSkinElement); var CDC: HDC; MemBmp: HBitmap; R1: TRect; begin R1 := R; OffsetRect(R1, -R1.Left, -R1.Top); CDC := CreateCompatibleDC(Canvas.Handle); MemBMP := CreateCompatibleBitmap(Canvas.Handle, R1.Right, R1.Bottom); MemBMP := SelectObject(CDC, MemBmp); if AIsCaption then DrawWindowCaption(CDC, R1, AElement) else dxSkinCheckSkinElement(AElement).Draw(CDC, R1, 0, FrameStates[Active]); BitBlt(Canvas.Handle, R.Left, R.Top, R1.Right, R1.Bottom, CDC, 0, 0, SRCCOPY); MemBMP := SelectObject(CDC, MemBmp); DeleteObject(MemBMP); DeleteDC(CDC); end; begin AAlphaBlendUsed := ViewInfo.IsAlphaBlendUsed; for ASide := bLeft to bBottom do begin R := ViewInfo.BorderBounds[ASide]; if not IsRectVisible(R) then Continue; AElement := PainterInfo.FormFrames[not ViewInfo.ToolWindow, ASide]; if (AElement = nil) or cxRectIsEmpty(R) then Continue; if ASide in [bLeft, bRight] then begin R.Top := ViewInfo.BorderBounds[bTop].Bottom; R.Bottom := ViewInfo.BorderBounds[bBottom].Top; end; if (ASide = bTop) or AAlphaBlendUsed then BufferedDraw(R, ASide = bTop, AElement) else dxSkinCheckSkinElement(AElement).Draw(Canvas.Handle, R, 0, FrameStates[Active]); end; // draw menubar separator if ViewInfo.HasMenu then begin FillRect(Canvas.Handle, cxRectSetBottom(ViewInfo.MenuBounds, ViewInfo.MenuBounds.Bottom, 1), GetSysColorBrush(COLOR_MENU)); end; if (ViewInfo.ScrollAreaElements <> []) and not ViewInfo.IsIconic then DrawScrollAreaElements(Canvas.Handle); end; procedure TdxSkinFormPainter.EndPaint; begin if FNeedRelease then ReleaseDC(ViewInfo.Handle, FDC); 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 dxSkinCheckSkinElement(AElement).Draw(DC, R, 0, FrameStates[ViewInfo.Active]); 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.CaptionTextShadowColor <> clDefault then begin APrevColor := SetTextColor(DC, ViewInfo.CaptionTextShadowColor); if ViewInfo.Active and not ViewInfo.ToolWindow 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 not RectVisible(DC, R) then Exit; if AElement <> nil then AElement.Draw(DC, R, 0, ViewInfo.IconState[AIcon]) else DrawIconEx(DC, R.Left, R.Top, ViewInfo.SysMenuIcon, R.Right - R.Left, R.Bottom - R.Top, 0, 0, DI_NORMAL); 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; { TdxSkinButtonPainter } constructor TdxSkinButtonPainter.Create(AViewInfo: TdxSkinButtonViewInfo); begin FViewInfo := AViewInfo; FCanvas := TCanvas.Create; FcxCanvas := TcxCanvas.Create(FCanvas); end; destructor TdxSkinButtonPainter.Destroy; begin FViewInfo := nil; FcxCanvas.Free; FCanvas.Free; inherited Destroy; end; function TdxSkinButtonPainter.GetController: TdxSkinWinController; begin Result := ViewInfo.Controller; end; function TdxSkinButtonPainter.GetPainter: TcxCustomLookAndFeelPainterClass; begin Result := Controller.LookAndFeelPainter; end; procedure TdxSkinButtonPainter.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 TdxSkinButtonPainter.EndPaint; begin Canvas.Canvas.Handle := 0; if NeedRelease then ReleaseDC(Controller.Handle, FDC); end; procedure TdxSkinButtonPainter.DrawBackground; var AControl: TWinControl; begin AControl := Controller.WinControl; if AControl <> nil then cxDrawTransparentControlBackground(AControl, Canvas, ViewInfo.ClientRect); end; procedure TdxSkinButtonPainter.DrawButton(const ACaption: string; const R: TRect; AState: TcxButtonState); begin Painter.DrawButton(Canvas, R, ACaption, AState, True, clDefault, clDefault, GetWindowLong(Controller.Handle, GWL_STYLE) and BS_MULTILINE <> 0); end; procedure TdxSkinButtonPainter.DrawFocus(const R: TRect); begin DrawFocusRect(Canvas.Handle, R); end; { TdxSkinButtonViewInfo } constructor TdxSkinButtonViewInfo.Create(AController: TdxSkinWinController); begin FController := AController; FCaption := GetWindowCaption(Controller.Handle); end; procedure TdxSkinButtonViewInfo.MouseClickEvent(ADown: Boolean); begin if ADown then State := cxbsPressed else State := cxbsNormal; FPressed := State = cxbsPressed; end; procedure TdxSkinButtonViewInfo.MouseHoverEvent(AEnter: Boolean); const AStates: array[Boolean] of TcxButtonState = (cxbsHot, cxbsPressed); begin if AEnter then State := AStates[Pressed] else State := cxbsNormal; end; function TdxSkinButtonViewInfo.GetClientRect: TRect; begin GetWindowRect(Controller.Handle, Result); OffsetRect(Result, -Result.Left, -Result.Top); end; function TdxSkinButtonViewInfo.GetIsEnabled: Boolean; begin Result := IsWindowEnabled(Controller.Handle); end; function TdxSkinButtonViewInfo.GetIsFocused: Boolean; begin Result := GetFocus = Controller.Handle; end; function TdxSkinButtonViewInfo.GetIsMouseAtControl: Boolean; begin Result := WindowFromPoint(Mouse.CursorPos) = FController.Handle; 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; Controller.RedrawWindow(True); end; end; { TdxSkinButtonController } constructor TdxSkinButtonController.Create(AHandle: HWND); begin inherited Create(AHandle); FViewInfo := TdxSkinButtonViewInfo.Create(Self); FPainter := TdxSkinButtonPainter.Create(FViewInfo); end; destructor TdxSkinButtonController.Destroy; begin FViewInfo.Free; FPainter.Free; inherited Destroy; end; procedure TdxSkinButtonController.DrawBackground(DC: HDC = 0); begin Painter.BeginPaint(DC); try Painter.DrawBackground; finally Painter.EndPaint; end; end; procedure TdxSkinButtonController.DrawContent(DC: HDC = 0); begin Painter.BeginPaint(DC); try with ViewInfo do begin Painter.DrawButton(Caption, ClientRect, State); if IsFocused then Painter.DrawFocus(cxRectInflate(ClientRect, -4, -4)); end; finally Painter.EndPaint; end; end; function TdxSkinButtonController.GetMaster(AHandle: HWND): TdxSkinWinController; var AParent: TCustomForm; ID: Integer; begin Result := nil; if Assigned(WinControl) then begin AParent := GetParentForm(WinControl); if Assigned(AParent) then begin ID := FormsList.IndexOf(Pointer(AParent.Handle)); if ID >= 0 then Result := FormControllers[ID] as TdxSkinWinController; end; end; end; procedure TdxSkinButtonController.InitializePainter; begin end; function TdxSkinButtonController.WMEraseBk(var AMessage: TWMEraseBkgnd): Boolean; begin DrawBackground(AMessage.DC); AMessage.Result := 1; Result := True; end; function TdxSkinButtonController.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 TdxSkinButtonController.MouseLeave; begin inherited MouseLeave; ViewInfo.MouseHoverEvent(False) end; procedure TdxSkinButtonController.WndProc(var AMessage: TMessage); var AHandled: Boolean; begin AHandled := False; if IsSkinUsed then case AMessage.Msg of WM_ERASEBKGND: AHandled := WMEraseBk(TWMEraseBkgnd(AMessage)); BM_SETSTATE: begin inherited WndProc(AMessage); ViewInfo.MouseClickEvent(AMessage.WParam <> 0); AHandled := True; end; WM_MOUSELEAVE, CM_MOUSELEAVE: begin inherited WndProc(AMessage); ViewInfo.MouseHoverEvent(False); AHandled := True; end; WM_PAINT: AHandled := WMPaint(TWMPaint(AMessage)); WM_SETTEXT: ViewInfo.FCaption := TWMSetText(AMessage).Text; WM_MOUSEMOVE, WM_MOUSEHOVER: with ViewInfo do begin inherited WndProc(AMessage); if IsMouseAtControl then MouseHoverEvent(True); AHandled := True; end; 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 DrawBackground(DC); AControl := WinControl; if Assigned(AControl) and (AControl is TCustomPanel) then with TCustomPanelAccess(AControl) do begin Painter.BeginPaint(DC); try R := ViewInfo.ClientRect; if Color = clBtnFace then begin if (BevelOuter <> bvNone) or (BevelInner <> bvNone) then Painter.Painter.DrawBorder(Painter.Canvas, R); Painter.Canvas.Brush.Style := bsClear; Painter.Canvas.Font := Font; end else Painter.Canvas.FillRect(R, Color); 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); finally Painter.EndPaint; end; end; end; procedure TdxSkinPanelController.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 DefWndProc(AMessage); end; // function dxSkinsWndProcHook(Code: Integer; wParam: WParam; lParam: LParam): LRESULT; stdcall; var AMsg: PCWPStruct; ASkinClass: TdxSkinWinControllerClass; function IsAnotherApplicatonWindow(AWnd: HWND): Boolean; var AProcessId: Cardinal; begin GetWindowThreadProcessId(AWnd, @AProcessId); Result := (AWnd = 0) or (AProcessId <> GetCurrentProcessId); end; function GetSkinClassForWindow(AWnd: HWND): TdxSkinWinControllerClass; var AControl: TWinControl; ASkinsSupport: IdxSkinSupport; begin Result := nil; if not IsAnotherApplicatonWindow(AWnd) then begin AControl := FindControl(AMsg.hwnd); if AControl is TCustomForm then Result := TdxSkinFormController else if not Supports(AControl, IdxSkinSupport, ASkinsSupport) then if AControl is TButton then Result := TdxSkinButtonController else if AControl is TPanel then Result := TdxSkinPanelController; end; end; procedure ChildChanged(AHandle: HWND); begin if AHandle <> 0 then if AnsiSameText(GetWindowClass(AHandle), 'MDICLIENT') then begin AHandle := GetParent(AHandle); if AHandle <> 0 then SendMessage(AHandle, WM_CHILDCHANGED, 0, 0); end; end; begin AMsg := PCWPStruct(lParam); Result := CallNextHookEx(WndProcHookHandle, Code, wParam, lParam); if IsDesigning then Exit; case AMsg.message of WM_CHILDACTIVATE, WM_MDIACTIVATE: ChildChanged(GetParent(AMsg.hwnd)); WM_CREATE, WM_MDICREATE: if TdxSkinFormController.IsMDIClientWindow(AMsg.hwnd) then PostMessage(GetParent(AMsg.hwnd), WM_POSTMDICREATE, 0, AMsg.hwnd) else begin ASkinClass := GetSkinClassForWindow(AMsg.hwnd); if ASkinClass <> nil then begin GetSystemMenu(AMsg.hwnd, True); // W2k redrawing bug ASkinClass.InitializeEngine(AMsg.hwnd); end; end; WM_DESTROY, WM_MDIDESTROY: if AMsg.wParam = 0 then begin TdxSkinWinController.FinalizeEngine(AMsg.hwnd); ChildChanged(GetParent(AMsg.hwnd)); end; 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; SkinControllersList := TList.Create; WndProcHookHandle := SetWindowsHookEx(WH_CALLWNDPROC, dxSkinsWndProcHook, 0, GetCurrentThreadId); WM_POSTREDRAW := RegisterWindowMessage('WM_POSTREDRAW'); WM_CHILDCHANGED := RegisterWindowMessage('WM_CHILDCHANGED'); WM_POSTMDICREATE := RegisterWindowMessage('WM_POSTMDICREATE'); FormsList := TList.Create; FormControllers := TcxObjectList.Create; end; procedure UnregisterAssistants; begin FlatSB_SetScrollPos := SetScrollPos; FlatSB_SetScrollInfo := SetScrollInfo; UnhookWindowsHookEx(WndProcHookHandle); while FormsList.Count > 0 do TdxSkinWinController.FinalizeEngine(HWND(FormsList.Last)); FormsList.Free; SkinControllersList.Free; FormControllers.Free; end; initialization RegisterAssistants; finalization UnregisterAssistants; end.