{*******************************************************************} { } { Developer Express Visual Component Library } { ExpressBars components } { } { Copyright (c) 1998-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 EXPRESSBARS 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 dxRibbonForm; {$I cxVer.inc} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ImgList, cxClasses, cxGraphics, cxControls, dxRibbonSkins, dxRibbonFormCaptionHelper, cxDWMApi; type { TdxCustomRibbonForm } TdxCustomRibbonForm = class(TForm) private FAutoScroll: Boolean; FCaption: TCaption; FCornerRegions: array[0..3] of HRGN; FExtendFrameAtTopHeight: Integer; FFakeClientHandle: HWND; FZoomedBoundsOffsets: TRect; FIsActive: Boolean; FSizingBorders: TSize; FSizingLoop: Boolean; FUseSkin: Boolean; FDefClientProc: TFarProc; FNewClientInstance: TFarProc; FRibbonNonClientHelper: TdxRibbonFormCaptionHelper; procedure CalculateCornerRegions; procedure CalculateZoomedOffsets; procedure CheckExtendFrame(AZoomed: Boolean); procedure CheckResizingNCHitTest(var AHitTest: Integer; const P: TPoint); procedure CorrectZoomedBounds(var R: TRect); procedure CreateCornerRegions; procedure DestroyCornerRegions; procedure ExcludeRibbonPaintArea(DC: HDC); function GetCurrentBordersWidth: TRect; function GetUseSkin: Boolean; function GetWindowState: TWindowState; procedure InvalidateFrame(AWnd: HWND); function IsNeedCorrectForAutoHideTaskBar: Boolean; function IsNormalWindowState: Boolean; procedure NewClientWndProc(var Message: TMessage); procedure SetAutoScroll(const Value: Boolean); procedure SetRibbonNonClientHelper(const Value: TdxRibbonFormCaptionHelper); procedure SetWindowState(const Value: TWindowState); //messages procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED; procedure WMCaptureChanged(var Message: TMessage); message WM_CAPTURECHANGED; procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMNCActivate(var Message: TWMNCActivate); message WM_NCACTIVATE; procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST; procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT; procedure WMPaint(var Message: TWMPaint); message WM_PAINT; procedure WMShowWindow(var Message: TMessage); message WM_SHOWWINDOW; procedure WMSize(var Message: TWMSize); message WM_SIZE; procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND; procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE; procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP; procedure WMNCRButtonUp(var Message: TWMNCRButtonUp); message WM_NCRBUTTONUP; procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN; procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP; procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED; //vista support procedure WMDWMCompositionChanged(var Message: TMessage); message WM_DWMCOMPOSITIONCHANGED; //caption procedure WMGetText(var Message: TWMGetText); message WM_GETTEXT; procedure WMGetTextLength(var Message: TWMGetTextLength); message WM_GETTEXTLENGTH; procedure WMSetText(var Message: TWMSetText); message WM_SETTEXT; protected procedure CallDWMWindowProc(var Message); procedure CreateWnd; override; procedure DestroyWindowHandle; override; procedure DrawNonClientArea(ADrawCaption: Boolean; AUpdateRegion: HRGN = 1); procedure ExtendFrameIntoClientAreaAtTop(AHeight: Integer); function GetFormBorderIcons: TBorderIcons; virtual; function HandleWithHelper(ADown: Boolean; AButton: TMouseButton): Boolean; virtual; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure UpdateWindowStates; function IsUseAeroNCPaint: Boolean; procedure WndProc(var Message: TMessage); override; property UseSkin: Boolean read GetUseSkin; public constructor Create(AOwner: TComponent); override; constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override; destructor Destroy; override; procedure Invalidate; override; property RibbonNonClientHelper: TdxRibbonFormCaptionHelper read FRibbonNonClientHelper write SetRibbonNonClientHelper; property IsActive: Boolean read FIsActive; published property AutoScroll: Boolean read FAutoScroll write SetAutoScroll default False; property KeyPreview default True; property WindowState: TWindowState read GetWindowState write SetWindowState default wsNormal; end; { TdxRibbonForm } TdxRibbonForm = class(TdxCustomRibbonForm); procedure SetWindowTextWithoutRedraw(AWnd: HWND; const AText: string); implementation uses {$IFDEF DELPHI6} Types, {$ENDIF} dxBar, cxGeometry, Math, dxOffice11, dxUxTheme, MultiMon, ShellAPI; const {$IFNDEF DELPHI7} WM_NCMOUSELEAVE = $02A2; {$ENDIF} WM_NCUAHDRAWCAPTION = $00AE; WM_NCUAHDRAWFRAME = $00AF; WM_SYNCPAINT = $0088; procedure SetWindowTextWithoutRedraw(AWnd: HWND; const AText: string); var AFlags: Cardinal; begin AFlags := GetWindowLong(AWnd, GWL_STYLE); SetWindowLong(AWnd, GWL_STYLE, AFlags and not WS_VISIBLE); DefWindowProc(AWnd, WM_SETTEXT, 0, LongInt(PChar(AText))); SetWindowLong(AWnd, GWL_STYLE, AFlags); end; { TdxCustomRibbonForm } constructor TdxCustomRibbonForm.Create(AOwner: TComponent); begin inherited Create(AOwner); //CBUILDER workaround end; constructor TdxCustomRibbonForm.CreateNew(AOwner: TComponent; Dummy: Integer = 0); begin inherited CreateNew(AOwner, Dummy); FAutoScroll := False; AutoScroll := False; KeyPreview := True; CreateCornerRegions; end; destructor TdxCustomRibbonForm.Destroy; begin DestroyCornerRegions; inherited Destroy; end; procedure TdxCustomRibbonForm.Invalidate; begin if HandleAllocated and not IsIconic(Handle) then CheckExtendFrame(IsZoomed(Handle)); inherited Invalidate; if ClientHandle <> 0 then InvalidateRect(ClientHandle, nil, True); end; procedure TdxCustomRibbonForm.CreateWnd; var ClientCreateStruct: TClientCreateStruct; begin FExtendFrameAtTopHeight := -1; inherited CreateWnd; if UseSkin then begin if not (csDesigning in ComponentState) and (FormStyle = fsMDIForm) then begin with ClientCreateStruct do begin idFirstChild := $FF00; //check hWindowMenu := 0; end; FFakeClientHandle := Windows.CreateWindowEx(WS_EX_CLIENTEDGE, 'MDICLIENT', nil, WS_CHILD or WS_VISIBLE or WS_GROUP or WS_TABSTOP or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or MDIS_ALLCHILDSTYLES, 0, 0, ClientWidth, ClientHeight, Handle, 0, HInstance, @ClientCreateStruct); SetWindowPos(FFakeClientHandle, 0, -20, -20, 20, 20, SWP_NOACTIVATE or SWP_NOZORDER); FDefClientProc := Pointer(GetWindowLong(FFakeClientHandle, GWL_WNDPROC)); FNewClientInstance := {$IFDEF DELPHI6}Classes.{$ENDIF}MakeObjectInstance(NewClientWndProc); SetWindowLong(ClientHandle, GWL_WNDPROC, Longint(FNewClientInstance)); if ClientHandle <> 0 then begin SetWindowLong(ClientHandle, GWL_EXSTYLE, GetWindowLong(ClientHandle, GWL_EXSTYLE) and not WS_EX_CLIENTEDGE); InvalidateFrame(ClientHandle); end; end; if not IsUseAeroNCPaint then begin GetSystemMenu(Handle, True); //W2k painting bug workaround RibbonNonClientHelper.InitWindowBorderIcons(GetFormBorderIcons); end; end; end; procedure TdxCustomRibbonForm.DestroyWindowHandle; begin inherited; if csDestroying in ComponentState then RibbonNonClientHelper := nil; end; procedure TdxCustomRibbonForm.CallDWMWindowProc(var Message); begin DwmDefWindowProc(Handle, TMessage(Message).Msg, TMessage(Message).WParam, TMessage(Message).LParam, Integer(@TMessage(Message).Result)); end; procedure TdxCustomRibbonForm.NewClientWndProc(var Message: TMessage); procedure Default; begin with Message do Result := CallWindowProc(FDefClientProc, ClientHandle, Msg, wParam, lParam); end; function MaximizedChildren: Boolean; var I: Integer; begin for I := 0 to MDIChildCount - 1 do if MDIChildren[I].WindowState = wsMaximized then begin Result := True; Exit; end; Result := False; end; var DC: HDC; PS: TPaintStruct; R: TRect; // F: TForm; AColor: TColor; begin if not UseSkin then begin Default; Exit; end; with Message do case Msg of WM_KEYDOWN: begin KeyDown(WParamLo, KeyDataToShiftState(LParam)); if WParamLo = 0 then Exit; Default; end; WM_NCHITTEST: begin Default; if Result = HTCLIENT then Result := HTTRANSPARENT; end; WM_ERASEBKGND: begin AColor := RibbonNonClientHelper.GetWindowColor; FillRectByColor(TWMEraseBkGnd(Message).DC, ClientRect, AColor); // Erase the background at the location of an MDI client window if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then begin Windows.GetClientRect(ClientHandle, R); FillRectByColor(TWMEraseBkGnd(Message).DC, R, AColor); end; Result := 1; end; WM_NCCALCSIZE:; WM_NCPAINT:; WM_MDIREFRESHMENU: Result := 0; WM_NCACTIVATE: Message.Result := 1; { $3F://! begin Default; F := ActiveMDIChild; if (F <> nil) and MaximizedChildren then begin //correct maximized bounds GetWindowRect(ClientHandle, R); R.Right := R.Right - R.Left + (F.Width - F.ClientWidth); R.Bottom := R.Bottom - R.Top + (F.Height - F.ClientHeight); if (F is TdxCustomRibbonForm) and TdxCustomRibbonForm(F).UseSkin then Inc(R.Bottom, TdxCustomRibbonForm(F).RibbonNonClientHelper.GetWindowCaptionHeight); SetWindowPos(F.Handle, 0, 0, 0, R.Right, R.Bottom, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOZORDER); end; end; } WM_PAINT: begin DC := TWMPaint(Message).DC; if DC = 0 then TWMPaint(Message).DC := BeginPaint(ClientHandle, PS); try if DC = 0 then begin GetWindowRect(ClientHandle, R); R.TopLeft := ScreenToClient(R.TopLeft); MoveWindowOrg(TWMPaint(Message).DC, -R.Left, -R.Top); end; PaintHandler(TWMPaint(Message)); finally if DC = 0 then EndPaint(ClientHandle, PS); end; end; else Default; end; end; procedure TdxCustomRibbonForm.DrawNonClientArea(ADrawCaption: Boolean; AUpdateRegion: HRGN = 1); var DC: HDC; AFlags: Integer; ARgn: HRGN; AZoomed: Boolean; begin if IsUseAeroNCPaint then Exit; UpdateWindowStates; AFlags := DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE; if AUpdateRegion <> 1 then begin ARgn := CreateRectRgnIndirect(cxEmptyRect); CombineRgn(ARgn, AUpdateRegion, 0, RGN_COPY); DC := GetDCEx(Handle, ARgn, AFlags or DCX_INTERSECTRGN); end else DC := GetDCEx(Handle, 0, AFlags); BarCanvas.BeginPaint(DC); BarCanvas.Canvas.Lock; try if IsIconic(Handle) then RibbonNonClientHelper.DrawWindowCaption(BarCanvas, Caption) else begin AZoomed := IsZoomed(Handle); if not AZoomed then RibbonNonClientHelper.DrawWindowBorders(BarCanvas); if ADrawCaption then RibbonNonClientHelper.DrawWindowCaption(nil, Caption); end; finally BarCanvas.Canvas.Unlock; BarCanvas.EndPaint; ReleaseDC(Handle, DC); end; end; function TdxCustomRibbonForm.HandleWithHelper(ADown: Boolean; AButton: TMouseButton): Boolean; var P: TPoint; begin Result := UseSkin; if Result then begin P := GetMouseCursorPos; if RibbonNonClientHelper.IsInCaptionArea(P.X, P.Y) then begin if ADown then Result := RibbonNonClientHelper.MouseDown(P, AButton) else Result := RibbonNonClientHelper.MouseUp(P, AButton); end else Result := False; end; end; procedure TdxCustomRibbonForm.KeyDown(var Key: Word; Shift: TShiftState); var I: Integer; AIntf: IdxFormKeyPreviewListener; AForm: TForm; begin inherited KeyDown(Key, Shift); if KeyPreview then begin if FormStyle = fsMDIChild then AForm := Application.MainForm else AForm := Self; for I := 0 to AForm.ControlCount - 1 do if Supports(TObject(AForm.Controls[I]), IdxFormKeyPreviewListener, AIntf) then begin AIntf.FormKeyDown(Key, Shift); AIntf := nil; end; end; end; procedure TdxCustomRibbonForm.CalculateCornerRegions; procedure CalculateRegion(ACornerRgn: HRGN; DX, DY: Integer; const ACornerRect: TRect); var R1, R2: HRGN; begin R1 := CreateRectRgnIndirect(cxEmptyRect); GetWindowRgn(Handle, ACornerRgn); GetWindowRgn(Handle, R1); OffsetRgn(R1, DX, DY); CombineRgn(ACornerRgn, ACornerRgn, R1, RGN_DIFF); R2 := CreateRectRgnIndirect(ACornerRect); CombineRgn(ACornerRgn, ACornerRgn, R2, RGN_AND); DeleteObject(R1); DeleteObject(R2); end; var H: Integer; begin H := GetSystemMetrics(SM_CYCAPTION); CalculateRegion(FCornerRegions[0], FSizingBorders.cx, FSizingBorders.cy, cxRect(0, 0, H, H)); CalculateRegion(FCornerRegions[1], -FSizingBorders.cx, FSizingBorders.cy, cxRect(Width - H, 0, Width, H)); CalculateRegion(FCornerRegions[2], -FSizingBorders.cx, -FSizingBorders.cy, cxRect(Width - H, Height - H, Width, Height)); CalculateRegion(FCornerRegions[3], FSizingBorders.cx, -FSizingBorders.cy, cxRect(0, Height - H, H, Height)); end; procedure TdxCustomRibbonForm.CalculateZoomedOffsets; var ABData: TAppBarData; begin FZoomedBoundsOffsets := cxEmptyRect; if IsNeedCorrectForAutoHideTaskBar then begin FillChar(ABData, sizeof(ABData), 0); ABData.cbSize := sizeof(ABData); ABData.hWnd := Handle; SHAppBarMessage(ABM_GETTASKBARPOS, ABData); if ABData.uEdge = ABE_LEFT then FZoomedBoundsOffsets.Left := 1 else if (ABData.uEdge = ABE_TOP) and not IsUseAeroNCPaint then FZoomedBoundsOffsets.Top := 1 else if ABData.uEdge = ABE_RIGHT then FZoomedBoundsOffsets.Right := 1 + Ord(IsUseAeroNCPaint) else if ABData.uEdge = ABE_BOTTOM then FZoomedBoundsOffsets.Bottom := 1; end; end; procedure TdxCustomRibbonForm.CheckExtendFrame(AZoomed: Boolean); var ANonClientHeight: Integer; begin if UseSkin and HandleAllocated and IsUseAeroNCPaint then begin ANonClientHeight := RibbonNonClientHelper.GetWindowCaptionHeight; //prevent client area rendering beyond the screen if maximized if AZoomed then Inc(ANonClientHeight, GetDefaultWindowBordersWidth(Handle).Top); ExtendFrameIntoClientAreaAtTop(ANonClientHeight); end; end; function TdxCustomRibbonForm.GetUseSkin: Boolean; begin Result := FUseSkin //and (FormStyle <> fsMDIChild); end; function TdxCustomRibbonForm.GetWindowState: TWindowState; begin Result := inherited WindowState; end; procedure TdxCustomRibbonForm.InvalidateFrame(AWnd: HWND); begin SetWindowPos(AWnd, 0, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_DRAWFRAME); end; function TdxCustomRibbonForm.IsNeedCorrectForAutoHideTaskBar: Boolean; var ABData : TAppBarData; begin FillChar(ABData, sizeof(ABData), 0); ABData.cbSize := sizeof(ABData); Result := ((SHAppBarMessage(ABM_GETSTATE, ABData) and ABS_AUTOHIDE) > 0) and (MonitorFromWindow(FindWindow('Shell_TrayWnd', nil), MONITOR_DEFAULTTONEAREST) = Monitor.Handle); end; function TdxCustomRibbonForm.IsNormalWindowState: Boolean; begin Result := not (IsIconic(Handle) or IsZoomed(Handle)); end; procedure TdxCustomRibbonForm.SetAutoScroll(const Value: Boolean); begin //don't change inherited AutoScroll := False; end; procedure TdxCustomRibbonForm.SetRibbonNonClientHelper(const Value: TdxRibbonFormCaptionHelper); var ASaveCaption: TCaption; begin if FRibbonNonClientHelper <> Value then begin FRibbonNonClientHelper := Value; ASaveCaption := Caption; FUseSkin := (Value <> nil) and (FRibbonNonClientHelper <> nil); if csDestroying in ComponentState then FUseSkin := False else begin RecreateWnd; Caption := ASaveCaption; end; end; end; procedure TdxCustomRibbonForm.SetWindowState(const Value: TWindowState); begin if Value <> WindowState then begin FZoomedBoundsOffsets := cxEmptyRect; if Value = wsMaximized then begin if HandleAllocated and not IsWindowVisible(Handle) then PostMessage(Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0) else begin CalculateZoomedOffsets; inherited WindowState := Value; end; end else inherited WindowState := Value; end; end; procedure TdxCustomRibbonForm.CMColorChanged(var Message: TMessage); begin if UseSkin then begin if (FormStyle = fsMDIForm) and (ClientHandle <> 0) then Windows.InvalidateRect(ClientHandle, nil, True); end; inherited; end; procedure TdxCustomRibbonForm.WMCancelMode(var Message: TWMCancelMode); begin if UseSkin then RibbonNonClientHelper.CancelMode; inherited; end; procedure TdxCustomRibbonForm.WMCaptureChanged(var Message: TMessage); begin if UseSkin and (THandle(Message.LParam) <> Handle) then begin FSizingLoop := False; RibbonNonClientHelper.CancelMode; end; inherited; end; procedure TdxCustomRibbonForm.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin if UseSkin and (IsUseAeroNCPaint or not DoubleBuffered or (TMessage(Message).wParam = TMessage(Message).lParam)) then FillRectByColor(Message.DC, ClientRect, RibbonNonClientHelper.GetWindowColor) else inherited; end; procedure TdxCustomRibbonForm.WMLButtonDown(var Message: TWMLButtonDown); begin if HandleWithHelper(True, mbLeft) then RibbonNonClientHelper.CaptionChanged else inherited; end; procedure TdxCustomRibbonForm.WMLButtonUp(var Message: TWMLButtonUp); begin if UseSkin then begin if HandleWithHelper(False, mbLeft) then Message.Result := 0 else begin RibbonNonClientHelper.CancelMode; inherited; end; end else inherited end; procedure TdxCustomRibbonForm.WMRButtonDown(var Message: TWMRButtonDown); begin if HandleWithHelper(True, mbRight) then Message.Result := 0 else inherited; end; procedure TdxCustomRibbonForm.WMRButtonUp(var Message: TWMRButtonUp); begin if HandleWithHelper(False, mbRight) then Message.Result := 0 else inherited; end; procedure TdxCustomRibbonForm.WMNCRButtonUp(var Message: TWMNCRButtonUp); begin if HandleWithHelper(False, mbRight) then Message.Result := 0 else inherited; end; procedure TdxCustomRibbonForm.WMNCActivate(var Message: TWMNCActivate); var I: Integer; begin FIsActive := Message.Active; if UseSkin then begin if IsUseAeroNCPaint then inherited; UpdateWindowStates; if not FIsActive then RibbonNonClientHelper.CancelMode; RibbonNonClientHelper.ActiveChanged(FIsActive); UpdateWindow(Handle); if FormStyle = fsMDIForm then for I := 0 to MDIChildCount - 1 do InvalidateFrame(MDIChildren[I].Handle); Message.Result := 1; end else inherited; end; procedure TdxCustomRibbonForm.WMNCCalcSize(var Message: TWMNCCalcSize); var R, SaveR0: TRect; T: Integer; AIsZoomed: Boolean; begin if not UseSkin or IsIconic(Handle) then inherited else begin if Message.CalcValidRects then begin AIsZoomed := IsZoomed(Handle); if IsUseAeroNCPaint then begin T := Message.CalcSize_Params^.rgrc[0].Top; if AIsZoomed then Message.CalcSize_Params^.rgrc[2].Top := T; inherited; SaveR0 := Message.CalcSize_Params^.rgrc[0]; SaveR0.Top := T; end else begin R := GetCurrentBordersWidth; SaveR0 := Message.CalcSize_Params^.rgrc[0]; with Message.CalcSize_Params^.rgrc[0] do begin Inc(SaveR0.Top, R.Top); Dec(SaveR0.Bottom, R.Bottom); Inc(SaveR0.Left, R.Left); Dec(SaveR0.Right, R.Right); end; end; if AIsZoomed then begin if FormStyle = fsMDIChild then //check for the OS version begin if IsCompositionEnabled then Dec(SaveR0.Top, GetDefaultWindowBordersWidth(Handle).Top + 1) else Dec(SaveR0.Top, 2); end else CorrectZoomedBounds(SaveR0); end; Message.CalcSize_Params^.rgrc[0] := SaveR0; end else inherited; Message.Result := 0; end; end; procedure TdxCustomRibbonForm.WMNCHitTest(var Message: TWMNCHitTest); var R: TRect; P: TPoint; begin if UseSkin then begin Message.Result := HTNOWHERE; if IsUseAeroNCPaint then begin CallDWMWindowProc(Message); if Message.Result = HTNOWHERE then inherited; if not ((Message.Result = HTCAPTION) or (Message.Result = HTCLIENT)) then Exit; Message.Result := HTNOWHERE; end; GetWindowRect(Handle, R); P := cxPoint(Message.XPos - R.Left, Message.YPos - R.Top); if (BorderStyle in [bsSizeable, bsSizeToolWin]) then CheckResizingNCHitTest(Message.Result, P); if (Message.Result = HTNOWHERE) and RibbonNonClientHelper.IsInCaptionArea(Message.XPos, Message.YPos) then RibbonNonClientHelper.GetWindowCaptionHitTest(Message); if Message.Result = HTNOWHERE then Message.Result := HTCLIENT; end else inherited; end; procedure TdxCustomRibbonForm.WMShowWindow(var Message: TMessage); begin inherited; if WordBool(Message.WParam) and UseSkin and IsNormalWindowState then RibbonNonClientHelper.InitWindowBorderIcons(GetFormBorderIcons); end; procedure TdxCustomRibbonForm.WMNCPaint(var Message: TMessage); begin if UseSkin then begin if IsUseAeroNCPaint then inherited; DrawNonClientArea(False, Message.WParam); Message.Result := 0; end else inherited; end; procedure TdxCustomRibbonForm.WMPaint(var Message: TWMPaint); begin if UseSkin then begin UpdateWindowStates; if IsUseAeroNCPaint then ExcludeRibbonPaintArea(Message.DC); inherited; end else inherited; end; procedure TdxCustomRibbonForm.WMSize(var Message: TWMSize); var R: TRect; begin UpdateWindowStates; inherited; if UseSkin then begin FSizingBorders.cx := GetSystemMetrics(SM_CXSIZEFRAME); FSizingBorders.cy := GetSystemMetrics(SM_CYSIZEFRAME); if IsUseAeroNCPaint then CheckExtendFrame(Message.SizeType = SIZE_MAXIMIZED) else begin if Message.SizeType = SIZE_MAXIMIZED then begin //clip borders GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top); with GetDefaultWindowBordersWidth(Handle) do R := cxRectInflate(R, -Left, -Top, -Right, -Bottom); SetWindowRgn(Handle, CreateRectRgnIndirect(R), True); end else begin SetWindowRgn(Handle, RibbonNonClientHelper.GetWindowRegion, True); CalculateCornerRegions; end; end; RibbonNonClientHelper.Resize; end; end; procedure TdxCustomRibbonForm.WMSysCommand(var Message: TWMSysCommand); begin if Message.CmdType and $FFF0 = SC_MAXIMIZE then CalculateZoomedOffsets; inherited; if UseSkin then begin case (Message.CmdType and $FFF0) of SC_MAXIMIZE, SC_RESTORE: DrawNonClientArea(True); end; end; end; procedure TdxCustomRibbonForm.WMWindowPosChanged(var Message: TWMWindowPosChanged); begin inherited; if UseSkin and not FSizingLoop and (Message.WindowPos.flags and SWP_NOSIZE = 0) then RibbonNonClientHelper.CaptionChanged; end; procedure TdxCustomRibbonForm.WMDWMCompositionChanged(var Message: TMessage); begin inherited; if UseSkin then begin RecreateWnd; UpdateWindowStates; InvalidateFrame(Handle); Invalidate; Message.Result := 0; end; end; procedure TdxCustomRibbonForm.WndProc(var Message: TMessage); begin if not UseSkin then inherited WndProc(Message) else with Message do begin case Msg of WM_ENTERSIZEMOVE: begin FSizingLoop := True; inherited WndProc(Message); end; WM_EXITSIZEMOVE: begin FSizingLoop := False; inherited WndProc(Message); DrawNonClientArea(True); end; WM_NCUAHDRAWCAPTION, WM_NCUAHDRAWFRAME: begin if IsUseAeroNCPaint then CallDWMWindowProc(Message); DrawNonClientArea(True); Message.Result := 0; end; WM_MOUSEACTIVATE, WM_SYNCPAINT: begin inherited WndProc(Message); DrawNonClientArea(True); end; WM_NCLBUTTONDOWN: begin if not IsUseAeroNCPaint then UpdateWindow(Handle); inherited WndProc(Message); if IsIconic(Handle) then begin DrawNonClientArea(True); Result := 0; Exit; end; end; WM_NCMOUSELEAVE: begin if IsUseAeroNCPaint then CallDWMWindowProc(Message) else inherited; end; WM_LBUTTONDOWN: begin //dmAutomatic suppress a dispatching if (DragMode = dmAutomatic) and not IsUseAeroNCPaint then if HandleWithHelper(True, mbLeft) then Exit; inherited; end; else inherited; end; end; end; procedure TdxCustomRibbonForm.UpdateWindowStates; var R: TRect; D: TdxRibbonFormData; begin if UseSkin then begin FillChar(D, SizeOf(TdxRibbonFormData), 0); if HandleAllocated then begin D.Handle := Handle; GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top); D.Bounds := R; if IsIconic(Handle) then D.State := wsMinimized else if IsZoomed(Handle) then D.State := wsMaximized else D.State := wsNormal; end; D.Active := FIsActive; D.Border := BorderStyle; D.Style := FormStyle; RibbonNonClientHelper.CheckWindowStates(D); end; end; function TdxCustomRibbonForm.IsUseAeroNCPaint: Boolean; begin Result := UseAeroNCPaint(FormStyle); end; procedure TdxCustomRibbonForm.CheckResizingNCHitTest(var AHitTest: Integer; const P: TPoint); const CornerHitTests: array[0..3] of DWORD = (HTTOPLEFT, HTTOPRIGHT, HTBOTTOMRIGHT, HTBOTTOMLEFT); var I: Integer; R, RW: TRect; begin if not IsNormalWindowState then Exit; for I := 0 to 3 do if PtInRegion(FCornerRegions[I], P.X, P.Y) then begin AHitTest := CornerHitTests[I]; Break; end; if AHitTest = HTNOWHERE then begin GetWindowRect(Handle, RW); OffsetRect(RW, -RW.Left, -RW.Top); R := RW; R.Bottom := R.Top + FSizingBorders.cy; if cxRectPtIn(R, P) then AHitTest := HTTOP else if not IsUseAeroNCPaint then begin R := RW; R.Left := R.Right - FSizingBorders.cx; if cxRectPtIn(R, P) then AHitTest := HTRIGHT else begin R := RW; R.Top := R.Bottom - FSizingBorders.cy; if cxRectPtIn(R, P) then AHitTest := HTBOTTOM else begin R := RW; R.Right := R.Left + FSizingBorders.cx; if cxRectPtIn(R, P) then AHitTest := HTLEFT; end; end; end; end; end; procedure TdxCustomRibbonForm.CreateCornerRegions; var I: Integer; begin for I := 0 to 3 do FCornerRegions[I] := CreateRectRgnIndirect(cxEmptyRect); end; procedure TdxCustomRibbonForm.DestroyCornerRegions; var I: Integer; begin for I := 0 to 3 do DeleteObject(FCornerRegions[I]); end; procedure TdxCustomRibbonForm.ExcludeRibbonPaintArea(DC: HDC); var R, CR: HRGN; ARibbonRect: TRect; begin if FExtendFrameAtTopHeight = 0 then Exit; R := GetClipRegion(DC); ARibbonRect := cxRect(0, 0, ClientWidth, FExtendFrameAtTopHeight); CR := CreateRectRgnIndirect(ARibbonRect); SelectClipRgn(DC, CR); FillRectByColor(DC, ARibbonRect, 0); CombineRgn(R, R, CR, RGN_DIFF); SelectClipRgn(DC, R); DeleteObject(R); DeleteObject(CR); end; procedure TdxCustomRibbonForm.ExtendFrameIntoClientAreaAtTop(AHeight: Integer); var M: TdxMargins; begin if FExtendFrameAtTopHeight <> AHeight then begin FExtendFrameAtTopHeight := AHeight; M.cxLeftWidth := 0; M.cxRightWidth := 0; M.cyBottomHeight := 0; M.cyTopHeight := AHeight; DwmExtendFrameIntoClientArea(Handle, @M); end; end; function TdxCustomRibbonForm.GetFormBorderIcons: TBorderIcons; var ABorderStyle: TFormBorderStyle; begin ABorderStyle := BorderStyle; if (FormStyle = fsMDIChild) and (ABorderStyle in [bsNone, bsDialog]) then ABorderStyle := bsSizeable; Result := BorderIcons; case ABorderStyle of bsNone: Result := []; bsDialog: Result := (Result * [biSystemMenu, biHelp]) - [biMaximize]; bsToolWindow, bsSizeToolWin: Result := Result * [biSystemMenu]; end; end; procedure TdxCustomRibbonForm.CorrectZoomedBounds(var R: TRect); begin Inc(R.Left, FZoomedBoundsOffsets.Left); Inc(R.Top, FZoomedBoundsOffsets.Top); Dec(R.Right, FZoomedBoundsOffsets.Right); Dec(R.Bottom, FZoomedBoundsOffsets.Bottom); end; function TdxCustomRibbonForm.GetCurrentBordersWidth: TRect; begin if IsZoomed(Handle) then begin Result := GetDefaultWindowBordersWidth(Handle); if FormStyle = fsMDIChild then Result.Top := 0; end else Result := RibbonNonClientHelper.GetWindowBordersWidth; end; procedure TdxCustomRibbonForm.WMGetText(var Message: TWMGetText); var L: Integer; begin if (csLoading in ComponentState) or UseSkin then begin L := Length(FCaption); FillChar(Pointer(Message.Text)^, Message.TextMax, #0); if Message.TextMax - 1 < L then L := Message.TextMax - 1; if L > 0 then Move(FCaption[1], Pointer(Message.Text)^, L); Message.Result := L; end else inherited; end; procedure TdxCustomRibbonForm.WMGetTextLength(var Message: TWMGetTextLength); begin if (csLoading in ComponentState) or UseSkin then Message.Result := Length(FCaption) else inherited; end; procedure TdxCustomRibbonForm.WMSetText(var Message: TWMSetText); var AForm: TdxCustomRibbonForm; begin if (csLoading in ComponentState) or UseSkin then begin FCaption := Message.Text; if UseSkin then begin UpdateWindowStates; RibbonNonClientHelper.CaptionChanged; if (FormStyle = fsMDIChild) and IsZoomed(Handle) and (Application.MainForm is TdxCustomRibbonForm) then begin AForm := TdxCustomRibbonForm(Application.MainForm); if AForm.UseSkin then begin AForm.UpdateWindowStates; AForm.RibbonNonClientHelper.CaptionChanged; end; end; Perform(CM_TEXTCHANGED, 0, 0); {$IFDEF DELPHI11} if Application.MainForm = Self then SetWindowTextWithoutRedraw(Handle, RibbonNonClientHelper.GetTaskBarCaption); {$ENDIF} end else inherited; end else inherited; end; end.