{ +-------------------------------------------------------------+ } { | | } { | GM-Software | } { | =========== | } { | | } { | Project: All Projects | } { | | } { | Description: Lean UI Area classes. Windowed and window- | } { | less. Non-rect shapes supported. | } { | | } { | Copyright (C) - 2002 - Gerrit Moeller. | } { | | } { | Source code distributed under MIT license. | } { | | } { | See: https://www.gm-software.de | } { | | } { +-------------------------------------------------------------+ } {$INCLUDE GMCompilerSettings.inc} unit GMUICore; interface uses {$IFDEF JEDIAPI}jwaWinType, jwaWinUser, jwaWinGdi,{$ELSE}Windows,{$ENDIF} // jwaWinNT, GMStrDef, GMMessages, GMIntf, GMCommon, GMCollections, GMGdi; type TEdge = (edgLeft, edgTop, edgRight, edgBottom); // <- must match order in TRect type for Left, Top, right, bottom properties! // to enable typecasting to TEdgeRectValue in Get/Set handlers for fast access. TEdgeRectValue = array [TEdge] of LongInt; PEdgeRectValue = ^TEdgeRectValue; TEdges = set of TEdge; TEdgeAlign = (ealFixed, ealAligned, ealCentered, ealWrap); // ealFixed: Edge is not changed, if zero is passed CalculateWidth/Height is called // ealAligned: Edge is set to parent edge, edge position is interpreted as space to parent edge // ealCentered: Edge is centered in parent extend, edge position is interpreted as space to center TEdgesAlign = array [TEdge] of TEdgeAlign; TGMLayoutEdgeOrderMap = array [TEdge] of TEdge; TGMAreaAlignRec = record EdgeAlign: TEdgesAlign; ShrinkRestX: Boolean; ShrinkRestY: Boolean; end; TFrameShape = (frsNone, frsLowered, frsRaised, frsSpace); TFrameKind = (frkNone, frkTile, frkSoft, frkFlat); TFrameScale = -1 .. 1; TGMAreaRegionKind = (arkBounds, arkClient); // Relayed messages will be re-send as Msg + WM_APP TRelayedMessage = (rlmWMCommand, rlmWMNotify, rlmWMScroll, rlmWMOwnerDraw); TRelayedMessages = set of TRelayedMessage; TGMDragControl = (drgLeave, drgCancel, drgFinished); TGMShowWndKind = (swShowNormal, swShowNoActivate, swHide, swShowMinimized, swShowMaximized); const {$IFDEF FPC} {$IFNDEF JEDIAPI} // gradient drawing modes {$EXTERNALSYM GRADIENT_FILL_RECT_H} GRADIENT_FILL_RECT_H = $00000000; {$EXTERNALSYM GRADIENT_FILL_RECT_V} GRADIENT_FILL_RECT_V = $00000001; {$EXTERNALSYM GRADIENT_FILL_TRIANGLE} GRADIENT_FILL_TRIANGLE = $00000002; {$EXTERNALSYM GRADIENT_FILL_OP_FLAG} GRADIENT_FILL_OP_FLAG = $000000ff; {$ENDIF} {$ENDIF} UM_USER = GM_USER + 100; //UM_CLOSE = GM_USER + 1; UM_HANDLECREATED = GM_USER + 2; //UM_SETTEMPCURSOR = GM_USER + 3; UM_CALCWIDTH = GM_USER + 4; UM_CALCHEIGHT = GM_USER + 5; UM_STARTMOUSETRACK = GM_USER + 6; UM_MOUSEENTER = GM_USER + 7; UM_MOUSELEAVE = GM_USER + 8; UM_SELECTNEXTDLGTABAREA = GM_USER + 9; UM_DRAG_QUERYDROP = GM_USER + 11; UM_DRAG_CONTROL = GM_USER + 12; UM_DRAG_DROPPED = GM_USER + 13; UM_LANGUAGECHANGED = GM_USER + 14; //cCannotClose = 0; cDfltWndText = ''; cDfltWndStyle = 0; cDfltWndExStyle = 0; cPrntWndExStyle = cDfltWndExStyle or WS_EX_CONTROLPARENT; cDfltWndMenu = 0; //cDfltWndParent = 0; cDfltDlgData = nil; cDfltColor = clrBtnFace; cMinimizedOrMaximized = WS_MAXIMIZE or WS_MINIMIZE; cMFEnable: array [Boolean] of DWORD = (MF_GRAYED, MF_ENABLED); cAllEdges = [Low(TEdge) .. High(TEdge)]; cEdgesX = [edgLeft, edgRight]; cEdgesY = [edgTop, edgBottom]; cEdgesLeftTop = [edgLeft, edgTop]; cEdgesRightBottom = [edgRight, edgBottom]; cSelectAll = 1; cInvalidLayoutVal = -1; cCalcSizeAlignments = [ealFixed, ealWrap]; //cQAlignMultiplier = 10000; cQAlign = 100000; cQAlignDivisor = cQAlign * 10000; // Some useful area alignments cFixedPlace: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealFixed, ealFixed, ealFixed); ShrinkRestX: False; ShrinkRestY: False); cTopAligned: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealAligned, ealFixed); ShrinkRestX: False; ShrinkRestY: True); cBottomAligned: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealFixed, ealAligned, ealAligned); ShrinkRestX: False; ShrinkRestY: True); cLeftAligned: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealFixed, ealAligned); ShrinkRestX: True; ShrinkRestY: False); cRightAligned: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealAligned, ealAligned, ealAligned); ShrinkRestX: True; ShrinkRestY: False); cClientAligned: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealAligned, ealAligned); ShrinkRestX: False; ShrinkRestY: False); cTopLeftCorner: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealFixed, ealFixed); ShrinkRestX: False; ShrinkRestY: False); cTopRightCorner: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealAligned, ealAligned, ealFixed); ShrinkRestX: False; ShrinkRestY: False); cBottomRightCorner: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealFixed, ealAligned, ealAligned); ShrinkRestX: False; ShrinkRestY: False); cBottomLeftCorner: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealFixed, ealFixed, ealAligned); ShrinkRestX: False; ShrinkRestY: False); cTopLeftX: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealFixed, ealFixed); ShrinkRestX: True; ShrinkRestY: False); cTopLeftY: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealFixed, ealFixed); ShrinkRestX: False; ShrinkRestY: True); cTopRightX: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealAligned, ealAligned, ealFixed); ShrinkRestX: True; ShrinkRestY: False); cTopRightY: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealAligned, ealAligned, ealFixed); ShrinkRestX: False; ShrinkRestY: True); cBottomLeftX: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealFixed, ealFixed, ealAligned); ShrinkRestX: True; ShrinkRestY: False); cBottomLeftY: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealFixed, ealFixed, ealAligned); ShrinkRestX: False; ShrinkRestY: True); cBottomRightX: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealFixed, ealAligned, ealAligned); ShrinkRestX: True; ShrinkRestY: False); cBottomRightY: TGMAreaAlignRec = (EdgeAlign: (ealFixed, ealFixed, ealAligned, ealAligned); ShrinkRestX: False; ShrinkRestY: True); cWrapRightY: TGMAreaAlignRec = (EdgeAlign: (ealAligned, ealAligned, ealWrap, ealFixed); ShrinkRestX: False; ShrinkRestY: True); cDfltRelayedMessages = [Low(TRelayedMessage) .. High(TRelayedMessage)]; cDfltWndAnimation = AW_BLEND; // AW_CENTER; AW_BLEND cDfltWndAniDuration = 250; //275 300; // WS_CLIPCHILDREN causes problems with page control and decreases paint performance cDlgBaseStyle = WS_CAPTION or WS_BORDER; // or WS_CLIPSIBLINGS or WS_CLIPCHILDREN or WS_DLGFRAME cFixedDlgWndStyle = cDlgBaseStyle or WS_SYSMENU; cSizeDlgWndStyle = cDlgBaseStyle or WS_SYSMENU or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_SIZEBOX; // or WS_THICKFRAME; cWSDisabled: array [Boolean] of DWORD = (0, WS_DISABLED); cVisibleTabstop = WS_VISIBLE or WS_TABSTOP; cBtnKindMask = $F; cFrameLines: array [TFrameShape] of LongInt = (0, 1, 1, 1); cWndObjPtrData = GWLP_USERDATA; //GWL_ID; GWLP_USERDATA //cShowWndFlag: array [Boolean] of LongInt = (SW_HIDE, SW_SHOW); cWinPosRedraw: array [Boolean] of DWORD = (SWP_NOREDRAW, 0); cWSVisible: array [Boolean] of DWORD = (0, WS_VISIBLE); cSWShow: array [Boolean] of DWORD = (SW_HIDE, SW_SHOW); cShowWndFlags: array [TGMShowWndKind] of DWORD = (SW_SHOWNORMAL, SW_SHOWNA, SW_HIDE, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED); IDC_GMHSPLIT = 'GMHSplitCursor'; // PGMChar(32764); IDC_GMVSPLIT = 'GMVSplitCursor'; // PGMChar(32765); //IDC_GMDRAGCOPY = 'GMDragCopyCursor'; // PGMChar(32766); cResTextRefPrefix: TGMString = '#!$'; cResTextFmtSeparator: TGMChar = '#'; cNoSizeCnstr = 0; cSizeCnstrNoChange = Low(LongInt); //cAllMouseMsgMask: set of Byte = [0, 1]; cLayeredWndFlag: array [Boolean] of DWORD = (0, WS_EX_LAYERED); type RGMResTextRefData = record ResStringPtr: PResStringRec; FormatStr: TGMString; end; SGMKeyStates = set of (ksShift, ksCtrl, ksAlt); TGMWndObj = Int64; TGMWndMsg = LongWord; //IGMWndMessage = interface(IUnknown) // ['{C180AF7B-37DA-4F76-B225-48ABB5071306}'] // function GetWndMessage: TGMWndMsg; // property WndMessage: TGMWndMsg read GetWndMessage; //end; //TGMWndMessageObj = class(TGMRefCountedObj, IGMWndMessage, IGMHashCode) // protected // FWndMessage: TGMWndMsg; // // public // constructor Create(const AWndMessage: TGMWndMsg; const ARefLifeTime: Boolean); reintroduce; // function GetWndMessage: TGMWndMsg; // function HashCode: TGMHashCode; //end; TGMSizeConstraintsRec = record case LongInt of 0: (MinWidth, MinHeight, MaxWidth, MaxHeight: LongInt); 1: (MinSize: TPoint; MaxSize: TPoint) end; PGMDragMessageRec = ^TGMDragMessageRec; TGMDragMessageRec = packed record Msg: UINT; {$IFDEF CPU64}Filler1: LongWord;{$ENDIF} XPos: Smallint; YPos: Smallint; {$IFDEF CPU64}Filler2: LongWord;{$ENDIF} DragData: IUnknown; Result: PtrInt; end; TGMWinMenu = class(TGMRefCountedObj, IGMGetHandle) protected FHandle: HMenu; function GetHandle: THandle; stdcall; //procedure CreateEntries; virtual; public constructor CreateMenu(const ARefLifeTime: Boolean = True); constructor CreatePopupMenu(const ARefLifeTime: Boolean = True); destructor Destroy; override; end; RGMWndCreateData = packed record WndStyle: DWORD; WndExStyle: DWORD; Text: TGMString; ParentWnd: HWnd; Menu: HMENU; end; TGMWindowClass = class(TGMRefCountedObj, IGMGetName) protected FWndClass: TWndClassEx; FWndClassName: TGMString; // <- memory allocation for RegisterWndClass FMenuName: TGMString; // <- memory allocation for menuname FRegisteredClass: ATOM; public constructor Create(const AWndClassName: TGMString; const AClassStyle: DWORD = 0; const AIcon: HICON = 0; const ACursor: HCURSOR = 0; const ABkgndBrush: HBRUSH = 0; const AMenuName: TGMString = ''; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; function ClassIsRegistered: Boolean; function GetName: TGMString; stdcall; property Name: TGMString read FWndClassName; end; IGMAreaFrameDrawer = interface(IUnknown) ['{83DBF669-B36C-40a2-962A-7FB6B32ED13E}'] procedure DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); function CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale = 1): TRect; end; IGMMultiFrameProperties = interface(IUnknown) ['{5F0E1DAD-3D5D-4c00-B227-A6EF2CC75D1E}'] function GetFrameKind: TFrameKind; function GetInnerFrame: TFrameShape; function GetOuterFrame: TFrameShape; function GetFramedEdges: TEdges; function GetOuterSpace: LongInt; function GetFrameLook3D: Boolean; procedure SetFrameKind(const Value: TFrameKind); procedure SetInnerFrame(const Value: TFrameShape); procedure SetOuterFrame(const Value: TFrameShape); procedure SetFramedEdges(const Value: TEdges); procedure SetOuterSpace(const Value: LongInt); procedure SetFrameLook3D(const Value: Boolean); property FrameKind: TFrameKind read GetFrameKind write SetFrameKind; property InnerFrame: TFrameShape read GetInnerFrame write SetInnerFrame; property OuterFrame: TFrameShape read GetOuterFrame write SetOuterFrame; property FramedEdges: TEdges read GetFramedEdges write SetFramedEdges; property OuterSpace: LongInt read GetOuterSpace write SetOuterSpace; property FrameLook3D: Boolean read GetFrameLook3D write SetFrameLook3D; end; IGMUiAreaFrame = interface(IUnknown) ['{0741BF81-E0EE-497A-83B8-707DAC3D5CDB}'] function GetFrame: IGMAreaFrameDrawer; procedure SetFrame(const AFrame: IGMAreaFrameDrawer); property Frame: IGMAreaFrameDrawer read GetFrame write SetFrame; end; TGMAreaMultiFrame = class(TGMRefCountedObj, IGMAreaFrameDrawer, IGMMultiFrameProperties) protected FFrameKind: TFrameKind; FInnerFrame: TFrameShape; FOuterFrame: TFrameShape; FFramedEdges: TEdges; FOuterSpace: LongInt; FFrameLook3D: Boolean; public // IGMMultiFrameProperties function GetFrameKind: TFrameKind; virtual; function GetInnerFrame: TFrameShape; virtual; function GetOuterFrame: TFrameShape; virtual; function GetFramedEdges: TEdges; virtual; function GetOuterSpace: LongInt; virtual; function GetFrameLook3D: Boolean; virtual; procedure SetFrameKind(const Value: TFrameKind); virtual; procedure SetInnerFrame(const Value: TFrameShape); virtual; procedure SetOuterFrame(const Value: TFrameShape); virtual; procedure SetFramedEdges(const Value: TEdges); virtual; procedure SetOuterSpace(const Value: LongInt); virtual; procedure SetFrameLook3D(const Value: Boolean); virtual; public constructor Create(const AReflifeTime: Boolean = True); reintroduce; function CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale = 1): TRect; virtual; //function Extend(const AEdges: TEdges = cAllEdges): TPoint; virtual; procedure DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); virtual; function EdgeWidth: LongInt; property FrameKind: TFrameKind read GetFrameKind write SetFrameKind; property InnerFrame: TFrameShape read GetInnerFrame write SetInnerFrame; property OuterFrame: TFrameShape read GetOuterFrame write SetOuterFrame; property FramedEdges: TEdges read GetFramedEdges write SetFramedEdges; property OuterSpace: LongInt read GetOuterSpace write SetOuterSpace; property FrameLook3D: Boolean read GetFrameLook3D write SetFrameLook3D; end; TGMAreaSimpleFrame = class(TGMRefCountedObj, IGMAreaFrameDrawer) protected FEdgeWidth: LongInt; FFramedEdges: TEdges; public constructor Create(const AEdgeWidth: LongInt = 1; const AFramedEdges: TEdges = cAllEdges; const AReflifeTime: Boolean = True); reintroduce; function CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale = 1): TRect; virtual; procedure DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); virtual; end; TGMAreaFakeFrame = class(TGMAreaSimpleFrame) public procedure DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); override; end; TGMAreaRegionFrame = class(TGMRefCountedObj, IGMAreaFrameDrawer) protected FFrameWidth, FFrameHeight: LongInt; public constructor Create(const AFrameWidth, AFrameHeight: LongInt; const AReflifeTime: Boolean = True); reintroduce; procedure DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); virtual; function CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale = 1): TRect; virtual; end; IGMGetSizeConstraints = interface(IUnknown) ['{26B7B511-1E51-47c4-8347-FF98122DABFF}'] function GetSizeContraints: TGMSizeConstraintsRec; end; IGMGetSetSizeConstraints = interface(IGMGetSizeConstraints) ['{26B7B511-1E51-47c4-8347-FF98122DABFF}'] procedure SetSizeContraints(const Value: TGMSizeConstraintsRec); end; IGMSetShowing = interface(IUnknown) ['{80B5A764-D144-4e35-88C9-6F546F2ADD84}'] procedure SetShowing(const Value: Boolean); end; IGMCalcAreaRegion = interface(IUnknown) ['{270D904B-EBF4-4D81-86DA-15288A2AC421}'] function CreateAreaRegion(const ABoundingRect: TRect; const ARegionKind: TGMAreaRegionKind): IGMGetHandle; end; IGMIsDefaultDlgBtn = interface(IUNknown) ['{774C8E43-C77A-46E2-8E6A-C86B6ACE743D}'] function IsDefaultDlgBtn: Boolean; procedure Click(const ASender: TObject = nil); end; IGMLanguageChanged = interface(IUNknown) ['{7CB496F0-83A0-4884-8A44-2983403B84CC}'] procedure LanguageChanged(const ANewLanguage: LPARAM); end; //IGMPaint = interface(IUnknown) // ['310DAC2E-45CA-472d-9C91-703CAA96D19F'] // function Paint(const ADC: HDC): Boolean; // <- return False to pass WM_PAINT to chained handlers too //end; //IGMIsTabStop = interface(IUnknown) // ['{88773B33-B60A-47B5-A3A0-6187A0FC1D19}'] // function IsTabstop: Boolean; //end; IGMMessageHandler = interface(IUnknown) ['{AB3B765C-C39F-4fd1-BB1D-60546C117FE4}'] procedure WindowProc(var Msg: TMessage); procedure DispatchMsg(var Msg: TMessage); end; IGMUiLayouter = interface(IUnknown) ['{F3857A7B-4C33-4454-9F4C-E9E5C6F01170}'] procedure LayoutContainedAreasIfNeeded(const ARepaint: Boolean); //: TPoint; end; IGMSetFonColor = interface(IUnknown) ['{C30F9B85-F641-44EC-B666-8C99C38A366E}'] procedure SetFontColor(const AColor: COLORREF); end; procedure GMSetFontColor(const AUIArea: IUnknown; const AColor: COLORREF); //IGMGetVisible = interface(IUnknown) // ['{70542EB9-376A-4179-B433-8DF3231FC484}'] // function GetVisible: Boolean; // property Visible: Boolean read GetVisible; // write SetVisible; //end; type IGMSetVisible = interface(IUnknown) ['{53849ADE-29C1-405f-A928-E81AD79F344A}'] procedure SetVisible(const Value: Boolean; const Relayout: Boolean = True); end; IGMUiArea = interface(IGMUiLayouter) ['{CB4FFF8D-8BF6-4522-BA2F-48F4D7FC1AE8}'] //function GetParentObj: TObject; stdcall; //procedure SetParentObj(const Value: TObject; const Relayout: Boolean = True); stdcall; function OwnArea(const Area: TObject): TObject; function ClientAreaSize: TPoint; function ClientAreaOrigin: TPoint; function GetVisible: Boolean; function GetAreaAlign: TGMAreaAlignRec; procedure SetAreaAilgn(const AAreaAlign: TGMAreaAlignRec); function GetLayoutBounds: TRect; function GetLayoutSpace: TRect; procedure SetLayoutSpace(const Value: TRect); function RootForRelayout: TObject; procedure SetLayoutBounds(const Value: TRect; const ARepaint: Boolean); procedure LayoutContainedAreas(const ARepaint: Boolean); // : TPoint; procedure InvalidateCachedLayoutValues; procedure SetVisible(const Value: Boolean; const Relayout: Boolean = True); procedure SetShowing(const Value: Boolean); function GetAutoCalcSize(const Direction: TGM2DDirection): Boolean; procedure SetAutoCalcSize(const Direction: TGM2DDirection; const Value: Boolean); // function GetAutoCalcWidth: Boolean; function CalculateWidth(const ANewSize: TPoint): LongInt; function CalculateHeight(const ANewSize: TPoint): LongInt; function CalculateSurfaceRect(const ARect: TRect): TRect; function CreateAreaRegion(const ABoundingRect: TRect; const ARegionKind: TGMAreaRegionKind): IGMGetHandle; function PointInsideArea(const APoint: TPoint): Boolean; function AreaContainingPoint(const APoint: TPoint): TObject; function SubtractContainedAreas(const ARect: TRect; const HFillRgn: HRGN): Boolean; function PaintingRect: TRect; function IsLayoutChild: Boolean; function IsTabstop: Boolean; function ProcessHelp(var AHelpInfo: THelpInfo): Boolean; function GetEnabled: Boolean; stdcall; // <- matches IGMGetEnabled interface method signature! function PaintsComplete: Boolean; function FillsComplete: Boolean; function ParticipateInLayouting: Boolean; function IsFramed: Boolean; function GetFrame: IGMAreaFrameDrawer; procedure SetFrame(const AFrame: IGMAreaFrameDrawer); procedure ScheduleRepaint; procedure CreateHandle; function GetContainedAreas: IGMObjArrayCollection; function GetOwnedAreas: IGMObjArrayCollection; function PaintToRect(const ADC: HDC; const ARect: TRect): Boolean; property Visible: Boolean read GetVisible; // write SetVisible; property AreaAlign: TGMAreaAlignRec read GetAreaAlign write SetAreaAilgn; property LayoutBounds: TRect read GetLayoutBounds; // write SetLayoutBounds; property LayoutSpace: TRect read GetLayoutSpace write SetLayoutSpace; function GetEdgeAlign(const Edge: TEdge): TEdgeAlign; procedure SetEdgeAlign(const Edge: TEdge; const Value: TEdgeAlign); function GetEdgePosition(const Edge: TEdge): LongInt; procedure SetEdgePosition(const Edge: TEdge; const Value: LongInt); function GetEdgeSpace(const Edge: TEdge): LongInt; procedure SetEdgeSpace(const Edge: TEdge; const Value: LongInt); property ContainedAreas: IGMObjArrayCollection read GetContainedAreas; // <- for painting and layouting property OwnedAreas: IGMObjArrayCollection read GetOwnedAreas; // <- for liftetime control property AutoCalcSize[const Direction: TGM2DDirection]: Boolean read GetAutoCalcSize write SetAutoCalcSize; property EdgeAlign[const Edge: TEdge]: TEdgeAlign read GetEdgeAlign write SetEdgeAlign; property EdgePosition[const Edge: TEdge]: LongInt read GetEdgePosition write SetEdgePosition; property EdgeSpace[const Edge: TEdge]: LongInt read GetEdgeSpace write SetEdgeSpace; property Frame: IGMAreaFrameDrawer read GetFrame write SetFrame; end; {TGMAreaLayouter = class(TGMRefCountedObj, IGMUiLayouter) protected FOwner: TObject; FChildList: TGMObjArrayCollection; public constructor Create(const AOwner: TObject; const AReflifeTime: Boolean = False); reintroduce; destructor Destroy; override; procedure LayoutContainedAreasIfNeeded(const ARepaint: Boolean); virtual; abstract; function SubtractContainedAreas(const HFillRgn: HRGN): Boolean; virtual; procedure PaintContainedAreas(const ADC: HDC); virtual; function AreaContainingPoint(const APoint: TPoint): TObject; virtual; //property Owner: TObject read FOwner; property ContainedAreas: TGMObjArrayCollection read FChildList; end; //TGMAreaLayouterClass = class of TGMAreaLayouter; TGMStandardLayouter = class(TGMAreaLayouter) protected function AdjustRestRect(const AreaAlign: TGMAreaAlignRec; const RCtl, RRest: TRect): TRect; function AdjustCalcSize(const Area: IGMUiArea; const RCtl: TRect): TRect; public procedure LayoutContainedAreasIfNeeded(const ARepaint: Boolean); override; end;} IGMAreaFiller = interface(IUnknown) ['{1EF3144A-CA8D-4208-8485-68097371384C}'] procedure Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); end; TGMAreaRegionFiller = class(TGMRefCountedObj, IGMAreaFiller) public procedure Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); end; TGMAreaRectFiller = class(TGMRefCountedObj, IGMAreaFiller) public procedure Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); end; TColorArray = array of COLORREF; TGMGlassLookFiller = class(TGMRefCountedObj, IGMAreaFiller) protected FColors: TColorArray; public constructor Create(const AColors: array of COLORREF; {const ARounded: Boolean = False;} const ARefLifeTime: Boolean = True); reintroduce; procedure Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); virtual; property Colors: TColorArray read FColors; end; TGMSimpleGlassLookFiller = class(TGMRefCountedObj, IGMAreaFiller) protected // FColor: COLORREF; public // constructor Create(const AColor: COLORREF; {const ARounded: Boolean = False;} const ARefLifeTime: Boolean = True); reintroduce; constructor Create(const ARefLifeTime: Boolean = True); override; procedure Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); virtual; end; TGMAreaGradientFiller = class(TGMGlassLookFiller, IGMAreaFiller) protected FDirection: TGM2DDirection; public constructor Create(const ADirection: TGM2DDirection; const AColors: array of COLORREF; const ARefLifeTime: Boolean = True); reintroduce; procedure Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); override; end; TGMGetColorFunc = function: COLORREF of object; stdcall; TGMGetHandleFunc = function: THandle of object; // A windowed area maintains a OS window handle. See: TGMWindow // A windowless area is just an logical area inside the parent area. TGMUiAreaBase = class(TGMRefCountedObj, IGMUiArea, IGMMessageHandler, IGMBkgndColor, IGMGetParentObj, IGMGetSetParentObj, IGMCalcAreaRegion, IGMGetSetBkgndColor, IGMUiAreaFrame, IGMUiLayouter, IGMSetShowing, // IGMPaint, IGMGetSizeConstraints, IGMGetSetSizeConstraints, IGMSetVisible, IGMGetEnabled, // IGMSetVisible, // IGMIsTabStop, IGMExecuteOperation, IGMClear) protected FParent: TObject; FLayoutBounds: TRect; FLayoutSpace: TRect; FAreaAlign: TGMAreaAlignRec; FFrame: IGMAreaFrameDrawer; FBkgndColor: COLORREF; FBkgndBrush: IGMGetHandle; //FAreaFiller: IGMAreaFiller; FVisible: Boolean; FSizeConstraints: TGMSizeConstraintsRec; FLastLayoutOrigin: TPoint; FLastLayoutSize: TPoint; FAutoCalcSize: array [TGM2DDirection] of Boolean; FOwnedAreas: IGMObjArrayCollection; FContainedAreas: IGMObjArrayCollection; //FCachedCalcWidth: TPoint; //FCachedCalcHeight: TPoint; procedure WMMouseMove(var Msg: TWMMouseMove); message WM_MOUSEMOVE; procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN; procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; procedure UMDragQueryDrop(var Msg: TMessage); message UM_DRAG_QUERYDROP; function GetVisible: Boolean; virtual; procedure InternalSetVisible(const Value: Boolean{; const Relayout: Boolean}); virtual; function InternalPaintToRect(const ADC: HDC; const ADestRect: TRect): Boolean; virtual; public function InternalCalcWidth(const ANewSize: TPoint): LongInt; virtual; function InternalCalcHeight(const ANewSize: TPoint): LongInt; virtual; public // Interfaces //function GetBkgndColor: COLORREF; virtual; stdcall; procedure Clear(const ANotify: Boolean = True); virtual; procedure SetBkgndColor(const AValue: COLORREF; const ARepaint: Boolean = True); virtual; stdcall; //nction QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} IID: TGUID; out Intf): HResult; override; function GetParentObj: TObject; virtual; function GetAreaAlign: TGMAreaAlignRec; virtual; procedure SetAreaAilgn(const AAreaAlign: TGMAreaAlignRec); function GetLayoutBounds: TRect; virtual; procedure SetLayoutBounds(const AValue: TRect; const ARepaint: Boolean); virtual; procedure LayoutContainedAreas(const ARepaint: Boolean); virtual; //: TPoint; virtual; procedure LayoutContainedAreasIfNeeded(const ARepaint: Boolean); virtual; //: TPoint; virtual; function CalculateWidth(const ANewSize: TPoint): LongInt; virtual; function CalculateHeight(const ANewSize: TPoint): LongInt; virtual; function PointInsideArea(const APoint: TPoint): Boolean; virtual; function AreaContainingPoint(const APoint: TPoint): TObject; virtual; //function ChildAreaContainingPoint(const APoint: TPoint): TObject; function GetLayoutSpace: TRect; virtual; procedure SetLayoutSpace(const AValue: TRect); function GetContainedAreas: IGMObjArrayCollection; function GetOwnedAreas: IGMObjArrayCollection; procedure SetShowing(const Value: Boolean); virtual; function GetSizeContraints: TGMSizeConstraintsRec; virtual; procedure SetSizeContraints(const AValue: TGMSizeConstraintsRec); function GetEdgeAlign(const Edge: TEdge): TEdgeAlign; virtual; procedure SetEdgeAlign(const Edge: TEdge; const Value: TEdgeAlign); function GetEdgePosition(const AEdge: TEdge): LongInt; virtual; procedure SetEdgePosition(const AEdge: TEdge; const AValue: LongInt); virtual; function GetEdgeSpace(const AEdge: TEdge): LongInt; virtual; procedure SetEdgeSpace(const AEdge: TEdge; const AValue: LongInt); virtual; function ExecuteOperation(const Operation: LongInt; const Parameter: IUnknown = nil): Boolean; virtual; stdcall; function GetFrame: IGMAreaFrameDrawer; virtual; procedure SetFrame(const AFrame: IGMAreaFrameDrawer); virtual; function GetEnabled: Boolean; virtual; stdcall; // function GetAutoCalcHeight: Boolean; // function GetAutoCalcWidth: Boolean; function ProcessHelp(var AHelpInfo: THelpInfo): Boolean; virtual; function GetAutoCalcSize(const ADirection: TGM2DDirection): Boolean; procedure SetAutoCalcSize(const ADirection: TGM2DDirection; const AValue: Boolean); public ScrollOffset: TPoint; CornerRounding: TPoint; BufferedPainting: Boolean; ClippedPainting: Boolean; OnGetHBkgndBrush: TGMGetHandleFunc; OnGetFontColor: TGMGetColorFunc; OnGetBkgndColor: TGMGetColorFunc; constructor Create(const ARefLifeTime: Boolean = False); overload; override; constructor Create(const AParent: TObject; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ABkgndColor: COLORREF = cDfltColor; const AVisible: Boolean = True; const ARefLifeTime: Boolean = False); reintroduce; overload; virtual; destructor Destroy; override; procedure CreateHandle; virtual; function OwnArea(const AArea: TObject): TObject; function ClientAreaOrigin: TPoint; virtual; function ClientAreaSize: TPoint; virtual; function CalculateSurfaceRect(const ARect: TRect): TRect; virtual; function PaintingRect: TRect; virtual; function IsFramed: Boolean; virtual; function IsLayoutChild: Boolean; virtual; function ParticipateInLayouting: Boolean; virtual; //function ClippedPainting: Boolean; virtual; function PaintsComplete: Boolean; virtual; function FillsComplete: Boolean; virtual; procedure InvalidateCachedLayoutValues; virtual; function Paint(const ADC: HDC): Boolean; virtual; // <- return False to pass WM_PAINT to chained handlers too function PaintToRect(const ADC: HDC; const ADestRect: TRect): Boolean; virtual; procedure PaintBackground(const ADC: HDC; const AClientRect: TRect; const ARegion: IGMGetHandle); virtual; function PaintArea(const ADC: HDC; const ARect: TRect): Boolean; virtual; procedure PaintContainedAreas(const ADC: HDC; const AClientRect: TRect); virtual; function SubtractContainedAreas(const ARect: TRect; const AResultRegion: HRGN): Boolean; virtual; procedure SetVisible(const AValue: Boolean; const ARelayout: Boolean = True); virtual; procedure SetParentObj(const AValue: TObject; const ARelayout: Boolean = True); virtual; procedure ScheduleRepaint; virtual; function RootForRelayout: TObject; virtual; function MouseInside: Boolean; virtual; function HasFocus: Boolean; virtual; function IsPopupWindow: Boolean; virtual; function IsDialogKeyMsg(const Msg: TMessage): Boolean; virtual; procedure DispatchMsg(var Msg: TMessage); virtual; procedure WindowProc(var Msg: TMessage); virtual; function BkgndColor: COLORREF; virtual; stdcall; function HBkgndBrush: THandle; virtual; function FontHandle: THandle; virtual; function FontColor: COLORREF; virtual; stdcall; function FontBkgndColor: COLORREF; virtual; function CreateAreaRegion(const ABoundingRect: TRect; const ARegionKind: TGMAreaRegionKind): IGMGetHandle; virtual; function AreaFiller: IGMAreaFiller; virtual; function FrameColor: COLORREF; virtual; function IsTabStop: Boolean; virtual; procedure AssignCtrlColorValues(var Msg: TMessage); virtual; procedure SurfaceOriginChanged; virtual; procedure AfterParentChanged; virtual; property LayoutBounds: TRect read GetLayoutBounds; // write SetLayoutBounds; //property LayoutSpace: TRect read FLayoutSpace write FLayoutSpace; property Parent: TObject read GetParentObj; //property BkgndColor: COLORREF read GetBkgndColor; // write SetBkgndColor; property Visible: Boolean read GetVisible; // write SetVisible; //property AreaFiller: IGMAreaFiller read FAreaFiller write FAreaFiller; property OwnedAreas: IGMObjArrayCollection read FOwnedAreas; property ContainedAreas: IGMObjArrayCollection read FContainedAreas; property Left: LongInt index edgLeft read GetEdgePosition write SetEdgePosition; property Top: LongInt index edgTop read GetEdgePosition write SetEdgePosition; property Right: LongInt index edgRight read GetEdgePosition write SetEdgePosition; property Bottom: LongInt index edgBottom read GetEdgePosition write SetEdgePosition; property EdgeAlign[const Edge: TEdge]: TEdgeAlign read GetEdgeAlign write SetEdgeAlign; property EdgePosition[const Edge: TEdge]: LongInt read GetEdgePosition write SetEdgePosition; property Frame: IGMAreaFrameDrawer read GetFrame write SetFrame; property AutoCalcSize[const Direction: TGM2DDirection]: Boolean read GetAutoCalcSize write SetAutoCalcSize; end; TGMUiArea = class(TGMUiAreaBase) // // Invalidates it's area and paints background if not completely covered by child areas. // protected //FDispatchToParentMessages: IGMIntfCollection; FDispatchToParentMessages: IGMGenericCollection<TGMWndMsg>; procedure InternalSetVisible(const Value: Boolean{; const Relayout: Boolean}); override; public //DispatchToParentMessages: TGMPtrIntArray; constructor Create(const ARefLifeTime: Boolean = False); override; overload; procedure SetShowing(const Value: Boolean); override; procedure DispatchMsg(var AMsg: TMessage); override; //function Paint(const ADC: HDC): Boolean; override; //function PaintClientArea(const ADC: HDC; var RClient: TRect): Boolean; virtual; procedure SetLayoutBounds(const AValue: TRect; const ARepaint: Boolean); override; property DispatchToParentMessages: IGMGenericCollection<TGMWndMsg> read FDispatchToParentMessages; end; TGMLayoutAreaClass = class of TGMUiArea; TGMForeignWndContainer = class(TGMUiArea) // // A layout area containing another window by only knowing its handle. // -> TGMForeignWinCtrlImpl is designed to be such a window. // protected FForeignWnd: HWnd; function InternalCreateForeignWnd: HWnd; virtual; abstract; procedure CreateForeignWnd; virtual; procedure InternalSetVisible(const Value: Boolean{; const Relayout: Boolean}); override; public constructor Create(const AParent: TObject; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AForeignWnd: HWnd; const ABkgndColor: COLORREF = cDfltColor; const AVisible: Boolean = True; const ARefLifeTime: Boolean = False); reintroduce; overload; procedure SetLayoutBounds(const Value: TRect; const ARepaint: Boolean); override; function InternalCalcWidth(const ANewSize: TPoint): LongInt; override; function InternalCalcHeight(const ANewSize: TPoint): LongInt; override; function PaintsComplete: Boolean; override; end; TGMSurroundingUiArea = class(TGMUiArea) // // Calculates size to contain all childs (recursive) + PaddSpace. // protected FPaddSpace: TPoint; public constructor Create(const AParent: TObject; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const APaddSpace: TPoint; const ABkgndColor: COLORREF = cDfltColor; const AVisible: Boolean = True; const ARefLifeTime: Boolean = False); reintroduce; overload; virtual; function InternalCalcWidth(const ANewSize: TPoint): LongInt; override; function InternalCalcHeight(const ANewSize: TPoint): LongInt; override; function RootForRelayout: TObject; override; end; //TGMWndPaintDisableImpl = class(TGMRefCountedObj, IGMEnableDisablePaint) // protected // FOwner: TObject; // FPaintDisableCount: LongInt; // // procedure SendEnableMsg(const AEnable: Boolean); // // public // // IUnknown // function QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} IID: TGUID; out Intf): HResult; override; // function _AddRef: LongInt; override; // function _Release: LongInt; override; // // public // constructor Create(const AOwner: TObject; const ARefLifeTime: Boolean = False); // function EnablePaint: LongInt; stdcall; // function DisablePaint: LongInt; stdcall; // function GetPaintDisabledCount: LongInt; stdcall; //end; TGMWindow = class(TGMUiAreaBase, IGMGetHandle, IGMHandleAllocated, IGMGetText, IGMGetSetText, IGMGetSetEnabled, IGMLanguageChanged) // // Maintains a window handle // protected //FPaintDisabler: TGMWndPaintDisableImpl; FTextResData: RGMResTextRefData; FCreateData: RGMWndCreateData; FHandle: HWnd; FOrgWndProc: Pointer; FOrgWndPtrData: PtrInt; FPassMessageToOriginalHandler: Boolean; FIsMouseTracking: Boolean; FRelayedMessages: TRelayedMessages; function GetWndStyle: DWORD; function GetWndExStyle: DWORD; procedure SetParentWnd(const AWnd: HWnd); procedure SetWndStyle(const AValue: DWORD); procedure SetWndExStyle(const AValue: DWORD); procedure SetText(const AValue: TGMString); virtual; stdcall; procedure InternalSetVisible(const AValue: Boolean{; const Relayout: Boolean}); override; procedure InternalCreateHandle; virtual; procedure CreateParentHandle; virtual; //function GetVisible: Boolean; override; public // Window message handlers procedure WMHelp(var Msg: TWMHelp); message WM_HELP; procedure WMSize(var Msg: TWMSize); message WM_SIZE; procedure WMPaint(var Msg: TWMPaint); message WM_PAINT; procedure WMMove(var Msg: TWMMove); message WM_MOVE; procedure WMMouseLeave(var Msg: TMessage); message WM_MOUSELEAVE; procedure UMStartMouseTrack(var Msg: TMessage); message UM_STARTMOUSETRACK; procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; //procedure WMPrint(var Msg: TMessage); message WM_PRINT; procedure WMPrintClient(var Msg: TMessage); message WM_PRINTCLIENT; procedure WMNCDestroy(var Msg: TWMNCDestroy); message WM_NCDESTROY; procedure WMNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE; procedure WMNCPaint(var Msg: TMessage); message WM_NCPAINT; procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO; procedure WMSetCursor(var Msg: TMessage); message WM_SETCURSOR; procedure WMCommand(var Msg: TMessage); message WM_COMMAND; procedure WMNotify(var Msg: TMessage); message WM_NOTIFY; procedure WMDrawItem(var Msg: TMessage); message WM_DRAWITEM; procedure WMVScroll(var Msg: TMessage); message WM_VSCROLL; procedure WMHScroll(var Msg: TMessage); message WM_HSCROLL; procedure WMSetFocus(var Msg: TMessage); message WM_SETFOCUS; procedure WMKillFocus(var Msg: TMessage); message WM_KILLFOCUS; public constructor Create(const ARefLifeTime: Boolean = False); override; constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AWndStyle: DWORD = cDfltWndStyle; const AWndExStyle: DWORD = cDfltWndExStyle; const AText: TGMString = cDfltWndText; const AMenu: HMENU = cDfltWndMenu; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); reintroduce; overload; virtual; destructor Destroy; override; procedure CreateHandle; override; procedure DestroyHandle(const ARememberState: Boolean); virtual; procedure DispatchMsg(var Msg: TMessage); override; procedure WindowProc(var Msg: TMessage); override; function HasWindowRegion: Boolean; virtual; function IsLayoutChild: Boolean; override; function IsTabStop: Boolean; override; function WndCreateRect: TRect; virtual; function ClientAreaOrigin: TPoint; override; function ClientAreaSize: TPoint; override; function PaintingRect: TRect; override; function RegisterWndClass: TGMString; virtual; function WndClassRegName: TGMString; virtual; function CursorHandle: HCURSOR; virtual; procedure LanguageChanged(const ANewLanguage: LPARAM); virtual; //function TempCursor: HCURSOR; virtual; function WndSizeFromClientSize(const AClientSize: TPoint): TPoint; virtual; //function Paint(const ADC: HDC): Boolean; override; procedure ScheduleRepaint; override; function GetHandle: THandle; stdcall; procedure SetLayoutBounds(const ALayoutBounds: TRect; const ARepaint: Boolean); override; function GetHandleAllocated: Boolean; stdcall; function GetEnabled: Boolean; override; procedure SetEnabled(const AValue: Boolean); stdcall; procedure SetShowing(const AValue: Boolean); override; //procedure SetParentObj(const Value: TObject; const Relayout: Boolean = True); override; procedure AfterParentChanged; override; function GetText: TGMString; virtual; stdcall; function ExecuteOperation(const Operation: LongInt; const Parameter: IUnknown): Boolean; override; function GetFrame: IGMAreaFrameDrawer; override; property Handle: THandle read GetHandle; //property PaintDisabler: TGMWndPaintDisableImpl read FPaintDisabler implements IGMEnableDisablePaint; property RelayedMessages: TRelayedMessages read FRelayedMessages; property WndStyle: DWORD read GetWndStyle write SetWndStyle; // FCreateData.WndStyle property WndExStyle: DWORD read GetWndExStyle write SetWndExStyle; // FCreateData.WndExStyle property ParentWnd: HWnd read FCreateData.ParentWnd write SetParentWnd; property HandleAllocated: Boolean read GetHandleAllocated; property Text: TGMString read GetText write SetText; end; TGMWinControl = class(TGMWindow) // // Always a child window, often a user input control // protected // FFocusNextControl: Boolean; procedure WMCancelMode(var Msg: TWMCancelMode); message WM_CANCELMODE; //procedure WMMouseActivate(var Msg: TWMMouseActivate); message WM_MOUSEACTIVATE; procedure WMKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; //procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN; // procedure WMEnable(var Msg: TWMEnable); message WM_ENABLE; procedure CreateParentHandle; override; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cDfltWndStyle; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); reintroduce; overload; virtual; function IsPopupWindow: Boolean; override; procedure SurfaceOriginChanged; override; //function IsDialogKeyMsg(const Msg: TMessage): Boolean; override; function ClosePopupState(const RestoreActiveCtrl: Boolean = False): Boolean; virtual; end; TGMWinControlClass = class of TGMWinControl; TGMOEMControl = class(TGMWinControl) // // Designed to have no contained areas, best base for existing controls of the OS // protected procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN; //procedure WMMouseActivate(var Msg: TWMMouseActivate); message WM_MOUSEACTIVATE; procedure WMPaint(var Msg: TWMPaint); message WM_PAINT; //procedure WMPrint(var Msg: TMessage); message WM_PRINT; procedure WMPrintClient(var Msg: TMessage); message WM_PRINTCLIENT; procedure WMMouseLeave(var Msg: TMessage); message WM_MOUSELEAVE; procedure UMStartMouseTrack(var Msg: TMessage); message UM_STARTMOUSETRACK; procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMNCPaint(var Msg: TMessage); message WM_NCPAINT; procedure WMNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE; public procedure WindowProc(var Msg: TMessage); override; end; TGMNCWinControl = class(TGMOEMControl) // // Some standard windows controls dont paint their frames into // WM_PRINT DC's. This class provides a simple work around. // protected procedure UMHandleCreated(var Msg: TMessage); message UM_HANDLECREATED; procedure FinalizeShow; virtual; end; //TGMPopupControl = class(TGMWindow) // protected // //end; TGMForeignWinCtrlImpl = class(TGMWinControl) // // A window that can participate layouting by only exposing a window handle. // -> TGMForeignWndContainer is designed to communicate with such windows. // protected procedure UMCalcWidth(var Msg: TMessage); message UM_CALCWIDTH; procedure UMCalcHeight(var Msg: TMessage); message UM_CALCHEIGHT; //public //function CalculateWidth(const ANewSize: TPoint): LongInt; override; //function CalculateHeight(const ANewSize: TPoint): LongInt; override; end; TGMDlgWindow = class(TGMWindow) protected //FParentWasEnabled: Boolean; FDlgData: Pointer; //FTempCursor: HCursor; //FModalDisabledWindows: TGMPtrIntArray; //FIsModalDialog: Boolean; //procedure WMDestroy(var Msg: TMessage); message WM_DESTROY; //procedure UMClose(var Msg: TMessage); message UM_CLOSE; // <- Introduce one level of indirection, to be able to override WM_CLOSE behavior procedure WMClose(var Msg: TMessage); message WM_CLOSE; procedure WMKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; procedure WMSysKeyDown(var Msg: TWMSysKeyDown); message WM_SYSKEYDOWN; //procedure WMSysKeyUp(var Msg: TMessage); message WM_SYSKEYUP; //procedure WMChar(var Msg: TMessage); message WM_CHAR; //procedure WMPrintClient(var Msg: TMessage); message WM_PRINTCLIENT; //procedure WMPrint(var Msg: TMessage); message WM_PRINT; //procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; procedure WMActivate(var Msg: TWMActivate); message WM_ACTIVATE; //procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCACTIVATE; //procedure UMSetTempCursor(var Msg: TMessage); message UM_SETTEMPCURSOR; procedure UMSelectNextDlgTabArea(var Msg: TMessage); message UM_SELECTNEXTDLGTABAREA; procedure UMLanguageChanged(var Msg: TMessage); message UM_LANGUAGECHANGED; //procedure ReEnableOtherWindows; //procedure InternalCreateHandle; override; // procedure CreateParentHandle; override; public ActiveControl: TObject; constructor Create(const APosition: TRect; const AWndStyle: DWORD = cSizeDlgWndStyle; const AWndExStyle: DWORD = cPrntWndExStyle; const ATitle: TGMString = cDfltWndText; const AParent: TGMWndObj = cDfltPrntWnd; const ADlgData: Pointer = cDfltDlgData; const AMenu: HMENU = cDfltWndMenu; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); reintroduce; overload; virtual; procedure CreateHandle; override; function IsModalDialog: Boolean; virtual; function IsDialogKeyMsg(const Msg: TMessage): Boolean; override; function CloseOnEscape: Boolean; virtual; procedure SetBkgndColor(const Value: COLORREF; const ARepaint: Boolean = True); override; function RegisterWndClass: TGMString; override; procedure InitControls; virtual; procedure SetupControls; virtual; function CanClose(const ASetData: Boolean): Boolean; virtual; procedure DoneDialog(const ASetData: Boolean); virtual; procedure GetDlgData; virtual; //procedure SetDlgData; virtual; property DlgData: Pointer read FDlgData; //property TempCursor: HCursor read FTempCursor write FTempCursor; //function TempCursor: HCURSOR; override; end; TGMDlgWindowClass = class of TGMDlgWindow; TGMStackedDlgWindow = class(TGMDlgWindow) // // The Handle will be pushed on the window stack, and popped when closed // protected procedure WMNCDestroy(var Msg: TWMNCDestroy); message WM_NCDESTROY; procedure InternalCreateHandle; override; end; TGMMainWindow = class(TGMStackedDlgWindow) // // Adds ExStyle WS_EX_APPWINDOW => will be shown on the task bar // Calls PostQuitMessage when cosed // protected procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION; procedure WMNCDestroy(var Msg: TWMNCDestroy); message WM_NCDESTROY; public constructor Create(const APosition: TRect; const AWndStyle: DWORD = cSizeDlgWndStyle; const AWndExStyle: DWORD = cPrntWndExStyle; const ATitle: TGMString = cDfltWndText; const AParent: TGMWndObj = cDfltPrntWnd; const ADlgData: Pointer = cDfltDlgData; const AMenu: HMENU = cDfltWndMenu; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); override; function CanClose(const ASetData: Boolean): Boolean; override; end; {TGMMainWindow = class(TGMMainWindow); protected procedure WMNCDestroy(var Msg: TWMNCDestroy); message WM_NCDESTROY; procedure InternalCreateHandle; override; end;} {TGMMsgHookWindow = class(TGMWindow) protected FHookWnd: HWnd; public constructor Create(const AHookWnd: HWnd; const AParent: TGMWndObj = 0; const ARefLifeTime: Boolean = False); //reintroduce; overload; property HookWnd: HWnd read FHookWnd write FHookWnd; end;} TGMWindowDisabler = class(TGMRefCountedObj) // // Temporary disable user input to a window. // Stable against cascaded usage. // protected FWnd: HWnd; FWasEnabled: Boolean; public constructor Create(const AWnd: HWnd; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; TGMDragPainter = class(TGMRefCountedObj, IGMMessageHandler, IGMGetParentObj) protected FParent: TObject; FDragData: IUnknown; FDragLastWndOver: HWnd; FOldKeyboardFocusArea: TObject; procedure WMKeyDown(var Msg: TWMKey); message WM_KEYDOWN; procedure WMKeyUp(var Msg: TWMKey); message WM_KEYUP; procedure WMMouseMove(var Msg: TWMMouseMove); message WM_MOUSEMOVE; procedure WMLButtonUp(var Msg: TWMLButtonUp); message WM_LBUTTONUP; procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; procedure WMCancelMode(var Msg: TWMCancelMode); message WM_CANCELMODE; procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL; procedure DragToScreenPos(const AScreenPos: TPoint); virtual; abstract; function FindWindowFromScreenPoint(const AScreenPos: TPoint): HWnd; virtual; procedure ExitDragState; virtual; public constructor Create(const AParent: TObject; //const ADragOffs: TPoint; const ADragData: IUnknown; const ARefLifeTime: Boolean = True); reintroduce; overload; function GetParentObj: TObject; virtual; procedure WindowProc(var Msg: TMessage); virtual; procedure DispatchMsg(var Msg: TMessage); virtual; procedure CancelDrag; virtual; // (const ScreenPos: TPoint); function DragAndQueryDropTarget(AScreenPos: TPoint): Boolean; virtual; property DragData: IUnknown read FDragData; property Parent: TObject read FParent; end; TGMDragWindow = class(TGMWindow) protected FBitmap, FBmpDC: IGMGetHandle; FImageSize: TPoint; //procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ABitmap: IGMGetHandle; const AWndStyle: DWORD = cDfltWndStyle; const AWndExStyle: DWORD = cDfltWndExStyle; // const AText: TGMString = cDfltWndText; const AMenu: HMENU = cDfltWndMenu; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = True); reintroduce; overload; function PaintToRect(const ADC: HDC; const ARect: TRect): Boolean; override; end; TGMTransparentDragPainter = class(TGMDragPainter) protected FDragWindow: IGMGetHandle; FDragOffs: TPoint; procedure DragToScreenPos(const AScreenPos: TPoint); override; procedure ExitDragState; override; public constructor Create(const AParent: TObject; const ABitmap: IGMGetHandle; const ATransparentColor: COLORREF; const ADragOffs: TPoint; const ADragData: IUnknown = nil; const ARefLifeTime: Boolean = True); reintroduce; overload; end; TGMTimerWnd = class(TGMWindow) protected FOwner: TObject; procedure WMTimer(var Msg: TMessage); message WM_TIMER; public constructor Create(const AOwner: TObject; const ARefLifeTime: Boolean = True); end; TGMWndTimerWithHandle = class(TGMWndTimer) protected FOnTimerProc: TGMObjNotifyProc; FWindow: IGMGetHandle; public Caller: TObject; constructor Create(const AOnTimerProc: TGMObjNotifyProc = nil; const ACaller: TObject = nil; const AMilliSeconds: LongInt = cDfltTimerInterval; const AAutoStart: Boolean = False; const ARefLifeTime: Boolean = True); reintroduce; overload; virtual; function GetHandle: THandle; override; end; TGMHideDragPainter = class(TGMRefCountedObj) protected FDragPainter: IGMSetVisible; public constructor Create(const ADragPainter: IUnknown; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; TGMWndPaintDisabler = class(TGMRefCountedObj) // // Temporary disable window painting. // NOT stable against cascaded usage. // protected FWnd: HWnd; public constructor Create(const AWnd: HWnd; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; //TGMWndTempCursor = class(TGMRefCountedObj) // protected // FDlgWnd: HWnd; // FOldCursor: HCursor; // // public // constructor Create(const ATempCursor: TGMCursor; AWnd: HWnd = 0; const ARefLifeTime: Boolean = True); reintroduce; // destructor Destroy; override; //end; {TGMAppTempCursor = class(TGMRefCountedObj) protected FOldCursor: HCursor; public constructor Create(const ATempCursor: TGMCursor; const ARefLifeTime: Boolean = True); destructor Destroy; override; end;} // Borlands definition of TriVertex is wrong .. {$IFNDEF JEDIAPI} PGMTriVertexRec = ^TGMTriVertexRec; TGMTriVertexRec = packed record X, Y: LongInt; Red, Green, Blue, Alpha: Word; end; {$ENDIF} TGMObjVisitFunc = function (const AObj: TObject; const AData: Pointer): Boolean; function GMWindowClassList: IGMIntfArrayCollection; function GMRegisterWindowClass(const AWndClassName: TGMString; const ACursor: HCURSOR = 0; const AClassStyle: DWORD = 0; const AIcon: HICON = 0; const ABkgndBrush: HBRUSH = 0; const AMenuName: TGMString = ''): IGMGetName; function GMOwnArea(const Owner, Area: TObject): TObject; function GMMessageRec(const Msg: UINT; const wParam: WPARAM = 0; const lParam: LPARAM = 0; const lResult: LRESULT = 0): TMessage; function GMTriVertex(const Pt: TPoint; Red: Word = 0; Green: Word = 0; Blue: Word = 0; Alpha: Word = 0): {$IFNDEF JEDIAPI}TGMTriVertexRec{$ELSE}TTriVertex{$ENDIF}; function GMRectCenterX(const RInner, ROuter: TRect): TRect; function GMRectCenterY(const RInner, ROuter: TRect): TRect; function GMLimitRectToScreen(const ARect: TRect; const Edges: TEdges = CAllEdges): TRect; function GMAreaRect(Left: LongInt = CInvalidUIPos; Top: LongInt = CInvalidUIPos; Width: LongInt = CInvalidUIPos; Height: LongInt = CInvalidUIPos): TRect; function GMDesktopClientRect: TRect; function GMCenteredWndRect(const WndSize: TPoint; const Parent: TGMWndObj = cDfltPrntWnd): TRect; function GMAreaAlign(const Left, Top, Right, Bottom: TEdgeAlign; const ShrinkRestX: Boolean = False; const ShrinkRestY: Boolean = False): TGMAreaAlignRec; function GMSplitDirectionFromAlign(const AAlign: TEdgesAlign; const ASpace: TRect): TGM2DDirection; function GMAreaRegionFiller: IGMAreaFiller; function GMAreaRectFiller: IGMAreaFiller; function GMLoadRect(const Source: IGMValueStorage; const DirPath, RectName: TGMString; const DefaultRect: TRect): TRect; procedure GMStoreRect(const Dest: IGMValueStorage; const DirPath, RectName: TGMString; const Value: TRect); function GMLoadDlgRect(const ASource: IGMValueStorage; const ALoadPath, ARectName: TGMString; const ADlgSize: TPoint; const AParent: TGMWndObj): TRect; overload; function GMLoadDlgRect(const ASource: IGMValueStorage; const ALoadPath, ARectName: TGMString; const ADlgRect: TRect): TRect; overload; function GMResTextRefDataRec(const AResStringPtr: PResStringRec; const AFormatStr: TGMString = ''): RGMResTextRefData; function GMMakeResRefText(const AResStringRecPtr: Pointer; const AFormatString: TGMString = ''): TGMString; function GMResolveTextResData(const AText: TGMString; var ATextResData: RGMResTextRefData): TGMString; function GMBuildTextFromResRef(const ATextResData: RGMResTextRefData; const AText: TGMString): TGMString; function GMNextCtrlID: PtrInt; function GMObjFromWnd(const AHWnd: HWnd): TObject; function GMHWndFromWndObj(const AWndObj: TGMWndObj): HWnd; function GMObjFromWndObj(const WndObj: TGMWndObj): TObject; function GMDlgParentWndFromObj(const AObj: TObject): HWnd; function GMStdWndProc(AWnd: HWND; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; function GMStdIWndProc(Wnd: HWND; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; //procedure GMHideAndShowWnd(const WndObj: TGMWndObj); //procedure GMRepaintArea(const Area: TObject); procedure GMPaintWndFrame(const AWndObj: TGMWndObj); function GMAnimateWindow(Wnd: HWND; dwTime: DWORD; dwFlags: DWORD): BOOL; procedure GMShowWindowAnimated(const AWnd: HWnd; const AShowKind: TGMShowWndKind = swShowNormal); //function GMWndAnimationData: TGMWndAnimationData; procedure GMExecPendingPainting(const AArea: TObject); procedure GMCloseAllThreadWindows(const ACallingWnd: HWnd); procedure GMLoadNewLanguageToUI(const ANewLanguage: LangId); procedure GMCallObjWindowProc(const AObj: TObject; var AMsg: TMessage); overload; function GMCallObjWindowProc(const AObj: TObject; const AMsg: UINT; const wParam: WPARAM = 0; const lParam: LPARAM = 0): LRESULT; overload; procedure GMCallIntfWindowProc(const Intf: IUnknown; var Msg: TMessage); overload; function GMCallIntfWindowProc(const Intf: IUnknown; const Msg: UINT; const wParam: WPARAM = 0; const lParam: LPARAM = 0): LRESULT; overload; procedure GMDispatchObjMsg(const AObj: TObject; var AMsg: TMessage); //function GMDispatchObjMsg(const Obj: TObject; const Msg: UINT; const wParam: WPARAM = 0; const lParam: LPARAM = 0): LongInt; //function GMPostIntfMessage(Intf: IUnknown; AMsg: UINT; wParam: WPARAM = 0; lParam: LPARAM = 0): Boolean; procedure GMPostSeletNextDlgTabAreaMsg(const AArea: TObject); procedure GMEnableWindow(const AObj: TObject; const Enable: Boolean); function GMPostObjMessage(const AObj: TObject; AMsg: UINT; wParam: WPARAM = 0; lParam: LPARAM = 0): Boolean; function GMPostIntfMessage(const AIntf: IUnknown; AMsg: UINT; wParam: WPARAM = 0; lParam: LPARAM = 0): Boolean; function GMSendObjMessage(const AObj: TObject; AMsg: UINT; wParam: WPARAM = 0; lParam: LPARAM = 0): LRESULT; procedure GMAddDispatchToParentMessages(const AArea: TObject; const AMessages: array of TGMWndMsg); procedure GMSetObjVisible(const AObj: TObject; const AVisible, ARelayout: Boolean); function GMFindParentDlg(const AArea: TObject; var ADlg: TObject): Boolean; function GMFindWindowedParent(AArea: TObject): IGMGetHandle; function GMFindAllocatedParentHandle(const AArea: TObject; var AHandle: HWnd): Boolean; function GMParentHandleAllocated(const AArea: TObject): Boolean; function GMModalDlgParentWndObj(const AParentWnd: TGMWndObj): TGMWndObj; function GMScreenRect: TRect; function GMScreenSize: TPoint; function GMClientToScreen(const AArea: TObject; const APoint: TPoint): TPoint; overload; function GMClientToScreen(const AArea: TObject; const ARect: TRect): TRect; overload; function GMScreenToClient(const AArea: TObject; const APoint: TPoint): TPoint; overload; function GMScreenToClient(const AArea: TObject; const ARect: TRect): TRect; overload; function GMAreaToScreen(const AArea: TObject; APoint: TPoint): TPoint; function GMScreenToArea(const AArea: TObject; const APoint: TPoint): TPoint; function GMCalcPopupRect(const AArea: TObject; const ARequestedHeight, ASpace: LongInt): TRect; function GMAreaBoundsOffset(const AContainerArea, AContainedArea: TObject): TRect; procedure GMCaptureMouseInput(const AArea: TObject); procedure GMReleaseMouseCapture; procedure GMSetFocus(const AArea: TObject); procedure GMCancelPopup; function GMFindNextDlgTabAreaByUIPosition(const ADlg, AStartArea: TObject; const AReverse: Boolean): TObject; function GMCalcHintShowTimeMS(const AText: TGMString): LongInt; function GMFrameExtent(const AFrame: IUnknown; const AEdges: TEdges = cAllEdges): TPoint; function GMSetSizeConstraints(const AArea: TObject; const AMinWidth: LongInt = cSizeCnstrNoChange; const AMaxWidth: LongInt = cSizeCnstrNoChange; const AMinHeight: LongInt = cSizeCnstrNoChange; const AMaxHeight: LongInt = cSizeCnstrNoChange): TObject; function GMCalculateClientRect(const AFrame: IGMAreaFrameDrawer; const ABoundsRect: TRect): TRect; procedure GMSetObjAreaFrame(const AArea: TObject; const AFrame: IUnknown); function GMSetIntfMultifFrame(const Area: IUnknown; const InnerFrame: TFrameShape; const OuterFrame: TFrameShape; const FramedEdges: TEdges = CAllEdges; const FrameKind: TFrameKind = frkTile; const OuterSpace: LongInt = 0; const FrameLook3D: Boolean = True): IUnknown; function GMSetObjMultiFrame(const Area: TObject; const InnerFrame: TFrameShape; const OuterFrame: TFrameShape; const FramedEdges: TEdges = CAllEdges; const FrameKind: TFrameKind = frkTile; const OuterSpace: LongInt = 0; const FrameLook3D: Boolean = True): TObject; //function GMPaintingClientRect(const AArea: TObject): TRect; function GMKeyDataToKeyState(const AKeyData: LongInt): SGMKeyStates; function GMIconInstance: THandle; function GMFindFirstIcon(const Module: HModule): HIcon; function GMAreaHasWndHandle(const AArea: TObject): Boolean; function GMIsEqualAlign(const AreaAlign1, AreaAlign2: TGMAreaAlignRec): Boolean; procedure GMReLayoutContainedAreas(const AArea: TObject; const ARepaint: Boolean = True; const ARecurse: Boolean = True); procedure GMScheduleRepaint(const Area: TObject); function GMParentRootForRelayout(const Area: TObject): TObject; //function GMIsAutoCalcHeight(const EdgeAlign: TEdgesAlign; const Bounds: TRect): Boolean; //function GMIsAutoCalcWidth(const EdgeAlign: TEdgesAlign; const Bounds: TRect): Boolean; function GMWndSizeFromClientSize(const AClientSize: TPoint; const AWndStyle, AWndExStyle: DWORD; const AHasMEnu: Boolean = False): TPoint; function GMCalcMsgDlgClientSize(const AMsgText: TGMString; const AFont: HFont; const ADlgMinSize, AExtraSize: TPoint; var AVScrollBarNeeded: Boolean): TPoint; function GMVisitAllChildAreas(const AArea: TObject; const AVisitFunc: TGMObjVisitFunc; const AAreasToIgnore: array of TObject; const ARecurse: Boolean = True; const AData: Pointer = nil): Boolean; procedure GMClearControls(const AArea: TObject; const ARecurse: Boolean; const AAreasToIgnore: array of TObject); procedure GMEnableControls(const AArea: TObject; const AEnable, ARecurse: Boolean; const AAreasToIgnore: array of TObject); function GMAreaIsShowing(const AArea: TObject): Boolean; //function GMCompareByWndMessage(const ItemA, ItemB: IUnknown): TGMCompareResult; function GMCompareByUIPosition(const ItemA, ItemB: IUnknown): TGMCompareResult; procedure GMCallInitProcs; procedure GMApplicationMessageLoop; function GMCallTerminateProcs: Boolean; function GMShowModalDlg(const ADlgWndClass: TGMDlgWindowClass; const AShowKind: TGMShowWndKind = swShowNormal; const ADlgData: Pointer = nil; const ATitle: TGMString = ''; const AParent: TGMWndObj = cDfltPrntWnd): PtrInt; function GMShowModalWnd(AModalWnd: TGMWndObj; const AShowKind: TGMShowWndKind = swShowNormal): PtrInt; function GMIsWindow(const AWindow: TGMWndObj): Boolean; inline; //function GMCalcBoundingChildHeight(const AContainedAreas: IGMObjArrayCollection): LongInt; //function GMCalcBoundingChildWidth(const AContainedAreas: IGMObjArrayCollection): LongInt; function GMCalcBoundingHeight(const AContainingArea: TGMUiAreaBase; const ANewSize: TPoint; const ARelayout: Boolean = True): LongInt; function GMCalcBoundingWidth(const AContainingArea: TGMUiAreaBase; const ANewSize: TPoint; const ARelayout: Boolean = True): LongInt; //function GMParticipateInLayouting(const AArea: IGMUiArea): Boolean; procedure GMLayoutContainedAreas(const Area: IGMUiArea; const ARepaint: Boolean; const ALayoutEdgeOrderMap: TGMLayoutEdgeOrderMap); //: TPoint; procedure GMWrapLayoutContainedAreas(const Area: IGMUiArea; const ARepaint: Boolean; const AHorzAlign: TGMHorizontalAlignment; const AVLineSpace: LongInt); //: TPoint; //function GMAreaAlignToLongInt(const Value: TGMAreaAlignRec): LongInt; //function GMAreaAlignFromLongInt(const Value: LongInt): TGMAreaAlignRec; //procedure GMPrintClientImpl(const Wnd: HWnd; const ADC: HDC; const Brush: HBRUSH); // Borlands definition of GradientFill is wrong .. {$IFNDEF JEDIAPI} function GMGradientFill(ADC: HDC; pVertex: PGMTriVertexRec; dwNumVertex: DWORD; pMesh: Pointer; dwNumMesh, dwMode: DWORD): BOOL; stdcall; external 'msimg32.dll' name 'GradientFill'; {$ENDIF} procedure GMGradientFillRect(const ADC: HDC; const Color1, Color2: COLORREF; const ARect: TRect; const Direction: TGM2DDirection); procedure GMGlassFillRect(const ADC: HDC; const ARect: TRect; const AColors: array of COLORREF); //const clTop, clMidHi, clMidLo, clBottom, clCorner: COLORREF); procedure GMGlassFillRectSimple(const ADC: HDC; const ARect: TRect; const ADarkestColor: COLORREF); function GMAssignRoundedAreaProperties(const AArea: TObject): TObject; function GMPanelAreaFrame: IGMAreaFrameDrawer; function SmallPointToPoint(const P: TSmallPoint): TPoint; function PointToSmallPoint(const P: TPoint): TSmallPoint; //procedure GMSetCornerPixels(const ADC: HDC; const ARect: TRect; const AColor: COLORREF); var //vDefaultUIFont: TDefaultFont = dfUIFont; vGMLayoutEdgeOrderMap: TGMLayoutEdgeOrderMap = (edgLeft, edgTop, edgRight, edgBottom); vGMMouseCaptureArea: TObject = nil; vGMPopupArea: TObject = nil; vGMMouseInsideArea: TObject = nil; vGMKeyboardFocusArea: TObject = nil; vGMDragPainter: IUnknown = nil; vGMDropTargetArea: TObject = nil; vGMWndAnimation: DWORD = cDfltWndAnimation; vGMWndAniDuration: DWORD = cDfltWndAniDuration; vGMPopupAniDuration: DWORD = 180; vLightGray: COLORREF = $EBEBEB; vGMDfltCornerRounding: TPoint = (x:4; y:4); vGMShrinkAnimationCount: LongInt = 15; implementation uses SysUtils{$IFDEF JEDIAPI}, jwaWinBase{$ENDIF}; type PHIcon = ^HIcon; var vGMAreaRegionFiller: IGMAreaFiller = nil; vGMAreaRectFiller: IGMAreaFiller = nil; vGMWindowClassList: IGMIntfArrayCollection = nil; vGMNextCtrlId: PtrInt = 0; vGMPanelAreaFrame: IGMAreaFrameDrawer = nil; vGMTerminateProcsCalled: Boolean = False; { ------------------------- } { ---- Global Routines ---- } { ------------------------- } function GMPanelAreaFrame: IGMAreaFrameDrawer; begin if vGMPanelAreaFrame = nil then vGMPanelAreaFrame := TGMAreaSimpleFrame.Create; Result := vGMPanelAreaFrame; end; function GMMessageRec(const Msg: UINT; const wParam: WPARAM; const lParam: LPARAM; const lResult: LRESULT): TMessage; begin Result.Msg := Msg; Result.WParam := wParam; Result.LParam := lParam; Result.Result := lResult; end; function GMTriVertex(const Pt: TPoint; Red: Word; Green: Word; Blue: Word; Alpha: Word): {$IFNDEF JEDIAPI}TGMTriVertexRec{$ELSE}TTriVertex{$ENDIF}; begin Result.X := Pt.X; Result.Y := Pt.Y; Result.Red := Red; Result.Green := Green; Result.Blue := Blue; Result.Alpha := Alpha; end; function SmallPointToPoint(const P: TSmallPoint): TPoint; begin Result.X := P.X; Result.Y := P.Y; end; function PointToSmallPoint(const P: TPoint): TSmallPoint; begin Result.X := P.X; Result.Y := P.Y; end; //function GMDispatchObjMsg(const Obj: TObject; const Msg: UINT; const wParam: WPARAM = 0; const lParam: LPARAM = 0): LongInt; //var PIWndProc: IGMMessageHandler; MsgRec: TMessage; //begin // if (Obj = nil) or not Obj.GetInterface(IGMMessageHandler, PIWndProc) then Result := 0 else // begin // MsgRec := GMMessageRec(Msg, WParam, LParam, 0); // PIWndProc.DispatchMsg(MsgRec); // Result := MsgRec.Result; // end; //end; procedure GMDispatchObjMsg(const AObj: TObject; var AMsg: TMessage); var msgHandler: IGMMessageHandler; // weakMsgHandler: Pointer; begin // We don't want a ref counted call here, the object may delete itself when executing the message and then decrementing the refcount crashes because the object is gone if AObj is TGMUiAreaBase then TGMUiAreaBase(AObj).DispatchMsg(AMsg) else // A Drag painter implements IGMMessageHandler but is NOT derived from TGMUiAreaBase if GMGetInterface(AObj, IGMMessageHandler, msgHandler) then msgHandler.DispatchMsg(AMsg); //if GMGetWeakInterface(AObj, IGMMessageHandler, weakMsgHandler) then IGMMessageHandler(weakMsgHandler).DispatchMsg(AMsg); end; procedure GMCallObjWindowProc(const AObj: TObject; var AMsg: TMessage); var msgHandler: IGMMessageHandler; // weakMsgHandler: Pointer; begin // We don't want a ref counted call here, the object may delete itself when executing the message and then decrementing the refcount crashes because the object is gone if AObj is TGMUiAreaBase then TGMUiAreaBase(AObj).WindowProc(AMsg) else // A Drag painter implements IGMMessageHandler but is NOT derived from TGMUiAreaBase if GMGetInterface(AObj, IGMMessageHandler, msgHandler) then msgHandler.WindowProc(AMsg); //if GMGetWeakInterface(AObj, IGMMessageHandler, weakMsgHandler) then IGMMessageHandler(weakMsgHandler).WindowProc(AMsg); end; function GMCallObjWindowProc(const AObj: TObject; const AMsg: UINT; const wParam: WPARAM; const lParam: LPARAM): LRESULT; var msgHandler: IGMMessageHandler; msg: TMessage; begin if not GMGetInterface(AObj, IGMMessageHandler, msgHandler) then Result := 0 else begin msg := GMMessageRec(AMsg, WParam, LParam, 0); msgHandler.WindowProc(msg); Result := msg.Result; end; end; procedure GMCallIntfWindowProc(const Intf: IUnknown; var Msg: TMessage); var msgHandler: IGMMessageHandler; begin if GMQueryInterface(Intf, IGMMessageHandler, msgHandler) then msgHandler.WindowProc(Msg); end; function GMCallIntfWindowProc(const Intf: IUnknown; const Msg: UINT; const wParam: WPARAM; const lParam: LPARAM): LRESULT; var msgHandler: IGMMessageHandler; MsgRec: TMessage; begin if (Intf = nil) or not GMQueryInterface(Intf, IGMMessageHandler, msgHandler) then Result := 0 else begin MsgRec := GMMessageRec(Msg, WParam, LParam, 0); msgHandler.WindowProc(MsgRec); Result := MsgRec.Result; end; end; //function GMPostIntfMessage(Intf: IUnknown; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): Boolean; ////var PIHAlloc: IGMHandleAllocated; PIHandle: IGMGetHandle; //var Handle: THandle; //begin // if GMGetAllocatedObjHandle(Intf, Handle) then Result := PostMessage(FHandle, AMsg, wParam, lParam) else Result := False; // // //if (Wnd <> nil) and ((Wnd.QueryInterface(IGMHandleAllocated, PIHAlloc) <> S_OK) or PIHAlloc.HandleAllocated) and // // (Wnd.QueryInterface(IGMGetHandle, PIHandle) = S_OK) then // // Result := PostMessage(PIHandle.Handle, AMsg, wParam, lParam) else Result := False; //end; procedure GMPostSeletNextDlgTabAreaMsg(const AArea: TObject); var dlg: TGMDlgWindow; begin if GMFindParentObj(AArea, TGMDlgWindow, dlg) then GMPostObjMessage(dlg, UM_SELECTNEXTDLGTABAREA); end; procedure GMEnableWindow(const AObj: TObject; const Enable: Boolean); var Wnd: THandle; begin if GMGetAllocatedObjHandle(AObj, Wnd) then EnableWindow(Wnd, Enable); end; function GMPostObjMessage(const AObj: TObject; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): Boolean; var Wnd: THandle; begin if GMGetAllocatedObjHandle(AObj, Wnd) then Result := PostMessage(Wnd, AMsg, wParam, lParam) else Result := False; end; function GMPostIntfMessage(const AIntf: IUnknown; AMsg: UINT; wParam: WPARAM = 0; lParam: LPARAM = 0): Boolean; var Wnd: THandle; begin if GMGetAllocatedIntfHandle(AIntf, Wnd) then Result := PostMessage(Wnd, AMsg, wParam, lParam) else Result := False; end; function GMSendObjMessage(const AObj: TObject; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; var Wnd: THandle; begin if GMGetAllocatedObjHandle(AObj, Wnd) then Result := SendMessage(Wnd, AMsg, wParam, lParam) else Result := 0; end; procedure GMSetObjVisible(const AObj: TObject; const AVisible, ARelayout: Boolean); var setVisible: IGMSetVisible; begin if GMGetInterface(AObj, IGMSetVisible, setVisible) then setVisible.SetVisible(AVisible, ARelayout); end; procedure GMAddDispatchToParentMessages(const AArea: TObject; const AMessages: array of TGMWndMsg); var msg: TGMWndMsg; begin if AArea is TGMUiArea then for msg in AMessages do TGMUiArea(AArea).DispatchToParentMessages.Add(msg); end; function GMFindParentDlg(const AArea: TObject; var ADlg: TObject): Boolean; var parent: IGMGetParentObj; area: IGMUiArea; begin ADlg := AArea; while (ADlg <> nil) and (not ADlg.GetInterface(IGMUiArea, area) or area.IsLayoutChild) do begin GMCheckGetInterface(ADlg, IGMGetParentObj, parent, {$I %CurrentRoutine%}); ADlg := parent.ParentObj; end; Result := ADlg <> nil; end; function GMFindWindowedParent(AArea: TObject): IGMGetHandle; var prntObj: IGMGetParentObj; begin while AArea <> nil do begin if AArea.GetInterface(IGMGetHandle, Result) then Exit; GMCheckGetInterface(AArea, IGMGetParentObj, prntObj, {$I %CurrentRoutine%}); AArea := prntObj.ParentObj; end; Result := nil; end; function GMParentHandleAllocated(const AArea: TObject): Boolean; begin Result := GMIsHandleAllocated(GMFindWindowedParent(AArea)); end; function GMFindAllocatedParentHandle(const AArea: TObject; var AHandle: HWnd): Boolean; begin Result := GMGetAllocatedIntfHandle(GMFindWindowedParent(AArea), THandle(AHandle)); end; function GMModalDlgParentWndObj(const AParentWnd: TGMWndObj): TGMWndObj; var obj, dlg: TObject; wnd: HWnd; begin Result := 0; obj := GMObjFromWndObj(AParentWnd); if (obj <> nil) and GMFindParentDlg(obj, dlg) and GMGetAllocatedObjHandle(dlg, wnd) then Result := -Int64(dlg); if Result = 0 then Result := GMModalDlgParentWnd(GMHWndFromWndObj(AParentWnd)); end; function GMWindowClassList: IGMIntfArrayCollection; begin if vGMWindowClassList = nil then vGMWindowClassList := TGMIntfArrayCollection.Create(False, True, GMCompareByName); Result := vGMWindowClassList; end; function GMScreenRect: TRect; begin Result := GMRect(GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN)); end; function GMScreenSize: TPoint; begin Result := GMPoint(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); end; function GMClientToScreen(const AArea: TObject; const APoint: TPoint): TPoint; var wnd: HWnd; begin Result := APoint; if not GMFindAllocatedParentHandle(AArea, wnd) then Exit; ClientToScreen(wnd, Result); end; function GMClientToScreen(const AArea: TObject; const ARect: TRect): TRect; begin Result.TopLeft := GMClientToScreen(AArea, ARect.TopLeft); Result.BottomRight := GMClientToScreen(AArea, ARect.BottomRight); end; function GMScreenToClient(const AArea: TObject; const APoint: TPoint): TPoint; var Wnd: HWnd; begin Result := APoint; if not GMFindAllocatedParentHandle(AArea, Wnd) then Exit; ScreenToClient(Wnd, Result); end; function GMScreenToClient(const AArea: TObject; const ARect: TRect): TRect; begin Result.TopLeft := GMScreenToClient(AArea, ARect.TopLeft); Result.BottomRight := GMScreenToClient(AArea, ARect.BottomRight); end; function GMAreaToScreen(const AArea: TObject; APoint: TPoint): TPoint; var area: IGMUiArea; begin if GMGetInterface(AArea, IGMUiArea, area) then APoint := GMAddPoints(APoint, area.ClientAreaOrigin); Result := GMClientToScreen(AArea, APoint); end; function GMScreenToArea(const AArea: TObject; const APoint: TPoint): TPoint; var area: IGMUiArea; begin Result := GMScreenToClient(AArea, APoint); if GMGetInterface(AArea, IGMUiArea, area) then Result := GMAddPoints(Result, area.ClientAreaOrigin, -1); end; function GMCalcPopupRect(const AArea: TObject; const ARequestedHeight, ASpace: LongInt): TRect; var area: IGMUiArea; rScreen: TRect; begin Result := cNullRect; if not GMGetInterface(AArea, IGMUiArea, area) then Exit; Result := GMClientToScreen(AArea, area.CalculateSurfaceRect(area.LayoutBounds)); rScreen := GMScreenRect; if (ARequestedHeight <= GMRectSize(rScreen).y - Result.Bottom - 1 - ASpace) or (GMRectSize(rScreen).y - Result.Bottom >= Result.Top) then begin Result.Top := Result.Bottom + 1 + ASpace; Result.Bottom := Min(rScreen.Bottom, Result.Top + ARequestedHeight); end else begin Result.Bottom := Result.Top - 1 - ASpace; Result.Top := Max(rScreen.Top, Result.Bottom - ARequestedHeight); end; end; function GMAreaBoundsOffset(const AContainerArea, AContainedArea: TObject): TRect; var PIPrnt: IGMGetParentObj; PIArea: IGMUiArea; begin //FillByte(Result, SizeOf(Result), 0); Result := Default(TRect); if not GMGetInterface(AContainedArea, IGMUiArea, PIArea) then Exit; Result := PIArea.LayoutBounds; if not GMGetInterface(AContainedArea, IGMGetParentObj, PIPrnt) then Exit; while PIPrnt.ParentObj <> AContainerArea do begin if PIPrnt.ParentObj = nil then Exit; if not GMGetInterface(PIPrnt.ParentObj, IGMUiArea, PIArea) then Exit; //Result := GMaddPoints(Result, PIArea.LayoutBounds.TopLeft); //OffsetRect(AreaRect, PIArea.LayoutBounds.TopLeft.x, PIArea.LayoutBounds.TopLeft.y); Result := GMMoveRect(Result, PIArea.LayoutBounds.TopLeft); if not GMGetInterface(PIPrnt.ParentObj, IGMGetParentObj, PIPrnt) then Exit; end; end; function GMOwnArea(const Owner, Area: TObject): TObject; begin if Area <> nil then (Owner as TGMUiAreaBase).OwnArea(Area); Result := Area; end; function GMRegisterWindowClass(const AWndClassName: TGMString; const ACursor: HCURSOR; const AClassStyle: DWORD; const AIcon: HICON; const ABkgndBrush: HBRUSH; const AMenuName: TGMString): IGMGetName; var searchName: IGMGetName; WndClass: IUnknown; begin searchName := TGMNameObj.Create(AWndClassName, True); if GMWindowClassList.Find(searchName, WndClass) then GMCheckQueryInterface(WndClass, IGMGetName, Result, {$I %CurrentRoutine%}) else begin Result := TGMWindowClass.Create(AWndClassName, AClassStyle, AIcon, ACursor, ABkgndBrush, AMenuName, True); GMWindowClassList.Add(Result); end; end; function GMIconInstance: THandle; begin Result := GetModuleHandle(nil); end; function TellIconRessourceName(hModule: HMODULE; lpszType: PGMChar; lpszName: PGMChar; Param: PtrInt): BOOL; stdcall; var Icon: HICON; begin if Param = 0 then begin Result := False; Exit; end; // <- Stop iteration Icon := LoadIcon(hModule, lpszName); if Icon <> 0 then begin PHIcon(Param)^ := Icon; Result := False; end else Result := True; end; function GMFindFirstIcon(const Module: HModule): HIcon; begin Result := LoadIcon(0, IDI_APPLICATION); EnumResourceNames(Module, Pointer(RT_GROUP_ICON), {$IFNDEF JEDIAPI}@{$ENDIF}TellIconRessourceName, PtrUInt(@Result)); end; function GMKeyDataToKeyState(const AKeyData: LongInt): SGMKeyStates; const cAltMask = $20000000; begin Result := []; if GetKeyState(VK_SHIFT) < 0 then Include(Result, ksShift); if GetKeyState(VK_CONTROL) < 0 then Include(Result, ksCtrl); if AKeyData and cAltMask <> 0 then Include(Result, ksAlt); end; function GMAreaHasWndHandle(const AArea: TObject): Boolean; var unk: IUnknown; begin Result := GMGetInterface(AArea, IGMGetHandle, unk); end; function GMIsEqualAlign(const AreaAlign1, AreaAlign2: TGMAreaAlignRec): Boolean; begin Result := CompareMem(@AreaAlign1.EdgeAlign, @AreaAlign2.EdgeAlign, SizeOf(AreaAlign1.EdgeAlign)); end; function GMIsAutoCalcHeight(const EdgeAlign: TEdgesAlign; const Bounds: TRect): Boolean; begin Result := ((EdgeAlign[edgBottom] in cCalcSizeAlignments) and (Bounds.Bottom = 0)) or ((EdgeAlign[edgTop] in cCalcSizeAlignments) and (Bounds.Top = 0)) or ((EdgeAlign[edgTop] = ealCentered) and (EdgeAlign[edgBottom] = ealCentered) and (GMRectSize(Bounds).y = 0)); end; function GMIsAutoCalcWidth(const EdgeAlign: TEdgesAlign; const Bounds: TRect): Boolean; begin Result := ((EdgeAlign[edgRight] in cCalcSizeAlignments) and (Bounds.Right = 0)) or ((EdgeAlign[edgLeft] in cCalcSizeAlignments) and (Bounds.Left = 0)) or ((EdgeAlign[edgLeft] = ealCentered) and (EdgeAlign[edgRight] = ealCentered) and (GMRectSize(Bounds).x = 0)); end; procedure GMCaptureMouseInput(const AArea: TObject); var parentWnd: HWnd; begin if AArea = nil then Exit; vGMMouseCaptureArea := AArea; if GMFindAllocatedParentHandle(AArea, parentWnd) then SetCapture(parentWnd); end; procedure GMReleaseMouseCapture; begin vGMMouseCaptureArea := nil; ReleaseCapture; end; procedure GMSetFocus(const AArea: TObject); var wndPrnt: HWnd; Dlg: TObject; //Fcs, Prnt: TObject; begin if (AArea = nil) or (AArea = vGMKeyboardFocusArea) or not GMFindAllocatedParentHandle(AArea, wndPrnt) then Exit; if GMFindParentDlg(AArea, Dlg) and (GMSendObjMessage(Dlg, WM_MOUSEACTIVATE) = MA_NOACTIVATE) then Exit; //Fcs := GMObjFromWnd(Getfocus); //Prnt := GMObjFromWnd(wndPrnt); if Getfocus <> wndPrnt then begin if GMObjFromWnd(Getfocus) <> vGMKeyboardFocusArea then GMCallObjWindowProc(vGMKeyboardFocusArea, WM_KILLFOCUS); if GMObjFromWnd(wndPrnt) <> AArea then vGMKeyboardFocusArea := AArea; // <- need to set vGMKeyboardFocusArea before WM_SETFOCUS is send to parent Window SetFocus(wndPrnt); end else begin GMCallObjWindowProc(vGMKeyboardFocusArea, WM_KILLFOCUS); GMCallObjWindowProc(AArea, WM_SETFOCUS); // <- will set vGMKeyboardFocusArea end; end; procedure GMCancelPopup; begin if vGMPopupArea <> nil then GMSendObjMessage(vGMPopupArea, WM_CANCELMODE); end; function GMAreaRegionFiller: IGMAreaFiller; begin if vGMAreaRegionFiller = nil then vGMAreaRegionFiller := TGMAreaRegionFiller.Create(True); Result := vGMAreaRegionFiller; end; function GMAreaRectFiller: IGMAreaFiller; begin if vGMAreaRectFiller = nil then vGMAreaRectFiller := TGMAreaRectFiller.Create(True); Result := vGMAreaRectFiller; end; function GMAssignRoundedAreaProperties(const AArea: TObject): TObject; begin Result := AArea; if AArea is TGMUiAreaBase then begin TGMUiAreaBase(AArea).CornerRounding := vGMDfltCornerRounding; TGMUiAreaBase(AArea).Frame := GMPanelAreaFrame; end; end; {function GMAreaAlignToLongInt(const Value: TGMAreaAlignRec): LongInt; begin Result := (Ord(Value[edgLeft]) shl 24) or (Ord(Value[edgTop]) shl 16) or (Ord(Value[edgRight]) shl 8) or Ord(Value[edgBottom]); end; function GMAreaAlignFromLongInt(const Value: LongInt): TGMAreaAlignRec; var Edge: TEdge; begin for Edge:=Low(Edge) to High(Edge) do Result[Edge] := TEdgeAlign(GMBoundedInt((Value and ($FF shl (Ord(Edge) * 8))) shr (Ord(Edge) * 8), Ord(Low(Edge)), Ord(High(Edge)))); end;} function GMSetSizeConstraints(const AArea: TObject; const AMinWidth, AMaxWidth, AMinHeight, AMaxHeight: LongInt): TObject; var PISizeCnstrnts: IGMGetSetSizeConstraints; Constraints: TGMSizeConstraintsRec; begin Result := AArea; if (AArea = nil) or not AArea.GetInterface(IGMGetSetSizeConstraints, PISizeCnstrnts) then Exit; Constraints := PISizeCnstrnts.GetSizeContraints; if AMinWidth <> cSizeCnstrNoChange then Constraints.MinWidth := AMinWidth; if AMaxWidth <> cSizeCnstrNoChange then Constraints.MaxWidth := AMaxWidth; if AMinHeight <> cSizeCnstrNoChange then Constraints.MinHeight := AMinHeight; if AMaxHeight <> cSizeCnstrNoChange then Constraints.MaxHeight := AMaxHeight; PISizeCnstrnts.SetSizeContraints(Constraints); end; function GMFrameExtent(const AFrame: IUnknown; const AEdges: TEdges = cAllEdges): TPoint; const cRDummy: TRect = (Left: 0; Top: 0; Right: 100; Bottom: 100); var frame: IGMAreaFrameDrawer; frameRect: TRect; begin Result := cNullPoint; if not GMQueryInterface(AFrame, IGMAreaFrameDrawer, frame) then Exit; frameRect := frame.CalculateClientRect(cRDummy); if edgLeft in AEdges then Inc(Result.x, frameRect.Left - cRDummy.Left); if edgTop in AEdges then Inc(Result.y, frameRect.Top - cRDummy.Top); if edgRight in AEdges then Inc(Result.x, cRDummy.Right - frameRect.Right); if edgBottom in AEdges then Inc(Result.y, cRDummy.Bottom - frameRect.Bottom); //Result := GMAddPoints(GMRectSize(cRDummy), GMRectSize(frameRect), -1); end; procedure GMSetObjAreaFrame(const AArea: TObject; const AFrame: IUnknown); var framedArea: IGMUiAreaFrame; frameDrawer: IGMAreaFrameDrawer; begin if not GMGetInterface(AArea, IGMUiAreaFrame, framedArea) or not GMQueryInterface(AFrame, IGMAreaFrameDrawer, frameDrawer) then Exit; framedArea.SetFrame(frameDrawer); end; function GMSetIntfMultifFrame(const Area: IUnknown; const InnerFrame: TFrameShape; const OuterFrame: TFrameShape; const FramedEdges: TEdges; const FrameKind: TFrameKind; const OuterSpace: LongInt; const FrameLook3D: Boolean): IUnknown; var PIDrawFrame: IGMAreaFrameDrawer; PIFrameProperties: IGMMultiFrameProperties; PIAreaFrame: IGMUiAreaFrame; begin Result := Area; if not GMQueryInterface(Area, IGMUiAreaFrame, PIAreaFrame) then Exit; PIDrawFrame := TGMAreaMultiFrame.Create; PIAreaFrame.Frame := PIDrawFrame; if not GMQueryInterface(PIDrawFrame, IGMMultiFrameProperties, PIFrameProperties) then Exit; PIFrameProperties.FrameKind := FrameKind; PIFrameProperties.InnerFrame := InnerFrame; PIFrameProperties.OuterFrame := OuterFrame; PIFrameProperties.FramedEdges := FramedEdges; PIFrameProperties.OuterSpace := OuterSpace; PIFrameProperties.FrameLook3D := FrameLook3D; end; function GMSetObjMultiFrame(const Area: TObject; const InnerFrame: TFrameShape; const OuterFrame: TFrameShape; const FramedEdges: TEdges = CAllEdges; const FrameKind: TFrameKind = frkTile; const OuterSpace: LongInt = 0; const FrameLook3D: Boolean = True): TObject; begin Result := Area; GMSetIntfMultifFrame(GMObjAsIntf(Area), InnerFrame, OuterFrame, FramedEdges, FrameKind, OuterSpace, FrameLook3D); end; function GMCalculateClientRect(const AFrame: IGMAreaFrameDrawer; const ABoundsRect: TRect): TRect; begin if AFrame = nil then Result := ABoundsRect else Result := AFrame.CalculateClientRect(ABoundsRect); end; //procedure GMPrintClientImpl(const Wnd: HWnd; const ADC: HDC; const Brush: HBRUSH); //var RClient: TRect; //begin // if (Wnd = 0) or (ADC = 0) or (Brush = 0) then Exit; // GetClientRect(Wnd, RClient); // FillRect(ADC, RClient, Brush); //end; // //function GMWndAnimationData: TGMWndAnimationData; //begin // Result.Animation := cDfltWndAnimation; // Result.Duration := cDfltWndAniDuration; //end; // //procedure GMRepaintArea(const Area: TObject); //var PIArea: IGMUiArea; //begin // if (Area = nil) or not Area.GetInterface(IGMUiArea, PIArea) then Exit; // PIArea.ScheduleRepaint; //end; procedure GMPaintWndFrame(const AWndObj: TGMWndObj); var Wnd: HWnd; begin Wnd := GMHWndFromWndObj(AWndObj); if (Wnd = 0) or (GetWindowLong(Wnd, GWL_STYLE) and WS_VISIBLE = 0) then Exit; SendMessage(Wnd, WM_NCPAINT, 1, 0); end; procedure GMReLayoutContainedAreas(const AArea: TObject; const ARepaint: Boolean; const ARecurse: Boolean); var layoutArea: IGMUiArea; layoutRoot: TObject; begin if (AArea = nil) or not AArea.GetInterface(IGMUiArea, layoutArea) then Exit; layoutRoot := layoutArea.RootForRelayout; if (layoutRoot = nil) or not layoutRoot.GetInterface(IGMUiArea, layoutArea) then Exit; if ARecurse then begin layoutArea.InvalidateCachedLayoutValues; layoutArea.LayoutContainedAreasIfNeeded(ARepaint); // layoutArea.LayoutContainedAreas(ARepaint); end else layoutArea.LayoutContainedAreas(ARepaint); if ARepaint then layoutArea.ScheduleRepaint; // <- childs may have moved and dont completely cover the area end; procedure GMScheduleRepaint(const Area: TObject); var PIArea: IGMUiArea; begin if (Area <> nil) and Area.GetInterface(IGMUiArea, PIArea) then PIArea.ScheduleRepaint; end; function GMParentRootForRelayout(const Area: TObject): TObject; var PIParent: IGMGetParentObj; PIArea: IGMUiArea; begin Result := Area; if (Area = nil) or not Area.GetInterface(IGMGetParentObj, PIParent) then Exit; if (PIParent.ParentObj = nil) or not PIParent.ParentObj.GetInterface(IGMUiArea, PIArea) then Exit; Result := PIArea.RootForRelayout; // <- recursive! end; function APIAnimateWindowProcAddr: Pointer; var HUser32: THandle; begin HUser32 := GetModuleHandle('user32.dll'); if HUser32 <> 0 then Result := GetProcAddress(HUser32, 'AnimateWindow') else Result := nil; end; function GMAnimateWindow(Wnd: HWND; dwTime: DWORD; dwFlags: DWORD): BOOL; var fAPIAnimateWindow: function (Wnd: HWND; dwTime: DWORD; dwFlags: DWORD): BOOL; stdcall; begin // // Windows NT does not have AnimateWindow // @fAPIAnimateWindow := APIAnimateWindowProcAddr; if not Assigned(fAPIAnimateWindow) then Result := ShowWindow(Wnd, cSWShow[dwFlags and AW_HIDE = 0]) else begin Result := fAPIAnimateWindow(Wnd, dwTime, dwFlags); if not Result then begin Result := ShowWindow(Wnd, cSWShow[dwFlags and AW_HIDE = 0]) {ToDo: AnimateWindow Sometimes returns "Access denied" on XP, why?} {ToDo: AnimateWindow for popup windows works only on the second call why? First call returns: Accessing invalid token} // GMTrace('AnimateWindow: ' + GMSysErrorMsg(LongInt(GetLastError), []), tpError); // Result := fAPIAnimateWindow(Wnd, dwTime, dwFlags); // if not Result then GMTrace('AnimateWindow: ' + GMSysErrorMsg(LongInt(GetLastError), []), tpError); end; end; end; procedure GMShowWindowAnimated(const AWnd: HWnd; const AShowKind: TGMShowWndKind); const cAnimateWnd: array [Boolean, Boolean] of DWORD = ((AW_HIDE, AW_HIDE), (0, AW_ACTIVATE)); begin if not IsWindow(AWnd) then Exit; if (AShowKind in [swShowNormal, swShowNoActivate, swHide]) and (vGMWndAniDuration > 0) and (vGMWndAnimation <> 0) then GMAnimateWindow(AWnd, vGMWndAniDuration, vGMWndAnimation or cAnimateWnd[AShowKind in [swShowNormal, swShowNoActivate], AShowKind = swShowNormal]) else ShowWindow(AWnd, cShowWndFlags[AShowKind]); //if (AShowKind in [swShowNormal, swShowNoActivate]) then UpdateWindow(AWnd); end; procedure GMExecPendingPainting(const AArea: TObject); var Wnd: HWnd; begin if GMFindAllocatedParentHandle(AArea, Wnd) then UpdateWindow(Wnd); //GMProcessMessages([WM_NCPAINT, WM_PAINT]); end; //procedure GMHideAndShowWnd(const WndObj: TGMWndObj); //var Wnd: HWnd; //begin // Wnd := GMHWndFromWndObj(WndObj); // if (Wnd = 0) or (GetWindowLong(Wnd, GWL_STYLE) and WS_VISIBLE = 0) then Exit; // ShowWindow(Wnd, SW_HIDE); // ShowWindow(Wnd, SW_SHOW); //end; function CloseThreadWndFunc(Wnd: HWnd; Param: LParam): BOOL; stdcall; begin Result := True; Wnd := GMDlgRootWindow(Wnd); if not IsWindow(Wnd) or (Wnd = HWnd(Param)) or (GetWindowLong(Wnd, GWL_STYLE) and WS_CHILD <> 0) or (GetWindowLong(Wnd, GWL_STYLE) and WS_VISIBLE = 0) then Exit; SendMessage(Wnd, WM_CLOSE, IDCANCEL, 0); end; procedure GMCloseAllThreadWindows(const ACallingWnd: HWnd); begin // // Should be called only by main thread. // Windows of other threads will be closed by the system when the threads are terminated/destroyed. // EnumThreadWindows(GetCurrentThreadID, {$IFNDEF JEDIAPI}@{$ENDIF}CloseThreadWndFunc, LPARAM(ACallingWnd)); end; function ReloadWndWithNewLanguage(Wnd: HWnd; Param: LParam): BOOL; stdcall; begin Result := True; Wnd := GMDlgRootWindow(Wnd); if Wnd <> 0 then SendMessage(Wnd, UM_LANGUAGECHANGED, 0, Param); end; procedure GMLoadNewLanguageToUI(const ANewLanguage: LangId); begin EnumThreadWindows(GetCurrentThreadID, {$IFNDEF JEDIAPI}@{$ENDIF}ReloadWndWithNewLanguage, ANewLanguage); end; function GMResTextRefDataRec(const AResStringPtr: PResStringRec; const AFormatStr: TGMString = ''): RGMResTextRefData; begin Result.ResStringPtr := AResStringPtr; Result.FormatStr := AFormatStr; end; function GMMakeResRefText(const AResStringRecPtr: Pointer; const AFormatString: TGMString): TGMString; begin Result := GMStringJoin(cResTextRefPrefix + '$' + GMIntToHexStr(PtrInt(AResStringRecPtr)), cResTextFmtSeparator, AFormatString); end; function GMResolveTextResData(const AText: TGMString; var ATextResData: RGMResTextRefData): TGMString; var resPtr: PtrUInt; convCode: Integer; chPos: PtrInt; token: TGMString; begin Result := AText; //ATextResData := GMResTextRefDataRec(nil); if GMIsPrefixStr(cResTextRefPrefix, AText) then begin chPos := Length(cResTextRefPrefix) + 1; token := GMNextWord(chPos, AText, cResTextFmtSeparator); Val(token, resPtr, convCode); if (convCode = 0) and not IsBadReadPtr(Pointer(resPtr), SizeOf(TResStringRec)) then ATextResData.ResStringPtr := Pointer(resPtr); ATextResData.FormatStr := Copy(AText, chPos, Length(AText) - chPos + 1); Result := GMBuildTextFromResRef(ATextResData, ''); end; end; function GMBuildTextFromResRef(const ATextResData: RGMResTextRefData; const AText: TGMString): TGMString; begin if ATextResData.ResStringPtr = nil then Result := AText else begin Result := LoadResString(ATextResData.ResStringPtr); if Length(ATextResData.FormatStr) > 0 then Result := GMFormat(ATextResData.FormatStr, [Result]); end; end; function GMNextCtrlID: PtrInt; begin if vGMNextCtrlId >= High(Word) then vGMNextCtrlId := 1 else Inc(vGMNextCtrlId); Result := vGMNextCtrlId; end; function GMVisitAllChildAreas(const AArea: TObject; const AVisitFunc: TGMObjVisitFunc; const AAreasToIgnore: array of TObject; const ARecurse: Boolean; const AData: Pointer): Boolean; var PIArea: IGMUiArea; i: LongInt; function IgnoreArea(const AArea: TObject): Boolean; var i: LongInt; begin for i:=Low(AAreasToIgnore) to High(AAreasToIgnore) do if AAreasToIgnore[i] = AArea then begin Result := True; Exit; end; Result := False; end; begin Result := True; if not Assigned(AVisitFunc) or (AArea = nil) or not AArea.GetInterface(IGMUiArea, PIarea) then Exit; for i:=0 to PIArea.ContainedAreas.Count-1 do begin if IgnoreArea(PIArea.ContainedAreas[i]) then Continue; Result := AVisitFunc(PIArea.ContainedAreas[i], AData) and (not ARecurse or GMVisitAllChildAreas(PIArea.ContainedAreas[i], AVisitFunc, AAreasToIgnore, ARecurse, AData)); if not Result then Exit; end; end; function ClearArea(const AArea: TObject; const AData: Pointer): Boolean; var clear: IGMClear; begin if GMGetInterface(AArea, IGMClear, clear) then clear.Clear; //GMExecuteOperation(AArea, Ord(opClear)); Result := True; end; procedure GMClearControls(const AArea: TObject; const ARecurse: Boolean; const AAreasToIgnore: array of TObject); begin GMVisitAllChildAreas(AArea, ClearArea, AAreasToIgnore, ARecurse, nil); end; function EnableArea(const AArea: TObject; const AData: Pointer): Boolean; const cOperation: array [Boolean] of LongInt = (Ord(goDisable), Ord(goEnable)); begin GMExecuteOperation(AArea, cOperation[AData <> nil]); Result := True; end; procedure GMEnableControls(const AArea: TObject; const AEnable, ARecurse: Boolean; const AAreasToIgnore: array of TObject); const cBoolPtr: array [Boolean] of Pointer = (nil, Pointer(1)); begin GMVisitAllChildAreas(AArea, EnableArea, AAreasToIgnore, ARecurse, cBoolPtr[AEnable]); end; function GMCompareByUIPosition(const ItemA, ItemB: IUnknown): TGMCompareResult; const cTolerance = 5; var AreaA, AreaB: IGMUiArea; uiPosA, uiPosB: TPoint; Wnd: HWnd; begin GMCheckQueryInterface(ItemA, IGMUiArea, AreaA, {$I %CurrentRoutine%}); GMCheckQueryInterface(ItemB, IGMUiArea, AreaB, {$I %CurrentRoutine%}); //uiPosA := AreaA.CalculateSurfaceRect(AreaA.LayoutBounds).TopLeft; // <- dont use PaintingRect here, it would return 0,0 for windowed controls uiPosA := AreaA.PaintingRect.TopLeft; if GMFindAllocatedParentHandle(GMObjFromIntf(AreaA), Wnd) then ClientToScreen(Wnd, uiPosA); //uiPosB := AreaB.CalculateSurfaceRect(AreaB.LayoutBounds).TopLeft; // <- dont use PaintingRect here, it would return 0,0 for windowed controls uiPosB := AreaB.PaintingRect.TopLeft; // <- dont use PaintingRect here, it would return 0,0 for windowed controls if GMFindAllocatedParentHandle(GMObjFromIntf(AreaB), Wnd) then ClientToScreen(Wnd, uiPosB); if GMIsInRange(uiPosA.y, uiPosB.y - cTolerance, uiPosB.y + cTolerance) then Result := crAEqualToB else if uiPosA.y < uiPosB.y then Result := crALessThanB else Result := crAGreaterThanB; if Result = crAEqualToB then if GMIsInRange(uiPosA.x, uiPosB.x - cTolerance, uiPosB.x + cTolerance) then Result := crAEqualToB else if uiPosA.x < uiPosB.x then Result := crALessThanB else Result := crAGreaterThanB; end; function GMAreaIsShowing(const AArea: TObject): Boolean; var parent: IGMGetParentObj; area: IGMUiArea; begin Result := ((AArea is TGMWindow) and (TGMWindow(AArea).WndStyle and WS_VISIBLE <> 0)) or (not (AArea is TGMWindow) and GMGetInterface(AArea, IGMUiArea, area) and area.Visible and GMGetInterface(AArea, IGMGetParentObj, parent) and GMAreaIsShowing(parent.ParentObj)); end; function GMFindNextDlgTabAreaByUIPosition(const ADlg, AStartArea: TObject; const AReverse: Boolean): TObject; var tabAreas: IGMObjArrayCollection; dlg: IGMUiArea; idx: PtrInt; procedure FindAllTabAreas(const ATabAreas: IGMObjCollection); var area: TObject; areaIntf: IGMUiArea; areaIt: IGMIterator; begin if ATabAreas = nil then Exit; areaIt := ATabAreas.CreateIterator; while areaIt.Nextentry(area) do // for i:=0 to ATabAreas.Count-1 do if GMAreaIsShowing(area) and GMGetInterface(area, IGMUiArea, areaIntf) and areaIntf.GetEnabled then begin if areaIntf.IsTabstop then tabAreas.Add(area); FindAllTabAreas(areaIntf.ContainedAreas); end; end; begin Result := nil; if not GMGetInterface(ADlg, IGMUiArea, dlg) then Exit; tabAreas := TGMObjArrayCollection.Create(False, True, True, GMCompareByUIPosition, True); FindAllTabAreas(dlg.ContainedAreas); if tabAreas.IsEmpty then Exit; idx := tabAreas.IndexOfObj(AStartArea); if idx = cInvalidItemIdx then idx := 0 else begin if AReverse then Dec(idx) else Inc(idx); if idx < 0 then idx := tabAreas.Count-1; if idx >= tabAreas.Count then idx := 0; end; Result := tabAreas[idx]; end; function GMCalcHintShowTimeMS(const AText: TGMString): LongInt; begin //Result := 3000 + GMWordCount(AText, cWhiteSpace + '&/\=+*-,.;:') * 330; Result := GMBoundedInt(3000 + ((Length(AText) div 5) * 330), 1000, High(SmallInt)); // <- the high word must be zero, interpreted as signed 16-Bit value! end; //procedure GMNotifyCursorChange; //var CurPos: TPoint; //begin // CurPos := GMMousePosition; // SetCursorPos(CurPos.x, CurPos.y); // <- trigger system to send a WM_SETCURSOR message // GMProcessMessages([WM_SETCURSOR]); //end; function GMFindDfltDlgCtrl(const AParentArea: TObject; var ADefaultCtrl: IGMIsDefaultDlgBtn): Boolean; var PIArea, PIChildArea: IGMUiArea; i: LongInt; begin Result := False; if not GMGetInterface(AParentArea, IGMUiArea, PIArea) then Exit; for i:=0 to PIArea.ContainedAreas.Count-1 do if GMAreaIsShowing(PIArea.ContainedAreas[i]) and GMGetInterface(PIArea.ContainedAreas[i], IGMUiArea, PIChildArea) and PIChildArea.GetEnabled then begin Result := GMQueryInterface(PIChildArea, IGMIsDefaultDlgBtn, ADefaultCtrl) and ADefaultCtrl.IsDefaultDlgBtn; if not Result then Result := GMFindDfltDlgCtrl(PIArea.ContainedAreas[i], ADefaultCtrl); if Result then Break else ADefaultCtrl := nil; end; end; //function GMCompareByWndMessage(const ItemA, ItemB: IUnknown): TGMCompareResult; //var MsgObjA, MsgObjB: IGMWndMessage; //begin // GMCheckQueryInterface(ItemA, IGMWndMessage, MsgObjA, {$I %CurrentRoutine%}); // GMCheckQueryInterface(ItemB, IGMWndMessage, MsgObjB, {$I %CurrentRoutine%}); // if MsgObjA.WndMessage > MsgObjB.WndMessage then Result := crAGreaterThanB else // if MsgObjA.WndMessage = MsgObjB.WndMessage then Result := crAEqualToB else // Result := crALessThanB; //end; procedure GMSetFontColor(const AUIArea: IUnknown; const AColor: COLORREF); var setFontColor: IGMSetFonColor; begin if GMQueryInterface(AUIArea, IGMSetFonColor, setFontColor) then setFontColor.SetFontColor(AColor); end; { -------------------------- } { ---- Window Procedure ---- } { -------------------------- } function GMHWndFromWndObj(const AWndObj: TGMWndObj): HWnd; begin if AWndObj >= 0 then Result := HWnd(AWndObj) else try if not GMGetAllocatedObjHandle(TObject(-AWndObj), THandle(Result)) then Result := 0; except Result := 0; end; if not IsWindow(Result) then Result := 0; // <- dont use GMIsWindow here -> endless recursion end; function GMObjFromWndObj(const WndObj: TGMWndObj): TObject; begin if WndObj < 0 then Result := TObject(-WndObj) else Result := nil; end; function GMIsWindow(const AWindow: TGMWndObj): Boolean; //var Wnd: HWnd; begin Result := AWindow <> 0; //Wnd := GMHWndFromWndObj(AWindow); //Result := (Wnd <> 0) and IsWindow(Wnd); end; function GMDlgParentWndFromObj(const AObj: TObject): HWnd; var Dlg: TObject; begin if GMFindParentDlg(AObj, Dlg) then Result := GMModalDlgParentWnd(GMHWndFromWndObj(-Int64(Dlg))) else Result := 0; end; function GMObjFromWnd(const AHWnd: HWnd): TObject; begin Result := nil; if AHWnd <> 0 then try Result := TObject(GetWindowLongPtr(AHWnd, cWndObjPtrData)); if Result <> nil then Result.ClassType; // <- just call something to see if it really is a TObject (otherwise an exception is thrown). And use it to avoid compiler hint except Result := nil; end; end; function GMStdWndProc(AWnd: HWND; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; // // Works only for classes derived from TGMWindow, but should be a bit faster than getting 3 interfaces // var Obj: TObject; Msg: TMessage; // PIHandle: IGMGetHandle; PIHAlloc: IGMHandleAllocated; WndProc: IGMMessageHandler; begin // The message handling code has high impact on performance! Everything done here should be as simple and fast as possible! //try Result := 0; if AWnd <> 0 then begin Obj := GMObjFromWnd(AWnd); if Obj is TGMWindow then // <- should be a bit faster than getting 3 interfaces with TGMWindow(Obj) do // with Obj as TGMWindow do begin _AddRef; // <- put an additional reference on the window object for the scope of this call. In case the object is // RefLifeTime and releases the last reference to itself when handling this message (e.g. WM_NCDESTROY). // The additional reference will do no harm if the window object is not RefLifeTime. try if {HandleAllocated} (AWnd <> 0) and (FHandle = AWnd) then begin Msg := GMMessageRec(AMsg, wParam, lParam, Result); WindowProc(Msg); //WndProc.WindowProc(Msg); Result := Msg.Result; end; finally _Release; // <- remove the additional reference now that we are done with this call, may cause freeing the window object end; end; end; //except // The modal message loop needs the exceptions to be handled there! // on ex: TObject do begin vfGMHrExceptionHandler(ex, cDfltPrntWnd); Result := 0; end; //end; end; function GMStdIWndProc(Wnd: HWND; AMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; // // Interfaced version for classes not derived from TGMWindow, works for TGMWindow decendants too // var obj: TObject; msg: TMessage; handle: IGMGetHandle; hAlloc: IGMHandleAllocated; wndProc: IGMMessageHandler; begin //try Result := 0; if Wnd <> 0 then begin obj := GMObjFromWnd(Wnd); if (obj <> nil) and (not obj.GetInterface(IGMHandleAllocated, hAlloc) or hAlloc.HandleAllocated) and obj.GetInterface(IGMGetHandle, handle) and (handle.Handle = Wnd) and obj.GetInterface(IGMMessageHandler, wndProc) then begin msg := GMMessageRec(AMsg, wParam, lParam, Result); //WindowProc(msg); wndProc.WindowProc(msg); Result := msg.Result; end; end; //except // on ex: TObject do begin vfGMHrExceptionHandler(ex, cDfltPrntWnd); Result := 0; end; //end; end; { ----------------------- } { ---- Message Loops ---- } { ----------------------- } procedure GMCallInitProcs; begin if InitProc <> nil then TProcedure(InitProc); end; function GMCallTerminateProcs: Boolean; begin if vGMTerminateProcsCalled then begin Result := True; Exit; end; if ExitProc <> nil then TProcedure(ExitProc); vGMTerminateProcsCalled := CallTerminateProcs; Result := vGMTerminateProcsCalled; if Result then PostQuitMessage(0); end; procedure GMApplicationMessageLoop; var Msg: TMsg; begin while True do try WaitMessage; while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin case Msg.message of // WM_QUERYENDSESSION is handeled by TGMMainWindow //WM_QUIT: begin ExitCode := GMWndStackCloseAll(0, IDABORT); Exit; end; // <- NOTE: Exit here! WM_QUIT: begin ExitCode := GMWndStackCloseAll(0, ExitCode); Exit; end; // <- NOTE: Exit here! WM_ENDSESSION: if Msg.wParam <> cFalseInt then Exit; // <- NOTE: Exit here! // WM_KEYDOWN, WM_KEYUP, WM_CHAR: // if Msg.wParam in [VK_RETURN, VK_ESCAPE, VK_TAB] then // begin // if not IsDialogMessage(Msg.hwnd, Msg) then GMTranslateAndDispatchMsg(Msg); // Continue; // end; end; //if not IsDialogMessage(Msg.hwnd, Msg) then GMTranslateAndDispatchMsg(Msg); end; except on ex: TObject do vfGMHrExceptionHandler(ex, cDfltPrntWnd); end; end; function EnumWindowToArrayFunc(wnd: HWnd; param: LPARAM): BOOL; stdcall; //var wndClassName: TGMString; begin Result := True; // <- continue iteration if param = 0 then Exit; wnd := GMDlgRootWindow(wnd); if IsWindow(wnd) and IsWindowEnabled(wnd) and (wnd <> vGMModalWnd) and (GetWindowLong(wnd, GWL_STYLE) and WS_VISIBLE <> 0) and not GMIsOneOfIntegers(PtrInt(wnd), PGMPtrIntArray(param)^) and (wnd <> GetDesktopWindow) then begin //SetLength(wndClassName, 255); //SetLength(wndClassName, GetClassName(wnd, PGMChar(wndClassName), Length(wndClassName))); // //if CompareText(wndClassName, 'tooltips_class32') = 0 then Exit; //if CompareText(wndClassName, 'TAppWindow') = 0 then Exit; GMAddIntegersToArray(PGMPtrIntArray(param)^, [PtrInt(wnd)]); end; end; function GMShowModalWnd(AModalWnd: TGMWndObj; const AShowKind: TGMShowWndKind): PtrInt; var oldModalWnd, oldForeGroundWnd: HWnd; disabledWindows: TGMPtrIntArray; modalDlg: TGMDlgWindow; procedure DisableAllOtherwindows; var wnd: PtrInt; begin SetLength(disabledWindows, 0); EnumThreadWindows(GetCurrentThreadID, {$IFNDEF JEDIAPI}@{$ENDIF}EnumWindowToArrayFunc, LPARAM(@disabledWindows)); if GetCurrentThreadID <> gGMMainThreadID then EnumThreadWindows(gGMMainThreadID, {$IFNDEF JEDIAPI}@{$ENDIF}EnumWindowToArrayFunc, LPARAM(@disabledWindows)); for wnd in disabledWindows do EnableWindow(HWnd(wnd), False); end; procedure ReEnableOtherWindows; var wnd: PtrInt; begin for wnd in disabledWindows do EnableWindow(HWnd(wnd), True); SetLength(disabledWindows, 0); end; function ModalMessageLoop(const AModalWnd: HWnd): WPARAM; var Msg: TMsg; begin Result := IDCANCEL; if not IsWindow(AModalWnd) then Exit; while True do try WaitMessage; while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin if (Msg.message = WM_CLOSE) and (Msg.hwnd = vGMModalWnd) then begin // ReEnableOtherWindows must be done before the modal dialog window is closed! // Otherwise the system cannot re-activate the window that was active before the modal dialog was displayed. // NOTE: modalDlg.CanClose may raise! if (modalDlg <> nil) and not modalDlg.CanClose(Msg.wParam = IDOK) then Continue; // <- NOTE: may skip rest of the loop! ReEnableOtherWindows; end; //Result := GMTranslateAndDispatchMsg(Msg); if (Msg.message = WM_CLOSE) and (Msg.hwnd = vGMModalWnd) then Exit(Msg.wParam); // <- NOTE: May Exit Here! // When the close button of a window is pressed the WM_CLOSE message will be send directly to the WndProc of the // corresponding window and we will NOT see that WM_CLOSE message here! // Or another thread handled the Message in a MsgWaitForMultipleObjects wait condition. // So this is the emergency exit if the modal window has gone by means we cannot see here. if not Iswindow(vGMModalWnd) then Exit(IDCANCEL); end; except on ex: TObject do Result := vfGMHrExceptionHandler(ex, AModalWnd); end; end; begin Result := IDCANCEL; AModalWnd := GMHWndFromWndObj(AModalWnd); if not GMIsWindow(AModalWnd) then Exit; if GMObjFromWnd(AModalWnd) is TGMDlgWindow then modalDlg := TGMDlgWindow(GMObjFromWnd(AModalWnd)) else modalDlg := nil; oldForeGroundWnd := GMActiveProcessWindow; oldModalWnd := vGMModalWnd; try vGMModalWnd := AModalWnd; GMPushModalDlgWnd(AModalWnd); try GMShowWindowAnimated(AModalWnd, AShowKind); //BringWindowToTop(AModalWnd); //SetForeGroundwindow(Dlg.Handle); DisableAllOtherwindows; try Result := ModalMessageLoop(AModalWnd); finally ReEnableOtherWindows; // <- should already have been done by ModalMessageLoop, but when a thread MsgWait.. function has handled the WM_CLOSE message we need to do this here! Does no harm if done twice! end; finally GMPopModalDlgWnd; SetForegroundWindow(oldForeGroundWnd); //BringWindowToTop(GMTopwindow); //SetActiveWindow(GMTopwindow); end; finally vGMModalWnd := oldModalWnd; end; end; function GMShowModalDlg(const ADlgWndClass: TGMDlgWindowClass; const AShowKind: TGMShowWndKind; const ADlgData: Pointer; const ATitle: TGMString; const AParent: TGMWndObj): PtrInt; var dlg: TGMDlgWindow; begin Result := IDCANCEL; if ADlgWndClass = nil then Exit; dlg := ADlgWndClass.Create(cNullRect, 0, cPrntWndExStyle, ATitle, {ParentWnd}AParent, ADlgData); try Result := GMShowModalWnd(dlg.Handle, AShowKind); finally dlg.Free; end; end; function GMWndSizeFromClientSize(const AClientSize: TPoint; const AWndStyle, AWndExStyle: DWORD; const AHasMEnu: Boolean): TPoint; const cOffs = 100; var R: TRect; begin R := GMRect(cOffs, cOffs, AClientSize.x + cOffs, AClientSize.y + cOffs); if AdjustWindowRectEx(R, AWndStyle, AHasMEnu, AWndExStyle) then Result := GMRectSize(R) else begin GMTrace('AdjustWindowRectEx: ' + GMSysErrorMsg(LongInt(GetLastError), []), tpError); Result := AClientSize; end; end; function GMCalcMsgDlgClientSize(const AMsgText: TGMString; const AFont: HFont; const ADlgMinSize, AExtraSize: TPoint; var AVScrollBarNeeded: Boolean): TPoint; var maxTxtSize: LongInt; begin // Calculate size without wrapping first Result := GMCalcTextAreaSize(AMsgText, GMPoint(10, 10), cNullPoint, cNullPoint, AFont, DT_NOCLIP or DT_NOPREFIX); // Limit width to half of the screen Result.x := Min(Result.x, (GetSystemMetrics(SM_CXSCREEN) div 2) - AExtraSize.x); // Now calculate again with word wrapping Result := GMCalcTextAreaSize(AMsgText, GMPoint(Result.x, 10), cNullPoint, cNullPoint, AFont, DT_NOCLIP or DT_NOPREFIX or DT_WORDBREAK); maxTxtSize := (GetSystemMetrics(SM_CYSCREEN) div 2) - AExtraSize.y; AVScrollBarNeeded := Result.y > maxTxtSize; Result.y := Min(Result.y, maxTxtSize); Result := GMAddPoints(Result, AExtraSize); Result.x := Max(Result.x, ADlgMinSize.x); Result.y := Max(Result.y, ADlgMinSize.y); if AVScrollBarNeeded then Inc(Result.x, GetSystemMetrics(SM_CXVSCROLL)); end; { ---------------------------- } { ---- Rectangle Routines ---- } { ---------------------------- } function GMRectCenterX(const RInner, ROuter: TRect): TRect; var RSize: TPoint; begin Result.Top := RInner.Top; Result.Bottom := RInner.Bottom; RSize := GMRectSize(RInner); Result.Left := ((ROuter.Left + ROuter.Right) div 2) - (RSize.x div 2); Result.Right := Result.Left + RSize.x; end; function GMRectCenterY(const RInner, ROuter: TRect): TRect; var RSize: TPoint; begin Result.Left := RInner.Left; Result.Right := RInner.Right; RSize := GMRectSize(RInner); Result.Top := ((ROuter.Top + ROuter.Bottom) div 2) - (RSize.y div 2); Result.Bottom := Result.Top + RSize.y; end; function GMLimitRectToScreen(const ARect: TRect; const Edges: TEdges = CAllEdges): TRect; var rScreen: TRect; begin Result := ARect; rScreen := GMScreenRect; //GMRect(GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), // GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN), // GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN)); if ([edgLeft, edgRight] <= Edges) and (Result.Right > rScreen.Right) then Result := GMMoveRect(Result, rScreen.Right - Result.Right, 0); if (edgLeft in Edges) and (Result.Left < rScreen.Left) then Result := GMMoveRect(Result, rScreen.Left - Result.Left, 0); if edgRight in Edges then Result.Right := Min(Result.Right, rScreen.Right); if ([edgTop, edgBottom] <= Edges) and (Result.Bottom > rScreen.Bottom) then Result := GMMoveRect(Result, 0, rScreen.Bottom - Result.Bottom); if (edgTop in Edges) and (Result.Top < rScreen.Top) then Result := GMMoveRect(Result, 0, rScreen.Top - Result.Top); if edgBottom in Edges then Result.Bottom := Min(Result.Bottom, rScreen.Bottom); end; function GMAreaRect(Left, Top, Width, Height: LongInt): TRect; begin if Left = CInvalidUIPos then Left := 50; if Top = CInvalidUIPos then Top := 50; if Width = CInvalidUIPos then Width := Round(GetSystemMetrics(SM_CXFULLSCREEN) * 0.33); if Height = CInvalidUIPos then Height := Round(GetSystemMetrics(SM_CYFULLSCREEN) * 0.66); Result := GMRect(Left, Top, Left + Width, Top + Height); end; function GMAreaAlign(const Left, Top, Right, Bottom: TEdgeAlign; const ShrinkRestX: Boolean; const ShrinkRestY: Boolean): TGMAreaAlignRec; begin Result.EdgeAlign[edgLeft] := Left; Result.EdgeAlign[edgTop] := Top; Result.EdgeAlign[edgRight] := Right; Result.EdgeAlign[edgBottom] := Bottom; Result.ShrinkRestX := ShrinkRestX; Result.ShrinkRestY := ShrinkRestY; end; function GMSplitDirectionFromAlign(const AAlign: TEdgesAlign; const ASpace: TRect): TGM2DDirection; begin if (AAlign[edgLeft] = ealAligned) and (ASpace.Left < cQAlign) and (AAlign[edgRight] = ealAligned) and (ASpace.Right < cQAlign) then Result := d2dVertical else Result := d2dHorizontal; end; function GMDesktopClientRect: TRect; begin Result := cNullRect; GetClientRect(GetDesktopWindow, Result); end; function GMCenteredWndRect(const WndSize: TPoint; const Parent: TGMWndObj): TRect; var prntRect: TRect; parentWnd: HWnd; begin parentWnd := GMModalDlgParentWnd(GMHWndFromWndObj(Parent)); if IsWindow(parentWnd) and (GetWindowLong(parentWnd, GWL_STYLE) and WS_VISIBLE <> 0) then GetWindowRect(parentWnd, prntRect) else prntRect := GMDesktopClientRect; Result := GMLimitRectToScreen(GMCenterExtentInRect(WndSize, prntRect)); end; function GMLoadRect(const Source: IGMValueStorage; const DirPath, RectName: TGMString; const DefaultRect: TRect): TRect; var threadSync: RGMCriticalSectionLock; dirKeeper: IUnknown; begin try Result := DefaultRect; threadSync.Lock(Source); dirKeeper := TGMVsdDirPathKeeper.Create(Source); if (DirPath = '') or GMVsdOpenDir(Source, DirPath, False) then Result := GMReadRect(Source, RectName, DefaultRect); except Result := DefaultRect; end; end; procedure GMStoreRect(const Dest: IGMValueStorage; const DirPath, RectName: TGMString; const Value: TRect); var threadSync: RGMCriticalSectionLock; dirKeeper: IUnknown; begin //try if (Dest = nil) or (DirPath = '') then Exit; threadSync.Lock(Dest); dirKeeper := TGMVsdDirPathKeeper.Create(Dest, DirPath, True); GMWriteRect(Dest, RectName, Value); //except end; end; function GMLoadDlgRect(const ASource: IGMValueStorage; const ALoadPath, ARectName: TGMString; const ADlgSize: TPoint; const AParent: TGMWndObj): TRect; begin Result := GMLimitRectToScreen(GMLoadRect(ASource, ALoadPath, ARectName, GMCenteredWndRect(ADlgSize, AParent))); end; function GMLoadDlgRect(const ASource: IGMValueStorage; const ALoadPath, ARectName: TGMString; const ADlgRect: TRect): TRect; overload; begin Result := GMLimitRectToScreen(GMLoadRect(ASource, ALoadPath, ARectName, ADlgRect)); end; procedure GMGradientFillRect(const ADC: HDC; const Color1, Color2: COLORREF; const ARect: TRect; const Direction: TGM2DDirection); const cFill: array [TGM2DDirection] of DWORD = (GRADIENT_FILL_RECT_H, GRADIENT_FILL_RECT_V); var Vertexes: array [0..1] of {$IFNDEF JEDIAPI}TGMTriVertexRec{$ELSE}TTriVertex{$ENDIF}; RGradient: GRADIENT_RECT; function WordColor(Value: Byte): Word; begin Result := Round((Value / $FF) * $FF00); end; begin Vertexes[0] := GMTriVertex(ARect.TopLeft, WordColor(GetRValue(Color1)), WordColor(GetGValue(Color1)), WordColor(GetBValue(Color1))); Vertexes[1] := GMTriVertex(ARect.BottomRight, WordColor(GetRValue(Color2)), WordColor(GetGValue(Color2)), WordColor(GetBValue(Color2))); RGradient.UpperLeft := 0; RGradient.LowerRight := 1; GMAPICheckObj('GradientFill', '', GetLastError, {$IFNDEF JEDIAPI}GMGradientFill{$ELSE}GradientFill{$ENDIF} (ADC, @Vertexes[0], 2, @RGradient, 1, cFill[Direction])); end; procedure GMGlassFillRect(const ADC: HDC; const ARect: TRect; const AColors: array of COLORREF); //const clTop, clMidHi, clMidLo, clBottom, clCorner: COLORREF); var m: LongInt; begin m := GMRectSize(ARect).y div 2; with ARect do begin GMGradientFillRect(ADC, AColors[0], AColors[1], GMRect(Left, Top, Right, Top + m), d2dVertical); GMGradientFillRect(ADC, AColors[2], AColors[3], GMRect(Left, Top + m, Right, Bottom), d2dVertical); end; {with ARect do begin GMGradientFillRect(ADC, clTop, clMidHi, GMRect(Left, Top, Right, Top + m), d2dVertical); GMGradientFillRect(ADC, clMidLo, clBottom, GMRect(Left, Top + m, Right, Bottom), d2dVertical); end;} end; procedure GMGlassFillRectSimple(const ADC: HDC; const ARect: TRect; const ADarkestColor: COLORREF); //var MidColor: COLORREF; begin //MidColor := GMChangeColorLightness(ADarkestColor, 150); GMGlassFillRect(ADC, ARect, [clWhite, GMChangeColorLightness(ADarkestColor, 100), ADarkestColor, GMChangeColorLightness(ADarkestColor, 150)]); end; {procedure GMSetCornerPixels(const ADC: HDC; const ARect: TRect; const AColor: COLORREF); begin with ARect do begin SetPixel(ADC, Left, Top, AColor); SetPixel(ADC, Right-1, Top, AColor); SetPixel(ADC, Right-1, Bottom-1, AColor); SetPixel(ADC, Left, Bottom-1, AColor); end; end;} { ------------------------- } { ---- Child layouting ---- } { ------------------------- } function GMCalcBoundingChildHeight(const AContainedAreas: IGMObjArrayCollection): LongInt; var i: LongInt; rCtl: TRect; childArea: IGMUiArea; edgeAlign: TEdgesAlign; begin Result := 0; if AContainedAreas = nil then Exit; // // If both horizontal edges are aligned the control cannot dictate it's height! // for i:=0 to AContainedAreas.Count-1 do if GMGetInterface(AContainedAreas[i], IGMUiArea, childArea) and childArea.Visible then begin edgeAlign := childArea.AreaAlign.EdgeAlign; if ((edgeAlign[edgTop] <> ealAligned) or ((edgeAlign[edgBottom] <> ealAligned))) then begin rCtl := childArea.LayoutBounds; if (edgeAlign[edgBottom] <> ealAligned) then Result := Max(Result, rCtl.Bottom) else Result := Max(Result, rCtl.Bottom - rCtl.Top); // <- rCtl.Top may be negative! end; end; end; function GMCalcBoundingChildWidth(const AContainedAreas: IGMObjArrayCollection): LongInt; var i: LongInt; rCtl: TRect; childArea: IGMUiArea; edgeAlign: TEdgesAlign; begin Result := 0; if AContainedAreas = nil then Exit; // // If both vertical edges are aligned the control cannot dictate it's width! // for i:=0 to AContainedAreas.Count-1 do if GMGetInterface(AContainedAreas[i], IGMUiArea, childArea) and childArea.Visible then begin edgeAlign := childArea.AreaAlign.EdgeAlign; if ((edgeAlign[edgLeft] <> ealAligned) or ((edgeAlign[edgRight] <> ealAligned))) then begin rCtl := childArea.LayoutBounds; if (edgeAlign[edgRight] <> ealAligned) then Result := Max(Result, rCtl.Right) else Result := Max(Result, rCtl.Right - rCtl.Left); // <- rCtl.Left may be negative! end; end; end; function GMCalcBoundingHeight(const AContainingArea: TGMUiAreaBase; const ANewSize: TPoint; const ARelayout: Boolean): LongInt; begin if AContainingArea = nil then Exit(0); if ARelayout then begin //AContainingArea.FLayoutBounds.Left := 0; // Layouting is always relative to parent AContainingArea client rect if AContainingArea.FLayoutBounds.Right <> AContainingArea.FLayoutBounds.Left + ANewSize.x then begin AContainingArea.FLastLayoutSize.x := cInvalidLayoutVal; AContainingArea.FLayoutBounds.Right := AContainingArea.FLayoutBounds.Left + ANewSize.x; end; AContainingArea.LayoutContainedAreasIfNeeded(False); end; // Layouting offset already includes top frame Result := GMCalcBoundingChildHeight(AContainingArea.ContainedAreas) + GMFrameExtent(AContainingArea.Frame, [edgTop, edgBottom]).y; end; function GMCalcBoundingWidth(const AContainingArea: TGMUiAreaBase; const ANewSize: TPoint; const ARelayout: Boolean): LongInt; begin if AContainingArea = nil then Exit(0); if ARelayout then begin //AContainingArea.FLayoutBounds.Top := 0; // Layouting is always relative to parent AContainingArea client rect if AContainingArea.FLayoutBounds.Bottom <> AContainingArea.FLayoutBounds.Top + ANewSize.y then begin AContainingArea.FLastLayoutSize.y := cInvalidLayoutVal; AContainingArea.FLayoutBounds.Bottom := AContainingArea.FLayoutBounds.Top + ANewSize.y; end; AContainingArea.LayoutContainedAreasIfNeeded(False); end; // Layouting offset already includes left frame Result := GMCalcBoundingChildWidth(AContainingArea.ContainedAreas) + GMFrameExtent(AContainingArea.Frame, [edgLeft, edgRight]).x; end; { ---------------------------- } { ---- Standard Layouting ---- } { ---------------------------- } function GMAdjustRestRect(const AreaAlign: TGMAreaAlignRec; const RCtl, RRest, RSpace: TRect): TRect; begin Result := RRest; with AreaAlign do begin if (EdgeAlign[edgTop] = ealAligned) and ((EdgeAlign[edgBottom] <> ealAligned) or (RSpace.Bottom >= cQAlign)) and AreaAlign.ShrinkRestY then Result.Top := Max(Result.Top, RCtl.Bottom); if (EdgeAlign[edgBottom] = ealAligned) and ((EdgeAlign[edgTop] <> ealAligned) or (RSpace.Top >= cQAlign)) and AreaAlign.ShrinkRestY then Result.Bottom := Min(Result.Bottom, RCtl.Top); if (EdgeAlign[edgLeft] = ealAligned) and ((EdgeAlign[edgRight] <> ealAligned) or (RSpace.Right >= cQAlign)) and AreaAlign.ShrinkRestX then Result.Left := Max(Result.Left, RCtl.Right); if (EdgeAlign[edgRight] = ealAligned) and ((EdgeAlign[edgLeft] <> ealAligned) or (RSpace.Left >= cQAlign)) and AreaAlign.ShrinkRestX then Result.Right := Min(Result.Right, RCtl.Left); end; end; procedure GMLayoutContainedAreas(const Area: IGMUiArea; const ARepaint: Boolean; const ALayoutEdgeOrderMap: TGMLayoutEdgeOrderMap); //: TPoint; const cFixedOrAligned: array [Boolean] of TEdgeAlign = (ealFixed, ealAligned); var i: LongInt; childArea: IGMUiArea; rRest, rBounds, rSpace: TRect; Edge: TEdge; childAreaAlign: TGMAreaAlignRec; clientAreas: array of IGMUiArea; usedQAlignX, UsedQAlignY: Double; isWrapAlgnX: Boolean; function QAlignSize(const RestSize, Quota: LongInt; var UsedQuota: Double): LongInt; function IntAsDouble(const Value: LongInt): Double; begin Result := Value; end; begin if UsedQuota >= 1 then begin Result := 0; Exit; end; Result := MulDiv(Round(IntAsDouble(RestSize) / (1 - UsedQuota)), Min(Quota, cQAlignDivisor), cQAlignDivisor); UsedQuota := UsedQuota + (Min(Quota, cQAlignDivisor) / cQAlignDivisor); end; begin //Result := cNullPoint; if (Area = nil) or Area.ContainedAreas.IsEmpty then Exit; // <- nothing to layout rRest := GMRect(cNullPoint, Area.clientAreaSize); usedQAlignX := 0; UsedQAlignY := 0; for i:=0 to Area.ContainedAreas.Count-1 do if (Area.ContainedAreas[i] <> nil) and Area.ContainedAreas[i].GetInterface(IGMUiArea, childArea) and childArea.ParticipateInLayouting then begin rSpace := childArea.LayoutSpace; childAreaAlign := childArea.AreaAlign; if GMIsEqualAlign(childAreaAlign, cClientAligned) and (rSpace.Left < cQAlign) and (rSpace.Top < cQAlign) and (rSpace.Right < cQAlign) and (rSpace.Bottom < cQAlign) then begin SetLength(clientAreas, Length(clientAreas) + 1); clientAreas[High(clientAreas)] := childArea; end else begin rBounds := childArea.LayoutBounds; isWrapAlgnX := False; // // Change wrap alignment to either fixed or aligned depending on the size // if (childAreaAlign.EdgeAlign[edgRight] = ealWrap) then begin childAreaAlign.EdgeAlign[edgRight] := cFixedOrAligned[rBounds.Left + childArea.CalculateWidth(GMRectSize(rBounds)) > rRest.Right - rSpace.Right]; isWrapAlgnX := childAreaAlign.EdgeAlign[edgRight] = ealAligned; end; if (childAreaAlign.EdgeAlign[edgLeft] = ealWrap) then begin childAreaAlign.EdgeAlign[edgLeft] := cFixedOrAligned[rBounds.Right - childArea.CalculateWidth(GMRectSize(rBounds)) < rRest.Left + rSpace.Left]; isWrapAlgnX := childAreaAlign.EdgeAlign[edgLeft] = ealAligned; end; for Edge:=Low(Edge) to High(Edge) do case childAreaAlign.EdgeAlign[ALayoutEdgeOrderMap[Edge]] of // ealFixed:; <- Nothing! ealCentered: case ALayoutEdgeOrderMap[Edge] of edgLeft: case childAreaAlign.EdgeAlign[edgRight] of ealCentered: rBounds := GMRectCenterX(rBounds, rRest); ealFixed: OffsetRect(rBounds, ((rRest.Left + rRest.Right) div 2) + rSpace.Left - rBounds.Left, 0); else rBounds.Left := ((rRest.Left + rRest.Right) div 2) + rSpace.Left; end; edgRight: case childAreaAlign.EdgeAlign[edgLeft] of ealCentered: rBounds := GMRectCenterX(rBounds, rRest); ealFixed: OffsetRect(rBounds, ((rRest.Left + rRest.Right) div 2) - rSpace.Right - rBounds.Right, 0); else rBounds.Right := ((rRest.Left + rRest.Right) div 2) - rSpace.Right; end; edgTop: case childAreaAlign.EdgeAlign[edgBottom] of ealCentered: rBounds := GMRectCenterY(rBounds, rRest); ealFixed: OffsetRect(rBounds, 0, ((rRest.Top + rRest.Bottom) div 2) + rSpace.Top - rBounds.Top); else rBounds.Top := ((rRest.Top + rRest.Bottom) div 2) + rSpace.Top; end; edgBottom: case childAreaAlign.EdgeAlign[edgTop] of ealCentered: rBounds := GMRectCenterY(rBounds, rRest); ealFixed: OffsetRect(rBounds, 0, ((rRest.Top + rRest.Bottom) div 2) - rSpace.Bottom - rBounds.Bottom); else rBounds.Bottom := ((rRest.Top + rRest.Bottom) div 2) - rSpace.Bottom; end; end; ealAligned: case ALayoutEdgeOrderMap[Edge] of edgLeft: case childAreaAlign.EdgeAlign[edgRight] of ealFixed: OffsetRect(rBounds, rRest.left + rSpace.Left - rBounds.Left, 0); else if rSpace.Left >= cQAlign then rBounds.Left := rRest.Right - QAlignSize(GMRectSize(rRest).x, rSpace.Left, usedQAlignX) else rBounds.Left := rRest.left + rSpace.Left; end; edgTop: case childAreaAlign.EdgeAlign[edgBottom] of ealFixed: OffsetRect(rBounds, 0, rRest.Top + rSpace.Top - rBounds.Top); else if rSpace.Top >= cQAlign then rBounds.Top := rRest.Bottom - QAlignSize(GMRectSize(rRest).y, rSpace.Top, UsedQAlignY) else rBounds.Top := rRest.Top + rSpace.Top; end; edgRight: case childAreaAlign.EdgeAlign[edgLeft] of ealFixed: OffsetRect(rBounds, rRest.Right - rSpace.Right - rBounds.Right, 0); else if rSpace.Right >= cQAlign then rBounds.Right := rRest.Left + QAlignSize(GMRectSize(rRest).x, rSpace.Right, usedQAlignX) else rBounds.Right := rRest.Right - rSpace.Right; end; edgBottom: case childAreaAlign.EdgeAlign[edgTop] of ealFixed: OffsetRect(rBounds, 0, rRest.Bottom - rSpace.Bottom - rBounds.Bottom); else if rSpace.Bottom >= cQAlign then rBounds.Bottom := rRest.Top + QAlignSize(GMRectSize(rRest).y, rSpace.Bottom, UsedQAlignY) else rBounds.Bottom := rRest.Bottom - rSpace.Bottom; end; end; end; // // If the child area does it's calculation itself // if childArea.AutoCalcSize[d2dHorizontal] and not isWrapAlgnX then if childAreaAlign.EdgeAlign[edgRight] in cCalcSizeAlignments then rBounds.Right := rBounds.Left + childArea.CalculateWidth(GMRectSize(rBounds)) else rBounds.Left := rBounds.Right - childArea.CalculateWidth(GMRectSize(rBounds)); if childArea.AutoCalcSize[d2dVertical] then if childAreaAlign.EdgeAlign[edgBottom] in cCalcSizeAlignments then rBounds.Bottom := rBounds.Top + childArea.CalculateHeight(GMRectSize(rBounds)) else rBounds.Top := rBounds.Bottom - childArea.CalculateHeight(GMRectSize(rBounds)); // // If both sides are centered, the complete extent is centered // if (childAreaAlign.EdgeAlign[edgLeft] = ealCentered) and (childAreaAlign.EdgeAlign[edgRight] = ealCentered) then rBounds := GMRectCenterX(rBounds, rRest); if (childAreaAlign.EdgeAlign[edgTop] = ealCentered) and (childAreaAlign.EdgeAlign[edgBottom] = ealCentered) then rBounds := GMRectCenterY(rBounds, rRest); childArea.SetLayoutBounds(rBounds, ARepaint); // <- Setting LayoutBounds will trigger layouting of contained controls if needed! // if rBounds.Right > Result.x then Result.x := rBounds.Right; // if rBounds.Bottom > Result.y then Result.y := rBounds.Bottom; rRest := GMAdjustRestRect(childAreaAlign, rBounds, rRest, rSpace); end; end; // set all client aligned areas to rRest for i:=Low(clientAreas) to High(clientAreas) do begin rSpace := clientAreas[i].LayoutSpace; clientAreas[i].SetLayoutBounds(GMRect(rRest.Left + rSpace.Left, rRest.Top + rSpace.Top, rRest.Right - rSpace.Right, rRest.Bottom - rSpace.Bottom), ARepaint); end; end; procedure GMWrapLayoutContainedAreas(const Area: IGMUiArea; const ARepaint: Boolean; const AHorzAlign: TGMHorizontalAlignment; const AVLineSpace: LongInt); //: TPoint; var i, x, y, w, h, hline: LongInt; childArea: IGMUiArea; rArea, rSpace: TRect; // rChild procedure ResetLine; begin hline := 0; if AHorzAlign = haLeft then x := rArea.Left else x := rArea.Right; end; begin //Result := cNullPoint; if (Area = nil) or Area.ContainedAreas.IsEmpty then Exit; // <- nothing to layout rArea := GMRect(cNullPoint, Area.clientAreaSize); y := rArea.Top; ResetLine; for i:=0 to Area.ContainedAreas.Count-1 do if (Area.ContainedAreas[i] <> nil) and Area.ContainedAreas[i].GetInterface(IGMUiArea, childArea) and childArea.ParticipateInLayouting then begin //rChild := childArea.GetLayoutBounds; rSpace := childArea.LayoutSpace; w := childArea.CalculateWidth(GMPoint(1, 1)); // GMRectSize(rChild) h := childArea.CalculateHeight(GMPoint(1, 1)); if AHorzAlign = haLeft then x := x + w + rSpace.Right else x := x - w - rSpace.Left; hline := Max(hLine, h); if (i > 0) and (x < rArea.Left) or (x > rArea.Right) then // <- i > 0: dont insert new line before first area! begin Inc(y, hLine + AVLineSpace); ResetLine; if AHorzAlign = haLeft then x := x + w + rSpace.Right else x := x - w - rSpace.Left; end; childArea.SetLayoutBounds(GMRect(x, y, x + w, y + h), ARepaint); // <- Setting LayoutBounds will trigger layouting of contained controls if needed! end; end; { -------------------- } { ---- TGMWinMenu ---- } { -------------------- } constructor TGMWinMenu.CreateMenu(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FHandle := {$IFDEF JEDIAPI}jwaWinUser.{$ELSE}Windows.{$ENDIF}CreateMenu; GMApiCheckObj('CreateMenu', '', GetLastError, FHandle <> 0, Self); //CreateEntries; end; constructor TGMWinMenu.CreatePopupMenu(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FHandle := {$IFDEF JEDIAPI}jwaWinUser.{$ELSE}Windows.{$ENDIF}CreatePopupMenu; GMApiCheckObj('CreatePopupMenu', '', GetLastError, FHandle <> 0, Self); //CreateEntries; end; destructor TGMWinMenu.Destroy; begin if FHandle <> 0 then begin DestroyMenu(FHandle); FHandle := 0; end; inherited Destroy; end; function TGMWinMenu.GetHandle: THandle; begin Result := FHandle; end; {procedure TGMWinMenu.CreateEntries; begin end;} { -------------------------- } { ---- TGMWndMessageObj ---- } { -------------------------- } //constructor TGMWndMessageObj.Create(const AWndMessage: TGMWndMsg; const ARefLifeTime: Boolean); //begin // inherited Create(ARefLifeTime); // FWndMessage := AWndMessage; //end; // //function TGMWndMessageObj.GetWndMessage: TGMWndMsg; //begin // Result := FWndMessage; //end; // //function TGMWndMessageObj.HashCode: TGMHashCode; //begin // Result := FWndMessage; //end; { ------------------------ } { ---- TGMWindowClass ---- } { ------------------------ } constructor TGMWindowClass.Create(const AWndClassName: TGMString; const AClassStyle: DWORD; const AIcon: HICON; const ACursor: HCURSOR; const ABkgndBrush: HBRUSH; const AMenuName: TGMString; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FWndClassName := AWndClassName; FMenuName := AMenuName; if Length(FWndClassName) > 0 then FWndClass.lpszClassName := PGMChar(FWndClassName); if Length(FMenuName) > 0 then FWndClass.lpszMenuName := PGMChar(FMenuName); FWndClass.cbSize := SizeOf(FWndClass); FWndClass.Style := AClassStyle; FWndClass.hIcon := AIcon; FWndClass.hCursor := ACursor; FWndClass.hbrBackground := ABkgndBrush; FWndClass.hInstance := {$IFDEF JEDIAPI}{$IFDEF FPC}System.{$ELSE}SysInit.{$ENDIF}{$ENDIF}HInstance; FWndClass.lpfnWndProc := {$IFNDEF JEDIAPI}@{$ENDIF}DefWindowProc; // GMStdWndProc; <- does not work FRegisteredClass := {$IFDEF JEDIAPI}jwaWinUser.{$ELSE}Windows.{$ENDIF}RegisterClassEx(FWndClass); GMAPICheckObj('RegisterClassEx', '', GetLastError, FRegisteredClass <> 0, Self); end; destructor TGMWindowClass.Destroy; begin if ClassIsRegistered then begin {$IFDEF JEDIAPI}jwaWinUser.{$ELSE}Windows.{$ENDIF}UnregisterClass(PGMChar(FWndClassName), {$IFDEF JEDIAPI}{$IFDEF FPC}System.{$ELSE}SysInit.{$ENDIF}{$ENDIF}HInstance); FRegisteredClass := 0; end; inherited Destroy; end; function TGMWindowClass.ClassIsRegistered: Boolean; begin Result := FRegisteredClass <> 0; end; function TGMWindowClass.GetName: TGMString; begin Result := FWndClassName; end; { --------------------------- } { ---- TGMAreaMultiFrame ---- } { --------------------------- } constructor TGMAreaMultiFrame.Create(const AReflifeTime: Boolean); begin inherited Create(AReflifeTime); FFrameKind := frkNone; FInnerFrame := frsNone; FOuterFrame := frsLowered; FFramedEdges := CAllEdges; FOuterSpace := 0; FFrameLook3D := True; end; //function TGMAreaMultiFrame.QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} IID: TGUID; out Intf): HResult; //var PIUnkOwner: IUnknown; //begin //Result := inherited QueryInterface(IID, Intf); //if (Result <> S_OK) and (FOwner <> nil) and FOwner.GetInterface(IUnknown, PIUnkOwner) then // Result := PIUnkOwner.QueryInterface(IID, Intf); //end; // //function TGMAreaMultiFrame._AddRef: LongInt; //var PIUnkOwner: IUnknown; //begin //if (FOwner <> nil) and FOwner.GetInterface(IUnknown, PIUnkOwner) then // Result := PIUnkOwner._AddRef //else // Result := inherited _AddRef; //end; // //function TGMAreaMultiFrame._Release: LongInt; //var PIUnkOwner: IUnknown; //begin //if (FOwner <> nil) and FOwner.GetInterface(IUnknown, PIUnkOwner) then // Result := PIUnkOwner._Release //else // Result := inherited _Release; //end; function TGMAreaMultiFrame.EdgeWidth: LongInt; begin Result := CFrameLines[InnerFrame] + CFrameLines[OuterFrame]; end; function TGMAreaMultiFrame.CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale): TRect; var EdgeSize: LongInt; begin Result := GMInflateRect(ABoundsRect, -OuterSpace * AScale, -OuterSpace * AScale); if FFrameKind = frkNone then Exit; EdgeSize := EdgeWidth * AScale; if edgLeft in FFramedEdges then Inc(Result.Left, EdgeSize); if edgTop in FFramedEdges then Inc(Result.Top, EdgeSize); if edgRight in FFramedEdges then Dec(Result.Right, EdgeSize); if edgBottom in FFramedEdges then Dec(Result.Bottom, EdgeSize); end; {function TGMAreaMultiFrame.Extend(const AEdges: TEdges): TPoint; var EdgeW: LongInt; Edge: TEdge; EdgesX, EdgesY: TEdges; begin Result := GMPoint(OuterSpace shl 1, OuterSpace shl 1); if FFrameKind = frkNone then Exit; EdgeW := EdgeWidth; // + OuterSpace EdgesX := cEdgesX * AEdges * FFramedEdges; EdgesY := cEdgesY * AEdges * FFramedEdges; for Edge := Low(Edge) to High(Edge) do begin if (Edge in EdgesX) then Inc(Result.x, EdgeW); if (Edge in EdgesY) then Inc(Result.y, EdgeW); end; end;} procedure TGMAreaMultiFrame.DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); const cInnerStyles: array [TFrameShape] of LongInt = (0, BDR_SUNKENINNER, BDR_RAISEDINNER, 0); cOuterStyles: array [TFrameShape] of LongInt = (0, BDR_SUNKENOUTER, BDR_RAISEDOUTER, 0); cEdgeStyles: array [TFrameKind] of LongInt = (0, 0, BF_SOFT, BF_FLAT); cCtl3DStyles: array [Boolean] of LongInt = (BF_MONO, 0); var RFrame: TRect; Brush, RgnOuter, RgnInner: IGMGetHandle; RBounds: TRect; begin // // Outerspace needs to be drawn even if (FrameKind = frkNone) or (FramedEdges = []) // if (ADC = 0) or (ARegion = 0) or (GetRgnBox(ARegion, RBounds) in [ERROR, NULLREGION]) then Exit; RFrame := GMInflateRect(RBounds, -OuterSpace, -OuterSpace); if (FrameKind <> frkNone) and (FramedEdges <> []) then {$IFDEF FPC} DrawEdge(ADC, RFrame, cInnerStyles[InnerFrame] or cOuterStyles[OuterFrame], LPByte(@FFramedEdges)^ or cEdgeStyles[FrameKind] or cCtl3DStyles[FrameLook3D]); {$ELSE} DrawEdge(ADC, RFrame, CInnerStyles[InnerFrame] or COuterStyles[OuterFrame], Byte(FramedEdges) or CEdgeStyles[FrameKind] or CCtl3DStyles[FrameLook3D]); {$ENDIF} // Fill space not covered by frame if OuterSpace = 0 then Exit; RgnOuter := TGMGdiRegion.CreateRect(0, RBounds); RgnInner := TGMGdiRegion.CreateRect(0, RFrame); if CombineRgn(RgnOuter.Handle, RgnOuter.Handle, RgnInner.Handle, RGN_DIFF) in [ERROR, NULLREGION] then Exit; Brush := TGMGdiBrush.Create(0, AColor); FillRgn(ADC, RgnOuter.Handle, Brush.Handle); end; function TGMAreaMultiFrame.GetFrameKind: TFrameKind; begin Result := FFrameKind; end; function TGMAreaMultiFrame.GetInnerFrame: TFrameShape; begin Result := FInnerFrame; end; function TGMAreaMultiFrame.GetOuterFrame: TFrameShape; begin Result := FOuterFrame; end; function TGMAreaMultiFrame.GetFramedEdges: TEdges; begin Result := FFramedEdges; end; function TGMAreaMultiFrame.GetOuterSpace: LongInt; begin Result := FOuterSpace; end; function TGMAreaMultiFrame.GetFrameLook3D: Boolean; begin Result := FFrameLook3D; end; procedure TGMAreaMultiFrame.SetFrameKind(const Value: TFrameKind); begin FFrameKind := Value; end; procedure TGMAreaMultiFrame.SetInnerFrame(const Value: TFrameShape); begin FInnerFrame := Value; end; procedure TGMAreaMultiFrame.SetOuterFrame(const Value: TFrameShape); begin FOuterFrame := Value; end; procedure TGMAreaMultiFrame.SetFramedEdges(const Value: TEdges); begin FFramedEdges := Value; end; procedure TGMAreaMultiFrame.SetOuterSpace(const Value: LongInt); begin FOuterSpace := Value; end; procedure TGMAreaMultiFrame.SetFrameLook3D(const Value: Boolean); begin FFrameLook3D := Value; end; { ---------------------------- } { ---- TGMAreaSimpleFrame ---- } { ---------------------------- } constructor TGMAreaSimpleFrame.Create(const AEdgeWidth: LongInt; const AFramedEdges: TEdges; const AReflifeTime: Boolean); begin inherited Create(AReflifeTime); FFramedEdges := AFramedEdges; FEdgeWidth := AEdgeWidth; end; function TGMAreaSimpleFrame.CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale): TRect; begin //Result := GMInflateRect(ABoundsRect, FEdgeWidth * -AScale, FEdgeWidth * -AScale); Result := ABoundsRect; if edgLeft in FFramedEdges then Inc(Result.Left, FEdgeWidth); if edgTop in FFramedEdges then Inc(Result.Top, FEdgeWidth); if edgRight in FFramedEdges then Dec(Result.Right, FEdgeWidth); if edgBottom in FFramedEdges then Dec(Result.Bottom, FEdgeWidth); end; procedure TGMAreaSimpleFrame.DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); var brush, rgnInner: IGMGetHandle; rBounds: TRect; calcRegion: IGMCalcAreaRegion; // FrmCol: COLORREF; begin if (ADC = 0) or (ARegion = 0) or (GetRgnBox(ARegion, rBounds) in [ERROR, NULLREGION]) then Exit; //RgnOuter := TGMGdiRegion.CreateRect(0, rBounds); if GMGetInterface(AArea, IGMCalcAreaRegion, calcRegion) then rgnInner := calcRegion.CreateAreaRegion(CalculateClientRect(rBounds), arkClient) else rgnInner := TGMGdiRegion.CreateRect(0, CalculateClientRect(rBounds)); if CombineRgn(rgnInner.Handle, ARegion, rgnInner.Handle, RGN_DIFF) in [ERROR, NULLREGION] then Exit; //if FFrameColor = CLR_INVALID then FrmCol := AColor else FrmCol := FFrameColor; brush := TGMGdiBrush.Create(0, AColor); FillRgn(ADC, rgnInner.Handle, brush.Handle); end; { -------------------------- } { ---- TGMAreaFakeFrame ---- } { -------------------------- } procedure TGMAreaFakeFrame.DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); begin // Nothing! end; { ---------------------------- } { ---- TGMAreaRegionFrame ---- } { ---------------------------- } constructor TGMAreaRegionFrame.Create(const AFrameWidth, AFrameHeight: LongInt; const AReflifeTime: Boolean); begin inherited Create(AReflifeTime); FFrameWidth := AFrameWidth; FFrameHeight := AFrameHeight; end; function TGMAreaRegionFrame.CalculateClientRect(const ABoundsRect: TRect; const AScale: TFrameScale): TRect; begin Result := GMInflateRect(ABoundsRect, -FFrameWidth, -FFrameHeight); end; procedure TGMAreaRegionFrame.DrawFrame(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const AColor: COLORREF); var Brush: IGMGetHandle; begin Brush := TGMGdiBrush.Create(0, AColor); FrameRgn(ADC, ARegion, Brush.Handle, FFrameWidth, FFrameHeight); end; { ------------------------- } { ---- TGMAreaLayouter ---- } { ------------------------- } {constructor TGMAreaLayouter.Create(const AOwner: TObject; const AReflifeTime: Boolean); begin inherited Create(AReflifeTime); FChildList := TGMObjArrayCollection.Create; FOwner := AOwner; end; destructor TGMAreaLayouter.Destroy; begin GMFreeAndNil(FChildList); inherited Destroy; end; function TGMAreaLayouter.SubtractContainedAreas(const HFillRgn: HRGN): Boolean; var i: LongInt; PIArea: IGMUiArea; RgnChild: IGMGetHandle; begin Result := True; if HFillRgn = 0 then Exit; for i:=0 to ContainedAreas.Count-1 do if (ContainedAreas[i] <> nil) and ContainedAreas[i].GetInterface(IGMUiArea, PIArea) and PIArea.Visible and (PIArea.PaintsComplete or PIArea.FillsComplete) then begin RgnChild := TGMGdiRegion.CreateRect(0, PIArea.CalculateSurfaceRect(PIArea.LayoutBounds)); if CombineRgn(HFillRgn, HFillRgn, RgnChild.Handle, RGN_DIFF) = NULLREGION then begin Result := False; Break; end; end; end; procedure TGMAreaLayouter.PaintContainedAreas(const ADC: HDC); var i: LongInt; PIPaint: IGMPaint; PIArea: IGMUiArea; begin if ADC = 0 then Exit; for i:=0 to ContainedAreas.Count-1 do // Paint only windowless controls here, windows will receive their own WM_PAINT from the system if (ContainedAreas[i] <> nil) and ContainedAreas[i].GetInterface(IGMUiArea, PIArea) and PIArea.Visible and not GMAreaHasWndHandle(ContainedAreas[i]) and ContainedAreas[i].GetInterface(IGMPaint, PIPaint) then PIPaint.Paint(ADC); end; function TGMAreaLayouter.AreaContainingPoint(const APoint: TPoint): TObject; var i: LongInt; PIArea: IGMUiArea; begin Result := nil; for i:=0 to ContainedAreas.Count-1 do if (ContainedAreas[i] <> nil) and not GMAreaHasWndHandle(ContainedAreas[i]) and ContainedAreas[i].GetInterface(IGMUiArea, PIArea) and PIArea.Visible and PIArea.PointInsideArea(APoint) then begin Result := PIArea.AreaContainingPoint(APoint); Break; end; end;} { ----------------------------- } { ---- TGMAreaRegionFiller ---- } { ----------------------------- } procedure TGMAreaRegionFiller.Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); begin FillRgn(ADC, ARegion, ABrush); end; { --------------------------- } { ---- TGMAreaRectFiller ---- } { --------------------------- } procedure TGMAreaRectFiller.Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); var RegionBounds: TRect; begin if (ARegion <> 0) and not (GetRgnBox(ARegion, RegionBounds) in [ERROR, NULLREGION]) then FillRect(ADC, RegionBounds, ABrush); end; { ---------------------------- } { ---- TGMGlassLookFiller ---- } { ---------------------------- } constructor TGMGlassLookFiller.Create(const AColors: array of COLORREF; const ARefLifeTime: Boolean); var i: LongInt; begin inherited Create(ARefLifeTime); SetLength(FColors, Length(AColors)); for i:=Low(AColors) to High(AColors) do FColors[i] := GMRGBColor(AColors[i]); end; procedure TGMGlassLookFiller.Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); var RegionBounds: TRect; begin if (ARegion <> 0) and not (GetRgnBox(ARegion, RegionBounds) in [ERROR, NULLREGION]) then GMGlassFillRect(ADC, RegionBounds, FColors); end; { ---------------------------------- } { ---- TGMSimpleGlassLookFiller ---- } { ---------------------------------- } constructor TGMSimpleGlassLookFiller.Create(const ARefLifeTime: Boolean); // const AColor: COLORREF; begin inherited Create(ARefLifeTime); //FColor := GMRGBColor(AColor); end; procedure TGMSimpleGlassLookFiller.Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); var RegionBounds: TRect; color: COLORREF; begin if AArea is TGMUiAreaBase then color := TGMUiAreaBase(AArea).BkgndColor else color := clrGlassBlue; // cDfltColor; if (ARegion <> 0) and not (GetRgnBox(ARegion, RegionBounds) in [ERROR, NULLREGION]) then GMGlassFillRectSimple(ADC, RegionBounds, color); // FColor end; { ------------------------------- } { ---- TGMAreaGradientFiller ---- } { ------------------------------- } constructor TGMAreaGradientFiller.Create(const ADirection: TGM2DDirection; const AColors: array of COLORREF; const ARefLifeTime: Boolean); //var i: LongInt; begin inherited Create(AColors, ARefLifeTime); //SetLength(FColors, Length(AColors)); //for i:=Low(AColors) to High(AColors) do FColors[i] := GMRGBColor(AColors[i]); FDirection := ADirection; end; procedure TGMAreaGradientFiller.Paint(const AArea: TObject; const ADC: HDC; const ARegion: HRGN; const ABrush: HBRUSH); var RegionBounds: TRect; begin if (ARegion <> 0) and not (GetRgnBox(ARegion, RegionBounds) in [ERROR, NULLREGION]) then GMGradientFillRect(ADC, FColors[0], FColors[1], RegionBounds, FDirection); end; { ----------------------- } { ---- TGMUiAreaBase ---- } { ----------------------- } constructor TGMUiAreaBase.Create(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); // // Sorting OwnedAreas for faster pointer lookup would change deletion order. // TGMUiAreaBase seems to be safe against this but it dont feels like a good idea. // AcceptDuplicates should be false since this area would be freed twice -> invlid pointer operation. // But with AcceptDuplicates=false a duplicate addition would be freed immediately which will propably // lead to an acces violation too. Not very much better .. // FOwnedAreas := TGMObjArrayCollection.Create(True, True, False, nil, True); // GMCompareByInstance // // Dont sort contained ares for faster pointer lookup, because insertion order matters in layouting! // AcceptDuplicates should be false but this will be slower because pointer lookup is needed then. // FContainedAreas := TGMObjArrayCollection.Create(False, True, False, nil, True); // GMCompareByInstance InvalidateCachedLayoutValues; end; constructor TGMUiAreaBase.Create(const AParent: TObject; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ABkgndColor: COLORREF; const AVisible: Boolean; const ARefLifeTime: Boolean); var Edge: TEdge; procedure SetupEdgeSpace(const Edge: TEdge); begin case Edge of edgLeft: begin FLayoutSpace.Left := APosition.Left; FLayoutBounds.Left := 0; end; edgTop: begin FLayoutSpace.Top := APosition.Top; FLayoutBounds.Top := 0; end; edgRight: begin FLayoutSpace.Right := APosition.Right; FLayoutBounds.Right := 0; end; edgBottom: begin FLayoutSpace.Bottom := APosition.Bottom; FLayoutBounds.Bottom := 0; end; end; end; begin {inherited} Create(ARefLifeTime); // <- No "inherited" here => route through virtual call hirarchy FVisible := AVisible; FParent := AParent; FBkgndColor := ABkgndColor; FAreaAlign := AAreaAlign; FLayoutBounds := APosition; for Edge:=Low(Edge) to High(Edge) do case AAreaAlign.EdgeAlign[Edge] of {if AAreaAlign.EdgeAlign[Edge] = ealAligned then} ealAligned, ealWrap: SetupEdgeSpace(Edge); ealCentered: case Edge of edgLeft: if (AAreaAlign.EdgeAlign[edgRight] <> ealCentered) then SetupEdgeSpace(Edge); edgTop: if (AAreaAlign.EdgeAlign[edgBottom] <> ealCentered) then SetupEdgeSpace(Edge); edgRight: if (AAreaAlign.EdgeAlign[edgLeft] <> ealCentered) then SetupEdgeSpace(Edge); edgBottom: if (AAreaAlign.EdgeAlign[edgTop] <> ealCentered) then SetupEdgeSpace(Edge); end; end; FAutoCalcSize[d2dHorizontal] := GMIsAutoCalcWidth(FAreaAlign.EdgeAlign, FLayoutBounds); FAutoCalcSize[d2dVertical] := GMIsAutoCalcHeight(FAreaAlign.EdgeAlign, FLayoutBounds); if (Parent is TGMUiAreaBase) and IsLayoutChild then TGMUiAreaBase(Parent).ContainedAreas.Add(Self); end; destructor TGMUiAreaBase.Destroy; //var clssName: TGMString; //var Dlg: TGMDlgWindow; procedure ResetActiveControl; // Dont use interfaces here when Walking Parents -> destructor stack overflow! // Another solution would be to add an artificial reference during destructor call var prnt: TObject; begin prnt := Parent; while prnt is TGMUiAreaBase do begin if not TGMUiAreaBase(prnt).IsLayoutChild and (prnt is TGMDlgWindow) and (TGMDlgWindow(prnt).ActiveControl = Self) then TGMDlgWindow(prnt).ActiveControl := nil; prnt := TGMUiAreaBase(prnt).Parent; end; end; begin // // Walking Parents by getting interfaces here may lead to stack overflow! // //if GMFindParentObj(Self, TGMDlgWindow, Dlg) and (Dlg.ActiveControl = Self) then Dlg.ActiveControl := nil; ResetActiveControl; // always try to remove, even if not IsLayoutChild! if vGMDropTargetArea = Self then vGMDropTargetArea := nil; if vGMKeyboardFocusArea = Self then vGMKeyboardFocusArea := nil; if vGMMouseInsideArea = Self then vGMMouseInsideArea := nil; if vGMPopupArea = Self then vGMPopupArea := nil; if vGMMouseCaptureArea = Self then GMReleaseMouseCapture; // <- sets vGMMouseCaptureArea := nil //clssName := ClassName; if (Parent is TGMUiAreaBase) and (TGMUiAreaBase(Parent).ContainedAreas <> nil) then TGMUiAreaBase(Parent).ContainedAreas.RemoveByKey(Self); //SetParent(nil, False); if FOwnedAreas <> nil then FOwnedAreas.Clear(False); // <- FOwnedAreas may be nil if there is an exception in the constructor of a derived calss before our constructor has been called via "inherited Carete(...)" FOwnedAreas := nil; // <- Area destructors will remove itself from our ContainedAreas list! inherited Destroy; end; //function TGMUiAreaBase.QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} IID: TGUID; out Intf): HResult; //var Frm: IGMAreaFrameDrawer; //begin //if GMEqualGuids(IID, IGMMultiFrameProperties) or GMEqualGuids(IID, IGMAreaFrameDrawer) then // // NOTE: Use FFrame member directly here! // begin Frm := FFrame; if Frm = nil then Result := E_NOINTERFACE else Result := Frm.QueryInterface(IID, Intf); end //else Result := inherited QueryInterface(IID, Intf); //end; //function TGMUiAreaBase.GetAutoCalcHeight: Boolean; //begin //Result := FAutoCalcHeight; //end; // //function TGMUiAreaBase.GetAutoCalcWidth: Boolean; //begin //Result := FAutoCalcWidth; //end; function TGMUiAreaBase.GetAutoCalcSize(const ADirection: TGM2DDirection): Boolean; begin Result := FAutoCalcSize[ADirection]; end; procedure TGMUiAreaBase.SetAutoCalcSize(const ADirection: TGM2DDirection; const AValue: Boolean); begin FAutoCalcSize[ADirection] := AValue; end; function TGMUiAreaBase.GetContainedAreas: IGMObjArrayCollection; begin Result := FContainedAreas; end; function TGMUiAreaBase.GetOwnedAreas: IGMObjArrayCollection; begin Result := FOwnedAreas; end; function TGMUiAreaBase.OwnArea(const AArea: TObject): TObject; begin if AArea <> nil then Result := OwnedAreas.Add(AArea) else Result := nil; end; function TGMUiAreaBase.GetSizeContraints: TGMSizeConstraintsRec; begin Result := FSizeConstraints; end; procedure TGMUiAreaBase.SetSizeContraints(const AValue: TGMSizeConstraintsRec); begin FSizeConstraints := AValue; end; function TGMUiAreaBase.GetEdgePosition(const AEdge: TEdge): LongInt; begin Result := PEdgeRectValue(@FLayoutBounds)[AEdge]; end; procedure TGMUiAreaBase.SetEdgePosition(const AEdge: TEdge; const AValue: LongInt); begin PEdgeRectValue(@FLayoutBounds)[AEdge] := AValue; end; function TGMUiAreaBase.GetEdgeSpace(const AEdge: TEdge): LongInt; begin Result := PEdgeRectValue(@FLayoutSpace)[AEdge]; end; procedure TGMUiAreaBase.SetEdgeSpace(const AEdge: TEdge; const AValue: LongInt); begin PEdgeRectValue(@FLayoutSpace)[AEdge] := AValue; end; function TGMUiAreaBase.GetFrame: IGMAreaFrameDrawer; begin Result := FFrame; end; procedure TGMUiAreaBase.SetFrame(const AFrame: IGMAreaFrameDrawer); begin FFrame := AFrame; end; function TGMUiAreaBase.GetEnabled: Boolean; stdcall; begin Result := True; end; function TGMUiAreaBase.ProcessHelp(var AHelpInfo: THelpInfo): Boolean; begin Result := False; end; function TGMUiAreaBase.ExecuteOperation(const Operation: LongInt; const Parameter: IUnknown): Boolean; stdcall; begin Result := True; case Operation of Ord(goShow): SetVisible(True); Ord(goHide): SetVisible(False); end; end; procedure TGMUiAreaBase.ScheduleRepaint; var wnd: HWnd; rInvalidate: Trect; begin if not Visible or not GMFindAllocatedParentHandle(Parent, wnd) then Exit; rInvalidate := PaintingRect; InvalidateRect(wnd, @rInvalidate, False); end; procedure TGMUiAreaBase.CreateHandle; var i: LongInt; PIArea: IGMUiArea; begin // Recursive! => Create handles of invisible areas too! for i:=0 to ContainedAreas.Count-1 do if (ContainedAreas[i] <> nil) and ContainedAreas[i].GetInterface(IGMUiArea, PIArea) then PIArea.CreateHandle; end; function TGMUiAreaBase.RootForRelayout: TObject; begin Result := Self; end; procedure TGMUiAreaBase.AssignCtrlColorValues(var Msg: TMessage); begin case Msg.Msg of WM_CTLCOLOR, WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC, WM_CTLCOLOR + WM_APP, WM_CTLCOLORMSGBOX + WM_APP .. WM_CTLCOLORSTATIC + WM_APP: begin SetTextColor(HDC(Msg.WParam), GMRGBColor(FontColor)); if FontBkgndColor = clrTransparent then SetBkMode(HDC(Msg.WParam), TRANSPARENT) else SetBkMode(HDC(Msg.WParam), OPAQUE); if BkgndColor = clrTransparent then Msg.Result := LRESULT(GetStockObject(NULL_BRUSH)) else begin SetBkColor(HDC(Msg.WParam), GMRGBColor(BkgndColor)); Msg.Result := LRESULT(HBkgndBrush); end; end; end; end; procedure TGMUiAreaBase.DispatchMsg(var Msg: TMessage); begin Dispatch(Msg); end; function TGMUiAreaBase.IsDialogKeyMsg(const Msg: TMessage): Boolean; begin Result := ((Msg.Msg = WM_SYSKEYDOWN) or (Msg.Msg = WM_SYSKEYUP) or (Msg.Msg = WM_SYSCHAR) or (Msg.Msg = WM_SYSDEADCHAR)) or (((Msg.Msg = WM_KEYDOWN) or (Msg.Msg = WM_KEYUP) or (Msg.Msg = WM_CHAR)) and (((Msg.WParamLo in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN]) and (GMCallObjWindowProc(Self, WM_GETDLGCODE) and DLGC_WANTARROWS = 0)) or ((Msg.WParamLo = VK_TAB) and (GMCallObjWindowProc(Self, WM_GETDLGCODE) and DLGC_WANTTAB = 0)) or ((Msg.WParamLo = VK_RETURN) and (GMCallObjWindowProc(Self, WM_GETDLGCODE) and DLGC_WANTALLKEYS = 0)) or ((Msg.WParamLo = VK_ESCAPE) and not IsPopupWindow))); end; procedure TGMUiAreaBase.WindowProc(var Msg: TMessage); var targetArea, Dlg: TObject; MousePos: TPoint; // TmpCur: HCursor; //PIArea: IGMUiArea; // Wnd: HWnd; //function DlgTempCursor: HCursor; //var Dlg: TObject; //begin // if GMFindParentDlg(Self, Dlg) and (Dlg is TGMDlgWindow) then // Result := (Dlg as TGMDlgWindow).TempCursor // else // Result := 0; //end; begin case Msg.Msg of //WM_CTLCOLOR, WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC: AssignCtrlColorValues(Msg); // Send WM_CTLCOLORXXXX GMMessages back to the original control to be handled there WM_CTLCOLOR, WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC: with Msg do Result := SendMessage(LParam, Msg + WM_APP, WParam, LParam); WM_CTLCOLOR + WM_APP, WM_CTLCOLORMSGBOX + WM_APP .. WM_CTLCOLORSTATIC + WM_APP: AssignCtrlColorValues(Msg); // WM_SETCURSOR: // begin // TmpCur := DlgTempCursor; // if TmpCur <> 0 then begin SetCursor(TmpCur); Msg.Result := 1; end // else // begin // // NOTE: WM_SETCURSOR GMMessages do not contain mouse position information! // MousePos := GMScreenToClient(Self, GMMousePosition); // targetArea := AreaContainingPoint(MousePos); // if (targetArea <> nil) and (targetArea <> Self) then GMCallObjWindowProc(targetArea, Msg); // if Msg.Result = 0 then DispatchMsg(Msg); // end; // end; WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN: begin if vGMPopupArea <> nil then GMCancelPopup; DispatchMsg(Msg); end; WM_MOUSEFIRST .. WM_MOUSELAST: // NOTE: WM_MOUSEWHEEL redirection to the window beneeth the mouse is done in overridden WindowProc of TGMWindow. begin if vGMMouseCaptureArea <> nil then targetArea := vGMMouseCaptureArea else begin MousePos := SmallPointToPoint(TWMMouse(Msg).Pos); if Msg.Msg = WM_MOUSEWHEEL then MousePos := GMScreenToClient(Self, MousePos); targetArea := AreaContainingPoint(MousePos); if targetArea = nil then targetArea := Self; end; case Msg.Msg of WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN: if (vGMPopupArea <> nil) and not GMIsParentObj(vGMPopupArea, targetArea, True) then GMCancelPopup; end; if {(targetArea = nil) or} (targetArea = Self) then DispatchMsg(Msg) else GMCallObjWindowProc(targetArea, Msg); end; UM_DRAG_QUERYDROP, UM_DRAG_DROPPED: // UM_DRAG_CONTROL begin MousePos := GMPoint(PGMDragMessageRec(@Msg).XPos, PGMDragMessageRec(@Msg).YPos); targetArea := AreaContainingPoint(MousePos); if (targetArea = nil) or (targetArea = Self) then DispatchMsg(Msg) else GMDispatchObjMsg(targetArea, Msg); end; // Scrollbars send WM_CANCELMODE to themself when getting fullsize. // Overriden TGMScrollBar.WindowProc prevents redirection of those GMMessages! WM_KEYFIRST .. WM_KEYLAST: // , WM_SETFOCUS, WM_KILLFOCUS: // , WM_CANCELMODE // if vGMMouseCaptureArea = Self then DispatchMsg(Msg) // else // if vGMMouseCaptureArea <> nil then GMCallObjWindowProc(vGMMouseCaptureArea, Msg) // else if //GMIsInRange(Msg.Msg, WM_KEYFIRST, WM_KEYLAST) and (vGMKeyboardFocusArea <> nil) and (vGMKeyboardFocusArea <> Self) then GMCallObjWindowProc(vGMKeyboardFocusArea, Msg) else // Dont redirect to dialog here via GMCallObjWindowProc -> use GMDispatchObjMsg instead! if IsDialogKeyMsg(Msg) then begin if GMFindParentDlg(Self, Dlg) then GMDispatchObjMsg(Dlg, Msg); end else DispatchMsg(Msg); else DispatchMsg(Msg); end; end; procedure TGMUiAreaBase.UMDragQueryDrop(var Msg: TMessage); begin // if we receive a UM_DRAG_QUERYDROP message any other area must have been left! if (vGMDropTargetArea <> nil) and (vGMDropTargetArea <> Self) then GMCallObjWindowProc(vGMDropTargetArea, UM_DRAG_CONTROL, Ord(drgLeave)); vGMDropTargetArea := Self; end; procedure TGMUiAreaBase.WMSetFocus(var Msg: TWMSetFocus); begin //inherited; vGMKeyboardFocusArea := Self; end; procedure TGMUiAreaBase.WMKillFocus(var Msg: TWMKillFocus); begin //inherited; if vGMKeyboardFocusArea = Self then vGMKeyboardFocusArea := nil; // <- needed if send from other application end; procedure TGMUiAreaBase.WMLButtonDown(var Msg: TWMLButtonDown); begin inherited; if IsTabStop then GMSetFocus(Self); end; procedure TGMUiAreaBase.WMMouseMove(var Msg: TWMMouseMove); var leaveArea: TObject; wnd: HWnd; mouseIsOverUs: Boolean; begin // Mouse Move is relative to Client area -> use PaintingRect here! // Selection of AreaContainingPoint has been done in TGMwindow.WindowProc! // Mouse may have been captured, so consider mouse outside too! mouseIsOverUs := PtInRect(PaintingRect, GMPoint(Msg.XPos, Msg.YPos)); if mouseIsOverUs then // (Msg.XPos, Msg.YPos) begin if not MouseInside then begin leaveArea := vGMMouseInsideArea; vGMMouseInsideArea := Self; // <- make leaveArea.MouseInside return False if leaveArea <> nil then GMCallObjWindowProc(leaveArea, UM_MOUSELEAVE, TMessage(Msg).WParam, TMessage(Msg).LParam); GMCallObjWindowProc(Self, UM_MOUSEENTER, TMessage(Msg).WParam, TMessage(Msg).LParam); if GMFindAllocatedParentHandle(Self, wnd) then SendMessage(wnd, UM_STARTMOUSETRACK, 0, 0); end; end else begin if MouseInside then begin vGMMouseInsideArea := nil; GMCallObjWindowProc(Self, UM_MOUSELEAVE, TMessage(Msg).WParam, TMessage(Msg).LParam); end; end; inherited; end; procedure TGMUiAreaBase.SurfaceOriginChanged; var i: LongInt; //PIOriginChange: IGMSurfaceOriginChanged; begin for i:=0 to ContainedAreas.Count-1 do if ContainedAreas[i] is TGMUiAreaBase then TGMUiAreaBase(ContainedAreas[i]).SurfaceOriginChanged; //if (ContainedAreas[i] <> nil) and ContainedAreas[i].GetInterface(IGMSurfaceOriginChanged, PIOriginChange) then //PIOriginChange.SurfaceOriginChanged; end; procedure TGMUiAreaBase.AfterParentChanged; var i: LongInt; begin for i:=0 to ContainedAreas.Count-1 do if ContainedAreas[i] is TGMUiAreaBase then TGMUiAreaBase(ContainedAreas[i]).AfterParentChanged; end; function TGMUiAreaBase.MouseInside: Boolean; begin Result := vGMMouseInsideArea = Self; end; function TGMUiAreaBase.HasFocus: Boolean; var prntWnd: HWnd; begin Result := (vGMKeyboardFocusArea = Self) and GMFindAllocatedParentHandle(Self, prntWnd) and (prntWnd = GetFocus); end; function TGMUiAreaBase.IsTabStop: Boolean; begin Result := False; end; procedure TGMUiAreaBase.InvalidateCachedLayoutValues; var i: LongInt; //PIOriginChange: IGMSurfaceOriginChanged; begin FLastLayoutSize := GMPoint(cInvalidLayoutVal, cInvalidLayoutVal); FLastLayoutOrigin := GMPoint(cInvalidLayoutVal, cInvalidLayoutVal); for i:=0 to ContainedAreas.Count-1 do if ContainedAreas[i] is TGMUiAreaBase then TGMUiAreaBase(ContainedAreas[i]).InvalidateCachedLayoutValues; end; function TGMUiAreaBase.FontHandle: THandle; begin Result := GetStockObject(DEFAULT_GUI_FONT); // <- Stock objects dont need to be deleted end; function TGMUiAreaBase.FontColor: COLORREF; stdcall; begin if Assigned(OnGetFontColor) then Result := OnGetFontColor else Result := clrWindowText; end; function TGMUiAreaBase.FontBkgndColor: COLORREF; begin Result := BkgndColor; end; function TGMUiAreaBase.GetVisible: Boolean; begin Result := FVisible; end; function TGMUiAreaBase.AreaFiller: IGMAreaFiller; begin Result := GMAreaRegionFiller; end; function TGMUiAreaBase.FrameColor: COLORREF; begin Result := clSilver; // clDkGray; // $e19e82; // cDfltColor; // BKgndColor ? end; function TGMUiAreaBase.IsLayoutChild: Boolean; begin Result := True; end; function TGMUiAreaBase.ParticipateInLayouting: Boolean; begin Result := Visible; end; //function TGMUiAreaBase.ClippedPainting: Boolean; //begin // Result := False; //end; function TGMUiAreaBase.IsPopupWindow: Boolean; begin Result := False; end; function TGMUiAreaBase.HBkgndBrush: THandle; begin if Assigned(OnGetHBkgndBrush) then Result := OnGetHBkgndBrush else Result := 0; if Result = 0 then begin if FBkgndBrush = nil then if BkgndColor = clrTransparent then FBkgndBrush := GMGetCachedBrush(0, BS_NULL) // TGMGdiBrush.Create(0, 0, BS_NULL) else FBkgndBrush := GMGetCachedBrush(BkgndColor); // TGMGdiBrush.Create(0, BkgndColor); Result := FBkgndBrush.Handle; end; end; function TGMUiAreaBase.BkgndColor: COLORREF; stdcall; begin if Assigned(OnGetBkgndColor) then Result := OnGetBkgndColor else Result := FBkgndColor; end; procedure TGMUiAreaBase.SetBkgndColor(const AValue: COLORREF; const ARepaint: Boolean); stdcall; begin if AValue = BkgndColor then Exit; FBkgndColor := AValue; FBkgndBrush := nil; if ARepaint then ScheduleRepaint; end; function TGMUiAreaBase.InternalCalcHeight(const ANewSize: TPoint): LongInt; begin Result := ANewSize.y; end; procedure TGMUiAreaBase.Clear(const ANotify: Boolean); begin // Nothing end; function TGMUiAreaBase.InternalCalcWidth(const ANewSize: TPoint): LongInt; begin Result := ANewSize.x; end; function TGMUiAreaBase.CalculateWidth(const ANewSize: TPoint): LongInt; //var y: LongInt; begin //if FAutoCalcSize[d2dHorizontal] then Result := InternalCalcWidth(GMPoint(ANewSize.x, Max(1, ANewSize.y))) else Result := ANewSize.x; Result := InternalCalcWidth(GMPoint(ANewSize.x, Max(1, ANewSize.y))); //y := Max(1, ANewSize.y); //if y = FCachedCalcWidth.Y then Result := FCachedCalcWidth.x else // begin // Result := InternalCalcWidth(GMPoint(ANewSize.x, y)); // FCachedCalcWidth := GMPoint(Result, y); // end; end; function TGMUiAreaBase.CalculateHeight(const ANewSize: TPoint): LongInt; //var x: LongInt; begin //if FAutoCalcSize[d2dVertical] then Result := InternalCalcHeight(GMPoint(Max(1, ANewSize.x), ANewSize.y)) else Result := ANewSize.y; Result := InternalCalcHeight(GMPoint(Max(1, ANewSize.x), ANewSize.y)); //x := Max(1, ANewSize.x); //if x = FCachedCalcHeight.x then Result := FCachedCalcHeight.y else // begin // Result := InternalCalcHeight(GMPoint(x, ANewSize.y)); // FCachedCalcHeight := GMPoint(x, Result); // end; end; procedure TGMUiAreaBase.SetShowing(const Value: Boolean); begin // Nothing! end; procedure TGMUiAreaBase.InternalSetVisible(const Value: Boolean); // Relayout begin // Nothing! end; procedure TGMUiAreaBase.SetVisible(const AValue: Boolean; const ARelayout: Boolean); begin if AValue = FVisible then Exit; FVisible := AValue; if ARelayout then GMReLayoutContainedAreas(Parent); InternalSetVisible(AValue); if not AValue and IsTabStop and (vGMKeyboardFocusArea = Self) then GMPostSeletNextDlgTabAreaMsg(Self); end; procedure TGMUiAreaBase.SetParentObj(const AValue: TObject; const ARelayout: Boolean); var PIArea: IGMUiArea; begin if FParent = AValue then Exit; if (FParent <> nil) and FParent.GetInterface(IGMUiArea, PIArea) then begin PIArea.ContainedAreas.RemoveByKey(Self); if ARelayout then GMReLayoutContainedAreas(FParent); end; FParent := AValue; if IsLayoutChild and GMGetInterface(AValue, IGMUiArea, PIArea) then begin PIArea.ContainedAreas.Add(Self); if ARelayout then GMReLayoutContainedAreas(AValue); end; AfterParentChanged; //if (Parent is TGMUiAreaBase) and IsLayoutChild then TGMUiAreaBase(Parent).ContainedAreas.Add(Self); //if Parent is TGMUiAreaBase then TGMUiAreaBase(Parent).ContainedAreas.Remove(Self); end; function TGMUiAreaBase.GetAreaAlign: TGMAreaAlignRec; begin Result := FAreaAlign; end; procedure TGMUiAreaBase.SetAreaAilgn(const AAreaAlign: TGMAreaAlignRec); begin FAreaAlign := AAreaAlign; end; function TGMUiAreaBase.GetEdgeAlign(const Edge: TEdge): TEdgeAlign; begin Result := FAreaAlign.EdgeAlign[Edge]; end; procedure TGMUiAreaBase.SetEdgeAlign(const Edge: TEdge; const Value: TEdgeAlign); begin FAreaAlign.EdgeAlign[Edge] := Value; end; function TGMUiAreaBase.GetLayoutSpace: TRect; begin Result := FLayoutSpace; end; procedure TGMUiAreaBase.SetLayoutSpace(const AValue: TRect); begin FLayoutSpace := AValue; end; function TGMUiAreaBase.GetLayoutBounds: TRect; begin Result := FLayoutBounds; end; procedure TGMUiAreaBase.SetLayoutBounds(const AValue: TRect; const ARepaint: Boolean); begin FLayoutBounds := AValue; end; function TGMUiAreaBase.ClientAreaOrigin: TPoint; var prntArea: IGMUiArea; begin Result := GMAddPoints(ScrollOffset, GMCalculateClientRect(Frame, LayoutBounds).TopLeft); if GMGetInterface(Parent, IGMUiArea, prntArea) and prntArea.IsLayoutChild then Result := GMAddPoints(Result, prntArea.ClientAreaOrigin); // <- Recursive! end; function TGMUiAreaBase.ClientAreaSize: TPoint; begin Result := GMRectSize(GMCalculateClientRect(Frame, LayoutBounds)); end; function TGMUiAreaBase.CalculateSurfaceRect(const ARect: TRect): TRect; var prntArea: IGMUiArea; begin Result := ARect; if IsLayoutChild and GMGetInterface(Parent, IGMUiArea, prntArea) then Result := GMMoveRect(Result, prntArea.ClientAreaOrigin); end; function TGMUiAreaBase.PaintingRect: TRect; begin Result := CalculateSurfaceRect(LayoutBounds); end; function TGMUiAreaBase.IsFramed: Boolean; begin Result := GMFrameExtent(FFrame) <> cNullPoint; // <- If FFrame is nil GMFrameExtent will return cNullPoint end; function TGMUiAreaBase.PointInsideArea(const APoint: TPoint): Boolean; begin Result := PtInRect(CalculateSurfaceRect(LayoutBounds), APoint); end; function TGMUiAreaBase.AreaContainingPoint(const APoint: TPoint): TObject; function ChildAreaContainingPoint(const APoint: TPoint): TObject; var i: LongInt; area: IGMUiArea; begin Result := nil; for i:=0 to ContainedAreas.Count-1 do if (ContainedAreas[i] <> nil) and not GMAreaHasWndHandle(ContainedAreas[i]) and ContainedAreas[i].GetInterface(IGMUiArea, area) and area.Visible and area.PointInsideArea(APoint) then begin Result := area.AreaContainingPoint(APoint); Break; end; end; begin Result := ChildAreaContainingPoint(APoint); if (Result = nil) and Self.PointInsideArea(APoint) then Result := Self; end; function TGMUiAreaBase.GetParentObj: TObject; begin Result := FParent; end; procedure TGMUiAreaBase.LayoutContainedAreas(const ARepaint: Boolean); // : TPoint; begin GMLayoutContainedAreas(Self, ARepaint, vGMLayoutEdgeOrderMap); FLastLayoutSize := GMRectSize(FLayoutBounds); end; procedure TGMUiAreaBase.LayoutContainedAreasIfNeeded(const ARepaint: Boolean); // : TPoint; var areaSize, areaOrigin: TPoint; begin areaSize := GMRectSize(FLayoutBounds); //Result := areaSize; if areaSize <> FLastLayoutSize then LayoutContainedAreas(ARepaint) else begin areaOrigin := ClientAreaOrigin; if areaOrigin <> FLastLayoutOrigin then begin SurfaceOriginChanged; FLastLayoutOrigin := areaOrigin; end; end; FLastLayoutSize := areaSize; end; function TGMUiAreaBase.CreateAreaRegion(const ABoundingRect: TRect; const ARegionKind: TGMAreaRegionKind): IGMGetHandle; //const cRndDiff: array [TGMAreaRegionKind] of LongInt = (0, 1); begin //Result := TGMGdiRegion.CreateRoundRect(0, ABoundingRect, GMPoint(Max(0, CornerRounding.x - cRndDiff[ARegionKind]), Max(0, CornerRounding.y - cRndDiff[ARegionKind]))); Result := TGMGdiRegion.CreateRoundRect(0, ABoundingRect, CornerRounding); end; function TGMUiAreaBase.FillsComplete: Boolean; begin Result := BkgndColor <> clrTransparent; end; function TGMUiAreaBase.PaintsComplete: Boolean; begin // if PaintArea always covers whole area return true Result := False; // <- Fill PaintingRect with HBkgndBrush end; function TGMUiAreaBase.SubtractContainedAreas(const ARect: TRect; const AResultRegion: HRGN): Boolean; var i: LongInt; childArea: IGMUiArea; rgnChild: IGMGetHandle; childRect: TRect; begin Result := False; if AResultRegion = 0 then Exit; for i:=0 to ContainedAreas.Count-1 do if GMGetInterface(ContainedAreas[i], IGMUiArea, childArea) and childArea.Visible then begin // // Child area calculation is done relatve to ARect. So the caller decides if the DC is // is a window DC at LayoutBounds or a Bitmap at origin <0,0> // childRect := GMMoveRect(childArea.LayoutBounds, GMAddPoints(ARect.TopLeft, ScrollOffset)); rgnChild := childArea.CreateAreaRegion(childRect, arkBounds); if childArea.PaintsComplete or childArea.FillsComplete then begin if CombineRgn(AResultRegion, AResultRegion, rgnChild.Handle, RGN_DIFF) = NULLREGION then begin Result := True; Break; end; end else if childArea.SubtractContainedAreas(childRect, AResultRegion) then begin Result := True; Break; end; end; end; procedure TGMUiAreaBase.PaintBackground(const ADC: HDC; const AClientRect: TRect; const ARegion: IGMGetHandle); var bkgndFiller: IGMAreaFiller; // ClipRgnKeeper: IUNknown; begin if not FillsComplete or (ARegion = nil) then Exit; if not SubtractContainedAreas(AClientRect, ARegion.Handle) then begin bkgndFiller := AreaFiller; if bkgndFiller = nil then bkgndFiller := GMAreaRegionFiller; // // When filled with a brush a bkgndFiller may use FillRgn -> then no clipping is needed. // If the bkgndFiller drawas an image it must set the clipping region to ARegion itself. // Since cliiping means overhead we dont always do this here. // //ClipRgnKeeper := TGMGdiClipRgnKeeper.Create(ADC, ARegion.Handle, RGN_AND); bkgndFiller.Paint(Self, ADC, ARegion.Handle, HBkgndBrush); end; end; procedure TGMUiAreaBase.PaintContainedAreas(const ADC: HDC; const AClientRect: TRect); var i: LongInt; area: TGMUiArea; begin if ADC = 0 then Exit; for i:=0 to ContainedAreas.Count-1 do if ContainedAreas[i] is TGMUiArea then begin area := TGMUiArea(ContainedAreas[i]); // // Child area calculation is done relatve to AClientRect. So the caller may decide if the DC is // is a window DC at LayoutBounds or a Bitmap at origin <0, 0> // // Paint only windowless areas here, windowed areas will receive their own WM_PAINT messages from the system // if area.Visible and not GMAreaHasWndHandle(ContainedAreas[i]) then area.PaintToRect(ADC, GMMoveRect(area.LayoutBounds, GMAddPoints(AClientRect.TopLeft, ScrollOffset))); end; end; function TGMUiAreaBase.PaintArea(const ADC: HDC; const ARect: TRect): Boolean; begin Result := True; // <- dont pass WM_PAINT to original handler end; function TGMUiAreaBase.InternalPaintToRect(const ADC: HDC; const ADestRect: TRect): Boolean; var areaRgn, clientRgn: IGMGetHandle; rClient: TRect; frm: IGMAreaFrameDrawer; clipRgn: IUnknown; //bkBrush, font, fontColors, state, clipRgn: IUnknown; begin Result := False; if ADC = 0 then Exit; areaRgn := CreateAreaRegion(ADestRect, arkBounds); if areaRgn = nil then Exit; //State := TGMGdiDCStateKeeper.Create(ADC); SelectObject(ADC, HBkgndBrush); SelectObject(ADC, FontHandle); SetTextColor(ADC, GMRGBColor(FontColor)); if FontBkgndColor = clrTransparent then SetBkMode(ADC, TRANSPARENT) else begin SetBkMode(ADC, OPAQUE); SetBkColor(ADC, GMRGBColor(FontBkgndColor)); end; // Setup temporary DC properites for the duration of this call //bkBrush := TGMGdiObjSelector.Create(ADC, HBkgndBrush); //font := TGMGdiObjSelector.Create(ADC, FontHandle); //fontColors := TGMGdiTextColorSelector.Create(ADC, FontColor, FontBkgndColor); // // Avoid painting outside of our area, useful for containers with many children that may overflow other areas when completely painted // Clipping causes Windows Buttons not being filled with backround anymore .. but not subtracting contained areas makes them fill again // if ClippedPainting then clipRgn := TGMGdiClipRgnKeeper.Create(ADC, areaRgn.Handle, RGN_AND); frm := Frame; if frm = nil then begin clientRgn := areaRgn; rClient := ADestRect; end else begin rClient := frm.CalculateClientRect(ADestRect); if EqualRect(rClient, ADestRect) then clientRgn := areaRgn else clientRgn := CreateAreaRegion(rClient, arkClient); end; if not PaintsComplete then PaintBackground(ADC, rClient, clientRgn); Result := PaintArea(ADC, rClient); PaintContainedAreas(ADC, rClient); if frm <> nil then frm.DrawFrame(Self, ADC, areaRgn.Handle, GMRGBColor(FrameColor)); // <- do this last! end; function TGMUiAreaBase.PaintToRect(const ADC: HDC; const ADestRect: TRect): Boolean; var paintDC, paintBmp: IGMGetHandle; paintSz: TPoint; begin //GetclipBox(ADC, RClip); //if not IntersectRect(RClip, RClip, RPaint) then Exit; // <- Exit early if no painting is needed if not RectVisible(ADC, ADestRect) then Exit(True); // <- Checks if RPaint intersects clipping region, Exit early if no painting is needed if not BufferedPainting then Result := InternalPaintToRect(ADC, ADestRect) else begin paintSz := GMRectSize(ADestRect); paintSz.x := Max(paintSz.x, 0); paintSz.y := Max(paintSz.y, 0); paintDC := TGMGdiCompatibleDC.Create(0, ADC); paintBmp := TGMGdiBitmap.CreateCompatibleBmp(paintDC.Handle, ADC, paintSz, True); if not (PaintsComplete or FillsComplete) then BitBlt(paintDC.Handle, 0, 0, paintSz.x, paintSz.y, ADC, ADestRect.Left, ADestRect.Top, SRCCOPY); // <- copy original area content Result := InternalPaintToRect(paintDC.Handle, GMRect(cNullPoint, paintSz)); BitBlt(ADC, ADestRect.Left, ADestRect.Top, paintSz.x, paintSz.y, paintDC.Handle, 0, 0, SRCCOPY); // <- copy drawed contens back to original DC end; end; function TGMUiAreaBase.Paint(const ADC: HDC): Boolean; begin // Painting is relative to window DC area! LayoutBounds is relative to parent Area! if ADC <> 0 then Result := PaintToRect(ADC, PaintingRect) else Result := True; end; { ------------------- } { ---- TGMUiArea ---- } { ------------------- } function CompareWndMsg(const ItemA, ItemB: TGMWndMsg): TGMCompareResult; begin if ItemA < ItemB then Result := crALessThanB else if ItemA > ItemB then Result := crAGreaterThanB else Result := crAEqualToB; end; constructor TGMUiArea.Create(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); //FDispatchToParentMessages := TGMIntfHashTable.Create(False, GMCompareByWndMessage, True); FDispatchToParentMessages := TGMGenericArrayCollection<TGMWndMsg>.Create(False, True, CompareWndMsg, nil, True); //FDispatchToParentMessages := TGMIntfArrayCollection.Create(False, True, GMCompareByWndMessage, True); //FDispatchToParentMessages := TGMAvlIntfTree.Create(False, GMCompareByWndMessage, True); end; procedure TGMUiArea.DispatchMsg(var AMsg: TMessage); //var msgObj: IUnknown; procedure DispatchToSelf; begin inherited DispatchMsg(AMsg); if (AMsg.Msg = WM_MOUSEWHEEL) and (AMsg.Result = 0) then GMDispatchObjMsg(Parent, AMsg); end; begin //if GMIsOneOfIntegers(AMsg.Msg, DispatchToParentMessages) then GMDispatchObjMsg(Parent, AMsg) else if DispatchToParentMessages.IsEmpty then DispatchToSelf else begin //msgObj := TGMWndMessageObj.Create(AMsg.Msg, True); //if GMCollectionContains(DispatchToParentMessages, msgObj) then GMDispatchObjMsg(Parent, AMsg) else DispatchToSelf; if DispatchToParentMessages.Contains(AMsg.Msg) then GMDispatchObjMsg(Parent, AMsg) else DispatchToSelf; end; end; procedure TGMUiArea.InternalSetVisible(const Value: Boolean); begin inherited; SetShowing(Value); end; procedure TGMUiArea.SetShowing(const Value: Boolean); var i: LongInt; PIArea: IGMUiArea; begin inherited; for i:=0 to ContainedAreas.Count-1 do if GMGetInterface(ContainedAreas[i], IGMUiArea, PIArea) and PIArea.Visible then PIArea.SetShowing(Value); end; procedure TGMUiArea.SetLayoutBounds(const AValue: TRect; const ARepaint: Boolean); var ARect: TRect; WndPrnt: HWnd; repaintBounds: TRect; begin UnionRect(repaintBounds, FLayoutBounds, AValue); inherited SetLayoutBounds(AValue, ARepaint); LayoutContainedAreasIfNeeded(ARepaint); if ARepaint and Visible and not IsRectEmpty(AValue) and GMFindAllocatedParentHandle(Parent, WndPrnt) then begin ARect := CalculateSurfaceRect(repaintBounds); if not IsRectEmpty(ARect) then InvalidateRect(WndPrnt, @ARect, False); end; end; { -------------------------------- } { ---- TGMForeignWndContainer ---- } { -------------------------------- } constructor TGMForeignWndContainer.Create(const AParent: TObject; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AForeignWnd: HWnd; const ABkgndColor: COLORREF; const AVisible: Boolean; const ARefLifeTime: Boolean); begin inherited Create(AParent, APosition, AAreaAlign, ABkgndColor, AVisible, ARefLifeTime); FForeignWnd := AForeignWnd; //if IsWindow(FForeignWnd) then SetWindowLong(FForeignWnd, GWL_STYLE, GetWindowLong(FForeignWnd, GWL_STYLE) or WS_CHILD); end; procedure TGMForeignWndContainer.CreateForeignWnd; begin if FForeignWnd = 0 then FForeignWnd := InternalCreateForeignWnd; end; procedure TGMForeignWndContainer.SetLayoutBounds(const Value: TRect; const ARepaint: Boolean); begin inherited; CreateForeignWnd; if IsWindow(FForeignWnd) then //GMAPICheckObj(... , Self, 'SetWindowPos'); SetWindowPos(FForeignWnd, 0, Value.Left, Value.Top, GMRectSize(Value).x, GMRectSize(Value).y, SWP_NOZORDER or SWP_NOACTIVATE or cWinPosRedraw[ARepaint]); end; function TGMForeignWndContainer.InternalCalcHeight(const ANewSize: TPoint): LongInt; begin CreateForeignWnd; if not IsWindow(FForeignWnd) then Result := inherited InternalCalcHeight(ANewSize) else Result := SendMessage(FForeignWnd, UM_CALCHEIGHT, ANewSize.x, ANewSize.y); end; function TGMForeignWndContainer.InternalCalcWidth(const ANewSize: TPoint): LongInt; begin CreateForeignWnd; if not IsWindow(FForeignWnd) then Result := inherited InternalCalcWidth(ANewSize) else Result := SendMessage(FForeignWnd, UM_CALCWIDTH, ANewSize.x, ANewSize.y); end; procedure TGMForeignWndContainer.InternalSetVisible(const Value: Boolean); // const Relayout: Boolean begin if Value then CreateForeignWnd; inherited; //InternalSetVisible(Value); // Relayout if not IsWindow(FForeignWnd) then Exit; ShowWindow(FForeignWnd, cSWShow[Value]); end; function TGMForeignWndContainer.PaintsComplete: Boolean; begin Result := IsWindow(FForeignWnd); end; { ------------------------------ } { ---- TGMSurroundingUiArea ---- } { ------------------------------ } constructor TGMSurroundingUiArea.Create(const AParent: TObject; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const APaddSpace: TPoint; const ABkgndColor: COLORREF; const AVisible, ARefLifeTime: Boolean); begin {inherited} Create(AParent, APosition, AAreaAlign, ABkgndColor, AVisible, ARefLifeTime); FPaddSpace := APaddSpace; end; function TGMSurroundingUiArea.RootForRelayout: TObject; begin // Child Text change => child size change => relayout parent (us) // since our size depends on child sizes we need to forward re-layout to our parent. Result := GMParentRootForRelayout(Self); end; function TGMSurroundingUiArea.InternalcalcHeight(const ANewSize: TPoint): LongInt; begin // The caller will assign his layoutbounds just after this. // So temporary setting our bounds to be able to correctly layout childs does no harm. Result := GMCalcBoundingHeight(Self, ANewSize) + FPaddSpace.y; end; function TGMSurroundingUiArea.InternalCalcWidth(const ANewSize: TPoint): LongInt; begin // The caller will assign his layoutbounds just after this. // So temporary setting our bounds to be able to correctly layout childs does no harm. Result := GMCalcBoundingWidth(Self, ANewSize) + FPaddSpace.x; end; { -------------------------------- } { ---- TGMWndPaintDisableImpl ---- } { -------------------------------- } //constructor TGMWndPaintDisableImpl.Create(const AOwner: TObject; const ARefLifeTime: Boolean); //begin //inherited Create(ARefLifeTime); //FOwner := AOwner; //end; // //function TGMWndPaintDisableImpl.QueryInterface({$IFDEF FPC}constref{$ELSE}const{$ENDIF} IID: TGUID; out Intf): HResult; //var PIUnkOwner: IUnknown; //begin //Result := inherited QueryInterface(IID, Intf); //if (Result <> S_OK) and (FOwner <> nil) and FOwner.GetInterface(IUnknown, PIUnkOwner) then // Result := PIUnkOwner.QueryInterface(IID, Intf); //end; // //function TGMWndPaintDisableImpl._AddRef: LongInt; //var PIUnkOwner: IUnknown; //begin //if (FOwner <> nil) and FOwner.GetInterface(IUnknown, PIUnkOwner) then // Result := PIUnkOwner._AddRef //else // Result := inherited _AddRef; //end; // //function TGMWndPaintDisableImpl._Release: LongInt; //var PIUnkOwner: IUnknown; //begin //if (FOwner <> nil) and FOwner.GetInterface(IUnknown, PIUnkOwner) then // Result := PIUnkOwner._Release //else // Result := inherited _Release; //end; // //function TGMWndPaintDisableImpl.GetPaintDisabledCount: LongInt; //begin //Result := FPaintDisableCount; //end; // //procedure TGMWndPaintDisableImpl.SendEnableMsg(const AEnable: Boolean); //var PIHandle: IGMGetHandle; HAlloc: IGMHandleAllocated; //begin //if (FPaintDisableCount = 0) and (FOwner <> nil) and // (not FOwner.GetInterface(IGMHandleAllocated, HAlloc) or HAlloc.HandleAllocated) and // FOwner.GetInterface(IGMGetHandle, PIHandle) then // begin // SendMessage(PIHandle.Handle, WM_SETREDRAW, Ord(AEnable), 0); // if AEnable then InvalidateRect(PIHandle.Handle, nil, False); // end; //end; // //function TGMWndPaintDisableImpl.DisablePaint: LongInt; //begin //SendEnableMsg(False); //Inc(FPaintDisableCount); //Result := FPaintDisableCount; //end; // //function TGMWndPaintDisableImpl.EnablePaint: LongInt; //begin //FPaintDisableCount := Max(0, FPaintDisableCount-1); //Result := FPaintDisableCount; //SendEnableMsg(True); //end; { ------------------- } { ---- TGMWindow ---- } { ------------------- } constructor TGMWindow.Create(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FRelayedMessages := cDfltRelayedMessages; end; constructor TGMWindow.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AWndStyle: DWORD; const AWndExStyle: DWORD; const AText: TGMString; const AMenu: HMENU; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); var vsbl: Boolean; begin //FPaintDisabler := TGMWndPaintDisableImpl.Create(Self, False); FCreateData.Text := GMResolveTextResData(AText, FTextResData); vsbl := AWndStyle and WS_VISIBLE <> 0; FCreateData.WndStyle := AWndStyle; FCreateData.WndExStyle := AWndExStyle; FCreateData.Menu := AMenu; FCreateData.ParentWnd := GMHWndFromWndObj(AParent); if AParent < 0 then {inherited} Create(TObject(-AParent), APosition, AAreaAlign, ABkgndColor, vsbl, ARefLifeTime) else {inherited} Create(GMObjFromWnd(HWnd(AParent)), APosition, AAreaAlign, ABkgndColor, vsbl, ARefLifeTime); end; destructor TGMWindow.Destroy; begin //GMFreeAndNil(FPaintDisabler); if HandleAllocated then DestroyHandle(False); inherited Destroy; end; function TGMWindow.ExecuteOperation(const Operation: LongInt; const Parameter: IUnknown): Boolean; begin Result := True; case Operation of Ord(goEnable): GMEnableWindow(Self, True); Ord(goDisable): GMEnableWindow(Self, False); else Result := inherited ExecuteOperation(Operation, Parameter); end; end; function TGMWindow.GetHandle: THandle; stdcall; begin if not HandleAllocated then CreateHandle; Result := FHandle; end; function TGMWindow.GetHandleAllocated: Boolean; stdcall; begin Result := FHandle <> 0; end; //function TGMWindow.GetVisible: Boolean; //begin //Result := WndStyle and WS_VISIBLE <> 0; //end; procedure TGMWindow.CreateParentHandle; var handle: IGMGetHandle; begin handle := GMFindWindowedParent(Parent); if handle <> nil then FCreateData.ParentWnd := handle.Handle; // <- accessing the Handle property will create the Handle if it has not yet been created end; function TGMWindow.WndSizeFromClientSize(const AClientSize: TPoint): TPoint; begin Result := GMWndSizeFromClientSize(AClientSize, WndStyle, WndExStyle, FCreateData.Menu <> 0); end; {function TGMWindow.Frame: IGMAreaFrameDrawer; begin // // Windows draw their frames via WM_NCPAINT and get adjusted via WM_NCCALCSIZE. // They dont draw or adjust by frame inside their client area. // Result := nil; // <- In WM_NCPAINT and WM_NCCALCSIZE we use FFrame memeber directly! end;} function TGMWindow.WndClassRegName: TGMString; begin Result := ClassName; end; function TGMWindow.CursorHandle: HCURSOR; begin Result := LoadCursor(0, Pointer(IDC_ARROW)); end; //function TGMWindow.TempCursor: HCURSOR; //begin //Result := 0; //end; function TGMWindow.RegisterWndClass: TGMString; begin Result := GMRegisterWindowClass(WndClassRegName, CursorHandle, CS_DBLCLKS).Name; // <- generates new class if neccessary end; function TGMWindow.WndCreateRect: TRect; begin Result := CalculateSurfaceRect(LayoutBounds); end; function TGMWindow.GetFrame: IGMAreaFrameDrawer; begin // // For windowed areas the NC (non client) messages are using the FFrame member directly. // Everybody else gets this nil pointer! // Note: The Frame can be set! // Result := nil; end; function TGMWindow.HasWindowRegion: Boolean; begin Result := (CornerRounding.x <> 0) and (CornerRounding.y <> 0); end; procedure TGMWindow.InternalCreateHandle; var rWnd: TRect; wndClassName: TGMString; begin //inherited; CreateParentHandle; // <- recursively create all parent handles rWnd := WndCreateRect; if rWnd.Left <> LongInt(CW_USEDEFAULT) then rWnd.Right := GMRectSize(rWnd).x; if rWnd.Top <> LongInt(CW_USEDEFAULT) then rWnd.Bottom := GMRectSize(rWnd).y; wndClassName := RegisterWndClass; with FCreateData do FHandle := CreateWindowEx(WndExStyle, PGMChar(wndClassName), PGMChar(Text), WndStyle, //rWnd.Left, rWnd.Top, GMRectSize(rWnd).x, GMRectSize(rWnd).y, rWnd.Left, rWnd.Top, rWnd.Right, rWnd.Bottom, ParentWnd, Menu, {$IFDEF JEDIAPI}{$IFDEF FPC}System.{$ELSE}SysInit.{$ENDIF}{$ENDIF}HInstance, nil); GMAPICheckObj('CreateWindowEx', '', GetLastError, FHandle <> 0, Self); if not IsLayoutChild then GetWindowRect(FHandle, FLayoutBounds); // <- CW_USEDEFAULT may have been used! FOrgWndPtrData := SetWindowLongPtr(FHandle, cWndObjPtrData, PtrInt(Self)); {ToDO: Use window extra memory to store self pointer?} FOrgWndProc := Pointer(SetWindowLongPtr(FHandle, GWL_WNDPROC, PtrInt(@GMStdWndProc))); if FontHandle <> 0 then GMCallObjWindowProc(Self, WM_SETFONT, PtrInt(FontHandle), 0); // SendMessage(FHandle, WM_SETFONT, FontHandle, 0); // SetWindowPos generates WM_SIZE, size delta will be (0, 0) if not framed if HasWindowRegion then // // Note: rWnd.Right and rWnd.Bottom contain Width and Height here // SetWindowRgn(FHandle, CreateRoundRectRgn(0, 0, rWnd.Right+1, rWnd.Bottom+1, CornerRounding.x, CornerRounding.y), False); //GMAPICheck(SetWindowRgn(FHandle, CreateRoundRectRgn(0, 0, rWnd.Right, rWnd.Bottom, CornerRounding.x, CornerRounding.y), False) <> 0, 'SetWindowRgn'); // Needed for framed OEM controls if FCreateData.WndStyle and (WS_VISIBLE or WS_CHILD) = (WS_VISIBLE or WS_CHILD) then SetWindowPos(FHandle, 0,0,0,0,0, SWP_NOACTIVATE or SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED); // Layout children before their handles are created to display them in the correct palce right away. LayoutContainedAreasIfNeeded(False); // <- just created invalidated anyway! // In case SetText has been called before the handle was created if Length(FCreateData.Text) > 0 then begin SendMessage(FHandle, WM_SETTEXT, 0, LPARAM(PGMChar(FCreateData.Text))); FCreateData.Text := ''; end; PostMessage(FHandle, UM_HANDLECREATED, 0, 0); // <- useful for operations that need to be done once after creation end; procedure TGMWindow.CreateHandle; begin if not HandleAllocated then InternalCreateHandle; // Call inherited if allocated -> new child windows may have been added inherited; // <- recursively create all child handles end; procedure TGMWindow.WMNCDestroy(var Msg: TWMNCDestroy); begin inherited; //SetWindowLongPtr(FHandle, cWndObjPtrData, FOrgWndPtrData); FHandle := 0; FOrgWndPtrData := 0; FOrgWndProc := nil; //FVisible := False; dont reset, keep FVisible for re-creation end; procedure TGMWindow.DestroyHandle(const ARememberState: Boolean); begin if HandleAllocated then begin if ARememberState then begin FCreateData.Text := GetText; // <- handle is allocated, taken from handle! FCreateData.WndStyle := WndStyle; // <- handle is allocated, taken from handle! FCreateData.WndExStyle := WndExStyle; // <- handle is allocated, taken from handle! // GetWindowRect(FHandle, FLayoutBounds); // FLayoutBounds := GetLayoutBounds; end; DestroyWindow(FHandle); // <- don't check, never raise in destructors! //GMAPICheckObj(Windows.DestroyWindow(FHandle), Self, 'DestroyWindow'); end; end; procedure TGMWindow.DispatchMsg(var Msg: TMessage); begin FPassMessageToOriginalHandler := True; inherited DispatchMsg(Msg); // <- may change FPassMessageToOriginalHandler in derived message handlers if no call to FOrgWndProc is wanted if FPassMessageToOriginalHandler and (FOrgWndProc <> nil) then Msg.Result := CallWindowProc(FOrgWndProc, FHandle, Msg.Msg, Msg.WParam, Msg.LParam); //else //Msg.Result := DefWindowProc(FHandle, Msg.Msg, Msg.WParam, Msg.LParam); end; procedure TGMWindow.WindowProc(var Msg: TMessage); const cForwardedToMousePos = $8000; // <- highest low word bit var mousePos: TPoint; mouseOverWnd: HWnd; begin case Msg.Msg of WM_MOUSEWHEEL: // // Do the forwarding to the window beneath the mouse cursor only once per wheel message! // if Msg.WParam and cForwardedToMousePos <> 0 then inherited WindowProc(Msg) else begin Msg.WParam := Msg.WParam or cForwardedToMousePos; mousePos := SmallPointToPoint(TWMMouse(Msg).Pos); //OutputDebugString(PGMChar(GMFormat('x: %d y: %d', [mousePos.x, mousePos.y]))); mouseOverWnd := WindowFromPoint(mousePos); if (mouseOverWnd = 0) or (mouseOverWnd = FHandle) then inherited WindowProc(Msg) // <- will use the AreaContainingPoint method else with Msg do Result := SendMessage(mouseOverWnd, Msg, WParam, LParam); end; else inherited WindowProc(Msg); end; end; procedure TGMWindow.WMCommand(var Msg: TMessage); begin inherited; if rlmWMCommand in RelayedMessages then //begin //with Msg do Result := SendMessage(LParam, Msg + WM_APP, WParam, LParam); with Msg do Result := GMCallObjWindowProc(GMObjFromWnd(LParam), Msg + WM_APP, WParam, LParam); // FPassMessageToOriginalHandler := False; // <- WM_COMMAND must be passed to ForgWndProc! // otherwise Comboboxes cant dropselect with the mouse //end; end; procedure TGMWindow.WMNotify(var Msg: TMessage); begin inherited; if rlmWMNotify in RelayedMessages then // SendMessage will not reach HintWindow unless subclassing is done by ourself. // This solution seems to be simpler than subclassing. // Should not be a problem since Msg + WM_APP will be understod only by our controls begin //with Msg do Result := SendMessage(PNMHdr(LParam)^.hWndFrom, Msg + WM_APP, WParam, LParam); with Msg do Result := GMCallObjWindowProc(GMObjFromWnd(PNMHdr(LParam)^.hWndFrom), Msg + WM_APP, WParam, LParam); FPassMessageToOriginalHandler := Msg.Result = 0; // dont let ForgWndProc overwrite Msg.Result of TVN_BEGINLABELEDIT and NM_CUSTOMDRAW //FPassMessageToOriginalHandler := (PNMHdr(Msg.LParam)^.code <> -410) and (PNMHdr(Msg.LParam)^.code <> -12) and // (PNMHdr(Msg.LParam)^.code <> -401); end; end; procedure TGMWindow.WMDrawItem(var Msg: TMessage); begin inherited; if rlmWMOwnerDraw in RelayedMessages then begin //with Msg do Result := SendMessage(PDrawItemStruct(LParam)^.hwndItem, Msg + WM_APP, WParam, LParam); with Msg do Result := GMCallObjWindowProc(GMObjFromWnd(PDrawItemStruct(LParam)^.hwndItem), Msg + WM_APP, WParam, LParam); FPassMessageToOriginalHandler := False; // <- dont let ForgWndProc overwrite Msg.Result end; end; procedure TGMWindow.WMHScroll(var Msg: TMessage); begin inherited; if (Msg.LParam <> 0) and (rlmWMScroll in RelayedMessages) then //begin with Msg do Result := GMCallObjWindowProc(GMObjFromWnd(LParam), Msg + WM_APP, WParam, LParam); // FPassMessageToOriginalHandler := False; // <- dont let ForgWndProc overwrite Msg.Result //end; end; procedure TGMWindow.WMVScroll(var Msg: TMessage); begin inherited; if (Msg.LParam <> 0) and (rlmWMScroll in RelayedMessages) then //begin with Msg do Result := GMCallObjWindowProc(GMObjFromWnd(LParam), Msg + WM_APP, WParam, LParam); // FPassMessageToOriginalHandler := False; // <- dont let ForgWndProc overwrite Msg.Result //end; end; procedure TGMWindow.WMNCCalcSize(var Msg: TWMNCCalcSize); begin inherited; // NOTE: Use FFrame member directly here! if (FFrame <> nil) and (Msg.CalcSize_Params <> nil) then with Msg.CalcSize_Params^ do rgrc[0] := FFrame.CalculateClientRect(rgrc[0]); end; procedure TGMWindow.WMHelp(var Msg: TWMHelp); var area: TObject; piArea: IGMUiArea; piParentObj: IGMGetParentObj; begin if Msg.HelpInfo <> nil then try //area := AreaContainingPoint(PPoint(@Msg.HelpInfo.MousePos)^); //if area <> nil then // begin // GMSendObjMessage(area, WM_HELP, 0, PtrInt(Msg.HelpInfo)); // Msg.Result := 1; // end; area := Self; while area <> nil do begin if GMGetInterface(area, IGMUiArea, piArea) and piArea.ProcessHelp(Msg.HelpInfo^) then area := nil; // Break; if GMGetInterface(area, IGMGetParentObj, piParentObj) then area := piParentObj.ParentObj else area := nil; end; except // The WM_HELP message may have been send outside from GMApplicationMassageLoop or GMModalMessageLoop and the // exception handling in GMStdWndProc has been removed because GMModalMessageLoop needs the exceptions to be handled there // so we need exception handling here if the message comes from outside on ex: TObject do vfGMHrExceptionHandler(ex, cDfltPrntWnd); end; FPassMessageToOriginalHandler := False; end; procedure TGMWindow.WMSize(var Msg: TWMSize); begin inherited; case Msg.SizeType of SIZE_RESTORED, SIZE_MAXIMIZED, SIZE_MINIMIZED: begin if not IsLayoutChild then GetWindowRect(FHandle, FLayoutBounds); LayoutContainedAreasIfNeeded(True); end; end; end; procedure TGMWindow.WMMove(var Msg: TWMMove); begin if not IsLayoutChild then GetWindowRect(FHandle, FLayoutBounds); inherited; end; procedure TGMWindow.WMSetCursor(var Msg: TMessage); var Area: TObject; MousePos: TPoint; begin inherited; if WndStyle and WS_DISABLED = 0 then begin // if TempCursor <> 0 then begin SetCursor(TempCursor); Msg.Result := 1; end // else // begin // NOTE: WM_SETCURSOR GMMessages do not contain mouse position information! MousePos := GMScreenToClient(Self, GMMousePosition); Area := AreaContainingPoint(MousePos); if (Area <> nil) and (Area <> Self) then GMCallObjWindowProc(Area, Msg); //if Msg.Result = 0 then DispatchMsg(Msg); FPassMessageToOriginalHandler := Msg.Result = 0; // end; end; end; procedure TGMWindow.UMStartMouseTrack(var Msg: TMessage); var MouseTrack: TTrackMouseEvent; begin // // Mouse entering child windows will cause a WM_MOUSELEAVE in the parent window and stop the parents tracking. // Some window should always be tracked otherwise a mouse leave may be missed. // if not FIsMouseTracking and HandleAllocated then // and not IsLayoutChild begin FillByte(MouseTrack, SizeOf(MouseTrack), 0); MouseTrack.cbSize := SizeOf(MouseTrack); MouseTrack.hwndTrack := Handle; MouseTrack.dwFlags := TME_LEAVE; FIsMouseTracking := TrackMouseEvent(MouseTrack); end; inherited; end; procedure TGMWindow.WMEraseBkgnd(var Msg: TWMEraseBkgnd); begin // Dont pass message to ForgWndProc! And don't fill it with background brush! // Assume that the complete window area will be painted (some of it painted by child areas) // This will reduce drawing flicker Msg.Result := 1; FPassMessageToOriginalHandler := False; end; procedure TGMWindow.WMMouseLeave(var Msg: TMessage); var mouseAreaBefore: TObject; begin FIsMouseTracking := False; inherited; if (vGMMouseInsideArea <> nil) and (vGMMouseInsideArea <> Self) then begin mouseAreaBefore := vGMMouseInsideArea; vGMMouseInsideArea := nil; // <- make mouseAreaBefore.MouseInside return False GMCallObjWindowProc(mouseAreaBefore, UM_MOUSELEAVE, TMessage(Msg).WParam, TMessage(Msg).LParam); end; end; procedure TGMWindow.WMSetFocus(var Msg: TMessage); begin if GMIsParentObj(Self, vGMKeyboardFocusArea, False, TGMWindow) then GMDispatchObjMsg(vGMKeyboardFocusArea, Msg) else inherited; end; procedure TGMWindow.WMKillFocus(var Msg: TMessage); begin if GMIsParentObj(Self, vGMKeyboardFocusArea, False, TGMWindow) then GMDispatchObjMsg(vGMKeyboardFocusArea, Msg) else inherited; end; function TGMWindow.ClientAreaOrigin: TPoint; begin Result := ScrollOffset; // cNullPoint; Result := Windows.GetClientRect.TopLeft; <- ??? end; function TGMWindow.ClientAreaSize: TPoint; var rClient: TRect; begin if not HandleAllocated then Result := inherited ClientAreaSize else begin GetClientRect(Handle, rClient); Result := GMRectSize(rClient); end; end; function TGMWindow.PaintingRect: TRect; begin if not HandleAllocated then begin Result.TopLeft := cNullPoint; Result.BottomRight := ClientAreaSize; end else if not GetClientRect(Handle, Result) then Result := Default(TRect); end; procedure TGMWindow.LanguageChanged(const ANewLanguage: LPARAM); begin Text := GMBuildTextFromResRef(FTextResData, Text); end; function TGMWindow.GetEnabled: Boolean; begin if HandleAllocated then Result := IsWindowEnabled(Handle) else Result := FCreateData.WndStyle and WS_DISABLED = 0; end; procedure TGMWindow.SetEnabled(const AValue: Boolean); stdcall; begin FCreateData.WndStyle := FCreateData.WndStyle and not WS_DISABLED or cWSDisabled[not AValue]; if HandleAllocated then begin EnableWindow(FHandle, AValue); if not AValue and IsTabStop and (vGMKeyboardFocusArea = Self) then GMPostSeletNextDlgTabAreaMsg(Self); end; end; procedure TGMWindow.SetLayoutBounds(const ALayoutBounds: TRect; const ARepaint: Boolean); var rWnd, rWndOld: TRect; hasRgn: Boolean; doRepaint: Boolean; begin //if EqualRect(AValue, FLayoutBounds) then Exit; {ToDo: Skip re-position if not neccessary} // Skipping re-positiovn needs to know if any of the non // windowed parents has changed its surface position. // This cannot be decided by just comparing to old LayoutBounds! //IsRounded := (CornerRounding.x <> 0) and (CornerRounding.y <> 0); // SetWindowPos may generate a WM_SIZE message, re-layouting of contained areas will be done there if HandleAllocated then begin rWnd := CalculateSurfaceRect(ALayoutBounds); if GetWindowRect(FHandle, rWndOld) and EqualRect(rWnd, rWndOld) then Exit; doRepaint := ARepaint and (WndStyle and WS_VISIBLE <> 0); // <- Don't use Visible property here! It may be different to WS_VISIBLE style //GMAPICheckObj(... , Self, 'SetWindowPos'); hasRgn := HasWindowRegion; if hasRgn then SetWindowRgn(Handle, 0, False); SetWindowPos(Handle, 0, rWnd.Left, rWnd.Top, GMRectSize(rWnd).x, GMRectSize(rWnd).y, SWP_NOZORDER or SWP_NOACTIVATE or cWinPosRedraw[doRepaint]); if hasRgn then SetWindowRgn(Handle, CreateRoundRectRgn(0, 0, GMRectSize(rWnd).x+1, GMRectSize(rWnd).y+1, CornerRounding.x, CornerRounding.y), doRepaint); end; if HandleAllocated and not IsLayoutChild then GetWindowRect(FHandle, FLayoutBounds) else FLayoutBounds := ALayoutBounds; end; procedure TGMWindow.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); begin inherited; if not ISLayoutChild then with Msg.MinMaxInfo^, FSizeConstraints do begin if MinWidth > 0 then ptMinTrackSize.x := MinWidth; if MinHeight > 0 then ptMinTrackSize.y := MinHeight; if MaxWidth > 0 then ptMaxTrackSize.x := MaxWidth; if MaxHeight > 0 then ptMaxTrackSize.y := MaxHeight; end; end; procedure TGMWindow.AfterParentChanged; var HWndPrnt: HWnd; begin // // No call to inherited, doesnt need to be propagated in windowed controls // if not HandleAllocated or not GMFindAllocatedParentHandle(Parent, HWndPrnt) then Exit; if HWndPrnt <> GetParent(FHandle) then SetParentWnd(HWndPrnt); end; //procedure TGMWindow.SetParentObj(const AWnd: TObject; const Relayout: Boolean); //var WndPrnt: HWnd; //begin //inherited; //if GMFindAllocatedParentHandle(Parent, WndPrnt) then SetParentWnd(WndPrnt); //end; procedure TGMWindow.SetParentWnd(const AWnd: HWnd); begin if AWnd = ParentWnd then Exit; if HandleAllocated then GMAPICheckObj('Windows.SetParent', '', GetLastError, SetParent(Handle, AWnd) <> 0, Self); FCreateData.ParentWnd := AWnd; end; function TGMWindow.GetWndStyle: DWORD; begin if HandleAllocated then Result := DWORD(GetWindowLong(FHandle, GWL_STYLE)) else Result := FCreateData.WndStyle; end; procedure TGMWindow.SetWndStyle(const AValue: DWORD); const cFrameStyles = WS_CAPTION or WS_BORDER or WS_DLGFRAME or WS_VSCROLL or WS_HSCROLL or WS_THICKFRAME; var oldWndStyle: DWORD; begin oldWndStyle := WndStyle; if AValue = oldWndStyle then Exit; if HandleAllocated then begin SetWindowLong(FHandle, GWL_STYLE, LongInt(AValue)); // If frame styles have been changed windows requires a SetWindowPos call to reflect the changes if AValue and cFrameStyles <> oldWndStyle and cFrameStyles then SetWindowPos(FHandle, 0,0,0,0,0, SWP_NOACTIVATE or SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED); end; FCreateData.WndStyle := AValue; end; function TGMWindow.GetWndExStyle: DWORD; begin if HandleAllocated then Result := DWORD(GetWindowLong(Handle, GWL_EXSTYLE)) else Result := FCreateData.WndExStyle; end; procedure TGMWindow.SetWndExStyle(const AValue: DWORD); const cFrameExStyles = WS_EX_CLIENTEDGE or WS_EX_DLGMODALFRAME or WS_EX_STATICEDGE or WS_EX_TOOLWINDOW; var OldWndExStyle: DWORD; begin OldWndExStyle := WndExStyle; if AValue = OldWndExStyle then Exit; if HandleAllocated then begin SetWindowLong(FHandle, GWL_EXSTYLE, LongInt(AValue)); // If frame styles have been changed windows requires a SetWindowPos call to reflect the changes if AValue and cFrameExStyles <> OldWndExStyle and cFrameExStyles then SetWindowPos(FHandle, 0,0,0,0,0, SWP_NOACTIVATE or SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED); end; FCreateData.WndExStyle := AValue; end; function TGMWindow.GetText: TGMString; stdcall; begin if not HandleAllocated then Result := FCreateData.Text else begin SetLength(Result, SendMessage(FHandle, WM_GETTEXTLENGTH, 0, 0)); // length 0 gives access violation on XP when started without manifest if Length(Result) > 0 then SendMessage(FHandle, WM_GETTEXT, Length(Result) + 1, LPARAM(PGMChar(Result))); //Assert(SendMessage(Handle, WM_GETTEXT, Length(Result) + 1, LPARAM(PGMChar(Result))) = Length(Result)); end; end; procedure TGMWindow.SetText(const AValue: TGMString); stdcall; begin if AValue = Text then Exit; if HandleAllocated then SendMessage(FHandle, WM_SETTEXT, 0, LPARAM(PGMChar(AValue))) //; //SetWindowText(Handle, PGMChar(AValue)); else FCreateData.Text := AValue; end; function TGMWindow.IsLayoutChild: Boolean; var _style: DWORD; begin _style := WndStyle; Result := (_style and WS_CHILD <> 0) and (_style and WS_POPUP = 0); end; function TGMWindow.IsTabStop: Boolean; begin Result := WndStyle and WS_TABSTOP <> 0; end; procedure TGMWindow.InternalSetVisible(const AValue: Boolean{; const Relayout: Boolean}); begin if AValue <> (WndStyle and WS_VISIBLE <> 0) then if HandleAllocated then ShowWindow(Handle, cSWShow[AValue]) else if AValue then WndStyle := WndStyle or WS_VISIBLE else WndStyle := WndStyle and not WS_VISIBLE; end; procedure TGMWindow.SetShowing(const AValue: Boolean); begin if Visible then InternalSetVisible(AValue); end; procedure TGMWindow.WMNCPaint(var Msg: TMessage); var dc: HDC; rBounds: TRect; areaRgn: IGMGetHandle; begin inherited; // NOTE: Use FFrame member directly here! //if GMEqualPoints(GMFrameExtent(FFrame), cNullPoint) then Exit; // <- matched if Frame returns nil! if not IsFramed then Exit; if Msg.LParam = 0 then dc := GetWindowDC(FHandle) else dc := HDC(Msg.LParam); if dc = 0 then Exit; try GetWindowRect(FHandle, rBounds); rBounds := GMMoveRect(rBounds, -rBounds.Left, -rBounds.Top); areaRgn := CreateAreaRegion(rBounds, arkBounds); FFrame.DrawFrame(Self, dc, areaRgn.Handle, FrameColor); finally if Msg.LParam = 0 then ReleaseDC(FHandle, dc); end; end; procedure TGMWindow.ScheduleRepaint; begin if HandleAllocated and Visible then InvalidateRect(Handle, nil, False); end; //procedure TGMWindow.PaintFrame(const ADC: HDC; const ARegion: IGMGetHandle); // : IGMGetHandle; //begin // // Nothing, windowed areas paint their frames via WM_NCPaint message // //Result := ARegion; //end; procedure TGMWindow.WMPaint(var Msg: TWMPaint); var dc: HDC; ps: TPaintStruct; begin try // // There will be no painting possible after EndPaint. Whoever gets the ADC first must pass it on. // Handlers must be prepared for ADC = 0. Chained Handlers must be called before EndPaint. // ps := Default(TPaintStruct); dc := Msg.DC; if dc = 0 then begin dc := BeginPaint(Handle, ps); GMAPICheckObj('BeginPaint', '', GetLastError, dc <> 0, Self); end; try //inherited; //if not ps.fErase then if not Paint(dc) and (FOrgWndProc <> nil) then Msg.Result := CallWindowProc(FOrgWndProc, FHandle, Msg.Msg, WPARAM(dc), 0); finally if Msg.DC = 0 then EndPaint(Handle, ps); Msg.Result := 0; // <- we handled it end; except // Never raise exceptions while painting! on ex: TObject do GMTraceException(ex); //GMTraceException(GMExceptObject); end; FPassMessageToOriginalHandler := False; // <- dont call FOrgWndProc in WindowProc after EndPaint end; //procedure TGMWindow.WMPrint(var Msg: TMessage); //var Msg2: TMessage; R: TRect; //begin // inherited; // if Msg.WParam = 0 then Exit; // // if (Msg.LParam and PRF_ERASEBKGND <> 0) and FillsComplete then // begin // GetWindowRect(FHandle, R); // <- ClientRect would not fill frame area! // FillRect(HDC(Msg.WParam), GMMoveRect(R, -R.Left, -R.Top), HBkgndBrush); // end; // // if Msg.LParam and PRF_NONCLIENT <> 0 then // begin // Msg2 := GMMessageRec(0, 0, Msg.WParam, 0); // WMNCPaint(Msg2); // end; //end; procedure TGMWindow.WMPrintClient(var Msg: TMessage); var wndRect: TRect; msg2: TMessage; begin if Msg.WParam = 0 then Exit; if (Msg.LParam and PRF_ERASEBKGND <> 0) then // and FillsComplete begin GetWindowRect(FHandle, wndRect); // <- ClientRect would not fill frame area! FillRect(HDC(Msg.WParam), GMMoveRect(wndRect, -wndRect.Left, -wndRect.Top), HBkgndBrush); FPassMessageToOriginalHandler := False; end; if Msg.LParam and PRF_CLIENT <> 0 then begin Paint(HDC(Msg.WParam)); // // The device context passed by the system does not support clipping by regions and causes some // other artefacts. So we paint to a Bitmap first and then copy the Result onto the original DC. // //ClientSz := ClientAreaSize; // GMRectSize(PaintingRect); // ; //ClientDC := TGMGdiCompatibleDC.Create(0, HDC(Msg.WParam)); //ClientBmp := TGMGdiBitmap.CreateCompatibleBmp(ClientDC.Handle, 0, ClientSz, True); ////ClientBmp := TGMGdiBitmap.CreateFromData(ClientDC.Handle, ClientSz.x, ClientSz.y, 1, 32, nil, True); //Paint(ClientDC.Handle); //BitBlt(HDC(Msg.WParam), 0, 0, ClientSz.x, ClientSz.y, ClientDC.Handle, 0, 0, SRCCOPY); FPassMessageToOriginalHandler := False; end; if Msg.LParam and PRF_NONCLIENT <> 0 then begin msg2 := GMMessageRec(Msg.Msg, 0, Msg.WParam, 0); WMNCPaint(msg2); FPassMessageToOriginalHandler := False; end; end; { ----------------------- } { ---- TGMWinControl ---- } { ----------------------- } constructor TGMWinControl.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AWndStyle: DWORD; const AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); const cWSChild: array [Boolean] of DWORD = (0, WS_CHILD); var CtlId: LongInt; begin // // inherited constructor will set FVisible := AWndStyle and WS_VISIBLE <> 0 // if AWndStyle and WS_POPUP = 0 then CtlId := GMNextCtrlID else CtlId := 0; {inherited} Create(AParent, APosition, AAreaAlign, (AWndStyle and not WS_CHILD) or cWSChild[(AParent <> 0) {and (AWndStyle and WS_POPUP = 0)}] {or WS_CLIPCHILDREN or WS_CLIPSIBLINGS}, AWndExStyle, AText, CtlId, ABkgndColor, ARefLifeTime); end; procedure TGMWinControl.CreateParentHandle; var PIParent: IGMGetParentObj; PrntObj: TObject; PIArea: IGMUiArea; begin inherited CreateParentHandle; // // Remove WS_VISIBLE from our window creation flags if one of our direkt // parents is an invisible windowless Area. // if (FCreateData.WndStyle and WS_VISIBLE <> 0) then begin PrntObj := Parent; while (PrntObj <> nil) and not GMAreaHasWndHandle(PrntObj) and PrntObj.GetInterface(IGMUiArea, PIArea) do begin if not PIArea.Visible then begin FCreateData.WndStyle := FCreateData.WndStyle and not WS_VISIBLE; Break; end; if not PrntObj.GetInterface(IGMGetParentObj, PIParent) then Break; PrntObj := PIParent.ParentObj; end; end; end; function TGMWinControl.IsPopupWindow: Boolean; begin Result := WndStyle and WS_POPUP <> 0; end; function TGMWinControl.ClosePopupState(const RestoreActiveCtrl: Boolean): Boolean; var Dlg: TObject; begin Result := IsPopupWindow; // WndStyle and WS_POPUP <> 0; if not Result then Exit; //GMShowWindowAnimated(FHandle, False); //ShowWindow(Handle, SW_HIDE); GMAnimateWindow(FHandle, vGMPopupAniDuration, AW_BLEND or AW_HIDE); //GMReleaseMouseCapture; vGMPopupArea := nil; if RestoreActiveCtrl and GMFindParentDlg(Parent, Dlg) then SetActiveWindow(GMHWndFromWndObj(-Int64(Dlg))); //GMPostObjMessage(Dlg, WM_ACTIVATE, WA_ACTIVE, 0); end; procedure TGMWinControl.WMKeyDown(var Msg: TWMKeyDown); begin inherited; if (Msg.CharCode = VK_ESCAPE) and (GMKeyDataToKeyState(Msg.KeyData) = []) then FPassMessageToOriginalHandler := not ClosePopupState(True); end; //function TGMWinControl.IsDialogKeyMsg(const Msg: TMessage): Boolean; //begin ////Result := //(((Msg.Msg = WM_SYSKEYDOWN) or (Msg.Msg = WM_SYSKEYUP) or (Msg.Msg = WM_SYSCHAR) or (Msg.Msg = WM_SYSDEADCHAR)) or //// ((Msg.Msg = WM_KEYDOWN) or (Msg.Msg = WM_KEYUP) or (Msg.Msg = WM_CHAR)) and //// (((Msg.WParamLo in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN]) and (GMCallObjWindowProc(Self, WM_GETDLGCODE) and DLGC_WANTARROWS = 0)) or //// ((Msg.WParamLo = VK_TAB) and (GMCallObjWindowProc(Self, WM_GETDLGCODE) and DLGC_WANTTAB = 0)) or //// ((Msg.WParamLo = VK_RETURN) and (GMCallObjWindowProc(Self, WM_GETDLGCODE) and DLGC_WANTALLKEYS = 0)) or //// ((Msg.WParamLo = VK_ESCAPE) and not IsPopupWindow)); // //Result := //(((Msg.Msg = WM_SYSKEYDOWN) or (Msg.Msg = WM_SYSKEYUP) or (Msg.Msg = WM_SYSCHAR) or (Msg.Msg = WM_SYSDEADCHAR)) or // ((Msg.Msg = WM_KEYDOWN) or (Msg.Msg = WM_KEYUP) or (Msg.Msg = WM_CHAR)) and // (((Msg.WParamLo in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN]) and (SendMessage(FHandle, WM_GETDLGCODE, 0, 0) and DLGC_WANTARROWS = 0)) or // ((Msg.WParamLo = VK_TAB) and (SendMessage(FHandle, WM_GETDLGCODE, 0, 0) and DLGC_WANTTAB = 0)) or // ((Msg.WParamLo = VK_RETURN) and (SendMessage(FHandle, WM_GETDLGCODE, 0, 0) and DLGC_WANTALLKEYS = 0)) or // ((Msg.WParamLo = VK_ESCAPE) and not IsPopupWindow)); //end; //procedure TGMWinControl.WMMouseActivate(var Msg: TWMMouseActivate); //begin //inherited; ////if IsPopupWindow then begin Msg.Result := MA_NOACTIVATE; FPassMessageToOriginalHandler := False; end; //// //// Controls are supposed to never activate themself //// ////Msg.Result := MA_NOACTIVATE; FPassMessageToOriginalHandler := False; //end; procedure TGMWinControl.WMCancelMode(var Msg: TWMCancelMode); begin // // If a Control becomes disabled then set focus to some other control // inherited; // (FHandle = GetFocus) if not ClosePopupState and (vGMKeyboardFocusArea = Self) then GMPostSeletNextDlgTabAreaMsg(Self); // FFocusNextControl := True; end; procedure TGMWinControl.SurfaceOriginChanged; var R: TRect; begin inherited; // // When a parent window is scrolled using SW_SCROLLCHILDREN only the window bits are scrolled. // But the positions of contained child windows remain unchanged. // if HandleAllocated then begin R := CalculateSurfaceRect(LayoutBounds); with R do SetWindowPos(FHandle, 0, Left, Top, 0, 0, SWP_NOSIZE or SWP_NOZORDER or SWP_NOACTIVATE); //ScheduleRepaint; end; end; //procedure TGMWinControl.WMEnable(var Msg: TWMEnable); ////var dlgWnd: HWnd; //begin //try // if not Msg.Enabled and FFocusNextControl then // <- FFocusNextControl has been set before in WMCancelMode // begin // GMPostSeletNextDlgTabAreaMsg(Self); //// dlgWnd := GMDlgRootWindow(FHandle); //// if GMIsWindow(dlgWnd) then PostMessage(dlgWnd, UM_SELECTNEXTDLGTABAREA, 0, 0); // end; //finally // FFocusNextControl := False; //end; //inherited; //end; { ----------------------- } { ---- TGMOEMControl ---- } { ----------------------- } procedure TGMOEMControl.WindowProc(var Msg: TMessage); begin case Msg.Msg of // Dont delegate this to contained controls, they probably are not // subclassed and wont understand WM_XXX + WM_APP GMMessages! WM_CTLCOLOR, WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC: AssignCtrlColorValues(Msg); //WM_CTLCOLOR + WM_APP, WM_CTLCOLORMSGBOX + WM_APP .. WM_CTLCOLORSTATIC + WM_APP: AssignCtrlColorValues(Msg); else inherited WindowProc(Msg); end; end; procedure TGMOEMControl.UMStartMouseTrack(var Msg: TMessage); begin // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc end; procedure TGMOEMControl.WMEraseBkgnd(var Msg: TWMEraseBkgnd); begin // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc //FillRect(Msg.DC, PaintingRect, HBkgndBrush); end; procedure TGMOEMControl.WMMouseLeave(var Msg: TMessage); begin // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc end; procedure TGMOEMControl.WMLButtonDown(var Msg: TWMLButtonDown); begin // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc end; //procedure TGMOEMControl.WMMouseActivate(var Msg: TWMMouseActivate); //begin // // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc //end; procedure TGMOEMControl.WMPaint(var Msg: TWMPaint); begin // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc end; //procedure TGMOEMControl.WMPrint(var Msg: TMessage); //begin // // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc //end; procedure TGMOEMControl.WMPrintClient(var Msg: TMessage); begin // Nothing (no call to inherited)! Leaves FPassMessageToOriginalHandler True -> will be handled only by FOrgWndProc end; procedure TGMOEMControl.WMNCCalcSize(var Msg: TWMNCCalcSize); begin // If we assigned a frame of ours we need to handle this! inherited; //if IsFramed then begin inherited; {FPassMessageToOriginalHandler := False;} end; // Otherwise FPassMessageToOriginalHandler stays True -> will be handled only by FOrgWndProc end; procedure TGMOEMControl.WMNCPaint(var Msg: TMessage); begin // If we assigned a frame of ours we need to handle this! inherited; //if IsFramed then begin inherited; {FPassMessageToOriginalHandler := False;} end; // Otherwise FPassMessageToOriginalHandler stays True -> will be handled only by FOrgWndProc end; { ------------------------------- } { ---- TGMForeignWinCtrlImpl ---- } { ------------------------------- } {function TGMForeignWinCtrlImpl.CalculateHeight(const ANewSize: TPoint): LongInt; begin Result := GMCalcBoundingHeight(Self, ANewSize); end; function TGMForeignWinCtrlImpl.CalculateWidth(const ANewSize: TPoint): LongInt; begin Result := GMCalcBoundingWidth(Self, ANewSize); end;} procedure TGMForeignWinCtrlImpl.UMCalcHeight(var Msg: TMessage); begin //Msg.Result := CalculateHeight(Point(Msg.WParam, Msg.LParam)); Msg.Result := GMCalcBoundingHeight(Self, GMPoint(Msg.WParam, Msg.LParam)); FPassMessageToOriginalHandler := False; // <- Default handler would set Result to 0 end; procedure TGMForeignWinCtrlImpl.UMCalcWidth(var Msg: TMessage); begin //Msg.Result := CalculateWidth(Point(Msg.WParam, Msg.LParam)); Msg.Result := GMCalcBoundingWidth(Self, GMPoint(Msg.WParam, Msg.LParam)); FPassMessageToOriginalHandler := False; // <- Default handler would set Result to 0 end; { ------------------------- } { ---- TGMNCWinControl ---- } { ------------------------- } procedure TGMNCWinControl.UMHandleCreated(var Msg: TMessage); var style: DWORD; begin //inherited; style := WndStyle; if (style and WS_VISIBLE <> 0) and ((WndExStyle and WS_EX_CLIENTEDGE <> 0) or (style and (WS_VSCROLL or WS_HSCROLL) <> 0)) then FinalizeShow; FPassMessageToOriginalHandler := False; end; procedure TGMNCWinControl.FinalizeShow; begin GMPaintWndFrame(-Int64(Self)); //GMHideAndShowWnd(-Int64(Self)); ScheduleRepaint; end; { ---------------------- } { ---- TGMDlgWindow ---- } { ---------------------- } constructor TGMDlgWindow.Create(const APosition: TRect; const AWndStyle: DWORD; const AWndExStyle: DWORD; const ATitle: TGMString; const AParent: TGMWndObj; const ADlgData: Pointer; const AMenu: HMENU; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); var style_: DWORD; // tmp: DWORD; //const cPopup: array [Boolean] of DWORD = (0, WS_POPUP); begin FDlgData := ADlgData; // If a dialog has a parent then WS_POPUP is needed for correct Z-Order handling. // If a dialog has no parent then WS_POPUP prevents dialog from coming to front. //tmp := not (LongInt(WS_CHILD) or LongInt(WS_POPUP)); // xor $ffffffff; //tmp := (WS_CHILD or WS_POPUP) xor $ffffffff; // Clear WS_CHILD and WS_POPUP bits in AWndStyle // use a XOR against $ffffffff instead a NOT to avoid compiler warning! style_ := (AWndStyle and ((WS_CHILD or WS_POPUP) xor $ffffffff)); // or cPopup[AParent <> 0] //style_ := (AWndStyle and not (WS_CHILD or WS_POPUP)) or cPopup[AParent <> 0]; //inherited Create(AParent, APosition, cFixedPlace, style_, AWndExStyle or WS_EX_CONTROLPARENT, ATitle, AMenu, ABkgndColor, ARefLifeTime); end; function TGMDlgWindow.RegisterWndClass: TGMString; var icon: HICON; begin icon := 0; if GMIsWindow(FCreateData.ParentWnd) then icon := GetClassLongPtr(FCreateData.ParentWnd, GCL_HICON); // GCL_HICONSM if icon = 0 then icon := GMFindFirstIcon(GMIconInstance); Result := GMRegisterWindowClass(WndClassRegName, CursorHandle, CS_DBLCLKS, icon, HBkgndBrush).Name; end; //procedure TGMDlgWindow.CreateParentHandle; //const cPopup: array [Boolean] of DWORD = (0, WS_POPUP); //begin //// If a dialog has a parent then WS_POPUP is needed for correct Z-Order handling. //// If a dialog doesnt has a parent then WS_POPUP prevents dialog from coming to front. //inherited CreateParentHandle; //FCreateData.ParentWnd := GMModalDlgParentWnd(FCreateData.ParentWnd); //FCreateData.WndStyle := (FCreateData.WndStyle and not WS_POPUP) or cPopup[FCreateData.ParentWnd <> 0]; //end; procedure TGMDlgWindow.SetBkgndColor(const Value: COLORREF; const ARepaint: Boolean); var BkColor: COLORREF; begin {ToDo: Create Brush for background color that are no system colors} if Value = BkgndColor then Exit; inherited SetBkgndColor(Value, ARepaint); if HandleAllocated then begin if GMIsSysColor(BkgndColor) then BkColor := GMSysColor(BkgndColor) + 1 else BkColor := 0; SetClassLong(Handle, GCL_HBRBACKGROUND, LongInt(BkColor)); end; end; //function TGMDlgWindow.TempCursor: HCURSOR; //begin //Result := FTempCursor; //end; //procedure TGMDlgWindow.WMPrint(var Msg: TMessage); //var R: TRect; CachedDC, DCBmp: IGMGetHandle; DCOrg: WPARAM; BmpSz: TPoint; //begin //if Msg.WParam = 0 then Exit; //GetWindowRect(FHandle, R); // <- ClientRect would not fill frame area! //BmpSz := GMRectSize(R); // //CachedDC := TGMGdiCompatibleDC.Create; // (0, HDC(Msg.WParam)); //DCBmp := TGMGdiBitmap.CreateCompatibleBmp(CachedDC.Handle, 0, BmpSz, True); // //DCOrg := Msg.WParam; //Msg.WParam := WPARAM(CachedDC.Handle); // //inherited; //if FOrgWndProc <> nil then // Msg.Result := CallWindowProc(FOrgWndProc, FHandle, Msg.Msg, Msg.WParam, Msg.LParam); // //Msg.WParam := DCOrg; //BitBlt(HDC(Msg.WParam), 0, 0, BmpSz.x, BmpSz.y, CachedDC.Handle, 0, 0, SRCCOPY); //FPassMessageToOriginalHandler := False; //end; //procedure TGMDlgWindow.WMEraseBkgnd(var Msg: TWMEraseBkgnd); //begin // // Dont pass message to ForgWndProc! // // Assume that the complete dialog area is covered by painted child areas, and don't fill it with background brush // // This will prevent drawing flicker // Msg.Result := 1; // FPassMessageToOriginalHandler := False; //end; function TGMDlgWindow.CanClose(const ASetData: Boolean): Boolean; begin Result := True; end; function TGMDlgWindow.IsDialogKeyMsg(const Msg: TMessage): Boolean; begin Result := False; // <- We are the Dialog, no further redirection! end; function TGMDlgWindow.IsModalDialog: Boolean; begin Result := FHandle = vGMModalWnd; //Result := FIsModalDialog; end; function TGMDlgWindow.CloseOnEscape: Boolean; begin Result := IsModalDialog; end; //procedure TGMDlgWindow.UMSetTempCursor(var Msg: TMessage); //begin //Msg.Result := LongInt(FTempCursor); //if HCursor(Msg.WParam) <> INVALID_HANDLE_VALUE then FTempCursor := HCursor(Msg.WParam); //FPassMessageToOriginalHandler := False; // <- dont let FOrgWndProc overwrite Msg.Result //end; function NotifyAreaLanguageChanged(const AArea: TObject; const AData: Pointer): Boolean; var langChanged: IGMLanguageChanged; begin Result := True; if GMGetInterface(AArea, IGMLanguageChanged, langChanged) then langChanged.LanguageChanged(LPARAM(AData)); end; procedure TGMDlgWindow.UMLanguageChanged(var Msg: TMessage); begin inherited; FPassMessageToOriginalHandler := False; GMVisitAllChildAreas(Self, NotifyAreaLanguageChanged, [], True, Pointer(Msg.LParam)); NotifyAreaLanguageChanged(Self, Pointer(Msg.LParam)); GMReLayoutContainedAreas(Self, True, True); end; procedure TGMDlgWindow.WMSetFocus(var Msg: TWMSetFocus); begin if ActiveControl = nil then inherited else begin if GMIsParentObj(Self, ActiveControl) then GMSetFocus(ActiveControl) else inherited; ActiveControl := nil; // <- use ActiveControl only once end; end; //procedure TGMDlgWindow.WMNCActivate(var Msg: TWMNCActivate); //begin //if not Msg.Active then // begin // if GMIsParentObj(Self, vGMKeyboardFocusArea, True) then begin ActiveControl := vGMKeyboardFocusArea; end; // vGMKeyboardFocusArea := nil; // if vGMPopupArea <> nil then GMCancelPopup; // end; //end; procedure TGMDlgWindow.WMActivate(var Msg: TWMActivate); ///var Wnd: HWnd; begin case Msg.Active of // WA_CLICKACTIVE inerferes when activating a special control after a popup closed //WA_ACTIVE, WA_CLICKACTIVE: GMSetFocus(ActiveControl); // PostMessage(FHandle, UM_SETACTIVECTRL, 0, 0); WA_INACTIVE: begin if GMIsParentObj(Self, vGMKeyboardFocusArea, True) then begin ActiveControl := vGMKeyboardFocusArea; end; // vGMKeyboardFocusArea := nil; if vGMPopupArea <> nil then GMPostObjMessage(vGMPopupArea, WM_CANCELMODE); //GMCancelPopup; end; end; end; //function WindowEnumToArrayFunc(wnd: HWnd; param: LPARAM): BOOL; stdcall; ////var Handles: PGMPtrIntArray; Title: TGMString; //var dlg: TGMDlgWindow; // WndClass, Title: TGMString; //begin // Result := True; // <- continue iteration // if param = 0 then Exit; // //Handles := PGMPtrIntArray(param); // dlg := TGMDlgWindow(param); // wnd := GMDlgRootWindow(wnd); // // //SetLength(WndClass, 255); // //SetLength(WndClass, GetClassName(wnd, PGMChar(WndClass), Length(WndClass))); // //if CompareText(WndClass, 'tooltips_class32') = 0 then Exit; // // //SetLength(Title, 255); // //SetLength(Title, GetWindowText(wnd, PGMChar(Title), Length(Title))); // // if IsWindow(wnd) and IsWindowEnabled(wnd) and (wnd <> dlg.FHandle) and (GetWindowLong(wnd, GWL_STYLE) and WS_VISIBLE <> 0) and // not GMIsOneOfIntegers(PtrInt(wnd), dlg.FModalDisabledWindows) and (wnd <> GetDesktopWindow) then // GMAddIntegersToArray(dlg.FModalDisabledWindows, [PtrInt(wnd)]); //end; // //procedure TGMDlgWindow.UMDisableModalDlgParent(var Msg: TMessage); //var i: LongInt; //begin // //FIsModalDialog := True; // // //if not GMIsWindow(ParentWnd) then Exit; // //FParentWasEnabled := IsWindowEnabled(ParentWnd); // //if {IsModalDialog and} FParentWasEnabled then EnableWindow(ParentWnd, False); // SetLength(FModalDisabledWindows, 0); // EnumThreadWindows(GetCurrentThreadID, {$IFNDEF JEDIAPI}@{$ENDIF}WindowEnumToArrayFunc, LPARAM(Self)); // if GetCurrentThreadID <> gGMMainThreadID then EnumThreadWindows(gGMMainThreadID, {$IFNDEF JEDIAPI}@{$ENDIF}WindowEnumToArrayFunc, LPARAM(Self)); // for i:=Low(FModalDisabledWindows) to High(FModalDisabledWindows) do EnableWindow(HWnd(FModalDisabledWindows[i]), False); //end; // //procedure TGMDlgWindow.ReEnableOtherWindows; //var wnd: PtrInt; //begin // for wnd in FModalDisabledWindows do EnableWindow(HWnd(wnd), True); // SetLength(FModalDisabledWindows, 0); //end; //procedure TGMDlgWindow.InternalCreateHandle; //begin // inherited InternalCreateHandle; // SetParent(FHandle, 0); //end; //procedure TGMDlgWindow.WMDestroy(var Msg: TMessage); //begin // // // // If we are a modal window that is directly destroyed by other means than closing it normally, we must re-enable the // // windows we disabled before and realease the modal message loop! // // // ReEnableOtherWindows; // //if IsModalDialog then PostMessage(0, UM_DONEMODAL, IDCANCEL, FHandle); // <- Release (Exit) the modal message loop // //end; // inherited; //end; procedure TGMDlgWindow.WMClose(var Msg: TMessage); var doClose: Boolean; begin inherited; // // Don't call CanClose for modal dialogs, it will have been already called by the ModalMessageLoop! // CanClose may raise an exception to prevent from closing! // doClose := IsModalDialog or CanClose(Msg.WParam = IDOK); // // Delegating WM_CLOSE to UM_CLOSE offers the opportunity to simply disable // the close button and wait for something else to finish before closing. // // Better use SendMessage here. If changed to PostMessage check // GMWndStackCloseAll and GMCloseAllThreadWindows for semantic changes // //Msg.Result := SendMessage(FHandle, UM_CLOSE, Msg.WParam, Msg.LParam); try if (vGMPopupArea <> nil) and GMIsParentObj(Self, vGMPopupArea) then GMCancelPopup; DoneDialog(Msg.WParam = IDOK); except on ex: TObject do vfGMHrExceptionHandler(ex, FHandle); end; if doClose then GMShowWindowAnimated(FHandle, swHide); FPassMessageToOriginalHandler := doClose; // <- FOrgWndProc will destroy the window! end; //procedure TGMDlgWindow.UMClose(var Msg: TMessage); //begin // inherited; // FPassMessageToOriginalHandler := False; // <- default handler would set Msg.Result to 0 // if not CanClose(Msg.WParam = IDOK) then begin Msg.Result := cCannotClose; Exit; end; // <- NOTE: May Exit here! // try // // TGMMainWindow: Terminate procs have been called in CanClose! Always quit application now! // try // if (vGMPopupArea <> nil) and GMIsParentObj(Self, vGMPopupArea) then GMCancelPopup; // DoneDialog(Msg.WParam = IDOK); // except // on ex: TObject do vfGMHrExceptionHandler(ex, cDfltPrntWnd); // //vfGMHrExceptionHandler(GMExceptObject, FHandle); // end; // finally // // Re-enable parent before destroying our handle, otherwise parent will miss becoming active window again // // See remarks of EnableWindow in MSDN! // //ReEnableOtherWindows; // GMShowWindowAnimated(FHandle, swHide); // //if IsModalDialog then PostMessage(0, UM_DONEMODAL, Msg.WParam, FHandle); // <- Release (Exit) the modal message loop, and Post closing reason // //Msg.Result := Msg.WParam; // <- tell closing reason as message Result too // DestroyHandle(True); // end; //end; procedure TGMDlgWindow.UMSelectNextDlgTabArea(var Msg: TMessage); var nextArea: TObject; begin //if not GMIsParentObj(Self, vGMKeyboardFocusArea) then Exit; nextArea := GMFindNextDlgTabAreaByUIPosition(Self, vGMKeyboardFocusArea, Msg.LParam = cTrueInt); if nextArea <> nil then GMSetFocus(nextArea); end; procedure TGMDlgWindow.WMSysKeyDown(var Msg: TWMSysKeyDown); begin inherited; GMSendObjMessage(self, WM_CHANGEUISTATE, MakeLong(UIS_CLEAR, UISF_HIDEACCEL)); // <- show underlines for button shortcuts end; procedure TGMDlgWindow.WMKeyDown(var Msg: TWMKeyDown); var keyState: SGMKeyStates; reverse: Boolean; defaultCtrl: IGMIsDefaultDlgBtn; // Ctl: HWnd; CtlClassName: TGMString; begin // Cannot use DefDlgProc, it is designed for the very limited MS CreateDialog things. // Anyway there is not very much magic about dialog behaviour. inherited; keyState := GMKeyDataToKeyState(Msg.KeyData); case Msg.CharCode of VK_TAB, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN: if (keyState = []) or (keyState = [ksShift]) then begin case Msg.CharCode of VK_TAB: reverse := GetKeyState(VK_SHIFT) < 0; VK_LEFT, VK_UP: reverse := True; else reverse := False; end; GMSendObjMessage(Self, WM_CHANGEUISTATE, MakeLong(UIS_CLEAR, UISF_HIDEFOCUS)); // <- show focus rectangle SendMessage(FHandle, UM_SELECTNEXTDLGTABAREA, 0, cBoolInt[reverse]); end; VK_ESCAPE: if (keyState = []) and CloseOnEscape and CanClose(False) then GMPostObjMessage(Self, WM_CLOSE, IDCANCEL); VK_RETURN: if (keyState = []) and GMFindDfltDlgCtrl(Self, defaultCtrl) then defaultCtrl.Click; end; end; procedure TGMDlgWindow.CreateHandle; begin // // Overriding InternalCreateHandle for this would not allocate child windows first. // Could be solved by placing a inherited CreateHandle Call in TGMWindow.InternalCreateHandle but // mixing Create and InernalCreate probably is not a good idea (-> hard to understand). // if HandleAllocated then inherited CreateHandle else begin inherited CreateHandle; InitControls; GetDlgData; SetupControls; end; end; procedure TGMDlgWindow.InitControls; begin // Nothing! end; procedure TGMDlgWindow.GetDlgData; begin // Nothing! end; procedure TGMDlgWindow.SetupControls; begin // Nothing! end; procedure TGMDlgWindow.DoneDialog(const ASetData: Boolean); begin // Nothing! end; { ----------------------------- } { ---- TGMStackedDlgWindow ---- } { ----------------------------- } procedure TGMStackedDlgWindow.InternalCreateHandle; begin inherited; GMPushModalDlgWnd(Handle); end; procedure TGMStackedDlgWindow.WMNCDestroy(var Msg: TWMNCDestroy); begin inherited; GMPopModalDlgWnd; end; //procedure TGMStackedDlgWindow.WMNCDestroy(var Msg: TWMNCDestroy); //begin // //end; // //procedure TGMStackedDlgWindow.InternalCreateHandle; //begin // inherited InternalCreateHandle; //end; { ----------------------- } { ---- TGMMainWindow ---- } { ----------------------- } constructor TGMMainWindow.Create(const APosition: TRect; const AWndStyle: DWORD; const AWndExStyle: DWORD; const ATitle: TGMString; const AParent: TGMWndObj; const ADlgData: Pointer; const AMenu: HMENU; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin // WS_EX_APPWINDOW style makes an owned window appear on the task bar (by default only unowned windows appear on the task bar) inherited Create(APosition, AWndStyle, AWndExStyle or WS_EX_APPWINDOW, ATitle, AParent, ADlgData, AMenu, ABkgndColor, ARefLifeTime); end; function TGMMainWindow.CanClose(const ASetData: Boolean): Boolean; begin {ToDo: Ask other opened dialog windows via for canclose here} // (GMWinCoreMsgBox('Close?', svConfirmation, FHandle, mb_YesNo) = IDYes) and Result := inherited CanClose(ASetData) and CallTerminateProcs; if Result then GMCloseAllThreadWindows(FHandle); // <- close non-modal windows end; procedure TGMMainWindow.WMNCDestroy(var Msg: TWMNCDestroy); begin inherited; // terminate procs have been called before! PostQuitMessage(0); // <- closing main window terminates application message loop end; procedure TGMMainWindow.WMQueryEndSession(var Msg: TMessage); //const cExit: array [Boolean] of LongInt = (0, 1); begin inherited; ExitCode := GMWndStackCloseAll(0, IDABORT); // <- closes our window too //Msg.Result := cExit[ExitCode <> cCannotClose]; //FPassMessageToOriginalHandler := False; // <- default handler would set Msg.Result to 1 end; { -------------------------- } { ---- TGMMsgHookWindow ---- } { -------------------------- } {constructor TGMMsgHookWindow.Create(const AHookWnd: HWnd; const AParent: TGMWndObj; const ARefLifeTime: Boolean); const cStrMsgHookWndName = 'GMMessageHookWindow'; begin inherited Create(AParent, cNullRect, cFixedPlace, 0, 0, cStrMsgHookWndName, 0, 0, ARefLifeTime); FHookWnd := AHookWnd; end;} { --------------------------- } { ---- TGMWindowDisabler ---- } { --------------------------- } constructor TGMWindowDisabler.Create(const AWnd: HWnd; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); if GMIsWindow(AWnd) then FWnd := AWnd; if FWnd <> 0 then FWasEnabled := not EnableWindow(FWnd, False); end; destructor TGMWindowDisabler.Destroy; begin if (FWnd <> 0) and FWasEnabled then EnableWindow(FWnd, True); inherited Destroy; end; { ------------------------ } { ---- TGMDragPainter ---- } { ------------------------ } constructor TGMDragPainter.Create(const AParent: TObject; // const ADragOffs: TPoint; const ADragData: IUnknown; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FParent := AParent; FDragData := ADragData; GMCaptureMouseInput(Self); FOldKeyboardFocusArea := vGMKeyboardFocusArea; vGMKeyboardFocusArea := Self; end; procedure TGMDragPainter.DispatchMsg(var Msg: TMessage); begin Dispatch(Msg); end; procedure TGMDragPainter.WindowProc(var Msg: TMessage); begin DispatchMsg(Msg); end; function TGMDragPainter.GetParentObj: TObject; begin Result := FParent; end; function TGMDragPainter.FindWindowFromScreenPoint(const AScreenPos: TPoint): HWnd; begin Result := WindowFromPoint(AScreenPos); end; procedure TGMDragPainter.WMMouseMove(var Msg: TWMMouseMove); begin //inherited; DragAndQueryDropTarget(GMMousePosition); end; procedure TGMDragPainter.WMKeyDown(var Msg: TWMKey); begin //inherited; if Msg.CharCode = VK_ESCAPE then CancelDrag else DragAndQueryDropTarget(GMMousePosition); end; procedure TGMDragPainter.WMKeyUp(var Msg: TWMKey); begin inherited; DragAndQueryDropTarget(GMMousePosition); end; procedure TGMDragPainter.WMMouseWheel(var Msg: TMessage); var MousePos: TPoint; MouseOverWnd: HWnd; begin inherited; MousePos := SmallPointToPoint(TWMMouse(Msg).Pos); MouseOverWnd := WindowFromPoint(MousePos); if (MouseOverWnd <> 0) and (vGMMouseCaptureArea = Self) then begin vGMMouseCaptureArea := nil; try With Msg do Result := SendMessage(MouseOverWnd, Msg, WParam, LParam); UpdateWindow(MouseOverWnd); finally vGMMouseCaptureArea := Self; end; DragAndQueryDropTarget(GMMousePosition); end; end; procedure TGMDragPainter.WMCancelMode(var Msg: TWMCancelMode); begin CancelDrag; end; procedure TGMDragPainter.WMKillFocus(var Msg: TWMKillFocus); begin CancelDrag; end; procedure TGMDragPainter.ExitDragState; begin GMReleaseMouseCapture; vGMKeyboardFocusArea := FOldKeyboardFocusArea; FDragLastWndOver := 0; vGMDropTargetArea := nil; end; procedure TGMDragPainter.CancelDrag; begin try GMCallObjWindowProc(vGMDropTargetArea, UM_DRAG_CONTROL, Ord(drgCancel)); finally ExitDragState; GMCallObjWindowProc(FParent, UM_DRAG_CONTROL, Ord(drgFinished), cBoolInt[False]); vGMDragPainter := nil; // <- may free us! end; end; function TGMDragPainter.DragAndQueryDropTarget(AScreenPos: TPoint): Boolean; var WndOver: HWnd; NewCursor: HCursor; OldDropTarget: TObject; OldWndOver: HWnd; begin DragToScreenPos(AScreenPos); OldDropTarget := vGMDropTargetArea; OldWndOver := FDragLastWndOver; WndOver := FindWindowFromScreenPoint(AScreenPos); FDragLastWndOver := WndOver; NewCursor := 0; if GMIsWindow(WndOver) then begin ScreenToClient(WndOver, AScreenPos); NewCursor := HCursor(SendMessage(WndOver, UM_DRAG_QUERYDROP, MakeLongInt(AScreenPos.x, AScreenPos.y), LPARAM(FDragData))); end; if NewCursor = 0 then NewCursor := LoadCursor(0, Pointer(IDC_NO)); if NewCursor <> GetCursor then SetCursor(NewCursor); Result := NewCursor <> LoadCursor(0, Pointer(IDC_NO)); if (vGMDropTargetArea <> nil) and (WndOver <> OldWndOver) and (vGMDropTargetArea = OldDropTarget) then begin GMCallObjWindowProc(vGMDropTargetArea, UM_DRAG_CONTROL, Ord(drgLeave)); vGMDropTargetArea := nil; end; end; procedure TGMDragPainter.WMLButtonUp(var Msg: TWMLButtonUp); var mousePos: TPoint; wndOver: HWnd; canDrop: Boolean; begin try mousePos := GMClientToScreen(Self, SmallPointToPoint(Msg.Pos)); ExitDragState; canDrop := DragAndQueryDropTarget(mousePos); GMCallObjWindowProc(FParent, UM_DRAG_CONTROL, Ord(drgFinished), cBoolInt[canDrop]); if not canDrop then GMCallObjWindowProc(vGMDropTargetArea, UM_DRAG_CONTROL, Ord(drgCancel)) else begin wndOver := FindWindowFromScreenPoint(mousePos); if IsWindow(wndOver) then begin ScreenToClient(wndOver, mousePos); SendMessage(wndOver, UM_DRAG_DROPPED, MakeLongInt(mousePos.x, mousePos.y), LPARAM(FDragData)); end; end; finally vGMDragPainter := nil; // <- may free us! end; end; { ----------------------- } { ---- TGMDragWindow ---- } { ----------------------- } constructor TGMDragWindow.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ABitmap: IGMGetHandle; const AWndStyle, AWndExStyle: DWORD; const AMenu: HMENU; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin inherited Create(AParent, APosition, AAreaAlign, AWndStyle, AWndExStyle, '', AMenu, ABkgndColor, ARefLifeTime); if ABitmap <> nil then begin FBitmap := ABitmap; FBmpDC := TGMGdiCompatibleDC.Create(FBitmap.Handle); FImageSize := GMBitmapSize(FBitmap); end; end; function TGMDragWindow.PaintToRect(const ADC: HDC; const ARect: TRect): Boolean; var sz: TPoint; begin Result := True; if FBitmap = nil then Exit; sz := GMRectSize(ARect); StretchBlt(ADC, ARect.Left, ARect.Top, sz.x, sz.y, FBmpDC.Handle, 0, 0, FImageSize.x, FImageSize.y, SRCCOPY); end; //procedure TGMDragWindow.WMEraseBkgnd(var Msg: TWMEraseBkgnd); //begin // Msg.Result := 1; // FPassMessageToOriginalHandler := False; //end; { ----------------------------------- } { ---- TGMTransparentDragPainter ---- } { ----------------------------------- } constructor TGMTransparentDragPainter.Create(const AParent: TObject; const ABitmap: IGMGetHandle; const ATransparentColor: COLORREF; const ADragOffs: TPoint; const ADragData: IUnknown; const ARefLifeTime: Boolean); var rWnd: TRect; rgnHole: IGMGetHandle; rgnWnd: THandle; imgSize: TPoint; begin inherited Create(APArent, ADragData, ARefLifeTime); FDragOffs := ADragOffs; if ABitmap <> nil then begin imgSize := GMBitmapSize(ABitmap); rWnd := GMMoveRect(GMRect(cNullPoint, imgSize), GMAddPoints(GMMousePosition, ADragOffs, -1)); FDragWindow := TGMDragWindow.Create(0, rWnd, cFixedPlace, ABitmap, WS_POPUP, cLayeredWndFlag[GMCanUseLayeredWindows], 0, clWhite, True); // WS_VISIBLE or WS_CHILD rgnWnd := CreateRectRgn(0, 0, imgSize.x, imgSize.y); // <- will be owned by the system if successfully set try // Drill a hole in the window at mouse cursor hotspot so WindowFromPoint can be used to find out who is beneath the drag window rgnHole := TGMGdiRegion.CreateRect(0, GMRect(FDragOffs, GMPoint(FDragOffs.x+1, FDragOffs.y+1))); CombineRgn(rgnWnd, rgnWnd, rgnHole.Handle, RGN_DIFF); SetWindowRgn(FDragWindow.Handle, rgnWnd, False); except DeleteObject(rgnWnd); end; GMSetLayeredWindowAttributes(FDragWindow.Handle, ATransparentColor, 150, LWA_ALPHA or LWA_COLORKEY); GMCaptureMouseInput(Self); end; end; procedure TGMTransparentDragPainter.DragToScreenPos(const AScreenPos: TPoint); begin if FDragWindow = nil then Exit; SetWindowPos(FDragWindow.Handle, 0, AScreenPos.x - FDragOffs.x, AScreenPos.y - FDragOffs.y, 0, 0, SWP_NOSIZE or SWP_NOOWNERZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW); end; procedure TGMTransparentDragPainter.ExitDragState; begin FDragWindow := nil; inherited; end; { --------------------- } { ---- TGMTimerWnd ---- } { --------------------- } constructor TGMTimerWnd.Create(const AOwner: TObject; const ARefLifeTime: Boolean); begin inherited Create(0, cNullRect, cFixedPlace, 0, 0, 'GMTimerWnd', 0, 0, ARefLifeTime); FOwner := AOwner; end; procedure TGMTimerWnd.WMTimer(var Msg: TMessage); begin if (FOwner is TGMWndTimerWithHandle) and Assigned(TGMWndTimerWithHandle(FOwner).FOnTimerProc) then TGMWndTimerWithHandle(FOwner).FOnTimerProc(TGMWndTimerWithHandle(FOwner).Caller); end; { ------------------------------- } { ---- TGMWndTimerWithHandle ---- } { ------------------------------- } constructor TGMWndTimerWithHandle.Create(const AOnTimerProc: TGMObjNotifyProc; const ACaller: TObject; const AMilliSeconds: Integer; const AAutoStart, ARefLifeTime: Boolean); begin inherited Create(0, 0, AMilliSeconds, AAutoStart, ARefLifeTime); FOnTimerProc := AOnTimerProc; Caller := ACaller; end; function TGMWndTimerWithHandle.GetHandle: THandle; begin if FWindow = nil then FWindow := TGMTimerWnd.Create(Self, True); // -Int64(Self), cNullRect, cFixedPlace, 0, 0, 'GMTimerWnd', 0, 0, True); Result := FWindow.Handle; end; { ---------------------------- } { ---- TGMHideDragPainter ---- } { ---------------------------- } constructor TGMHideDragPainter.Create(const ADragPainter: IUnknown; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); if ADragPainter <> nil then ADragPainter.QueryInterface(IGMSetVisible, FDragPainter); if FDragPainter <> nil then FDragPainter.SetVisible(False); end; destructor TGMHideDragPainter.Destroy; begin if FDragPainter <> nil then FDragPainter.SetVisible(True); inherited; end; { ----------------------------- } { ---- TGMWndPaintDisabler ---- } { ----------------------------- } constructor TGMWndPaintDisabler.Create(const AWnd: HWnd; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); if GMIsWindow(AWnd) then FWnd := AWnd; if FWnd <> 0 then SendMessage(FWnd, WM_SETREDRAW, cFalseInt, 0); end; destructor TGMWndPaintDisabler.Destroy; begin if FWnd <> 0 then begin SendMessage(FWnd, WM_SETREDRAW, cTrueInt, 0); InvalidateRect(FWnd, nil, False); end; inherited Destroy; end; { -------------------------- } { ---- TGMWndTempCursor ---- } { -------------------------- } //constructor TGMWndTempCursor.Create(const ATempCursor: TGMCursor; AWnd: HWnd; const ARefLifeTime: Boolean); //var NewCursor: HCursor; //begin //inherited Create(ARefLifeTime); //AWnd := GMDlgRootWindow(AWnd); //if AWnd = 0 then AWnd := GMModalDlgParentWnd; //if not GMIsWindow(AWnd) then Exit; // //FDlgWnd := AWnd; //NewCursor := LoadCursor(0, cWinCursorRes[ATempCursor]); //FOldCursor := SendMessage(FDlgWnd, UM_SETTEMPCURSOR, WPARAM(INVALID_HANDLE_VALUE), 0); // //if NewCursor = FOldCursor then FDlgWnd := 0 else // <- Prevent re-setting the cursor in destructor if we did not change it // begin // //FOldCursor := // SendMessage(FDlgWnd, UM_SETTEMPCURSOR, WPARAM(NewCursor), 0); // SendMessage(FDlgWnd, WM_SETCURSOR, FDlgWnd, 0); // end; //end; // //destructor TGMWndTempCursor.Destroy; //begin //if GMIsWindow(FDlgWnd) and (FOldCursor <> INVALID_HANDLE_VALUE) then // begin // SendMessage(FDlgWnd, UM_SETTEMPCURSOR, WPARAM(FOldCursor), 0); // SendMessage(FDlgWnd, WM_SETCURSOR, FDlgWnd, 0); // end; //inherited Destroy; //end; { -------------------------- } { ---- TGMAppTempCursor ---- } { -------------------------- } //constructor TGMAppTempCursor.Create(const ATempCursor: TGMCursor; const ARefLifeTime: Boolean); //var NewCursor: HCursor; //begin // inherited Create(ARefLifeTime); // NewCursor := LoadCursor(0, cWinCursorRes[ATempCursor]); // FOldCursor := vAppTempCursor; // if NewCursor = FOldCursor then Exit; // vAppTempCursor := NewCursor; GMNotifyCursorChange; //end; // //destructor TGMAppTempCursor.Destroy; //begin // if FOldCursor <> vAppTempCursor then begin vAppTempCursor := FOldCursor; GMNotifyCursorChange; end; // inherited Destroy; //end; initialization vLightGray := GMChangeColorLightness(cDfltColor, 100); end.