{ +-------------------------------------------------------------+ } { | | } { | GM-Software | } { | =========== | } { | | } { | Project: All Projects | } { | | } { | Description: Controls offered by the underlying | } { | Operating System. | } { | | } { | Copyright (C) - 2012 - Gerrit Moeller. | } { | | } { | Source code distributed under MIT license. | } { | | } { | See: https://www.gm-software.de | } { | | } { +-------------------------------------------------------------+ } {$INCLUDE GMCompilerSettings.inc} unit GMOsCtrls; interface uses {$IFDEF JEDIAPI}jwaWinType, jwaWinUser,{$ELSE}Windows,{$ENDIF} GMMessages, GMStrDef, GMIntf, GMCommon, GMGdi, GMUICore, GMxCtrls {$IFDEF RICHEDIT}, GMRichEdit, GMActiveX{$ENDIF}; const {$EXTERNALSYM BS_TYPEMASK} BS_TYPEMASK = $F; {$EXTERNALSYM ECM_FIRST} ECM_FIRST = $1500; {$EXTERNALSYM EM_SETCUEBANNER} EM_SETCUEBANNER = ECM_FIRST + 1; cWin2DDirections: array [TGM2DDirection] of LongInt = (SB_HORZ, SB_VERT); cWinBtnCheck: array [Boolean] of LongInt = (BST_UNCHECKED, BST_CHECKED); type RGMUiItemData = record Title: TGMString; Data: PtrInt; end; PGMUiItemDataArray = ^TGMUiItemDataArray; TGMUiItemDataArray = array of RGMUiItemData; TGMEditBase = class(TGMNCWinControl) protected FMaxEditLength: PtrInt; FTextWhenEmpty: UnicodeString; // <- Must be UnicodeString! Because EM_SETCUEBANNER is only supported as Unicode! FOnBeforeTextChange: TGMObjNotifyProc; FOnAfterTextChange: TGMObjNotifyProc; procedure WMGetDlgCode(var AMsg: TMessage); message WM_GETDLGCODE; // TWMGetDlgCode procedure WMAppCommand(var AMsg: TWMCommand); message WM_COMMAND + WM_APP; procedure WMChar(var Msg: TWMKey); message WM_CHAR; //procedure WMPrint(var Msg: TMessage); message WM_PRINT; //procedure WMPaint(var Msg: TWMPaint); message WM_PAINT; //procedure UMHandleCreated(var Msg: TMessage); message UM_HANDLECREATED; procedure SetMaxEditLength(const AValue: PtrInt); procedure SetText(const AValue: TGMString); override; procedure SetOnBeforeTextChange(const AValue: TGMObjNotifyProc); virtual; procedure SetOnAfterTextChange(const AValue: TGMObjNotifyProc); virtual; public //OnBeforeTextChange: TGMObjNotifyProc; //OnAfterTextChange: TGMObjNotifyProc; constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = clrWindow; const ARefLifeTime: Boolean = False); override; procedure SelectAll; procedure Clear(const ANotify: Boolean = True); override; function RegisterWndClass: TGMString; override; //function ExecuteOperation(const AOperation: LongInt; const AParameter: IUnknown): Boolean; override; procedure InternalCreateHandle; override; procedure SetTextWhenEmpty(const AValue: UnicodeString); function FillsComplete: Boolean; override; property OnBeforeTextChange: TGMObjNotifyProc read FOnBeforeTextChange write SetOnBeforeTextChange; property OnAfterTextChange: TGMObjNotifyProc read FOnAfterTextChange write SetOnAfterTextChange; property MaxEditLength: PtrInt read FMaxEditLength write SetMaxEditLength; property TextWhenEmpty: UnicodeString read FTextWhenEmpty write SetTextWhenEmpty; // <- Must be UnicodeString! Because EM_SETCUEBANNER is only supported as Unicode! end; TGMEdit = Class(TGMEditBase) //protected //procedure WMChar(var Msg: TWMChar); message WM_CHAR; //procedure WMPaste(var Msg: TMessage); message WM_PASTE; //procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = clrWindow; const ARefLifeTime: Boolean = False); override; procedure InternalCreateHandle; override; end; TGMFramedEdit = class(TGMEditBase) //protected //procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = clrWindow; const ARefLifeTime: Boolean = False); override; //procedure FinalizeShow; override; end; TGMColorTextFramedEdit = class(TGMFramedEdit, IGMSetFonColor) protected FFontColor: COLORREF; public constructor Create(const ARefLifeTime: Boolean = False); override; procedure SetFontColor(const AColor: COLORREF); function FontColor: COLORREF; override; end; TGMMemo = Class(TGMEditBase) public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = clrWindow; const ARefLifeTime: Boolean = False); override; end; TGMComboBox = class; TGMComboBoxEdit = class(TGMOEMControl) protected FComboBox: TGMComboBox; procedure WMKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; // procedure WMAppCommand(var Msg: TWMCommand); message WM_COMMAND + WM_APP; // procedure EMSetSel(var Msg: TMessage); message EM_SETSEL; // procedure WMSysKeyDown(var Msg: TWMKeyDown); message WM_SYSKEYDOWN; // procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; public constructor Create(const AComboBox: TGMComboBox; const AHandle: HWnd; const AText: TGMString; const ABkgndColor: COLORREF; const ARefLifeTime: BOolean); reintroduce; overload; procedure SurfaceOriginChanged; override; function IsDialogKeyMsg(const Msg: TMessage): Boolean; override; end; TGMComboBox = class(TGMOEMControl) protected FEditWnd: IGMGetHandle; FSelectedIndex: PtrInt; FCalculatedMinWidth: LongInt; FTextWhenEmpty: UnicodeString; //FOnAfterSelectionChange: TGMObjNotifyProc; //FOnAfterEditTextChange: TGMObjNotifyProc; procedure CBResetContent(var Msg: TWMKeyDown); message CB_RESETCONTENT; procedure WMKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; procedure WMAppCommand(var Msg: TWMCommand); message WM_COMMAND + WM_APP; procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; procedure UMHandleCreated(var Msg: TMessage); message UM_HANDLECREATED; procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL; procedure FillDropValues; virtual; public OnAfterSelectionChange: TGMObjNotifyProc; OnAfterEditTextChange: TGMObjNotifyProc; constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = clrWindow; const ARefLifeTime: Boolean = False); override; procedure Clear(const ANotify: Boolean = True); override; procedure LanguageChanged(const ANewLanguage: LParam); override; function IsDialogKeyMsg(const Msg: TMessage): Boolean; override; //function ExecuteOperation(const Operation: Integer; const Parameter: IUnknown): Boolean; override; function InternalCalcWidth(const ANewSize: TPoint): LongInt; override; procedure InternalCreateHandle; override; function WndCreateRect: TRect; override; function RegisterWndClass: TGMString; override; function IsPopupWindow: Boolean; override; function GetListBoxString(const AIndex: PtrInt): TGMString; function GetItemData(const AItemIdx: PtrInt): PtrInt; function GetItemCount: PtrInt; procedure SelectAll; function SelectString(const AValue: TGMString; const ANotifyOnChange: Boolean): PtrInt; function SelectItemData(const AItemData: PtrInt; const ANotifyOnChange: Boolean): PtrInt; function GetSelectedIndex: PtrInt; procedure SetSelectedIndex(const AIndex: PtrInt); function GetCBInfo: TComboBoxInfo; procedure SetTextWhenEmpty(const AValue: UnicodeString); property SelectedIndex: PtrInt read GetSelectedIndex write SetSelectedIndex; property TextWhenEmpty: UnicodeString read FTextWhenEmpty write SetTextWhenEmpty; //procedure FinalizeShow; override; //procedure WindowProc(var Msg: TMessage); override; //function CalculateHeight(const NewSize: TPoint): LongInt; override; //property OnAfterSelectionChange: TGMObjNotifyProc read FOnAfterSelectionChange write FOnAfterSelectionChange; //property OnAfterEditTextChange: TGMObjNotifyProc read FOnAfterEditTextChange write FOnAfterEditTextChange; end; {$IFDEF RICHEDIT} TGMRichTextEdit = class(TGMEditBase, IGMSetFonColor) // TGMNCWinControl protected FEventMask: PtrInt; FInitialEreaseBkngd: Boolean; //procedure UMFocusEnter(var Msg: TMessage); message UM_FOCUSENTER; //procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; // procedure WMPrintClient(var Msg: TMessage); message WM_PRINTCLIENT; procedure SetOnBeforeTextChange(const AValue: TGMObjNotifyProc); override; procedure SetOnAfterTextChange(const AValue: TGMObjNotifyProc); override; public constructor Create(const ARefLifeTime: Boolean = False); override; //constructor Create(const AParent: TGMWndObj; // const APosition: TRect; // const AAreaAlign: TGMAreaAlignRec; // const AText: TGMString = cDfltWndText; // const AWndStyle: DWORD = cVisibleTabstop; // const AWndExStyle: DWORD = cDfltWndExStyle; // const ABkgndColor: COLORREF = clrWindow; // const ARefLifeTime: Boolean = False); override; function RegisterWndClass: TGMString; override; procedure InternalCreateHandle; override; procedure SaveToStream(const AStream: IStream; const AFormat: PtrInt = SF_RTF); procedure LoadFromStream(const AStream: IStream; const AFormat: PtrInt = SF_RTF); //procedure Print(const Caption: TGMString); procedure SetFontColor(const AColor: COLORREF); end; {$ENDIF} TGMScollPosChangeProc = procedure (const AOldPos, ANewPos: LongInt) of Object; TGMCalcIntegerFunc = function: LongInt of object; TGMScrollBar = class(TGMOEMControl, IGMScrollBar) protected FDirection: TGM2DDirection; FMin, FMax, FPage, FPos: LongInt; procedure WMAppHScroll(var Msg: TWMScroll); message WM_HSCROLL + WM_APP; procedure WMAppVScroll(var Msg: TWMScroll); message WM_VSCROLL + WM_APP; //procedure UMHandleCreated(var Msg: TMessage); message UM_HANDLECREATED; procedure SetScrollData(const AScrollData: TScrollInfo; const ARedraw: Boolean = True); function GetPosition: PtrInt; stdcall; procedure SetPosition(const AValue: PtrInt); stdcall; function GetMinPosition: LongInt; stdcall; procedure SetMinPosition(const Value: LongInt); stdcall; function GetMaxPosition: LongInt; stdcall; procedure SetMaxPosition(const Value: LongInt); stdcall; function GetPageSize: LongInt; stdcall; procedure SetPageSize(const Value: LongInt); stdcall; function CalcPageSize: LongInt; procedure HandleScroll(var Msg: TWMScroll); procedure SetupArrows(const AScrollData: TScrollInfo); //procedure DisableIfNoScroll; public OnCalcPageSize: TGMCalcIntegerFunc; OnScrollPosChange: TGMScollPosChangeProc; constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ADirection: TGM2DDirection; const AOnScrollPosChanged: TGMScollPosChangeProc = nil; const AWndStyle: DWORD = WS_VISIBLE; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); reintroduce; overload; //procedure InternalCreateHandle; override; function InternalCalcWidth(const NewSize: TPoint): LongInt; override; function InternalCalcHeight(const NewSize: TPoint): LongInt; override; procedure InternalCreateHandle; override; procedure WindowProc(var Msg: TMessage); override; function HBkgndBrush: THandle; override; function RegisterWndClass: TGMString; override; procedure SetLayoutBounds(const Value: TRect; const Repaint: Boolean); override; procedure ResetValues; procedure SetupPageSize; property Position: PtrInt read GetPosition write SetPosition; property MinPosition: LongInt read GetMinPosition write SetMinPosition; property MaxPosition: LongInt read GetMaxPosition write SetMaxPosition; property PageSize: LongInt read GetPageSize write SetPageSize; end; TGMScrollingWinCtrl = class(TGMWinControl) protected FContainedSize: TPoint; procedure WMHScroll(var Msg: TWMScroll); message WM_HSCROLL; // + WM_APP; procedure WMVScroll(var Msg: TWMScroll); message WM_VSCROLL; // + WM_APP; procedure WMMouseWheel(var Msg: TWMMouseWheel); message WM_MOUSEWHEEL; procedure DoScroll(const ADirection: TGM2DDirection; var AScrollOrigin: LongInt; const ANewPos: LongInt); procedure DoScrollMsg(const ADirection: TGM2DDirection; var AScrollOrigin: Integer; var Msg: TWMScroll); procedure ScrollToVPosition(const ADirection: TGM2DDirection; const APosition: Integer); public procedure ShowScrollBarsIfNeeded; procedure LayoutContainedAreas(const ARepaint: Boolean); override; //: TPoint; procedure ScrollRectVisible(const ARect: TRect); procedure ScrollAreaVisible(const AArea: TObject); end; TGMButton = class(TGMOEMControl, IGMIsDefaultDlgBtn) protected FOnClick: TGMObjNotifyProc; FHFont: THandle; // procedure WMMouseWheel(var Msg: TWMMouseWheel); message WM_MOUSEWHEEL; procedure WMAppCommand(var Msg: TWMCommand); message WM_COMMAND + WM_APP; //procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; //procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; // TWMGetDlgCode procedure WMKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; //procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AOnClick: TGMObjNotifyProc = nil; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = cDfltColor; const AHFont: HFONT = 0; const ARefLifeTime: Boolean = False); reintroduce; overload; function IsDefaultDlgBtn: Boolean; function FontHandle: THandle; override; function IsDialogKeyMsg(const Msg: TMessage): Boolean; override; function RegisterWndClass: TGMString; override; //procedure WindowProc(var Msg: TMessage); override; procedure Click(const ASender: TObject = nil); virtual; function FillsComplete: Boolean; override; //function PaintsComplete: Boolean; override; function InternalCalcHeight(const NewSize: TPoint): LongInt; override; function InternalCalcWidth(const NewSize: TPoint): LongInt; override; property OnClick: TGMObjNotifyProc read FOnClick write FOnClick; end; TGMMinWidthBtn = class(TGMButton) // // Never narrower than cDlgBtnWidth // public function InternalCalcWidth(const NewSize: TPoint): LongInt; override; end; TGMBtnImgKind = (bikIcon, bikBitmap); TGMImageButton = class(TGMMinWidthBtn) protected FImageKind: TGMBtnImgKind; FImage: THandle; FDestroyImage: Boolean; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = ''; const AImage: THandle = 0; const AImageKind: TGMBtnImgKind = bikIcon; const ADestroyImage: Boolean = False; const AOnClick: TGMObjNotifyProc = nil; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); reintroduce; overload; destructor Destroy; override; procedure InternalCreateHandle; override; // function CalculateWidth(const NewSize: TPoint): LongInt; override; end; TGMDlgButton = class(TGMMinWidthBtn) protected FBtnKind: TDlgBtnKind; public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ABtnKind: TDlgBtnKind; const AWndStyle: DWORD = cVisibleTabstop; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); reintroduce; overload; // procedure SetBtnKind(const ABtnKind: TDlgBtnKind); procedure Click(const ASender: TObject = nil); override; property ButtonKind: TDlgBtnKind read FBtnKind write FBtnKind; end; TGMDlgButtonClass = class of TGMDlgButton; TGMCheckButton = class(TGMButton) protected FChecked: Boolean; // <- used when window handle is not allocated function GetChecked: Boolean; procedure SetChecked(const AValue: Boolean); procedure InternalCreateHandle; override; public procedure Clear(const ANotify: Boolean = True); override; function InternalCalcWidth(const NewSize: TPoint): LongInt; override; function InternalCalcHeight(const NewSize: TPoint): LongInt; override; //function ExecuteOperation(const Operation: Integer; const Parameter: IUnknown): Boolean; override; property Checked: Boolean read GetChecked write SetChecked; end; TGMRadioButton = class(TGMCheckButton) public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); override; end; TGMCheckBox = class(TGMCheckButton) public constructor Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString = cDfltWndText; const AWndStyle: DWORD = cVisibleTabstop; const AWndExStyle: DWORD = cDfltWndExStyle; const ABkgndColor: COLORREF = cDfltColor; const ARefLifeTime: Boolean = False); override; end; //const // //cDfltDlgBtnCreateClass: TGMDlgButtonClass = TGMDlgButton; // //type TDlgButtons = array [TDlgBtnKind] of TGMDlgButton; TGMDlgBottomArea = class(TGMUiArea) protected FButtons: TDlgButtons; public constructor Create(const AParent: TObject; const AButtons: TDlgBtnKinds; const ADfltBtn: TDlgBtnKind = dbkNone; //const ADlgSpace: LongInt = cDlgSpace; ABtnCreateClass: TGMDlgButtonClass = nil; // cDfltDlgBtnCreateClass; const ABkgndColor: COLORREF = cDfltColor; const AHeight: LongInt = cDlgBtnAreaHeight; const ARefLifeTime: Boolean = False); reintroduce; overload; property Buttons: TDlgButtons read FButtons; end; function GMInitUiItemData(const ATitle: TGMString; const AData: PtrInt = 0): RGMUiItemData; procedure GMAddUiItemDataToArray(const AItemData: RGMUiItemData; var AItems: TGMUiItemDataArray); procedure GMFillComboBox(const AComboBox: TObject; const AItems: array of RGMUiItemData; const ARemoveExisting: Boolean = True); procedure GMFillComboBoxFromStrings(const AComboBox: TObject; const AStrings: array of TGMString; const ARemoveExisting: Boolean = True); procedure GMFillComboBoxFromCollection(const AComboBox: TObject; const ACollection: IUnknown; const ARemoveExisting: Boolean = True); function GMInsertLabeledCtrl(const ADisplayName: TGMString; const ALabelParent, CtlParent: TObject; const ACtrlClass: TGMWinControlClass; const AWndstyle: DWORD = 0; // cVisibleTabstop; const ACtlColor: COLORREF = clrWindow; const ABkgndColor: COLORREF = cDfltColor; const ADlgSpace: LongInt = cDlgSpace; const ACtlHeight: LongInt = cEditHeight; ACtlSpace: LongInt = 0): TGMLabelAndCtrlRec; implementation uses GMCollections {$IFDEF JEDIAPI}{$IFDEF RICHEDIT}, jwaWinError{$ENDIF}, jwaWinGdi{$ENDIF}; {$IFDEF RICHEDIT} //const cStrRichEditDLL = 'Riched32.dll'; const cStrRichEditDLL = 'Msftedit.dll'; // 'Riched20.dll'; //resourcestring RStrRichEditNotFound = cStrRichEditDLL + ' not Found'; var vRichEditDLL: IGMGetHandle = nil; {$ENDIF} { ------------------------- } { ---- Global Routines ---- } { ------------------------- } function GMInitUiItemData(const ATitle: TGMString; const AData: PtrInt): RGMUiItemData; begin Result.Title := ATitle; Result.Data := AData; end; procedure GMAddUiItemDataToArray(const AItemData: RGMUiItemData; var AItems: TGMUiItemDataArray); begin SetLength(AItems, Length(AItems)+1); AItems[High(AItems)] := AItemData; end; function GMInsertLabeledCtrl(const ADisplayName: TGMString; const ALabelParent, CtlParent: TObject; const ACtrlClass: TGMWinControlClass; const AWndstyle: DWORD; const ACtlColor: COLORREF; const ABkgndColor: COLORREF; const ADlgSpace, ACtlHeight: LongInt; ACtlSpace: LongInt): TGMLabelAndCtrlRec; var IsLabeled: Boolean; ctlText: TGMString; TopSpace: LongInt; //resTextRef: RGMResTextRefData; begin //FillByte(Result, SizeOf(Result), 0); Result := Default(TGMLabelAndCtrlRec); if ACtrlClass = nil then Exit; //resTextRef := GMResTextRefDataRec(nil); //ADisplayName := GMResolveTextResData(ADisplayName, resTextRef); IsLabeled := not GMIsClass(ACtrlClass, TGMCheckButton); // (ACtrlClass <> TGMRadioButton) and (ACtrlClass <> TGMCheckBox); if ACtlSpace = 0 then ACtlSpace := c2CtlSpace; //ADlgSpace; if (ALabelParent is TGMUiAreaBase) and TGMUiAreaBase(ALabelParent).ContainedAreas.IsEmpty then TopSpace := ADlgSpace else TopSpace := cCtlSpace; if (ADisplayName = '') or not IsLabeled then Result.Label_ := GMOwnArea(ALabelParent, TGMUiArea.Create(ALabelParent, GMRect(ADlgSpace, TopSpace, ADlgSpace, ACtlHeight), cLabelAlign, ABkgndColor)) else // if resTextRef.ResStringPtr = nil then Result.Label_ := GMOwnArea(ALabelParent, TGMxLabel.Create(ALabelParent, GMRect(ADlgSpace, TopSpace, 0, ACtlHeight), cLabelAlign, cNullRect, ADisplayName, ABkgndColor)); // else // Result.Label_ := GMOwnArea(ALabelParent, TGMxResLabel.Create(ALabelParent, GMRect(ADlgSpace, TopSpace, 0, ACtlHeight), cLabelAlign, cNullRect, resTextRef, '%s:', ABkgndColor)); if IsLabeled then ctlText := '' else ctlText := ADisplayName; Result.Ctrl := GMOwnArea(CtlParent, ACtrlClass.Create(-Int64(CtlParent), GMRect(ACtlSpace, TopSpace, ADlgSpace, ACtlHeight), cTopAligned, ctlText, cVisibleTabstop or AWndstyle, 0, ACtlColor)); //Inc(Top, ACtlHeight + cCtlSpace); end; procedure GMFillComboBox(const AComboBox: TObject; const AItems: array of RGMUiItemData; const ARemoveExisting: Boolean); var i, wMax, idx: LongInt; // wnd: THandle; txt: TGMString; textResetNeeded: Boolean; selIdx begin if not (AComboBox is TGMUiAreaBase) then Exit; // or not GMGetAllocatedObjHandle(AComboBox, wnd) //selIdx := GMSendObjMessage(AComboBox, CB_GETCURSEL); GMSendObjMessage(AComboBox, CB_RESETCONTENT); // <- will reset selected index too //if ARemoveExisting then // GMSendObjMessage(AComboBox, CB_RESETCONTENT); <- Would reset selected index too // for i:=GMSendObjMessage(AComboBox, CB_GETCOUNT)-1 downto 0 do GMSendObjMessage(AComboBox, CB_DELETESTRING, i); // // CB_SETDROPPEDWIDTH does a SelectAll, we want to prevent that, resetting to empty text helps // //textResetNeeded := GetWindowLong(wnd, GWL_STYLE) and $000f = CBS_DROPDOWNLIST; //if textResetNeeded then // begin // txt := GMGetObjText(AComboBox); // GMSetObjText(AComboBox, ''); // end; //try // Calculate max width of drop strings in pixels wMax := 0; for i:=Low(AItems) to High(AItems) do begin idx := GMSendObjMessage(AComboBox, CB_ADDSTRING, 0, LPARAM(PGMChar(AItems[i].Title))); wMax := Max(wMax, GMTextExtent(AItems[i].Title, TGMUiAreaBase(AComboBox).FontHandle).x); if (idx >= 0) and (AItems[i].Data <> 0) then GMSendObjMessage(AComboBox, CB_SETITEMDATA, idx, AItems[i].Data); end; // Set width of drop window to show strings in full length if wMax > 0 then begin if GMWinVersion >= wvVista then Inc(wMax, GetSystemMetrics(SM_CXVSCROLL)); GMSendObjMessage(AComboBox, CB_SETDROPPEDWIDTH, wMax + 8, 0); end; //GMPostObjMessage(AComboBox, EM_SETSEL, -1, 0); //finally // if textResetNeeded then GMSetObjText(AComboBox, txt); // if selIdx >= 0 then GMSendObjMessage(AComboBox, CB_SETCURSEL, selIdx); //end; end; procedure GMFillComboBoxFromStrings(const AComboBox: TObject; const AStrings: array of TGMString; const ARemoveExisting: Boolean); var i: Integer; itemDataArr: TGMUiItemDataArray; begin for i:=Low(AStrings) to High(AStrings) do GMAddUiItemDataToArray(GMInitUiItemData(AStrings[i]), itemDataArr); GMFillComboBox(AComboBox, itemDataArr, ARemoveExisting); end; procedure GMFillComboBoxFromCollection(const AComboBox: TObject; const ACollection: IUnknown; const ARemoveExisting: Boolean); var it: IGMIterator; collection: IGMIntfCollection; unkItem: IUnknown; getName: IGMGetName; itemDataArr: TGMUiItemDataArray; dataRec: RGMUiItemData; begin if (AComboBox = nil) or not GMQueryInterface(ACollection, IGMIntfCollection, collection) then Exit; it := collection.CreateIterator; while it.NextEntry(unkItem) and GMQueryInterface(unkItem, IGMGetName, getName) do begin dataRec.Title := getName.Name; dataRec.Data := PtrInt(Pointer(unkItem)); GMAddUiItemDataToArray(dataRec, itemDataArr); end; GMFillComboBox(AComboBox, itemDataArr, ARemoveExisting); end; //procedure GMFillComboBox(const AComboBox: TObject; const AItems: IUnknown; const ARemoveExisting: Boolean); //var it: IGMIterator; collection: IGMIntfCollection; i, WMax, idx: Integer; Wnd: THandle; unkItem: IUnknown; getName: IGMGetName; itemName: UnicodeString; //begin //if not (AComboBox is TGMUiAreaBase) or not GMGetAllocatedObjHandle(AComboBox, Wnd) or // not GMQueryInterface(AItems, IGMIntfCollection, collection) then Exit; // //if ARemoveExisting then // GMSendObjMessage(AComboBox, CB_RESETCONTENT); // for i:=GMSendObjMessage(AComboBox, CB_GETCOUNT)-1 downto 0 do GMSendObjMessage(AComboBox, CB_DELETESTRING, i); // //WMax := 0; //it := collection.CreateIterator; //while it.NextEntry(unkItem) and GMQueryInterface(unkItem, IGMGetName, getName) do // begin //// itemName := getName.Name; // idx := GMSendObjMessage(AComboBox, CB_ADDSTRING, 0, PtrInt(PGMChar(getName.Name))); // WMax := Max(WMax, GMTextExtent(getName.Name, TGMUiAreaBase(AComboBox).FontHandle).x); // if (idx >= 0) then GMSendObjMessage(AComboBox, CB_SETITEMDATA, idx, LParam(Pointer(unkItem))); // end; //if WMax <= 0 then Exit; //if GMWinVersion >= wvVista then Inc(WMax, GetSystemMetrics(SM_CXVSCROLL)); //GMSendObjMessage(AComboBox, CB_SETDROPPEDWIDTH, WMax + 8, 0); //end; {$IFDEF RICHEDIT} procedure LoadRichEditDLL; begin if vRichEditDLL = nil then vRichEditDLL := TGMDLLHandleObj.Create(cStrRichEditDLL, True); //if vRichEditDLL.Handle = 0 then // begin // vRichEditDLL := nil; // raise EGMException.ObjError(RStrRichEditNotFound, nil, 'LoadRichEditDLL'); // end; {if vRichEditDLL = nil then vRichEditDLL := TGMDLLHandleObj.Create('Riched20.dll'); Result := rev20; if vRichEditDLL.Handle = 0 then begin vRichEditDLL := TGMDLLHandleObj.Create('Riched32.dll'); if vRichEditDLL.Handle = 0 then begin vRichEditDLL := nil; raise EGMException.ObjError(RStrRichEditNotFound, nil, 'LoadRichEditDLL'); end; Result := rev20; end;} end; {$ENDIF} { --------------------- } { ---- TGMEditBase ---- } { --------------------- } // // Single Row edit controls neither print frame nor client // MUlti Row edit controls dont print frame // Single Row edits only adjust their edit rect nicely when they have a client edge // Edit controls properly handle WM_PRINT on fade out, so it may be some state problem on fade in // constructor TGMEditBase.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 cAutoHScroll: array [Boolean] of DWORD = (0, ES_AUTOHSCROLL); begin inherited Create(AParent, APosition, AAreaAlign, AText, AWndStyle or cAutoHScroll[AWndStyle and ES_MULTILINE = 0], AWndExStyle, ABkgndColor, ARefLifeTime); end; function TGMEditBase.RegisterWndClass: TGMString; begin Result := 'EDIT'; end; {procedure TGMEditBase.WMPaint(var Msg: TWMPaint); begin // Nothing! end;} {procedure TGMEditBase.WMPrintClient(var Msg: TMessage); begin if WndStyle and ES_MULTILINE = 0 then begin GMPrintClientImpl(Handle, HDC(Msg.WParam), HBkgndBrush); FPassMessageToOriginalHandler := False; end; end;} procedure TGMEditBase.SetTextWhenEmpty(const AValue: UnicodeString); begin if AValue = FTextWhenEmpty then Exit; FTextWhenEmpty := AValue; if HandleAllocated then SendMessage(FHandle, EM_SETCUEBANNER, 0, LPARAM(PWideChar(FTextWhenEmpty))); end; function TGMEditBase.FillsComplete: Boolean; begin //Result := inherited FillsComplete; Result := True; end; procedure TGMEditBase.InternalCreateHandle; begin inherited InternalCreateHandle; if FMaxEditLength > 0 then GMSendObjMessage(Self, EM_LIMITTEXT, FMaxEditLength); if Length(FTextWhenEmpty) > 0 then SendMessage(FHandle, EM_SETCUEBANNER, 0, LPARAM(PWideChar(FTextWhenEmpty))); end; //function TGMEditBase.ExecuteOperation(const AOperation: LongInt; // const AParameter: IUnknown): Boolean; //begin // case AOperation of // Ord(opClear): begin Text := ''; Result := True; end; // else Result := inherited ExecuteOperation(AOperation, AParameter); // end; //end; procedure TGMEditBase.SetText(const AValue: TGMString); var doNotify: Boolean; begin // // Edit controls with ES_MULTILINE don't send EN_CHANGE notifications when the text is changed via WM_SETTEXT // doNotify := HandleAllocated and (WndStyle and ES_MULTILINE <> 0) and (AValue <> Text); if doNotify and Assigned(OnBeforeTextChange) then OnBeforeTextChange(Self); inherited SetText(AValue); if doNotify and Assigned(OnAfterTextChange) then OnAfterTextChange(Self); end; procedure TGMEditBase.SetOnBeforeTextChange(const AValue: TGMObjNotifyProc); begin FOnBeforeTextChange := AValue; end; procedure TGMEditBase.SetOnAfterTextChange(const AValue: TGMObjNotifyProc); begin FOnAfterTextChange := AValue; end; procedure TGMEditBase.SetMaxEditLength(const AValue: PtrInt); begin if HandleAllocated then GMSendObjMessage(Self, EM_LIMITTEXT, AValue); FMaxEditLength := AValue; end; //procedure TGMEditBase.WMPrint(var Msg: TMessage); //begin // if (WndStyle and ES_MULTILINE = 0) and (Self is TGMWindow) then TGMWindow(Self).WMPrint(Msg); //end; procedure TGMEditBase.WMGetDlgCode(var AMsg: TMessage); begin if FOrgWndProc <> nil then AMsg.Result := CallWindowProc(FOrgWndProc, FHandle, AMsg.Msg, AMsg.WParam, AMsg.LParam); //else //AMsg.Result := DefWindowProc(FHandle, AMsg.Msg, AMsg.WParam, AMsg.LParam); if WndStyle and ES_READONLY <> 0 then AMsg.Result := AMsg.Result and not (DLGC_WANTTAB or DLGC_WANTALLKEYS); FPassMessageToOriginalHandler := False; // <- dont call FOrgWndProc again, we called it already end; procedure TGMEditBase.WMAppCommand(var AMsg: TWMCommand); begin //inherited; case AMsg.NotifyCode of EN_UPDATE: if Assigned(OnBeforeTextChange) then OnBeforeTextChange(Self); EN_CHANGE: if Assigned(OnAfterTextChange) then OnAfterTextChange(Self); end; FPassMessageToOriginalHandler := False; end; procedure TGMEditBase.SelectAll; begin if HandleAllocated then SendMessage(FHandle, EM_SETSEL, 0, -1); end; procedure TGMEditBase.Clear(const ANotify: Boolean); begin inherited Clear(ANotify); Text := ''; end; //procedure TGMEditBase.UMFocusEnter(var Msg: TMessage); //begin ////SelectAll; //if Msg.LParam and cSelectAll <> 0 then SendMessage(FHandle, EM_SETSEL, 0, -1); //end; procedure TGMEditBase.WMChar(var Msg: TWMKey); begin inherited; case Msg.CharCode of // otherwise select all does not word when readonly or multiline Ord(^A): begin SelectAll; FPassMessageToOriginalHandler := False; end; end; end; //procedure TGMEditBase.WMPrint(var Msg: TMessage); //begin // //if (WndStyle and ES_MULTILINE = 0) and (Self is TGMWindow) then TGMWindow(Self).WMPrint(Msg); //end; {procedure TGMEditBase.WMPrintClient(var Msg: TMessage); var ADC: HDC; Brush: IGMGetHandle; R: TRect; begin if (ExStyle and WS_EX_CLIENTEDGE <> 0) and (Msg.LParam and PRF_NONCLIENT <> 0) and (Msg.WParam <> 0) then begin ADC := HDC(Msg.WParam); Brush := TGMGdiBrush.Create(0, GMRGBColor(cDfltColor)); GetWindowRect(FHandle, R); FillRect(ADC, GMMoveRect(R, -R.Left, -R.Top), Brush.Handle); end; end;} {procedure TGMEditBase.WMSetFocus(var Msg: TWMSetFocus); begin inherited; SelectAll; end;} { ----------------- } { ---- TGMEdit ---- } { ----------------- } constructor TGMEdit.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AWndStyle, AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin // Without ES_MULTILINE the edit rect cannot be set inherited; // Create(AParent, APosition, AAreaAlign, AText, AWndStyle or ES_AUTOHSCROLL, AWndExStyle, ABkgndColor, ARefLifeTime); GMSetIntfMultifFrame(Frame, frsLowered, frsLowered); end; {function TGMEdit.FontHeight: LongInt; begin Result := GMFontProperties(FontHandle).lfHeight; if Result = 0 then Result := -12; end;} procedure TGMEdit.InternalCreateHandle; begin //if HandleAllocated then begin inherited CreateHandle; Exit; end else inherited CreateHandle; inherited; SendMessage(FHandle, EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN, MakeLong(2, 2)); //SendMessage(Handle, EM_SETMARGINS, EC_LEFTMARGIN, MakeLong(1, 1)); //AdjustWndEditRect(Handle, FontHeight); end; {procedure TGMEdit.WMGetDlgCode(var Msg: TWMGetDlgCode); begin // we need to be multiline to adjust the edit rect, but we dont want to handle VK_TAB and VK_RETURN //inherited; FPassMessageToOriginalHandler := False; Msg.Result := 0; end;} {procedure TGMEdit.WMPaste(var Msg: TMessage); var Clipboard: IGMClipboard; begin inherited; Clipboard := TGMClipboard.Create(Handle, True); Clipboard.AsText := GMFirstLine(Clipboard.AsText); end;} {procedure TGMEdit.WMPrintClient(var Msg: TMessage); begin //inherited; if (WndStyle and ES_MULTILINE <> 0) or (Msg.WParam = 0) then Exit; GMPrintClientImpl(Handle, HDC(Msg.WParam), HBkgndBrush); end;} {procedure TGMEdit.WMPrint(var Msg: TMessage); begin end;} {procedure TGMEdit.UMHandleCreated(var Msg: TMessage); begin //inherited; if ExStyle and WS_EX_CLIENTEDGE <> 0 then GMHideAndShowWnd(-Int64(Self)); //InvalidateRect(Handle, nil, False); end;} { ----------------------- } { ---- TGMFramedEdit ---- } { ----------------------- } constructor TGMFramedEdit.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AWndStyle, AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); //const CClientEdge: array [Boolean] of DWORD = (0, WS_EX_CLIENTEDGE); begin //FUseClientEdge := GMWinVersion >= wvWinXP; //if GMWinVersion = wvWin10_11 then CornerRounding := GMPoint(1, 1); inherited Create(AParent, APosition, AAreaAlign, AText, AWndStyle, AWndExStyle or {CClientEdge[FUseClientEdge]} WS_EX_CLIENTEDGE, ABkgndColor, ARefLifeTime); GMSetIntfMultifFrame(Self, frsNone, frsNone); end; {procedure TGMFramedEdit.FinalizeShow; begin if WndStyle and ES_PASSWORD <> 0 then GMHideAndShowWnd(-Int64(Self)) else inherited FinalizeShow; end;} {procedure TGMFramedEdit.WMSetFocus(var Msg: TWMSetFocus); begin inherited; end;} //procedure TGMFramedEdit.UMHandleCreated(var Msg: TMessage); //begin // //inherited; // GMHideAndShowWnd(-Int64(Self)); // //if FUseClientEdge or (GetWindowLong(Handle, GWL_STYLE) and ES_MULTILINE = 0) then GMHideAndShowWnd(-Int64(Self)); //end; //procedure TGMFramedEdit.WMPrintClient(var Msg: TMessage); //begin // //inherited; // //if (GetWindowLong(Handle, GWL_STYLE) and ES_MULTILINE <> 0) or (Msg.WParam = 0) then Exit; // GMPrintClientImpl(Handle, HDC(Msg.WParam), HBkgndBrush); //end; { -------------------------------- } { ---- TGMColorTextFramedEdit ---- } { -------------------------------- } constructor TGMColorTextFramedEdit.Create(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FFontColor := clrWindowText; end; function TGMColorTextFramedEdit.FontColor: COLORREF; begin Result := FFontColor; end; procedure TGMColorTextFramedEdit.SetFontColor(const AColor: COLORREF); begin if AColor = FFontColor then Exit; FFontColor := AColor; ScheduleRepaint; end; //procedure TGMColorTextFramedEdit.WMSetFocus(var Msg: TMessage); //begin //inherited; //if FOrgWndProc <> nil then with Msg do Result := CallWindowProc(FOrgWndProc, FHandle, Msg, WParam, LParam); //SelectAll; //end; { ----------------- } { ---- TGMMemo ---- } { ----------------- } constructor TGMMemo.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AWndStyle, AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin inherited Create(AParent, APosition, AAreaAlign, AText, AWndStyle or ES_AUTOHSCROLL or ES_AUTOVSCROLL or ES_MULTILINE, AWndExStyle, ABkgndColor, ARefLifeTime); GMSetIntfMultifFrame(Frame, frsLowered, frsLowered); end; //procedure TGMMemo.CreateHandle; //begin // if HandleAllocated then begin inherited CreateHandle; Exit; end else inherited CreateHandle; // SetClassLong(FHandle, GCL_STYLE, GetClassLong(FHandle, GCL_STYLE) or CS_HREDRAW or CS_VREDRAW); //end; { ------------------------- } { ---- TGMComboBoxEdit ---- } { ------------------------- } constructor TGMComboBoxEdit.Create(const AComboBox: TGMComboBox; const AHandle: HWnd; const AText: TGMString; const ABkgndColor: COLORREF; const ARefLifeTime: BOolean); begin FHandle := AHandle; inherited Create(GetParent(AHandle), cNullRect, cFixedPlace, AText, GetWindowLong(AHandle, GWL_STYLE), GetWindowLong(AHandle, GWL_EXSTYLE), ABkgndColor, ARefLifeTime); FOrgWndPtrData := SetWindowLongPtr(FHandle, cWndObjPtrData, PtrInt(Self)); {ToDO: Use window extra memory to store self pointer?} FOrgWndProc := Pointer(SetWindowLongPtr(FHandle, GWL_WNDPROC, PtrInt(@GMStdWndProc))); FComboBox := AComboBox; end; //procedure TGMComboBoxEdit.EMSetSel(var Msg: TMessage); //begin //inherited; //end; function TGMComboBoxEdit.IsDialogKeyMsg(const Msg: TMessage): Boolean; begin //if GMSendObjMessage(FComboBox, CB_GETDROPPEDSTATE) <> 0 then Result := False else // Result := ((Msg.Msg <> WM_SYSKEYDOWN) and (Msg.Msg <> WM_SYSKEYUP) and (Msg.WParamLo <> VK_DOWN)) and inherited IsDialogKeyMsg(Msg); // and () if FComboBox <> nil then Result := FComboBox.IsDialogKeyMsg(Msg) else Result := True; // // We are not a tabstop, our parent, the combobox, is the tabstop. But tab navigation is based on vGMKeyboardFocusArea // whhich points to us, so before processing tab navigation we set vGMKeyboardFocusArea to our combobox parent. // if (Msg.Msg = WM_KEYDOWN) and (Msg.WParamLo = VK_TAB) and (vGMKeyboardFocusArea = Self) then vGMKeyboardFocusArea := FComboBox; end; //procedure TGMComboBoxEdit.WMGetDlgCode(var Msg: TMessage); //begin //Msg.Result := DLGC_WANTALLKEYS; //FPassMessageToOriginalHandler := False; //end; procedure TGMComboBoxEdit.SurfaceOriginChanged; begin // Nothing! Will always be placed correctly by MS Windows end; //procedure TGMComboBoxEdit.WMAppCommand(var Msg: TWMCommand); //begin //case Msg.NotifyCode of // EN_CHANGE: // if FComboBox <> nil then FComboBox.OnAfterEditTextChange(FComboBox); //end; //end; procedure TGMComboBoxEdit.WMKeyDown(var Msg: TWMKeyDown); begin inherited; if (GMKeyDataToKeyState(Msg.KeyData) = []) then //and (Wndstyle and BS_TYPEMASK in [BS_PUSHBUTTON, BS_DEFPUSHBUTTON]) then case Msg.CharCode of VK_ESCAPE, VK_RETURN: GMSendObjMessage(FComboBox, CB_SHOWDROPDOWN, 0); end; end; //procedure TGMComboBoxEdit.WMSysKeyDown(var Msg: TWMKeyDown); //begin //inherited; //if (GMKeyDataToKeyState(Msg.KeyData) = []) then //and (Wndstyle and BS_TYPEMASK in [BS_PUSHBUTTON, BS_DEFPUSHBUTTON]) then // case Msg.CharCode of // VK_DOWN: GMSendObjMessage(FComboBox, CB_SHOWDROPDOWN, 0); // end; //end; { --------------------- } { ---- TGMComboBox ---- } { --------------------- } constructor TGMComboBox.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); var RPos: TRect; begin // ComboBoxes always show a border even if no border WndStyle has been set .. // In W2K or less popup list wont show unless height is 21, only bill knows why .. RPos := APosition; FSelectedIndex := -1; //if GMWinVersion <= wvWin2000 then case AAreaAlign.EdgeAlign[edgTop] of ealFixed: RPos.Bottom := RPos.Top + cEditHeight; ealAligned, ealCentered: RPos.Bottom := cEditHeight; end; // Always add CBS_AUTOHSCROLL // Always add WS_VSCROLL, scrollbar will only be shown if needed (automatically handeled by the windows control) inherited Create(AParent, RPos, AAreaAlign, AText, AWndStyle or WS_VSCROLL or CBS_AUTOHSCROLL, AWndExStyle, ABkgndColor, ARefLifeTime); end; function TGMComboBox.RegisterWndClass: TGMString; begin Result := 'COMBOBOX'; end; function TGMComboBox.IsPopupWindow: Boolean; begin Result := HandleAllocated and (SendMessage(Handle, CB_GETDROPPEDSTATE, 0, 0) <> 0); end; function TGMComboBox.GetCBInfo: TComboBoxInfo; begin //FillByte(Result, SizeOf(Result), 0); Result := Default(TComboBoxInfo); Result.cbSize := SizeOf(Result); if HandleAllocated then SendMessage(FHandle, CB_GETCOMBOBOXINFO, 0, LPARAM(@Result)); end; procedure TGMComboBox.SetTextWhenEmpty(const AValue: UnicodeString); begin if AValue = FTextWhenEmpty then Exit; FTextWhenEmpty := AValue; if (FEditWnd <> nil) and GMIsHandleAllocated(FEditWnd) then SendMessage(FEditWnd.Handle, EM_SETCUEBANNER, 0, LPARAM(PWideChar(FTextWhenEmpty))); end; function TGMComboBox.IsDialogKeyMsg(const Msg: TMessage): Boolean; begin if GMSendObjMessage(Self, CB_GETDROPPEDSTATE) <> 0 then Result := False else Result := ((Msg.Msg <> WM_SYSKEYDOWN) and (Msg.Msg <> WM_SYSKEYUP) and (Msg.WParamLo <> VK_DOWN)) and //((Msg.Msg <> WM_KEYDOWN) and (Msg.Msg <> WM_KEYUP) and not (Msg.WParamLo in [VK_UP, VK_DOWN])) and inherited IsDialogKeyMsg(Msg); end; procedure TGMComboBox.WMGetDlgCode(var Msg: TMessage); begin Msg.Result := DLGC_WANTARROWS; // or DLGC_WANTALLKEYS FPassMessageToOriginalHandler := False; end; function TGMComboBox.WndCreateRect: TRect; begin // Rect(APosition.Left, APosition.Top, APosition.Right, APosition.Bottom + 350) Result := inherited WndCreateRect; Inc(Result.Bottom, 700); end; function TGMComboBox.GetSelectedIndex: PtrInt; begin if HandleAllocated then Result := SendMessage(FHandle, CB_GETCURSEL, 0, 0) else Result := FSelectedIndex; end; function TGMComboBox.GetItemCount: PtrInt; begin if HandleAllocated then Result := SendMessage(FHandle, CB_GETCOUNT, 0, 0) else Result := 0; end; procedure TGMComboBox.SetSelectedIndex(const AIndex: PtrInt); begin if HandleAllocated then FSelectedIndex := GMSendObjMessage(Self, CB_SETCURSEL, AIndex); FSelectedIndex := AIndex; end; procedure TGMComboBox.FillDropValues; begin // Nothing, should be overridden in derived classes to fill items into the combobox end; procedure TGMComboBox.WMMouseWheel(var Msg: TMessage); begin // // The windows combobox sends VK_UP, VK_DOWN key GMMessages to the focus control when it receives a wheel message // if HasFocus then inherited else begin Msg.Result := DefWindowProc(FHandle, Msg.Msg, Msg.wParam, Msg.lParam); FPassMessageToOriginalHandler := False; end; end; function TGMComboBox.InternalCalcWidth(const ANewSize: TPoint): LongInt; var i: LongInt; entry: TGMString; // tmp begin if not HandleAllocated then Result := inherited InternalCalcWidth(ANewSize) else begin Result := FCalculatedMinWidth; if Result > 0 then Exit; for i:=0 to SendMessage(FHandle, CB_GETCOUNT, 0, 0)-1 do begin SetLength(entry, SendMessage(FHandle, CB_GETLBTEXTLEN, i, 0)); SendMessage(FHandle, CB_GETLBTEXT, i, LPARAM(PGMChar(entry))); Result := Max(Result, GMTextExtent(entry, FontHandle).x); end; Inc(Result, GMRectSize(GetCBInfo.rcButton).x + 10); FCalculatedMinWidth := Result; end; end; procedure TGMComboBox.InternalCreateHandle; var editWnd: HWnd; begin // // If the edit control inside the combobox is not subclassed it won't recognize dialog keys like ESC and RETURN. // inherited; editWnd := GetWindow(Handle, GW_CHILD); if editWnd <> 0 then FEditWnd := TGMComboBoxEdit.Create(Self, editWnd, Text, BkgndColor, True); FillDropValues; if FSelectedIndex >= 0 then GMSendObjMessage(Self, CB_SETCURSEL, FSelectedIndex); if (Length(FTextWhenEmpty) > 0) and (editWnd <> 0) then SendMessage(editWnd, EM_SETCUEBANNER, 0, LPARAM(PWideChar(FTextWhenEmpty))); end; procedure TGMComboBox.UMHandleCreated(var Msg: TMessage); begin if WndStyle and CBS_DROPDOWNLIST <> 0 then ScheduleRepaint; end; procedure TGMComboBox.Clear(const ANotify: Boolean); begin inherited Clear(ANotify); GMSendObjMessage(Self, CB_SETCURSEL, -1); end; //function TGMComboBox.ExecuteOperation(const Operation: Integer; const Parameter: IUnknown): Boolean; //begin // case Operation of // Ord(opClear): begin GMSendObjMessage(Self, CB_SETCURSEL, -1); Result := True; end; // else Result := inherited ExecuteOperation(Operation, Parameter); // end; //end; procedure TGMComboBox.CBResetContent(var Msg: TWMKeyDown); begin inherited; FCreateData.Text := ''; FSelectedIndex := -1; end; procedure TGMComboBox.WMKeyDown(var Msg: TWMKeyDown); //var passmsg: boolean; begin // // Nothing, dont call inherited (TGMWinControl.WMKeyDown) and leave FPassMessageToOriginalHandler = True! // //if (Msg.CharCode = VK_ESCAPE) and (GMKeyDataToKeyState(Msg.KeyData) = []) then //inherited; //passmsg := FPassMessageToOriginalHandler; //case Msg.CharCode of // VK_ESCAPE: SendMessage(FHandle, CB_SHOWDROPDOWN, 0, 0); //end; end; function TGMComboBox.GetListBoxString(const AIndex: PtrInt): TGMString; begin //if not HandleAllocated then Exit; SetLength(Result, GMSendObjMessage(Self, CB_GETLBTEXTLEN, AIndex)); if Length(Result) > 0 then GMSendObjMessage(Self, CB_GETLBTEXT, AIndex, LPARAM(PGMChar(Result))); end; function TGMComboBox.GetItemData(const AItemIdx: PtrInt): PtrInt; begin Result := GMSendObjMessage(Self, CB_GETITEMDATA, AItemIdx); end; procedure TGMComboBox.WMAppCommand(var Msg: TWMCommand); begin //inherited; case Msg.NotifyCode of // CBN_SELCHANGE CBN_SELENDOK CBN_SELCHANGE: if Assigned(OnAfterSelectionChange) and (FSelectedIndex <> SendMessage(FHandle, CB_GETCURSEL, 0, 0)) then begin FSelectedIndex := SendMessage(FHandle, CB_GETCURSEL, 0, 0); // // Neither the cb-edit control nor the combobox have the new text set at this point, // better set the new text before notifying. // // if (FEditWnd <> nil) and (FSelectedIndex >= 0) then Text := GetListBoxString(FSelectedIndex); // // well, text is set at this point .. if Assigned(OnAfterSelectionChange) then OnAfterSelectionChange(Self); FPassMessageToOriginalHandler := False; end; //CBN_SELENDOK: if Assigned(OnAfterSelectionChange) then OnAfterSelectionChange(Self); CBN_EDITCHANGE: if Assigned(OnAfterEditTextChange) then begin OnAfterEditTextChange(Self); FPassMessageToOriginalHandler := False; end; //CBN_DROPDOWN: if Assigned(OnBeforeListDrop) then OnBeforeListDrop(Self); end; //FPassMessageToOriginalHandler := False; end; procedure TGMComboBox.SelectAll; begin if HandleAllocated then SendMessage(FHandle, CB_SETEDITSEL, 0, LPARAM($FFFF0000)); end; function TGMComboBox.SelectString(const AValue: TGMString; const ANotifyOnChange: Boolean): PtrInt; var oldSelIdx: PtrInt; begin if not HandleAllocated then Exit(CB_ERR); oldSelIdx := GMSendObjMessage(Self, CB_GETCURSEL); Result := GMSendObjMessage(Self, CB_FINDSTRINGEXACT, -1, LPARAM(PGMChar(AValue))); if Result = CB_ERR then SetSelectedIndex(-1); if oldSelIdx <> Result then begin SetSelectedIndex(Result); if ANotifyOnChange and Assigned(OnAfterSelectionChange) then OnAfterSelectionChange(Self); end; end; function TGMComboBox.SelectItemData(const AItemData: PtrInt; const ANotifyOnChange: Boolean): PtrInt; var oldSelIdx: PtrInt; begin if not HandleAllocated then begin Result := CB_ERR; Exit; end; oldSelIdx := GMSendObjMessage(Self, CB_GETCURSEL); for Result:=0 to GetItemCount-1 do if GetItemData(Result) = AItemData then begin if Result <> oldSelIdx then begin SelectedIndex := Result; if ANotifyOnChange and Assigned(OnAfterSelectionChange) then OnAfterSelectionChange(Self); end; Exit; end; Result := CB_ERR; end; procedure TGMComboBox.LanguageChanged(const ANewLanguage: LParam); var selIdx: Integer; begin selIdx := SelectedIndex; FillDropValues; if selIdx >= 0 then SelectedIndex := selIdx; end; //procedure TGMComboBox.FinalizeShow; //begin // GMHideAndShowWnd(-Int64(Self)); //end; // //function TGMComboBox.CalculateHeight(const NewSize: TPoint): LongInt; //begin // Result := 21; // <- the MS ComboBox will always be this height //end; // //procedure TGMComboBox.WMKeyDown(var Msg: TWMKeyDown); //begin // if (Msg.CharCode <> VK_ESCAPE) or not IsPopupWindow then inherited; //end; // //procedure TGMComboBox.WindowProc(var Msg: TMessage); //begin // if IsDialogKeyMsg(Msg) and (SendMessage(Handle, CB_GETDROPPEDSTATE, 0, 0) = 0) then PassMsgToParentDlg(Msg) // else // case Msg.Msg of // WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC, WM_CTLCOLORMSGBOX + WM_APP .. WM_CTLCOLORSTATIC + WM_APP: // begin // SetTextColor(HDC(Msg.WParam), GMRGBColor(FontColor)); // SetBkColor(HDC(Msg.WParam), GMRGBColor(BkgndColor)); // Msg.Result := LRESULT(HBkgndBrush); // end; // else Msg.Result := CallWindowProc(FOrgWndProc, FHandle, Msg.Msg, Msg.WParam, Msg.LParam); // end; //end; // //procedure TGMComboBox.WMPrintClient(var Msg: TMessage); //begin // //inherited; // GMPrintClientImpl(Handle, HDC(Msg.WParam), HBkgndBrush); //end; // //procedure TGMComboBox.CreateHandle; //var EditWnd: HWnd; //begin // if HandleAllocated then begin inherited CreateHandle; Exit; end else inherited CreateHandle; // if WndStyle and $F <> CBS_DROPDOWN then Exit; // EditWnd := GetWindow(Handle, GW_CHILD); // if EditWnd = 0 then Exit; // // //FOrgEditId := SetWindowLongPtr(EditWnd, CWndObjPtrTag, WPARAM(Self)); // //FOrgEditProc := Pointer(SetWindowLongPtr(EditWnd, GWL_WNDPROC, PtrInt(@GMStdWndProc))); //end; { ------------------------- } { ---- TGMRichTextEdit ---- } { ------------------------- } // EDITSTREAMCALLBACK = function (dwCookie:PDWORD; pbBuff:LPBYTE; cb:LONG; var pcb:LONG):DWORD; {$IFDEF RICHEDIT} function RichEditStreamReadFunc(dwCookie: PtrUInt; Buffer: PByte; cb: LongInt; pcb: PLongInt): LongInt; stdcall; var Strm: IStream; begin Result := 0; try if dwCookie = 0 then Exit(E_INVALIDARG); Strm := IStream(dwCookie); Result := Strm.Read(Buffer, cb, pcb); except Result := E_UNEXPECTED; end; end; function RichEditStreamWriteFunc(dwCookie: PtrUInt; Buffer: PByte; cb: LongInt; pcb: PLongInt): LongInt; stdcall; var Strm: IStream; begin Result := 0; try if dwCookie = 0 then Exit(E_INVALIDARG); Strm := IStream(dwCookie); Result := Strm.Write(Buffer, cb, pcb); except Result := E_UNEXPECTED; end; end; constructor TGMRichTextEdit.Create(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FMaxEditLength := $7FFFFFFF; // <- RichEdit Max edit length is 32 KB by default (FMaxEditLength = 0)! end; //constructor TGMRichTextEdit.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); //begin // inherited Create(AParent, APosition, AAreaAlign, AText, AWndStyle or ES_AUTOHSCROLL or ES_AUTOVSCROLL, // AWndExStyle, ABkgndColor, ARefLifeTime); //end; procedure TGMRichTextEdit.InternalCreateHandle; begin inherited; SendMessage(FHandle, EM_SETBKGNDCOLOR, 0, GMRGBColor(BkgndColor)); SendMessage(FHandle, EM_SETEVENTMASK, 0, FEventMask); end; procedure TGMRichTextEdit.SetOnBeforeTextChange(const AValue: TGMObjNotifyProc); begin inherited SetOnBeforeTextChange(AValue); if Assigned(FOnBeforeTextChange) then FEventMask := FEventMask or ENM_UPDATE else FEventMask := FEventMask and not ENM_UPDATE; if HandleAllocated then SendMessage(FHandle, EM_SETEVENTMASK, 0, FEventMask); end; procedure TGMRichTextEdit.SetOnAfterTextChange(const AValue: TGMObjNotifyProc); begin inherited SetOnAfterTextChange(AValue); if Assigned(FOnAfterTextChange) then FEventMask := FEventMask or ENM_CHANGE else FEventMask := FEventMask and not ENM_CHANGE; if HandleAllocated then SendMessage(FHandle, EM_SETEVENTMASK, 0, FEventMask); end; function TGMRichTextEdit.RegisterWndClass: TGMString; begin LoadRichEditDLL; Result := MSFTEDIT_CLASS; // RICHEDIT_CLASS; end; procedure TGMRichTextEdit.WMEraseBkgnd(var Msg: TWMEraseBkgnd); begin if not FInitialEreaseBkngd then begin // // If not filled once, shows in black Bkgnd until resized, .. // FillRect(Msg.DC, PaintingRect, HBkgndBrush); GMPaintWndFrame(-Int64(Self)); //GMHideAndShowWnd(-Int64(Self)); FInitialEreaseBkngd := True; end; //inherited; end; //procedure TGMRichTextEdit.WMPrintClient(var Msg: TMessage); //var R: TRect; //begin //GetWindowRect(FHandle, R); // <- ClientRect would not fill frame area! //FillRect(HDC(Msg.WParam), R, HBkgndBrush); //end; //procedure TGMRichTextEdit.WMPrintClient(var Msg: TMessage); //begin ////inherited; ////GMPrintClientImpl(Handle, HDC(Msg.WParam), HBkgndBrush); //end; procedure TGMRichTextEdit.LoadFromStream(const AStream: IStream; const AFormat: PtrInt); var StrmRec: TEditStream; begin FillByte(StrmRec, SizeOf(StrmRec), 0); StrmRec.dwCookie := PtrUInt(AStream); StrmRec.pfnCallback := RichEditStreamReadFunc; GMSendObjMessage(Self, EM_STREAMIN, AFormat, LPARAM(@StrmRec)); GMHrCheckObj(StrmRec.dwError, Self, 'LoadFromStream'); //GMAPICheckObj('LoadFromStream', '', StrmRec.dwError, False, Self); end; procedure TGMRichTextEdit.SaveToStream(const AStream: IStream; const AFormat: PtrInt); var StrmRec: TEditStream; begin FillByte(StrmRec, SizeOf(StrmRec), 0); StrmRec.dwCookie := PtrUInt(AStream); StrmRec.pfnCallback := RichEditStreamWriteFunc; GMSendObjMessage(Self, EM_STREAMOUT, AFormat, LPARAM(@StrmRec)); GMHrCheckObj(StrmRec.dwError, Self, 'SaveToStream'); //GMAPICheckObj('SaveToStream', '', StrmRec.dwError, False, Self); end; procedure TGMRichTextEdit.SetFontColor(const AColor: COLORREF); begin end; //procedure TGMRichTextEdit.UMFocusEnter(var Msg: TMessage); //begin //if Msg.LParam and cSelectAll <> 0 then SendMessage(FHandle, EM_SETSEL, 0, -1); //end; //procedure TGMRichTextEdit.WMGetDlgCode(var Msg: TMessage); //begin // inherited; // if (WndStyle and ES_READONLY <> 0) then begin Msg.Result := DLGC_WANTARROWS; FPassMessageToOriginalHandler := False; end; //end; //procedure TGMRichTextEdit.Print(const Caption: TGMString); //var Range: TFormatRange; LastChar, MaxLen, LogX, LogY, OldMap: Integer; SaveRect: TRect; //begin // FillByte(Range, SizeOf(TFormatRange), 0); // with Printer, Range do // begin // Title := Caption; // BeginDoc; // hdc := Handle; // hdcTarget := hdc; // LogX := GetDeviceCaps(Handle, LOGPIXELSX); // LogY := GetDeviceCaps(Handle, LOGPIXELSY); // if IsRectEmpty(PageRect) then // begin // rc.right := PageWidth * 1440 div LogX; // rc.bottom := PageHeight * 1440 div LogY; // end // else begin // rc.left := PageRect.Left * 1440 div LogX; // rc.top := PageRect.Top * 1440 div LogY; // rc.right := PageRect.Right * 1440 div LogX; // rc.bottom := PageRect.Bottom * 1440 div LogY; // end; // rcPage := rc; // SaveRect := rc; // LastChar := 0; // MaxLen := GetTextLen; // chrg.cpMax := -1; // // ensure printer DC is in text map mode // OldMap := SetMapMode(hdc, MM_TEXT); // SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0); // flush buffer // try // repeat // rc := SaveRect; // chrg.cpMin := LastChar; // LastChar := SendMessage(Self.Handle, EM_FORMATRANGE, 1, LongInt(@Range)); // if (LastChar < MaxLen) and (LastChar <> -1) then NewPage; // until (LastChar >= MaxLen) or (LastChar = -1); // EndDoc; // finally // SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0); // flush buffer // SetMapMode(hdc, OldMap); // restore previous map mode // end; // end; //end; {$ENDIF} { ---------------------- } { ---- TGMScrollBar ---- } { ---------------------- } constructor TGMScrollBar.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ADirection: TGM2DDirection; const AOnScrollPosChanged: TGMScollPosChangeProc; const AWndStyle: DWORD; const AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); const cDirection: array [TGM2DDirection] of DWORD = (SBS_HORZ, SBS_VERT); begin FDirection := ADirection; OnScrollPosChange := AOnScrollPosChanged; inherited Create(AParent, APosition, AAreaAlign, '', AWndStyle or cDirection[ADirection], AWndExStyle, ABkgndColor, ARefLifeTime); end; function TGMScrollBar.RegisterWndClass: TGMString; begin Result := 'SCROLLBAR'; end; procedure TGMScrollBar.WindowProc(var Msg: TMessage); begin case Msg.Msg of // scrollbars send WM_CANCELMODE to themself when getting fullsize, dont redirect those messages! WM_CANCELMODE: DispatchMsg(Msg); else inherited WindowProc(Msg); end; end; procedure TGMScrollBar.InternalCreateHandle; begin //FCreateData.WndStyle := FCreateData.WndStyle or WS_DISABLED; inherited InternalCreateHandle; FPage := CalcPageSize; SetScrollData(GMScrollData(SIF_POS or SIF_PAGE or SIF_RANGE, FMin, FMax, FPage, FPos)); //if FMax - FMin <= FPage then SendMessage(FHandle, WM_CANCELMODE, 0, 0); end; //procedure TGMScrollBar.UMHandleCreated(var Msg: TMessage); //begin //inherited; //FPage := CalcPageSize; //SetScrollData(GMScrollData(SIF_POS or SIF_PAGE or SIF_RANGE, FMin, FMax, FPage, FPos)); ////if FMax - FMin <= FPage then SendMessage(FHandle, WM_CANCELMODE, 0, 0); //end; function TGMScrollBar.HBkgndBrush: THandle; begin Result := 0; // <- Returning NULL brush will use system standard scrollbar background end; procedure TGMScrollBar.ResetValues; begin Position := 0; MinPosition := 0; MaxPosition := 0; // PageSize := 1; end; function TGMScrollBar.CalcPageSize: LongInt; begin if Assigned(OnCalcPageSize) then Result := OnCalcPageSize else //Max(cDfltSBPageSize, OnCalcPageSize) else case FDirection of d2dHorizontal: Result := Max(0, GMRectSize(FLayoutBounds).x); d2dVertical: Result := Max(0, GMRectSize(FLayoutBounds).y); else Result := 0; // cDfltSBPageSize end; end; procedure TGMScrollBar.SetupPageSize; begin if HandleAllocated then PageSize := CalcPageSize; end; procedure TGMScrollBar.SetLayoutBounds(const Value: TRect; const Repaint: Boolean); var PageSizeChanged: Boolean; begin if Assigned(OnCalcPageSize) then begin inherited; Exit; end; // <- SetupPageSize should be done by whoever has hooked OnCalcPageSize PageSizeChanged := HandleAllocated and (((FDirection = d2dHorizontal) and (GMRectSize(Value).x <> GMRectSize(LayoutBounds).x)) or ((FDirection = d2dVertical) and (GMRectSize(Value).y <> GMRectSize(LayoutBounds).y))); inherited; if PageSizeChanged then SetupPageSize; end; procedure TGMScrollBar.WMAppHScroll(var Msg: TWMScroll); begin HandleScroll(Msg); end; procedure TGMScrollBar.WMAppVScroll(var Msg: TWMScroll); begin HandleScroll(Msg); end; procedure TGMScrollBar.HandleScroll(var Msg: TWMScroll); //var NewPos: LongInt; //function LineScrollAmmount: LongInt; //begin // Result := Max(1, Round(PageSize * 0.06)); //end; // //function PageScrollAmmount: LongInt; //begin // Result := Max(1, Round(PageSize * 0.95)); //end; begin //NewPos := Position; //case Msg.ScrollCode of // SB_TOP: NewPos := MinPosition; // SB_BOTTOM: NewPos := MaxPosition; // SB_LINEDOWN: Inc(NewPos, LineScrollAmmount); // SB_LINEUP: Dec(NewPos, LineScrollAmmount); // SB_PAGEDOWN: Inc(NewPos, PageScrollAmmount); // SB_PAGEUP: Dec(NewPos, PageScrollAmmount); // SB_THUMBPOSITION, SB_THUMBTRACK: NewPos := GMScrollDataFromWnd(Handle, SB_CTL, SIF_TRACKPOS).nTrackPos; // //SB_ENDSCROLL: //end; //Position := GMBoundedInt(NewPos, MinPosition, MaxPosition - Max(PageSize-1, 0)); //Position := NewPos; Position := GMCalcScrollPos(Msg.ScrollCode, GMScrollDataFromWnd(FHandle, SB_CTL, SIF_RANGE or SIF_PAGE or SIF_POS or SIF_TRACKPOS)); FPassMessageToOriginalHandler := False; end; procedure TGMScrollBar.SetupArrows(const AScrollData: TScrollInfo); begin //EnableScrollBar(Handle, SB_CTL, cScrollArrowStates[FDirection][Position <= MinPosition, Position >= MaxPosition - PageSize + 1]); // On Windows XP or Vista clicking a disabled scroll arrow causes a hangup inside msctl32.dll, MS should explain why .. if GMWinVersion <= wvWin2000 then with AScrollData do EnableScrollBar(Handle, SB_CTL, cScrollArrowStates[FDirection][nPos <= nMin, nPos >= nMax - LongInt(nPage) + 1]); end; procedure TGMScrollBar.SetScrollData(const AScrollData: TScrollInfo; const ARedraw: Boolean); var newPos: LongInt; _ScollData: TScrollInfo; begin if not HandleAllocated then begin if AScrollData.fMask and SIF_POS <> 0 then FPos := AScrollData.nPos; if AScrollData.fMask and SIF_PAGE <> 0 then FPage := AScrollData.nPage; if AScrollData.fMask and SIF_RANGE <> 0 then begin FMin := AScrollData.nMin; FMax := AScrollData.nMax; end; end else begin _ScollData := GMScrollDataFromWnd(Handle, SB_CTL, SIF_PAGE or SIF_RANGE or SIF_POS); if (AScrollData.fMask = SIF_POS) and ((_ScollData.nPos = AScrollData.nPos) or (_ScollData.nMax - _ScollData.nMin <= LongInt(_ScollData.nPage))) then Exit; // Setting the range may change the position too! if AScrollData.fMask and (SIF_PAGE or SIF_RANGE) <> 0 then PScrollInfo(@AScrollData)^.fMask := AScrollData.fMask or SIF_DISABLENOSCROLL; newPos := SetScrollInfo(Handle, SB_CTL, AScrollData, ARedraw); //newPos := SendMessage(FHandle, SBM_GETPOS, 0, 0); if Assigned(OnScrollPosChange) and (_ScollData.nPos <> newPos) then OnScrollPosChange(_ScollData.nPos, newPos); //SetupArrows(GMScrollDataFromWnd(Handle, SB_CTL, SIF_RANGE or SIF_PAGE or SIF_POS)); // ScrollData // // SIF_DISABLENOSCROLL does not always work .. // _ScollData := GMScrollDataFromWnd(Handle, SB_CTL, SIF_PAGE or SIF_RANGE or SIF_POS); EnableWindow(FHandle, _ScollData.nMax - _ScollData.nMin > LongInt(_ScollData.nPage)); SetupArrows(AScrollData); end; end; //procedure TGMScrollBar.DisableIfNoScroll; //begin ////if HandleAllocated then EnableWindow(FHandle, PageSize + 1 < (MaxPosition - MinPosition)); //end; function TGMScrollBar.GetPosition: PtrInt; begin // Result := GMScrollDataFromWnd(Handle, SB_CTL, SIF_POS).nPos; if not HandleAllocated then Result := FPos else Result := GetScrollPos(Handle, SB_CTL); // Result := SendMessage(FHandle, SBM_GETPOS, 0, 0); end; procedure TGMScrollBar.SetPosition(const AValue: PtrInt); begin SetScrollData(GMScrollData(SIF_POS, 0, 0, 0, AValue), True); end; function TGMScrollBar.GetMinPosition: LongInt; var DummyMaxPos: LongInt; begin // Result := GMScrollDataFromWnd(Handle, SB_CTL, SIF_RANGE).nMin; if not HandleAllocated then Result := FMin else // SendMessage(FHandle, SBM_GETRANGE, WPARAM(@Result), LPARAM(@DummyMaxPos)); GetScrollRange(Handle, SB_CTL, Result, DummyMaxPos); end; procedure TGMScrollBar.SetMinPosition(const Value: LongInt); begin SetScrollData(GMScrollData(SIF_RANGE or SIF_PAGE, Value, MaxPosition, CalcPageSize), True); end; function TGMScrollBar.GetMaxPosition: LongInt; var DummyMinPos: LongInt; begin // Result := GMScrollDataFromWnd(Handle, SB_CTL, SIF_RANGE).nMax; if not HandleAllocated then Result := FMax else //SendMessage(Handle, SBM_GETRANGE, WPARAM(@DummyMinPos), LPARAM(@Result)); GetScrollRange(Handle, SB_CTL, DummyMinPos, Result); end; procedure TGMScrollBar.SetMaxPosition(const Value: LongInt); begin SetScrollData(GMScrollData(SIF_RANGE or SIF_PAGE, MinPosition, Value, CalcPageSize), True); end; function TGMScrollBar.GetPageSize: LongInt; begin if not HandleAllocated then Result := FPage else Result := GMScrollDataFromWnd(Handle, SB_CTL, SIF_PAGE).nPage; // cDfltSBPageSize end; procedure TGMScrollBar.SetPageSize(const Value: LongInt); begin SetScrollData(GMScrollData(SIF_PAGE, 0, 0, Max(0, Value)), True); end; function TGMScrollBar.InternalCalcWidth(const NewSize: TPoint): LongInt; begin Result := GetSystemMetrics(SM_CXVSCROLL); end; function TGMScrollBar.InternalCalcHeight(const NewSize: TPoint): LongInt; begin Result := GetSystemMetrics(SM_CYHSCROLL); end; { ----------------------------- } { ---- TGMScrollingWinCtrl ---- } { ----------------------------- } procedure TGMScrollingWinCtrl.DoScroll(const ADirection: TGM2DDirection; var AScrollOrigin: LongInt; const ANewPos: LongInt); var Delta: TPoint; // R, RUpdate: TRect; begin case ADirection of d2dHorizontal: Delta := GMPoint(-AScrollOrigin - ANewPos, 0); d2dVertical: Delta := GMPoint(0, -AScrollOrigin - ANewPos); else Delta := cNullPoint; end; if (Delta.x = 0) and (Delta.y = 0) then Exit; //R := PaintingRect;//GMCalculateClientRect(Frame, PaintingRect); // CalculateSurfaceRect(LayoutBounds)); //ScrollWindowEx(FHandle, 0, Delta, @R, @R, 0, nil, SW_SCROLLCHILDREN or SW_INVALIDATE); // or SW_SCROLLCHILDREN SW_ERASE @RUpdate ScrollWindowEx(FHandle, Delta.x, Delta.y, nil, nil, 0, nil, SW_SCROLLCHILDREN or SW_INVALIDATE); // or SW_SCROLLCHILDREN SW_ERASE @RUpdate //MakeLong(SW_INVALIDATE or SW_SCROLLCHILDREN or SW_SMOOTHSCROLL, Abs(Round(ScrollDelta/1.75))) //InvalidateRect(FHandle, @RUpdate, False); SetScrollInfo(FHandle, cWin2DDirections[ADirection], GMScrollData(SIF_POS, 0, 0, 0, ANewPos), True); AScrollOrigin := -ANewPos; SurfaceOriginChanged; end; procedure TGMScrollingWinCtrl.DoScrollMsg(const ADirection: TGM2DDirection; var AScrollOrigin: LongInt; var Msg: TWMScroll); var NewPos: LongInt; begin if Msg.ScrollCode = SB_ENDSCROLL then Exit; NewPos := GMCalcScrollPos(Msg.ScrollCode, GMScrollDataFromWnd(FHandle, cWin2DDirections[ADirection], SIF_RANGE or SIF_PAGE or SIF_POS or SIF_TRACKPOS)); DoScroll(ADirection, AScrollOrigin, NewPos); FPassMessageToOriginalHandler := False; end; procedure TGMScrollingWinCtrl.WMHScroll(var Msg: TWMScroll); begin DoScrollMsg(d2dHorizontal, ScrollOffset.x, Msg); end; procedure TGMScrollingWinCtrl.WMVScroll(var Msg: TWMScroll); begin DoScrollMsg(d2dVertical, ScrollOffset.y, Msg); end; procedure TGMScrollingWinCtrl.ScrollToVPosition(const ADirection: TGM2DDirection; const APosition: LongInt); var ScrollData: TScrollInfo; begin if HandleAllocated then begin ScrollData := GMScrollDataFromWnd(FHandle, cWin2DDirections[ADirection], SIF_RANGE or SIF_PAGE or SIF_POS or SIF_TRACKPOS); ScrollData.nTrackPos := APosition; DoScroll(ADirection, ScrollOffset.y, GMCalcScrollPos(SB_THUMBTRACK, ScrollData)); end; end; procedure TGMScrollingWinCtrl.ScrollRectVisible(const ARect: TRect); var RSurface: TRect; begin if HandleAllocated then begin RSurface := GMRect(GMPoint(0, 0), ClientAreaSize); //PaintingRect; if ARect.Top + ScrollOffset.y < RSurface.Top then ScrollToVPosition(d2dVertical, ARect.Top) // + RSurface.Top else if ARect.Bottom + ScrollOffset.y > RSurface.Bottom then ScrollToVPosition(d2dVertical, Min(ARect.Top, ARect.Bottom - GMRectSize(RSurface).y)); //ScrollToVPosition(d2dVertical, Min(ARect.Top + RSurface.Top, ARect.Bottom - GMRectSize(RSurface).y + RSurface.Top)); end; end; procedure TGMScrollingWinCtrl.ScrollAreaVisible(const AArea: TObject); var area: IGMUiArea; begin if HandleAllocated and GMGetInterface(AArea, IGMUiArea, area) then ScrollRectVisible(GMAreaBoundsOffset(Self, AArea)); end; procedure TGMScrollingWinCtrl.WMMouseWheel(var Msg: TWMMouseWheel); begin ScrollToVPosition(d2dVertical, -ScrollOffset.y - GMWheelScrollDelta(ClientAreaSize.y, Msg.WheelDelta)); Msg.Result := 1; FPassMessageToOriginalHandler := False; end; procedure TGMScrollingWinCtrl.ShowScrollBarsIfNeeded; const cVScroll: array [Boolean] of DWORD = (0, WS_VSCROLL); cHScroll: array [Boolean] of DWORD = (0, WS_HSCROLL); var i, newPos: LongInt; rArea: TRect; oldStyle, newStyle: DWORD; clientSz: TPoint; childArea: IGMUiArea; begin clientSz := ClientAreaSize; if (clientSz.x <= 0) or (clientSz.y <= 0) then Exit; FContainedSize := cNullPoint; for i:=0 to ContainedAreas.Count-1 do if GMGetInterface(ContainedAreas[i], IGMUiArea, childArea) and childArea.Visible then begin rArea := childArea.LayoutBounds; if rArea.Right > FContainedSize.x then FContainedSize.x := rArea.Right; if rArea.Bottom > FContainedSize.y then FContainedSize.y := rArea.Bottom; end; oldStyle := WndStyle; newStyle := (oldStyle and not (WS_VSCROLL or WS_HSCROLL)) or cVScroll[FContainedSize.y > clientSz.y] or cHScroll[FContainedSize.x > clientSz.x]; if oldStyle <> newStyle then FLastLayoutSize := GMPoint(cInvalidLayoutVal, cInvalidLayoutVal); WndStyle := newStyle; // <- will set FCreateData WndStyle if handle has not yet been created if not HandleAllocated then Exit; if (newStyle or oldStyle) and WS_VSCROLL <> 0 then begin // FLastLayoutSize.y := cInvalidLayoutVal; newPos := SetScrollInfo(FHandle, SB_VERT, GMScrollData(SIF_RANGE or SIF_PAGE, 0, FContainedSize.y-1, clientSz.y), True); if newPos <> -ScrollOffset.y then SendMessage(FHandle, WM_VSCROLL, MakeLong(SB_THUMBPOSITION, newPos), FHandle); end; if (newStyle or oldStyle) and WS_HSCROLL <> 0 then begin // FLastLayoutSize.x := cInvalidLayoutVal; newPos := SetScrollInfo(FHandle, SB_HORZ, GMScrollData(SIF_RANGE or SIF_PAGE, 0, FContainedSize.x-1, clientSz.x), True); if newPos <> -ScrollOffset.x then SendMessage(FHandle, WM_HSCROLL, MakeLong(SB_THUMBPOSITION, newPos), FHandle); end; end; procedure TGMScrollingWinCtrl.LayoutContainedAreas(const ARepaint: Boolean); // : TPoint; begin inherited LayoutContainedAreas(False); ShowScrollBarsIfNeeded; if ARepaint then ScheduleRepaint; end; { ------------------- } { ---- TGMButton ---- } { ------------------- } constructor TGMButton.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AOnClick: TGMObjNotifyProc; const AWndStyle: DWORD; const AWndExStyle: DWORD; const ABkgndColor: COLORREF; const AHFont: HFONT; const ARefLifeTime: Boolean); begin Create(AParent, APosition, AAreaAlign, AText, AWndStyle, AWndExStyle, ABkgndColor, ARefLifeTime); FOnClick := AOnClick; FHFont := AHFont; end; function TGMButton.IsDefaultDlgBtn: Boolean; begin Result := (WndStyle and BS_TYPEMASK) = BS_DEFPUSHBUTTON; end; function TGMButton.RegisterWndClass: TGMString; begin Result := 'BUTTON'; end; //procedure TGMButton.WindowProc(var Msg: TMessage); //var i: LongInt; //begin // case Msg.Msg of // WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC, WM_CTLCOLORMSGBOX + WM_APP .. WM_CTLCOLORSTATIC + WM_APP: // begin // //SetTextColor(HDC(Msg.WParam), GMRGBColor(FontColor)); // //SetBkColor(HDC(Msg.WParam), GMRGBColor(BkgndColor)); // //Msg.Result := LRESULT(HBkgndBrush); // i := 1; // end; // // //else Msg.Result := CallWindowProc(FOrgWndProc, FHandle, Msg.Msg, Msg.WParam, Msg.LParam); // end; // // inherited WindowProc(Msg); //end; function TGMButton.FontHandle: THandle; begin if FHFont <> 0 then Result := FHFont else Result := inherited FontHandle; end; function TGMButton.IsDialogKeyMsg(const Msg: TMessage): Boolean; begin Result := ((Msg.Msg = WM_KEYDOWN) or (Msg.Msg = WM_KEYUP) or (Msg.Msg = WM_CHAR)) and ((Msg.WParamLo <> VK_RETURN) or (vGMKeyboardFocusArea <> Self) or not (Wndstyle and BS_TYPEMASK in [BS_PUSHBUTTON, BS_DEFPUSHBUTTON])) and inherited IsDialogKeyMsg(Msg); end; procedure TGMButton.WMKeyDown(var Msg: TWMKeyDown); begin inherited; if (GMKeyDataToKeyState(Msg.KeyData) = []) and (Wndstyle and BS_TYPEMASK in [BS_PUSHBUTTON, BS_DEFPUSHBUTTON]) then case Msg.CharCode of VK_RETURN: if GetEnabled then Click(Self); // , Ord(' ') end; end; //procedure TGMButton.WMEraseBkgnd(var Msg: TWMEraseBkgnd); //begin // //if Msg.DC <> 0 then // // begin // // FillRect(Msg.DC, PaintingRect, HBkgndBrush); // // end; //end; procedure TGMButton.Click(const ASender: TObject); begin if Assigned(OnClick) then OnClick(ASender); end; //procedure TGMButton.WMMouseWheel(var Msg: TWMMouseWheel); //begin //inherited; //Msg.Result := 0; ////FPassMessageToOriginalHandler := False; //end; {procedure TGMButton.WMGetDlgCode(var Msg: TMessage); // TWMGetDlgCode begin with Msg do Result := CallWindowProc(FOrgWndProc, FHandle, Msg, WParam, LParam) or DLGC_WANTALLKEYS; FPassMessageToOriginalHandler := False; end;} {procedure TGMButton.WMKeyDown(var Msg: TWMKeyDown); begin if (Msg.CharCode = VK_RETURN) and (GMKeyDataToKeyState(Msg.KeyData) = []) then Click else inherited; end;} {procedure TGMButton.WMSetFocus(var Msg: TWMSetFocus); begin WndStyle := WndStyle or BS_DEFPUSHBUTTON; end;} procedure TGMButton.WMAppCommand(var Msg: TWMCommand); begin case Msg.NotifyCode of BN_CLICKED: Click(Self); end; end; function TGMButton.FillsComplete: Boolean; begin // ODS_NOFOCUSRECT //Result := GMWinVersion < wvWinXP; //Result := True; Result := False; end; //function TGMButton.PaintsComplete: Boolean; //begin // //Result := inherited PaintsComplete; // Result := False; //end; function TGMButton.InternalCalcWidth(const NewSize: TPoint): LongInt; begin Result := GMTextExtent(Text, FontHandle).x + GMFrameExtent(Frame).x + (2*cDlgSpace); //Result := GMCalcTextAreaSize(Text, NewSize, GMFrameExtent(Frame), GMPoint(2*cDlgSpace, 0), FontHandle, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).x; end; function TGMButton.InternalCalcHeight(const NewSize: TPoint): LongInt; //var Padd: TPoint; begin //if GMWinVersion < wvWinXP then Padd := GMPoint(4, 6) else Padd := GMPoint(2, 6); //Result := GMCalcTextAreaSize(Text, NewSize, GMPoint(4, 4), Padd, FontHandle, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).y; Result := GMCalcTextAreaSize(Text, NewSize, GMFrameExtent(Frame), GMPoint(2*cDlgSpace, 10), FontHandle, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).y; end; { ------------------------ } { ---- TGMImageButton ---- } { ------------------------ } // // BS_ICON style and BM_SETIMAGE message -> Show icon only // no BS_ICON style but BM_SETIMAGE message -> Show icon and Text // constructor TGMImageButton.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AImage: THandle; const AImageKind: TGMBtnImgKind; const ADestroyImage: Boolean; const AOnClick: TGMObjNotifyProc; const AWndStyle, AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); const cImage: array [TGMBtnImgKind, Boolean] of LongWord = ((BS_ICON, 0), (BS_BITMAP, 0)); begin inherited Create(AParent, APosition, AAreaAlign, AText, AOnClick, AWndStyle or cImage[AImageKind, Length(AText) > 0], AWndExStyle, ABkgndColor, 0, ARefLifeTime); FImage := AImage; FImageKind := AImageKind; FDestroyImage := ADestroyImage; end; destructor TGMImageButton.Destroy; begin if (FImage <> 0) and FDestroyImage then begin case FImageKind of bikIcon: DestroyIcon(FImage); bikBitmap: DeleteObject(FImage); end; FImage := 0; end; inherited Destroy; end; procedure TGMImageButton.InternalCreateHandle; const cImgKind: array [TGMBtnImgKind] of LongWord = (IMAGE_ICON, IMAGE_BITMAP); begin //if HandleAllocated then begin inherited CreateHandle; Exit; end else inherited CreateHandle; inherited; if FImage <> 0 then SendMessage(FHandle, BM_SETIMAGE, cImgKind[FImageKind], LPARAM(FImage)); //SendMessage(Handle, EM_SETMARGINS, EC_LEFTMARGIN, MakeLong(1, 1)); //AdjustWndEditRect(Handle, FontHeight); end; //function TGMImageButton.CalculateWidth(const NewSize: TPoint): LongInt; //begin //Result := Max(20 + GMTextExtent(Text, FontHandle).x + (cDlgSpace+2) * 2, inherited CalculateWidth(NewSize)); // NewSize.x ////Result := inherited CalculateWidth(NewSize); ////if FImage <> 0 then Inc(Result, 20); //end; { ------------------------ } { ---- TGMMinWidthBtn ---- } { ------------------------ } function TGMMinWidthBtn.InternalCalcWidth(const NewSize: TPoint): LongInt; begin Result := Max(inherited InternalCalcWidth(NewSize), cDlgBtnWidth); end; { ---------------------- } { ---- TGMDlgButton ---- } { ---------------------- } constructor TGMDlgButton.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const ABtnKind: TDlgBtnKind; const AWndStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin inherited Create(AParent, APosition, AAreaAlign, GMDlgBtnTitle(ABtnKind), AWndStyle, 0, ABkgndColor, ARefLifeTime); FBtnKind := ABtnKind; end; procedure TGMDlgButton.Click(const ASender: TObject); var dlg: TObject; HelpInfo: THelpInfo; begin if Assigned(OnClick) then inherited else case FBtnKind of {ToDo: WM_HELP gets eaten by message queue if sended or posted - why?} dbkHelp: if GMFindParentDlg(Self, dlg) then begin FillByte(HelpInfo, SizeOf(HelpInfo), 0); GMCallObjWindowProc(dlg, WM_HELP, 0, LPARAM(@HelpInfo)); //GMSendObjMessage(dlg, WM_HELP, 0, LPARAM(@HelpInfo)); end; else if GMFindParentDlg(Self, dlg) then GMPostObjMessage(dlg, vDlgBtnMessage[FBtnKind], vDlgBtnModalResult[FBtnKind]); end; end; //procedure TGMDlgButton.SetBtnKind(const ABtnKind: TDlgBtnKind); //begin //if FBtnKind = ABtnKind then Exit; //FBtnKind := ABtnKind; //Text := GMDlgBtnTitle(ABtnKind); //end; { ------------------------ } { ---- TGMCheckButton ---- } { ------------------------ } function TGMCheckButton.GetChecked: Boolean; begin if not HandleAllocated then Result := FChecked else Result := SendMessage(FHandle, BM_GETCHECK, 0, 0) = BST_CHECKED; end; procedure TGMCheckButton.SetChecked(const AValue: Boolean); begin //if HandleAllocated then SendMessage(FHandle, BM_SETCHECK, cWinBtnCheck[AValue], 0); FChecked := AValue; GMSendObjMessage(Self, BM_SETCHECK, cWinBtnCheck[AValue]); end; procedure TGMCheckButton.InternalCreateHandle; begin inherited; GMSendObjMessage(Self, BM_SETCHECK, cWinBtnCheck[FChecked]); end; procedure TGMCheckButton.Clear(const ANotify: Boolean); begin inherited Clear(ANotify); Checked := False; end; //function TGMCheckButton.ExecuteOperation(const Operation: Integer; const Parameter: IUnknown): Boolean; //begin // case Operation of // Ord(opClear): begin Checked := False; Result := True; end; // else Result := inherited ExecuteOperation(Operation, Parameter); // end; //end; function TGMCheckButton.InternalCalcWidth(const NewSize: TPoint): LongInt; //var ADC: IGMGetHandle; RText: TRect; begin {ADC := TGMGdiCompatibleDC.Create(FontHandle, True); RText := GMRect(0, 0, NewSize.x, NewSize.y); Result := GMMultiLineTextSize(ADC.Handle, Text, RText, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).x + GMCheckBoxSize.x + 6;} //Result := GMCalcTextAreaSize(Text, NewSize, GMFrameExtent(Frame), cNullPoint, FontHandle, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).x + GMCheckBoxSize.x + 6; Result := GMTextExtent(Text, FontHandle).x + GMFrameExtent(Frame).x + GMCheckBoxSize.x + 2; end; function TGMCheckButton.InternalCalcHeight(const NewSize: TPoint): LongInt; //const cPaddX: array [Boolean] of LongInt = (3, 0); //var ADC: IGMGetHandle; RText: TRect; begin {ADC := TGMGdiCompatibleDC.Create(FontHandle, True); RText := GMRect(0, 0, NewSize.x - GMCheckBoxSize.x - 7, NewSize.y); Result := GMMultiLineTextSize(ADC.Handle, Text, RText, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).y + 2;} //Result := GMCalcTextAreaSize(Text, NewSize, GMFrameExtent(Frame), GMPoint(GMCheckBoxSize.x+cPaddX[GMWinVersion < wvWinXP], 0), FontHandle, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).y + 2; Result := GMCalcTextAreaSize(Text, GMPoint(NewSize.x - GMCheckBoxSize.x - 1, NewSize.y), GMFrameExtent(Frame), cNullPoint, FontHandle, cBtnDTFlags[WndStyle and BS_MULTILINE <> 0]).y + 2; end; { ------------------------ } { ---- TGMRadioButton ---- } { ------------------------ } constructor TGMRadioButton.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AWndStyle, AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin // BS_AUTORADIOBUTTON BS_RADIOBUTTON inherited Create(AParent, APosition, AAreaAlign, AText, AWndStyle or BS_AUTORADIOBUTTON, AWndExStyle, ABkgndColor, ARefLifeTime); end; { --------------------- } { ---- TGMCheckBox ---- } { --------------------- } constructor TGMCheckBox.Create(const AParent: TGMWndObj; const APosition: TRect; const AAreaAlign: TGMAreaAlignRec; const AText: TGMString; const AWndStyle, AWndExStyle: DWORD; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean); begin inherited Create(AParent, APosition, AAreaAlign, AText, AWndStyle or BS_AUTOCHECKBOX, AWndExStyle, ABkgndColor, ARefLifeTime); end; { -------------------------- } { ---- TGMDlgBottomArea ---- } { -------------------------- } constructor TGMDlgBottomArea.Create(const AParent: TObject; const AButtons: TDlgBtnKinds; const ADfltBtn: TDlgBtnKind; //const ADlgSpace: LongInt; ABtnCreateClass: TGMDlgButtonClass; const ABkgndColor: COLORREF; const AHeight: LongInt; const ARefLifeTime: Boolean); const cDfltBtn: array [Boolean] of DWORD = (0, BS_DEFPUSHBUTTON); var b: TDlgBtnKind; //TopSep: TObject; begin inherited Create(AParent, GMRect(0, -AHeight, 0, 0), cBottomAligned, ABkgndColor, True, ARefLifeTime); //TopSep := OwnArea(TGMUiArea.Create(Self, GMRect(ADlgSpace, 0, ADlgSpace, 2), cTopAligned)); //GMSetObjMultiFrame(TopSep, frsNone, frsLowered); GMSetObjMultiFrame(OwnArea(TGMUiArea.Create(Self, GMRect(0, 0, 0, 2), cTopAligned)), frsNone, frsLowered); OwnArea(TGMxSizeGrip.Create(Self, GMRect(-cSizeGripSize, -cSizeGripSize, 0, 0), cBottomRightCorner, cDfltSizeGripAppearance, ABkgndColor)); if ABtnCreateClass = nil then ABtnCreateClass := TGMDlgButton; for b:=Low(b) to High(b) do if b in AButtons then FButtons[b] := OwnArea(ABtnCreateClass.Create(-Int64(Self), cDlgBtnRect, cDlgBtnAlign, b, cVisibleTabstop or cDfltBtn[b = ADfltBtn])) as TGMDlgButton; end; end.