{ +-------------------------------------------------------------+ } { | | } { | GM-Software | } { | =========== | } { | | } { | Project: All Projects | } { | | } { | Description: Windows GDI classes | } { | | } { | | } { | Copyright (C) - 1996 - Gerrit Moeller. | } { | | } { | Source code distributed under MIT license. | } { | | } { | See: https://www.gm-software.de | } { | | } { +-------------------------------------------------------------+ } {$INCLUDE GMCompilerSettings.inc} unit GMGdi; interface uses {$IFDEF JEDIAPI}jwaWinType, jwaWinGdi, jwaWinUser,{$ELSE}Windows,{$ENDIF} GMStrDef, GMIntf, GMCollections, GMCommon; const {$IFDEF FPC} {$IFNDEF JEDIAPI} {$EXTERNALSYM RGN_ERROR} RGN_ERROR = ERROR; {$ENDIF} {$ENDIF} cSysColFlag = $80000000; // DWORD($80000000); //cNotSysColFlag = $7FFFFFFF; // not $80000000; clrTransparent = CLR_INVALID; clrAutoTransparent = $80FFFFFF; // System colors clrScrollBar = COLOR_SCROLLBAR or cSysColFlag; clrBackground = COLOR_BACKGROUND or cSysColFlag; clrActiveCaption = COLOR_ACTIVECAPTION or cSysColFlag; clrGradientActiveCaption = COLOR_GRADIENTACTIVECAPTION or cSysColFlag; clrGradientInactiveCaption = COLOR_GRADIENTINACTIVECAPTION or cSysColFlag; clrInactiveCaption = COLOR_INACTIVECAPTION or cSysColFlag; clrMenu = COLOR_MENU or cSysColFlag; clrWindow = COLOR_WINDOW or cSysColFlag; clrWindowFrame = COLOR_WINDOWFRAME or cSysColFlag; clrMenuText = COLOR_MENUTEXT or cSysColFlag; clrWindowText = COLOR_WINDOWTEXT or cSysColFlag; clrCaptionText = COLOR_CAPTIONTEXT or cSysColFlag; clrActiveBorder = COLOR_ACTIVEBORDER or cSysColFlag; clrInactiveBorder = COLOR_INACTIVEBORDER or cSysColFlag; clrAppWorkSpace = COLOR_APPWORKSPACE or cSysColFlag; clrHighlight = COLOR_HIGHLIGHT or cSysColFlag; clrHighlightText = COLOR_HIGHLIGHTTEXT or cSysColFlag; clrBtnFace = COLOR_BTNFACE or cSysColFlag; clrBtnShadow = COLOR_BTNSHADOW or cSysColFlag; clrGrayText = COLOR_GRAYTEXT or cSysColFlag; clrBtnText = COLOR_BTNTEXT or cSysColFlag; clrInactiveCaptionText = COLOR_INACTIVECAPTIONTEXT or cSysColFlag; clrBtnHighlight = COLOR_BTNHIGHLIGHT or cSysColFlag; clr3DDkShadow = COLOR_3DDKSHADOW or cSysColFlag; clr3DLight = COLOR_3DLIGHT or cSysColFlag; clrInfoText = COLOR_INFOTEXT or cSysColFlag; clrInfoBkgnd = COLOR_INFOBK or cSysColFlag; clrHotLight = COLOR_HOTLIGHT or cSysColFlag; // Standard colors clBlack = $000000; clMaroon = $000080; clGreen = $008000; clOlive = $008080; clNavy = $800000; clPurple = $800080; clTeal = $808000; clGray = $808080; clSilver = $C0C0C0; clRed = $0000FF; clLime = $00FF00; clYellow = $00FFFF; clBlue = $FF0000; clPink = $FF00FF; clAqua = $FFFF00; clLtGray = clSilver; // $C0C0C0; clDkGray = $808080; clWhite = $FFFFFF; // Other useful colors clrLightBlue = $FFF0E6; // 255-240-230 //clrLightBlue = $FFEEE7; clrColdBlue = $f8b08c; clrWarmBlue = $eca800; // $efad00 clrGlassBlue = $fbdabe; // $FDDCCB clrGlassGreen = $bfdea9; // $a2cf81; clrOrange = $0080FF; clrDkOrange = $4080ff; clrCreme = $F0FBFF; CLR_DEFAULT = $FF000000; cInvalidHIcon = $ffffffff; cFrameDarknessDelta = -400; type {$IFDEF FPC} {$IFNDEF JEDIAPI} PBitmapV5Header = ^TBitmapV5Header; BITMAPV5HEADER = record bV5Size: DWORD; bV5Width: LONG; bV5Height: LONG; bV5Planes: WORD; bV5BitCount: WORD; bV5Compression: DWORD; bV5SizeImage: DWORD; bV5XPelsPerMeter: LONG; bV5YPelsPerMeter: LONG; bV5ClrUsed: DWORD; bV5ClrImportant: DWORD; bV5RedMask: DWORD; bV5GreenMask: DWORD; bV5BlueMask: DWORD; bV5AlphaMask: DWORD; bV5CSType: DWORD; bV5Endpoints: CIEXYZTRIPLE; bV5GammaRed: DWORD; bV5GammaGreen: DWORD; bV5GammaBlue: DWORD; bV5Intent: DWORD; bV5ProfileData: DWORD; bV5ProfileSize: DWORD; bV5Reserved: DWORD; end; {$EXTERNALSYM BITMAPV5HEADER} LPBITMAPV5HEADER = ^BITMAPV5HEADER; {$EXTERNALSYM LPBITMAPV5HEADER} TBitmapV5Header = BITMAPV5HEADER; {$ENDIF} {$ENDIF} TGMGdiObjSelector = class(TGMRefCountedObj, IGMGetHandle, IGMHandleAllocated) protected FDC: HDC; FPrevObject: THandle; FGdiObject: THandle; public //constructor Create(const ADC: HDC; const GdiObj: IGMGetHandle; const ARefLifeTime: Boolean = True); reintroduce; overload; constructor Create(const ADC: HDC; const AGdiObject: THandle = 0; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; procedure ReleaseGdiObject; virtual; function GetHandleAllocated: Boolean; stdcall; function GetHandle: THandle; virtual; stdcall; property Handle: THandle read GetHandle; property HandleAllocated: Boolean read GetHandleAllocated; property DC: HDC read FDC; end; TGMGdiObject = class(TGMGdiObjSelector) //protected //FDC: HDC; //FPrevObject: THandle; //FGdiObject: THandle; public //constructor Create(const ADC: HDC; const AGdiObject: THandle = 0; const ARefLifeTime: Boolean = True); reintroduce; //destructor Destroy; override; procedure ReleaseGdiObject; override; end; TGMGdiPen = class(TGMGdiObject) public constructor Create(const ADC: HDC; const AColor: COLORREF; const AStyle: LongInt = PS_SOLID; const AWidth: LongInt = 1; const ARefLifeTime: Boolean = True); end; TGMGdiBrush = class(TGMGdiObject, IGMHashCode) public constructor Create(const ADC: HDC; const AColor: COLORREF; const AStyle: LongInt = BS_SOLID; const AHatch: LongInt = 0; const ARefLifeTime: Boolean = True); constructor CreateFromBmp(const ADC: HDC; const AHBmp: HBitmap; const ARefLifeTime: Boolean = True); function HashCode: TGMHashCode; end; TGMGdiCachedBrush = class(TGMGdiBrush) public destructor Destroy; override; end; IGMGdiFont = interface(IGMGetHandle) ['{A11854F1-B57E-4c5e-B1A8-F96D64D07215}'] function GetFontData: TLogFont; stdcall; procedure SetFontData(const Value: TLogFont); stdcall; property FontData: TLogFont read GetFontData write SetFontData; end; TFontStyle = (fsItalic, fsUnderline, fsStrikeOut); TFontStyles = set of TFontStyle; TDefaultFont = (dfAnsiFixedFont, dfOEMFixedFont, dfAnsiVarFont, dfDeviceFont, dfUIFont, dfSysFont, dfSysFixedFont); TGMGdiFont = class(TGMGdiObject, IGMGdiFont) protected function GetFontData: TLogFont; stdcall; procedure SetFontData(const Value: TLogFont); stdcall; public constructor Create(const ADC: HDC; const AFont: TDefaultFont; const ARefLifeTime: Boolean = True); overload; constructor Create(const ADC: HDC; const AFontData: TLogFont; const ARefLifeTime: Boolean = True); overload; constructor Create(const ADC: HDC; const AName: TGMString; const AHeight: LongInt = 0; const AWeight: LongInt = FW_NORMAL; const AStyle: TFontStyles = []; const ARefLifeTime: Boolean = True); overload; property FontData: TLogFont read GetFontData write SetFontData; end; TGMGdiBitmap = class(TGMGdiObject) public constructor CreateFromRes(const ADC: HDC; const AResName: PGMChar; const AInstance: THandle; const ACheckLoad: Boolean = True; const ARefLifeTime: Boolean = True); constructor CreateFromBmpData(const ADC: HDC; const ABmpData: TBitmap; const ARefLifeTime: Boolean = True); constructor CreateCompatibleBmp(const ADC, ADcCompatible: HDC; const ASize: TPoint; const ARefLifeTime: Boolean = True); constructor CreateFromData(const ADC: HDC; const ASize: TPoint; const APlanes, ABitCount: LongInt; const ADataBits: Pointer = nil; const ARefLifeTime: Boolean = True); //constructor CreateCompatibleBmp(const ADC: HDC; const ASize: TPoint; const ARefLifeTime: Boolean = True); overload; end; TGMGdiDIBitmap = class(TGMGdiObject) protected FBmpInfo: TBitmapInfoHeader; FBits: Pointer; public constructor Create(const ADC: HDC; const ASize: TPoint; const ABitsPerPixel: LongInt; const ARefLifeTime: Boolean = True); end; {TGMGdiDCBitmap = class; IGMGdiDCBitmap = interface(IGMGetHandle) ['F32674B8-013F-4406-B151-E79EC71338A1'] function Obj: TGMGdiDCBitmap; end; TGMGdiDCBitmap = class(TGMGdiBitmap, IGMGdiDCBitmap) public constructor CreateCompatible(const ASize: TPoint; const ARefLifeTime: Boolean = True); function Obj: TGMGdiDCBitmap; end;} TGMGdiRegion = class(TGMGdiObject) public constructor CreateRect(const ADC: HDC; const ARect: TRect; const ARefLifeTime: Boolean = True); constructor CreateRoundRect(const ADC: HDC; const ARect: TRect; const ARounding: TPoint; const ARefLifeTime: Boolean = True); constructor CreatePolygon(const ADC: HDC; const APoints: array of TPoint; const AFilleMode: LongInt = WINDING; const ARefLifeTime: Boolean = True); constructor CreateElipse(const ADC: HDC; const ABounds: TRect; const ARefLifeTime: Boolean = True); constructor CreatefromWindow(const ADC: HDC; const AWnd: HWnd; const ARefLifeTime: Boolean = True); end; TGMGdiPalette = class(TGMGdiObject) public constructor Create(const ADC: HDC; const ALogPalette: TLogPalette; const ARefLifeTime: Boolean = True); end; TGMWindowDC = class(TGMRefCountedObj, IGMGetHandle) protected FWnd: HWnd; FDC: HDC; public constructor Create(const AWnd: HWnd; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; function GetHandle: THandle; virtual; stdcall; property Handle: THandle read GetHandle; end; TGMGdiCompatibleDC = class(TGMRefCountedObj, IGMGetHandle, IGMCriticalSection) protected FDC: HDC; FCriticalSection: IGMCriticalSection; //FGdiObject: THandle; //FPrevObject: THandle; public // constructor Create(const ARefLifeTime: Boolean = True); override; overload; constructor Create(const AGdiObj: THandle = 0; const ADcCompatible: HDC = 0; const ARefLifeTime: Boolean = True); reintroduce; // overload; destructor Destroy; override; function GetHandle: THandle; virtual; stdcall; property Handle: THandle read GetHandle; property CriticalSection: IGMCriticalSection read FCriticalSection implements IGMCriticalSection; end; //TGMGdiBitmapDC = class; // //IGMGdiBitmapDC = interface(IUnknown) // ['{A8AEE541-DC9E-438C-B044-C792D9829622}'] // function Obj: TGMGdiBitmapDC; //end; TGMGdiBitmapDC = class(TGMRefCountedObj, IGMGetHandle, IGMCriticalSection) // IGMGdiBitmapDC protected FCriticalSection: IGMCriticalSection; FBitmap, FDC: IGMGetHandle; // <- FBitmap released first public constructor Create(const ARefLifeTime: Boolean = True); override; constructor CreateFromRes(const ADcCompatible: HDC; const AResName: PGMChar; const AInstance: THandle; const ACheckLoad: Boolean = True; const ARefLifeTime: Boolean = True); constructor CreateFromBmpData(const ADcCompatible: HDC; const ABmpData: TBitmap; const ARefLifeTime: Boolean = True); constructor CreateCompatible(const ADcCompatible: HDC; const ASize: TPoint; const ARefLifeTime: Boolean = True); constructor CreateFromData(const ADcCompatible: HDC; const ASize: TPoint; const APlanes, ABitCount: LongInt; const ADataBits: Pointer = nil; const ARefLifeTime: Boolean = True); // destructor Destroy; override; function Obj: TGMGdiBitmapDC; function GetHandle: THandle; virtual; stdcall; property Handle: THandle read GetHandle; property CriticalSection: IGMCriticalSection read FCriticalSection implements IGMCriticalSection; end; TGMGdiDIBitmapedDC = class(TGMRefCountedObj, IGMGetHandle) protected FBitmap, FDC: IGMGetHandle; // <- FBitmap released first public constructor Create(const ADcCompatible: HDC; const ASize: TPoint; const ABitsPerPixel: Integer; const ARefLifeTime: Boolean = True); reintroduce; function GetHandle: THandle; virtual; stdcall; // procedure DetachBitmap; end; {ToDo: Change TGMGdiClipRgn to managed record} TGMGdiClipRgn = class(TGMRefCountedObj) protected FDC: HDC; FOrgRgn: IGMGetHandle; public constructor Create(const ADC: HDC; const ARgn: HRGN; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; {ToDo: Change TGMGdiTextColorSelector to managed record} TGMGdiTextColorSelector = class(TGMRefCountedObj) protected FDC: HDC; FTextColor: COLORREF; FTextBkColor: COLORREF; FPrevTextColor: COLORREF; FPrevBkColor: COLORREF; FPrevTextBkMode: LongInt; public constructor Create(const ADC: HDC; const ATextColor, ATextBkColor: COLORREF; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; {ToDo: Change TGMGdiDCKeeperBase to managed record} TGMGdiDCKeeperBase = class(TGMRefCountedObj, IGMGetHandle) protected FDC: HDC; public constructor Create(const ADC: HDC; const ARefLifeTime: Boolean = True); reintroduce; function GetHandle: THandle; stdcall; end; {ToDo: Change TGMGdiDCStateKeeper to managed record} TGMGdiDCStateKeeper = class(TGMGdiDCKeeperBase) protected FDCState: LongInt; public constructor Create(const ADC: HDC; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; {ToDo: Change TGMGdiROPKeeper to managed record} TGMGdiROPKeeper = class(TGMGdiDCKeeperBase) protected FROP: LongInt; public constructor Create(const ADC: HDC; const AROP: LongInt; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; {ToDo: Change TGMGdiClipRgnKeeper to managed record} TGMGdiClipRgnKeeper = class(TGMGdiDCKeeperBase) protected FOldClipRgn: IGMGetHandle; public constructor Create(const ADC: HDC; const AAdditionalRgn: HRGN; const ACombineMode: LongInt = RGN_AND; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; end; TGMCursorWithPlus = class(TGMRefCountedObj, IGMGetHandle) protected FDoDestroyCursor: Boolean; FHandle: LongWord; public constructor Create(const ACursor: MakeIntResource; const ARefLifeTime: Boolean = True); reintroduce; destructor Destroy; override; function GetHandle: THandle; stdcall; end; PGMImgCollectionDesc = ^TGMImgCollectionDesc; TGMImgCollectionDesc = record XOffset: LongInt; Size: TPoint; end; TGMImgCollectionDescs = array of TGMImgCollectionDesc; TGMImageCollection = class; IGMImageCollection = interface(IUnknown) ['{8A775175-F8A4-458A-B473-E9E2E852C719}'] function Obj: TGMImageCollection; end; TGMImageCollection = class(TGMRefCountedObj, IGMImageCollection) protected FBmpSize: TPoint; FDcCompatible: HDC; FImageDescs: TGMImgCollectionDescs; FImagesDC, FDisabledImgDC, FBkgndMaskDC: IGMGetHandle; procedure EnlargeBitmaps(const ASizeDelta: TPoint); procedure BuildDisabledImg(const AXOffset: Integer; const ASize: TPoint); public constructor Create(const ACompatibleDc: HDC; const ARefLifeTime: Boolean = True); reintroduce; overload; constructor Create(const AResBmpName: PGMChar; const AInstance: THandle; const ASplitWidth: LongInt = 0; ATransparentColor: COLORREF = clrAutoTransparent; const ADcCompatible: HDC = 0; const ALightnessDelta: LongInt = 0; const ADisabledLightnessDelta: LongInt = 0; const ARefLifeTime: Boolean = True); reintroduce; overload; function Obj: TGMImageCollection; procedure AddIcon(const AIcon: HIcon; const ALightnessDelta: LongInt = 0); procedure AddBitmap(const ABitmap: HBitmap; ASplitWidth: LongInt = 0; ATransparentColor: COLORREF = clrAutoTransparent; const ALightnessDelta: LongInt = 0; const ADisabledLightnessDelta: LongInt = 0); procedure DrawImage(const AImageIndex: LongInt; const ADestDC: HDC; const ADstRect: TRect; const ADisabled: Boolean = False); property ImageDescs: TGMImgCollectionDescs read FImageDescs; end; //function GMCachedBrushes: IGMGenericCollection<TGMGdiBrush>; function GMGetCachedBrush(const AColor: COLORREF; const AStyle: LongInt = BS_SOLID; const AHatch: LongInt = 0): IGMGetHandle; function GMBoldUIFont: HFont; function GMDitheredBrush: HBrush; //function GMDitheredBrush: HBrush; //function UICalcMemDC: IGMGetHandle; //function CsUICalcMemDC: IGMCriticalSection; function GMFontProperties(const AFont: HFONT): TLogFont; function GMBrushProperties(const ABrush: HBRUSH): TLogBrush; function GMRGBColor(const AColor: COLORREF): COLORREF; function GMSysColor(const AColor: COLORREF): COLORREF; function GMIsSysColor(const AColor: COLORREF): Boolean; function GMCheckBoxSize: TPoint; function GMBitmapSize(const ABitmap: IGMGetHandle): TPoint; overload; function GMBitmapSize(const ABitmap: HBitmap): TPoint; overload; function GMIconSize(const AIcon: HIcon): TPoint; function GMCalcTextAreaSize(const Text: TGMString; const NewSize, FrameSize, PaddSpace: TPoint; const Font: HFont; const DrawFlags: DWORD): TPoint; function GMTextExtent(const AText: TGMString; const AFont: HFont): TPoint; procedure GMDrawIcon(const ADC: HDC; const AIcon: HIcon; const ARect: TRect; const ADisabled: Boolean = False); function GMChangeColorLightness(AColor: COLORREF; ALightnessDelta: LongInt): COLORREF; function GMShadeColor(const Value: COLORREF; const Scale: Single): COLORREF; function GMFrameColorFromBkgndColor(const AColor: COLORREF): COLORREF; procedure GMGrayScaleDCArea(const ADC: HDC; const AAreaRect: TRect; const AIgnoreColor: COLORREF = CLR_INVALID); procedure GMChangeDCAreaLightness(const ADC: HDC; const AAreaRect: TRect; const ALightnessDelta: LongInt); procedure GMDrawDropArrow(const ADC: HDC; const AEnabled, ADown: Boolean; ARect: TRect; const AColors: array of COLORREF); procedure GMDrawRoundFrame(const ADC: HDC; const ABounds: TRect; const ColorShade: COLORREF; const ColorLight: COLORREF = CLR_INVALID); function GMPaintText(const ADC: HDC; const AText: TGMString; ARText: TRect; const AEnabled: Boolean; const AHAlignment: TGMHorizontalAlignment; const AVAlignment: TGMVerticalAlignment; const ADrawFlags: LongWord = cDfltTextDrawFlags): TRect; function GMSetBmpStretchMode(const ADC: HDC; const AStretchMode: LongInt; const Caller: TObject): LongInt; function GMFindMajorityColor(const ADC: HDC; const ARect: TRect): COLORREF; function GMMultiLineTextSize(const ADC: HDC; const AText: TGMString; ARText: TRect; const ADrawFlags: LongWord = cDfltTextDrawFlags): TPoint; function GMDrawText(const ADC: HDC; const AText: TGMString; const ARText: TRect; const AHAlignment: TGMHorizontalAlignment; const AVAlignment: TGMVerticalAlignment; const ADrawFlags: LongWord = cDfltTextDrawFlags): TRect; procedure GMDrawCenteredText(const ADC: HDC; const AText: TGMString; const ARText: TRect; const ADrawFlags: LongWord = cDfltTextDrawFlags); const cDefaultFont: array [TDefaultFont] of LongInt = (ANSI_FIXED_FONT, OEM_FIXED_FONT, ANSI_VAR_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT, SYSTEM_FONT, SYSTEM_FIXED_FONT); cGMSeverityColor: array [TGMSeverityLevel] of COLORREF = (clrWindowText, clNavy, clBlue, clrOrange, clRed); implementation uses SysUtils {$IFDEF JEDIAPI},jwaWinBase{$ENDIF}; const cImgCollectionYOffs = 0; var vCheckBoxSize: TPoint = (X: 0; Y: 0); //vGMDefaultFont: IGMGdiFont = nil; vGMBoldUIFont: IGMGdiFont = nil; vGMDitheredBrushBmp: IGMGetHandle = nil; vGMDitheredBrush: IGMGetHandle = nil; vGMCachedBrushes: IGMGenericCollection<TGMGdiBrush> = nil; //vUICalcMemDC: IGMGetHandle = nil; //vCsUICalcMemDC: IGMCriticalSection = nil; { ------------------------- } { ---- Global Routines ---- } { ------------------------- } {function UICalcMemDC: IGMGetHandle; begin // Creation is done in unit initialisation part because it should be done by the main thread! Result := vUICalcMemDC; end;} {function CsUICalcMemDC: IGMCriticalSection; begin // Creation is done in unit initialisation part Result := vCsUICalcMemDC; end;} function GMRGBColor(const AColor: COLORREF): COLORREF; begin if AColor and cSysColFlag = 0 then Result := AColor else Result := GetSysColor(AColor and not LongInt(cSysColFlag)); end; function GMIsSysColor(const AColor: COLORREF): Boolean; begin Result := AColor and cSysColFlag <> 0; end; function GMSysColor(const AColor: COLORREF): COLORREF; begin if AColor and cSysColFlag = 0 then Result := CLR_INVALID else Result := AColor and not LongInt(cSysColFlag); end; //function GMChangeColorLightness(AColor: COLORREF; Amount: LongInt): COLORREF; //var Table: array [0..255] of Byte; i: Byte; //begin //AColor := GMRGBColor(AColor); // //if Amount < 0 then // begin // Amount := -Amount; // for i:=0 to 255 do Table[i] := Byte(i-((Amount*i) shr 8)); // end else // for i:=0 to 255 do Table[i] := Byte(i+((Amount*(i xor 255)) shr 8)); // //Result := RGB(Table[GetRValue(AColor)], Table[GetGValue(AColor)], Table[GetBValue(AColor)]); //end; function GMChangeColorLightness(AColor: COLORREF; ALightnessDelta: LongInt): COLORREF; function LimitByte(AValue: LongInt): LongInt; begin Result := AValue; if Result > 255 then Result := 255 else if Result < 0 then Result := 0; end; begin ALightnessDelta := ALightnessDelta div 12; AColor := GMRGBColor(AColor); Result := RGB(LimitByte(GetRValue(AColor) + ALightnessDelta), LimitByte(GetGValue(AColor) + ALightnessDelta), LimitByte(GetBValue(AColor) + ALightnessDelta)); end; function GMShadeColor(const Value: COLORREF; const Scale: Single): COLORREF; function ShadeByte(ValByte: Byte): Byte; begin Result := GMBoundedInt(Round(ValByte * Scale), 0, $FF); end; begin Result := RGB(ShadeByte(GetRValue(Value)), ShadeByte(GetGValue(Value)), ShadeByte(GetBValue(Value))); end; function GMFrameColorFromBkgndColor(const AColor: COLORREF): COLORREF; begin Result := GMChangeColorLightness(AColor, cFrameDarknessDelta); end; function GMFontProperties(const AFont: HFONT): TLogFont; begin //FillByte(Result, SizeOf(Result), 0); Result := Default(TLogFont); if (AFont = 0) or (GetObject(AFont, 0, nil) <> SizeOf(Result)) then Exit; GMApiCheckObj('GMFontProperties', '', GetLastError, GetObject(AFont, SizeOf(Result), @Result) <> 0); end; function GMBrushProperties(const ABrush: HBRUSH): TLogBrush; begin //FillByte(Result, SizeOf(Result), 0); Result := Default(TLogBrush); if (ABrush = 0) or (GetObject(ABrush, 0, nil) <> SizeOf(Result)) then Exit; GMApiCheckObj('GMBrushProperties', '', GetLastError, GetObject(ABrush, SizeOf(Result), @Result) <> 0); end; function GMBitmapSize(const ABitmap: HBitmap): TPoint; var bmpData: TBitmap; begin if (ABitmap = 0) or (GetObject(ABitmap, 0, nil) <> SizeOf(bmpData)) or (GetObject(ABitmap, SizeOf(bmpData), @bmpData) = 0) then Result := cNullPoint else Result := GMPoint(bmpData.bmWidth, bmpData.bmHeight); end; function GMBitmapSize(const ABitmap: IGMGetHandle): TPoint; begin if ABitmap = nil then Result := cNullPoint else Result := GMBitmapSize(ABitmap.Handle); end; function GMIconSize(const AIcon: HIcon): TPoint; var iconInfo: TIconInfo; begin Result := cNullPoint; if AIcon = 0 then Exit; //FillByte(iconInfo, SizeOf(iconInfo), 0); iconInfo := Default(TIconInfo); //GMApiCheck(GetIconInfo(AIcon, iconInfo), 'GetIconInfo'); if GetIconInfo(AIcon, iconInfo) then begin if iconInfo.hbmColor <> 0 then begin Result := GMBitmapSize(iconInfo.hbmColor); DeleteObject(iconInfo.hbmColor); end; if iconInfo.hbmMask <> 0 then DeleteObject(iconInfo.hbmMask); end; end; function GMCheckBoxSize: TPoint; var ChkBmp: IGMGetHandle; begin if (vCheckBoxSize.x = 0) {or (vCheckBoxSize.y = 0)} then begin ChkBmp := TGMGdiBitmap.CreateFromRes(0, MakeIntResource(OBM_CHECK), 0); vCheckBoxSize := GMBitmapSize(ChkBmp.Handle); end; Result := vCheckBoxSize; end; procedure GMDrawRoundFrame(const ADC: HDC; const ABounds: TRect; const ColorShade, ColorLight: COLORREF); var Points: array of TPoint; Pen: IUnknown; begin Pen := TGMGdiPen.Create(ADC, GMRGBColor(ColorShade)); SetLength(Points, 6); with ABounds do begin Points[0] := GMPoint(Left+2, Bottom-1); Points[1] := GMPoint(Left, Bottom-3); Points[2] := GMPoint(Left, top+2); Points[3] := GMPoint(Left+2, top); Points[4] := GMPoint(Right-3, top); Points[5] := GMPoint(Right-1, top+2); end; PolyLine(ADC, {$IFDEF JEDIAPI}@{$ENDIF}Points[0], Length(Points)); if (ColorShade <> ColorLight) and (ColorLight <> CLR_INVALID) then begin Pen := nil; Pen := TGMGdiPen.Create(ADC, GMRGBColor(ColorLight)); end; //SetLength(Points, 4); with ABounds do begin Points[0] := GMPoint(Right-1, Top+2); Points[1] := GMPoint(Right-1, Bottom-3); Points[2] := GMPoint(Right-3, Bottom-1); Points[3] := GMPoint(Left+2, Bottom-1); end; PolyLine(ADC, {$IFDEF JEDIAPI}@{$ENDIF}Points[0], Length(Points)-2); end; {procedure GMDrawRoundFrame(const ADC: HDC; const ABounds: TRect; const ColorShade, ColorLight: COLORREF); var FrameColor: COLORREF; Pen: IUnknown; begin with ABounds do begin FrameColor := GMRGBColor(ColorShade); Pen := TGMGdiPen.Create(ADC, FrameColor); MoveToEx(ADC, Left, Bottom-3, nil); LineTo(ADC, Left, Top+1); SetPixel(ADC, Left+1, Top+1, FrameColor); MoveToEx(ADC, Left+2, Top, nil); LineTo(ADC, Right-2, Top); if (ColorShade <> ColorLight) and (ColorLight <> CLR_INVALID) then begin Pen := nil; FrameColor := GMRGBColor(ColorLight); Pen := TGMGdiPen.Create(ADC, FrameColor); end; MoveToEx(ADC, Right-1, Top+2, nil); LineTo(ADC, Right-1, Bottom-2); MoveToEx(ADC, Right-3, Bottom-1, nil); LineTo(ADC, Left+1, Bottom-1); SetPixel(ADC, Right-2, Top+1, FrameColor); SetPixel(ADC, Right-2, Bottom-2, FrameColor); SetPixel(ADC, Left+1, Bottom-2, FrameColor); end; end;} procedure GMDrawDropArrow(const ADC: HDC; const AEnabled, ADown: Boolean; ARect: TRect; const AColors: array of COLORREF); //const cColor: array [Boolean] of COLORREF = (clrBtnShadow, clrHighLight); var ArrowPoints: array of TPoint; Pen, Brush: IUnknown; begin if ADC = 0 then Exit; Pen := TGMGdiPen.Create(ADC, AColors[Ord(AEnabled)], PS_NULL); Brush := TGMGdiBrush.Create(ADC, AColors[Ord(AEnabled)]); SetLength(ArrowPoints, 3); if ADown then begin ArrowPoints[0] := GMPoint(ARect.Left, ARect.Top); ArrowPoints[1] := GMPoint(ARect.Right, ARect.Top); ArrowPoints[2] := GMPoint((ARect.Right + ARect.Left) div 2, ARect.Bottom); end else begin Dec(ARect.Top); Dec(ARect.Left); ArrowPoints[2] := GMPoint((ARect.Right + ARect.Left) div 2, ARect.Top); ArrowPoints[0] := GMPoint(ARect.Left, ARect.Bottom); ArrowPoints[1] := GMPoint(ARect.Right, ARect.Bottom); end; Polygon(ADC, {$IFDEF JEDIAPI}@{$ENDIF}ArrowPoints[0], Length(ArrowPoints)); end; procedure GMGrayScaleDCArea(const ADC: HDC; const AAreaRect: TRect; const AIgnoreColor: COLORREF); var x, y: LongInt; lum: Byte; color: COLORREF; // Div3: array [0..767] of Byte; begin // x:=0; // for i:=0 to 255 do // begin // Div3[x]:=i; Inc(x); // Div3[x]:=i; Inc(x); // Div3[x]:=i; Inc(x); // end; // Graysacle the image for y:=AAreaRect.Top to AAreaRect.Bottom-1 do for x:=AAreaRect.Left to AAreaRect.Right-1 do begin color := GetPixel(ADC, x, y); if color = AIgnoreColor then Continue; // lum := Div3[GetRValue(color) + GetGValue(color) + GetBValue(color)]; lum := Round(GetRValue(color)*0.3 + GetGValue(color)*0.59 + GetBValue(color)*0.11); SetPixel(ADC, x, y, RGB(lum, lum, lum)); end; end; procedure GMChangeDCAreaLightness(const ADC: HDC; const AAreaRect: TRect; const ALightnessDelta: LongInt); var x, y: LongInt; begin for y:=AAreaRect.Top to AAreaRect.Bottom-1 do for x:=AAreaRect.Left to AAreaRect.Right-1 do SetPixel(ADC, x, y, GMChangeColorLightness(GetPixel(ADC, x, y), ALightnessDelta)); end; {function UICalcMemDC: HDC; // // Must always be created by main thread, so better do it in the unit initialisation part // begin if vUICalcMemDC = nil then vUICalcMemDC := TGMGdiCompatibleDC.Create(True); Result := vUICalcMemDC.Handle; end;} function GMMultiLineTextSize(const ADC: HDC; const AText: TGMString; ARText: TRect; const ADrawFlags: LongWord = cDfltTextDrawFlags): TPoint; begin Result := CNullPoint; if (ADC <> 0) and (Length(AText) > 0) then begin if ARText.Left <> 0 then OffsetRect(ARText, -ARText.Left, 0); if ARText.Top <> 0 then OffsetRect(ARText, 0, -ARText.Top); if (ARText.Right <= ARText.Left) and (ADrawFlags and DT_WORDBREAK <> 0) then ARText.Right := ARText.Left + 1; //if ARText.Bottom < 0 then ARText.Bottom := 0; Result.y := DrawText(ADC, PGMChar(AText), Length(AText), ARText, ADrawFlags or DT_CALCRECT); if Result.y = 0 then Result.y := ARText.Bottom - ARText.Top; Result.x := ARText.Right - ARText.Left; end; end; function GMDrawText(const ADC: HDC; const AText: TGMString; const ARText: TRect; const AHAlignment: TGMHorizontalAlignment; const AVAlignment: TGMVerticalAlignment; const ADrawFlags: LongWord = cDfltTextDrawFlags): TRect; //var RDraw: TRect; begin if (ADC <> 0) then begin Result := GMLayoutRect(ARText, GMMultiLineTextSize(ADC, AText, ARText, ADrawFlags), AHAlignment, AVAlignment); DrawText(ADC, PGMChar(AText), Length(AText), Result, ADrawFlags); end else Result := Default(TRect); end; procedure GMDrawCenteredText(const ADC: HDC; const AText: TGMString; const ARText: TRect; const ADrawFlags: LongWord = cDfltTextDrawFlags); begin if ADC <> 0 then GMDrawText(ADC, AText, ARText, haCenter, vaCenter, ADrawFlags); end; function GMCalcTextAreaSize(const Text: TGMString; const NewSize, FrameSize, PaddSpace: TPoint; const Font: HFont; const DrawFlags: DWORD): TPoint; var PIFont: IUnknown; MemDC: IGMGetHandle; begin Result := cNullPoint; //SyncLock := TGMCriticalSectionLock.Create(UICalcMemDC); MemDC := TGMGdiCompatibleDC.Create; PIFont := TGMGdiObjSelector.Create(MemDC.Handle, Font); if DrawFlags and DT_SINGLELINE <> 0 then begin if not GetTextExtentPoint32(MemDC.Handle, PGMChar(Text), Length(Text), TSize(Result)) then Result := cNullPoint; Result := GMPoint(Result.x + FrameSize.x + PaddSpace.x, Result.y + FrameSize.y + PaddSpace.y); end else begin Result := GMMultiLineTextSize(MemDC.Handle, Text, GMRect(0, 0, NewSize.x - FrameSize.x - PaddSpace.x, NewSize.y - FrameSize.y - PaddSpace.y), DrawFlags); Inc(Result.x, FrameSize.x + PaddSpace.x); Inc(Result.y, FrameSize.y + PaddSpace.y); end; end; function GMTextExtent(const AText: TGMString; const AFont: HFont): TPoint; var Font: IUnknown; MemDC: IGMGetHandle; // Size: TSize; begin //SyncLock := TGMCriticalSectionLock.Create(UICalcMemDC); Result := cNullPoint; MemDC := TGMGdiCompatibleDC.Create; Font := TGMGdiObjSelector.Create(MemDC.Handle, AFont); if not GetTextExtentPoint32(MemDC.Handle, PGMChar(AText), Length(AText), TSize(Result)) then Result := cNullPoint; //Result.x := Size.cx; //Result.y := Size.cy; end; function GMPaintText(const ADC: HDC; const AText: TGMString; ARText: TRect; const AEnabled: Boolean; const AHAlignment: TGMHorizontalAlignment; const AVAlignment: TGMVerticalAlignment; const ADrawFlags: LongWord = cDfltTextDrawFlags): TRect; var prevTextColor: COLORREF; begin if AEnabled then Result := GMDrawText(ADC, AText, ARText, AHAlignment, AVAlignment, ADrawFlags) else begin ARText := GMMoveRect(ARText, 1, 1); prevTextColor := SetTextColor(ADC, GMRGBColor(clWhite)); GMDrawText(ADC, AText, ARText, AHAlignment, AVAlignment, ADrawFlags); ARText := GMMoveRect(ARText, -1, -1); SetTextColor(ADC, GMRGBColor(prevTextColor)); Result := GMDrawText(ADC, AText, ARText, AHAlignment, AVAlignment, ADrawFlags); Inc(Result.Right); Inc(Result.Bottom); end; end; function GMSetBmpStretchMode(const ADC: HDC; const AStretchMode: LongInt; const Caller: TObject): LongInt; begin if ADC = 0 then begin Result := 0; Exit; end; Result := SetStretchBltMode(ADC, AStretchMode); //GMApiCheckObj(Result <> 0, Caller, 'GMSetBmpStretchMode: SetStretchBltMode'); if AStretchMode = HALFTONE then SetBrushOrgEx(ADC, 0, 0, nil); //GMApiCheckObj(SetBrushOrgEx(ADC, 0, 0, nil), Caller, 'GMSetBmpStretchMode: SetBrushOrgEx'); end; procedure GMDrawIcon(const ADC: HDC; const AIcon: HIcon; const ARect: TRect; const ADisabled: Boolean); var dcImage, dcPaintResult, dcBkgndMask: IGMGetHandle; imgSize: TPoint; transparentColor, oldBmpBkgndColor: COLORREF; begin if AIcon = 0 then Exit; with ARect do if not ADisabled then DrawIconEx(ADC, Left, Top, AIcon, Right - Left, Bottom - Top, 0, 0, DI_NORMAL) else begin // Sadly DrawState does not work to draw disabled icons .. // DrawState(ADC, GetStockObject(GRAY_BRUSH), nil, LPARAM(AIcon), 0, Left, Top, Right-Left, Bottom-Top, DST_ICON or DSS_MONO); imgSize := GMRectSize(ARect); // Draw only the image dcImage := TGMGdiBitmapDC.CreateCompatible(ADC, imgSize, True); DrawIconEx(dcImage.Handle, 0, 0, AIcon, imgSize.x, imgSize.y, 0, 0, DI_IMAGE); transparentColor := GMFindMajorityColor(dcImage.Handle, GMRect(cNullPoint, imgSize)); // Make the image gray GMGrayScaleDCArea(dcImage.Handle, GMRect(cNullPoint, imgSize), transparentColor); // Build monochrome background mask //dcBkgndMask := TGMGdiBitmapDC.CreateFromData(ADC, imgSize.x, imgSize.y, 1, 1, nil, True); //DrawIconEx(dcBkgndMask.Handle, 0, 0, AIcon, imgSize.x, imgSize.y, 0, 0, DI_MASK); // // Starting with Windows 8 DrawIconEx(,, , DI_MASK) the mask always covers the whole image, no proper mask is drawn anymore, // at least for system images/icons returned from SHGetFileInfo. // So we need to build the mask ourselfs here .. // // Build the background mask dcBkgndMask := TGMGdiBitmapDC.CreateFromData(ADC, imgSize, 1, 1, nil); oldBmpBkgndColor := SetBkColor(dcImage.Handle, transparentColor); BitBlt(dcBkgndMask.Handle, 0, 0, imgSize.x, imgSize.y, dcImage.Handle, 0, 0, SRCCOPY); SetBkColor(dcImage.Handle, oldBmpBkgndColor); // Get original background dcPaintResult := TGMGdiBitmapDC.CreateCompatible(ADC, imgSize, True); Bitblt(dcPaintResult.Handle, 0, 0, imgSize.x, imgSize.y, ADC, left, Top, SRCCOPY); // Mask the background BitBlt(dcPaintResult.Handle, 0, 0, imgSize.x, imgSize.y, dcBkgndMask.Handle, 0, 0, SRCAND); // Combine masked background with masked image BitBlt(dcPaintResult.Handle, 0, 0, imgSize.x, imgSize.y, dcImage.Handle, 0, 0, SRCPAINT); // Draw the Result back to original device context Bitblt(ADC, left, Top, imgSize.x, imgSize.y, dcPaintResult.Handle, 0, 0, SRCCOPY); end; end; function GMFindMajorityColor(const ADC: HDC; const ARect: TRect): COLORREF; type TColorCount = record Color: COLORREF; Count: LongInt; end; var colorCounts: array of TColorCount; i: LongInt; procedure AddColor(const AColor: COLORREF); var i: LongInt; begin for i:=Low(colorCounts) to High(colorCounts) do if colorCounts[i].Color = AColor then begin Inc(colorCounts[i].Count); Exit; end; SetLength(colorCounts, Length(colorCounts)+1); colorCounts[High(colorCounts)].Color := AColor; colorCounts[High(colorCounts)].Count := 1; end; begin AddColor(GetPixel(ADC, ARect.Left, ARect.Top)); AddColor(GetPixel(ADC, ARect.Right-1, ARect.Top)); AddColor(GetPixel(ADC, ARect.Right-1, ARect.Bottom-1)); AddColor(GetPixel(ADC, ARect.Left, ARect.Bottom-1)); for i:=Low(colorCounts) to High(colorCounts) do if colorCounts[i].Count >= 3 then begin Result := colorCounts[i].Color; Exit; end; for i:=Low(colorCounts) to High(colorCounts) do if colorCounts[i].Count >= 2 then begin Result := colorCounts[i].Color; Exit; end; Result := colorCounts[Low(colorCounts)].Color; end; { ---------------------------- } { ---- Global GDI Objects ---- } { ---------------------------- } //function GMCompareBrushes(const ItemA, ItemB: IUnknown): TGMCompareResult; //var BrushA, BrushB: IGMGetHandle; LogBrushA, LogBrushB: TLogBrush; //begin // GMCheckQueryInterface(ItemA, IGMGetHandle, BrushA, {$I %CurrentRoutine%}); // GMCheckQueryInterface(ItemB, IGMGetHandle, BrushB, {$I %CurrentRoutine%}); // // LogBrushA := GMBrushProperties(BrushA.Handle); // LogBrushB := GMBrushProperties(BrushB.Handle); // // if LogBrushA.lbColor > LogBrushB.lbColor then Result := crAGreaterThanB else // if LogBrushA.lbColor < LogBrushB.lbColor then Result := crALessThanB else // if LogBrushA.lbStyle > LogBrushB.lbStyle then Result := crAGreaterThanB else // if LogBrushA.lbStyle < LogBrushB.lbStyle then Result := crALessThanB else // if LogBrushA.lbHatch > LogBrushB.lbHatch then Result := crAGreaterThanB else // if LogBrushA.lbHatch < LogBrushB.lbHatch then Result := crALessThanB else // Result := crAEqualToB; //end; function GMCompareBrushes(const ItemA, ItemB: TGMGdiBrush): TGMCompareResult; var LogBrushA, LogBrushB: TLogBrush; // BrushA, BrushB: IGMGetHandle; begin //GMCheckQueryInterface(ItemA, IGMGetHandle, BrushA, {$I %CurrentRoutine%}); //GMCheckQueryInterface(ItemB, IGMGetHandle, BrushB, {$I %CurrentRoutine%}); LogBrushA := GMBrushProperties(ItemA.Handle); LogBrushB := GMBrushProperties(ItemB.Handle); if LogBrushA.lbColor > LogBrushB.lbColor then Result := crAGreaterThanB else if LogBrushA.lbColor < LogBrushB.lbColor then Result := crALessThanB else if LogBrushA.lbStyle > LogBrushB.lbStyle then Result := crAGreaterThanB else if LogBrushA.lbStyle < LogBrushB.lbStyle then Result := crALessThanB else if LogBrushA.lbHatch > LogBrushB.lbHatch then Result := crAGreaterThanB else if LogBrushA.lbHatch < LogBrushB.lbHatch then Result := crALessThanB else Result := crAEqualToB; end; function GMCachedBrushes: IGMGenericCollection<TGMGdiBrush>; begin //if vGMCachedBrushes = nil then vGMCachedBrushes := TGMObjArrayCollection.Create(False, False, True, GMCompareBrushes, True); //if vGMCachedBrushes = nil then vGMCachedBrushes := TGMObjHashTable.Create(False, False, GMCompareBrushes, True); if vGMCachedBrushes = nil then vGMCachedBrushes := TGMGenericArrayCollection<TGMGdiBrush>.Create(False, True, GMCompareBrushes); Result := vGMCachedBrushes; end; function GMGetCachedBrush(const AColor: COLORREF; const AStyle: LongInt; const AHatch: LongInt): IGMGetHandle; var newBrush, foundBrush: TGMGdiBrush; begin newBrush := TGMGdiCachedBrush.Create(0, AColor, AStyle, AHatch, True); // <- A TGMGdiCachedBrush will remove itself from GMCachedBrushes in its destructor! Result := newBrush; if GMCachedBrushes.Find(newBrush, foundBrush) then GMCheckGetInterface(foundBrush, IGMGetHandle, Result) // <- re-assign Result to the brush found in the list, will free original brush else //begin GMCachedBrushes.Add(newBrush); // GMTrace('Brushes: ' + IntToStr(GMCachedBrushes.Count)); //end; end; function GMBoldUIFont: HFont; var fontData: TLogFont; begin if vGMBoldUIFont = nil then begin vGMBoldUIFont := TGMGdiFont.Create(0, dfUIFont, True); fontData := vGMBoldUIFont.fontData; fontData.lfWeight := FW_BOLD; //fontData.lfOutPrecision := OUT_TT_PRECIS; vGMBoldUIFont.fontData := fontData; end; Result := vGMBoldUIFont.Handle; end; function GMDitheredBrush: HBrush; const HatchBits: array [0..7] of word = ($aa, $55, $aa, $55, $aa, $55, $aa, $55); begin // // This Brush will be painted 0 => BkgndColor, 1 => FontColor. // So better overwrite FontColor and BkgndColor to set these colors. // if vGMDitheredBrush = nil then begin if vGMDitheredBrushBmp = nil then //vGMDitheredBrushBmp := TGMGdiBitmap.CreateFromRes(0, cResGMDitheredBrushBmp, HInstance); vGMDitheredBrushBmp := TGMGdiBitmap.CreateFromData(0, GMPoint(8, 8), 1, 1, @HatchBits); vGMDitheredBrush := TGMGdiBrush.CreateFromBmp(0, vGMDitheredBrushBmp.Handle); end; Result := vGMDitheredBrush.Handle; end; { --------------------------- } { ---- TGMGdiObjSelector ---- } { --------------------------- } constructor TGMGdiObjSelector.Create(const ADC: HDC; const AGdiObject: THandle; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FDC := ADC; FGdiObject := AGdiObject; if (FDC <> 0) and (FGdiObject <> 0) then FPrevObject := SelectObject(FDC, FGdiObject); end; destructor TGMGdiObjSelector.Destroy; begin ReleaseGdiObject; inherited Destroy; end; function TGMGdiObjSelector.GetHandle: THandle; begin Result := FGdiObject; end; function TGMGdiObjSelector.GetHandleAllocated: Boolean; begin Result := FGdiObject <> 0; end; procedure TGMGdiObjSelector.ReleaseGdiObject; begin //if (FDC <> 0) and (FPrevObject <> 0) and (FGdiObject <> 0) and //(GetCurrentObject(FDC, GetObjectType(FGdiObject)) = FGdiObject) then SelectObject(FDC, FPrevObject); // Only restore if ours is still the current object ?!? if FPrevObject <> 0 then begin if (FGdiObject <> 0) and (FDC <> 0) and (GetCurrentObject(FDC, GetObjectType(FGdiObject)) = FGdiObject) then SelectObject(FDC, FPrevObject) else DeleteObject(FPrevObject) end; FPrevObject := 0; end; //destructor TGMGdiObjSelector.Destroy; //begin //// Only restore if ours is still the current ?!? //if (FDC <> 0) and (FPrevObject <> 0) and (FGdiObject <> 0) and // (GetCurrentObject(FDC, GetObjectType(FGdiObject)) = FGdiObject) then SelectObject(FDC, FPrevObject); //inherited Destroy; //end; // //procedure TGMGdiObject.ReleaseHandle; //begin //// Only restore if ours is still the current ?!? //if (FDC <> 0) and (FPrevObject <> 0) and (FGdiObject <> 0) and // (GetCurrentObject(FDC, GetObjectType(FGdiObject)) = FGdiObject) then SelectObject(FDC, FPrevObject); //FPrevObject := 0; //if FGdiObject <> 0 then begin DeleteObject(FGdiObject); FGdiObject := 0; end; //end; { ---------------------- } { ---- TGMGdiObject ---- } { ---------------------- } procedure TGMGdiObject.ReleaseGdiObject; begin inherited; if FGdiObject <> 0 then begin DeleteObject(FGdiObject); FGdiObject := 0; end; end; { ------------------- } { ---- TGMGdiPen ---- } { ------------------- } constructor TGMGdiPen.Create(const ADC: HDC; const AColor: COLORREF; const AStyle, AWidth: LongInt; const ARefLifeTime: Boolean); begin inherited Create(ADC, CreatePen(AStyle, AWidth, GMRGBColor(AColor)), ARefLifeTime); GMAPICheckObj('CreatePen', '', GetLastError, FGdiObject <> 0, Self); end; { --------------------- } { ---- TGMGdiBrush ---- } { --------------------- } constructor TGMGdiBrush.Create(const ADC: HDC; const AColor: COLORREF; const AStyle: LongInt; const AHatch: LongInt; const ARefLifeTime: Boolean); var brushData: TLogBrush; begin //FillByte(brushData, SizeOf(brushData), 0); brushData := Default(TLogBrush); brushData.lbStyle := AStyle; brushData.lbColor := GMRGBColor(AColor); brushData.lbHatch := AHatch; inherited Create(ADC, CreateBrushIndirect(brushData), ARefLifeTime); //FGdiObject := CreateBrushIndirect(brushData); GMAPICheckObj('CreateBrushIndirect', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiBrush.CreateFromBmp(const ADC: HDC; const AHBmp: HBitmap; const ARefLifeTime: Boolean); begin inherited Create(ADC, CreatePatternBrush(AHBmp), ARefLifeTime); //FGdiObject := CreatePatternBrush(AHBmp); GMAPICheckObj('CreateBrushIndirect', '', GetLastError, FGdiObject <> 0, Self); end; function TGMGdiBrush.HashCode: TGMHashCode; var LogBrush: TLogBrush; begin LogBrush := GMBrushProperties(FGdiObject); Result := LogBrush.lbColor xor LogBrush.lbStyle xor UINT(LogBrush.lbHatch); end; {constructor TGMGdiBrush.CreateFromBmp(const ADC: HDC; const AHBmp: HBitmap; const ARefLifeTime: Boolean); var BrushData: TLogBrush; begin inherited Create(ADC, 0, ARefLifeTime); FillByte(BrushData, SizeOf(BrushData), 0); BrushData.lbStyle := BS_PATTERN; //BrushData.lbColor := GMRGBColor(AColor); BrushData.lbHatch := LongInt(AHBmp); FGdiObject := CreateBrushIndirect(BrushData); GMAPICheckObj(FGdiObject <> 0, Self, 'CreateBrushIndirect'); end;} { --------------------------- } { ---- TGMGdiCachedBrush ---- } { --------------------------- } destructor TGMGdiCachedBrush.Destroy; begin GMCachedBrushes.RemoveByKey(Self); inherited; end; { -------------------- } { ---- TGMGdiFont ---- } { -------------------- } constructor TGMGdiFont.Create(const ADC: HDC; const AFont: TDefaultFont; const ARefLifeTime: Boolean); begin inherited Create(ADC, GetStockObject(cDefaultFont[AFont]), ARefLifeTime); GMAPICheckObj('GetStockObject', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiFont.Create(const ADC: HDC; const AFontData: TLogFont; const ARefLifeTime: Boolean); begin inherited Create(ADC, 0, ARefLifeTime); FontData := AFontData; end; constructor TGMGdiFont.Create(const ADC: HDC; const AName: TGMString; const AHeight: LongInt; const AWeight: LongInt; const AStyle: TFontStyles; const ARefLifeTime: Boolean); const cBoolInt: array [Boolean] of BYte = (0, 1); var fontData: TLogFont; begin //inherited Create(ADC, ARefLifeTime); //FillByte(fontData, SizeOf(fontData), 0); fontData := Default(TLogFont); fontData.lfHeight := AHeight; fontData.lfWeight := AWeight; fontData.lfItalic := cBoolInt[fsItalic in AStyle]; fontData.lfUnderline := cBoolInt[fsUnderline in AStyle]; fontData.lfStrikeOut := cBoolInt[fsStrikeOut in AStyle]; fontData.lfCharSet := DEFAULT_CHARSET; fontData.lfQuality := DEFAULT_QUALITY; fontData.lfOutPrecision := OUT_DEFAULT_PRECIS; fontData.lfClipPrecision := CLIP_DEFAULT_PRECIS; fontData.lfPitchAndFamily := DEFAULT_PITCH; lstrcpyn(fontData.lfFaceName, PGMChar(AName), Min(Length(AName)+1, SizeOf(fontData.lfFaceName) div SizeOf(TGMChar))); Create(ADC, fontData, ARefLifeTime); end; function TGMGdiFont.GetFontData: TLogFont; begin //FillByte(Result, SizeOf(Result), 0); Result := Default(TLogFont); if not HandleAllocated or (GetObject(Handle, 0, nil) <> SizeOf(Result)) then Exit; GMApiCheckObj('GetFontData', '', GetLastError, GetObject(Handle, SizeOf(Result), @Result) <> 0, Self) end; procedure TGMGdiFont.SetFontData(const Value: TLogFont); begin ReleaseGdiObject; FGdiObject := CreateFontIndirect({$IFDEF FPC}{$IFNDEF JEDIAPI}@{$ENDIF}{$ENDIF}Value); //{$IFDEF FPC} //FGdiObject := CreateFontIndirect((PLogFont(@Value)^); //{$ELSE} //FGdiObject := CreateFontIndirect(Value); //{$ENDIF} GMAPICheckObj('CreateFontIndirect', '', GetLastError, FGdiObject <> 0, Self); if FDC <> 0 then FPrevObject := SelectObject(FDC, FGdiObject); end; { ---------------------- } { ---- TGMGdiBitmap ---- } { ---------------------- } constructor TGMGdiBitmap.CreateFromRes(const ADC: HDC; const AResName: PGMChar; const AInstance: THandle; const ACheckLoad: Boolean; const ARefLifeTime: Boolean); begin inherited Create(ADC, LoadBitmap(AInstance, AResName), ARefLifeTime); //if AInstance = 0 then AInstance := HInstance; No, otherwise OEM bitmaps can not be loaded! if ACheckLoad then GMAPICheckObj('LoadBitmap', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiBitmap.CreateFromBmpData(const ADC: HDC; const ABmpData: TBitmap; const ARefLifeTime: Boolean); begin {$IFDEF FPC} inherited Create(ADC, CreateBitmapIndirect(PBitmap(@ABmpData)^), ARefLifeTime); {$ELSE} inherited Create(ADC, CreateBitmapIndirect(ABmpData), ARefLifeTime); {$ENDIF} GMAPICheckObj('CreateBitmapIndirect', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiBitmap.CreateCompatibleBmp(const ADC, ADcCompatible: HDC; const ASize: TPoint; const ARefLifeTime: Boolean); var BmpDC: HDC; FreeDC: Boolean; begin if ADcCompatible <> 0 then begin BmpDC := ADcCompatible; FreeDC := False; end else begin BmpDC := GetDC(0); FreeDC := True; end; GMAPICheckObj('CreateCompatibleBmp-GetDC', '', GetLastError, BmpDC <> 0, Self); try inherited Create(ADC, {$IFDEF JEDIAPI}jwaWinGdi{$ELSE}Windows{$ENDIF}.CreateCompatibleBitmap(BmpDC, ASize.x, ASize.y), ARefLifeTime); GMAPICheckObj('CreateCompatibleBitmap', '', GetLastError, FGdiObject <> 0, Self); finally if FreeDC then ReleaseDC(0, BmpDC); end; end; {constructor TGMGdiBitmap.CreateCompatibleBmp(const ADC, ADC: HDC; const ASize: TPoint; const ARefLifeTime: Boolean); var BmpDC: HDC; FreeDC: Boolean; begin inherited Create(ADC, 0, ARefLifeTime); //FreeDC := False; //if ADC <> 0 then begin BmpDC := ADC; FreeDC := False; end else begin BmpDC := GetDC(0); FreeDC := True; end; BmpDC := GetDC(0); FreeDC := True; GMAPICheckObj(BmpDC <> 0, Self, 'CreateCompatibleBmp.GetDC'); try FGdiObject := Windows.CreateCompatibleBitmap(BmpDC, ASize.x, ASize.y); GMAPICheckObj(FGdiObject <> 0, Self, 'CreateCompatibleBitmap'); finally if FreeDC then ReleaseDC(0, BmpDC); end; end;} constructor TGMGdiBitmap.CreateFromData(const ADC: HDC; const ASize: TPoint; const APlanes, ABitCount: LongInt; const ADataBits: Pointer; const ARefLifeTime: Boolean); begin inherited Create(ADC, CreateBitmap(ASize.x, ASize.y, APlanes, ABitCount, ADataBits), ARefLifeTime); GMAPICheckObj('CreateBitmap', '', GetLastError, FGdiObject <> 0, Self); end; { ------------------------ } { ---- TGMGdiDIBitmap ---- } { ------------------------ } constructor TGMGdiDIBitmap.Create(const ADC: HDC; const ASize: TPoint; const ABitsPerPixel: Integer; const ARefLifeTime: Boolean); begin FBmpInfo.biSize := SizeOf(FBmpInfo); FBmpInfo.biWidth := ASize.x; FBmpInfo.biHeight := ASize.y; FBmpInfo.biPlanes := 1; FBmpInfo.biBitCount := ABitsPerPixel; FBmpInfo.biCompression := BI_RGB; inherited Create(ADC, CreateDIBSection(0, PBitmapInfo(@FBmpInfo){$IFNDEF JEDIAPI}^{$ENDIF}, DIB_RGB_COLORS, FBits, 0, 0), ARefLifeTime); GMAPICheckObj('CreateDIBSection', '', GetLastError, FGdiObject <> 0, Self); end; { ------------------------ } { ---- TGMGdiDCBitmap ---- } { ------------------------ } {constructor TGMGdiDCBitmap.CreateCompatible(const ASize: TPoint; const ARefLifeTime: Boolean); var ScreenDC: HDC; begin inherited Create(0, ARefLifeTime); FDC := CreateCompatibleDC(0); GMAPICheckObj(FDC <> 0, Self, 'CreateCompatibleDC'); ScreenDC := GetDC(0); GMAPICheckObj(ScreenDC <> 0, Self, 'CreateCompatible.GetDC'); try FGdiObject := CreateCompatibleBitmap(ScreenDC, ASize.x, ASize.y); GMAPICheckObj(FGdiObject <> 0, Self, 'CreateCompatibleBitmap'); finally ReleaseDC(0, ScreenDC); end; // if FDC <> 0 then FPrevObject := SelectObject(FDC, FGdiObject); FillRect(DC, GMRect(0, 0, Asize.X, Asize.y), GetStockObject(WHITE_BRUSH)); end; function TGMGdiDCBitmap.Obj: TGMGdiDCBitmap; begin Result := Self; end;} { --------------------- } { ---- TGMWindowDC ---- } { --------------------- } constructor TGMWindowDC.Create(const AWnd: HWnd; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FWnd := AWnd; FDC := GetDC(FWnd); end; destructor TGMWindowDC.Destroy; begin if FDC <> 0 then ReleaseDC(FWnd, FDC); inherited Destroy; end; function TGMWindowDC.GetHandle: THandle; begin Result := FDC; end; { ---------------------------- } { ---- TGMGdiCompatibleDC ---- } { ---------------------------- } //constructor TGMGdiCompatibleDC.Create(const ARefLifeTime: Boolean); //begin //inherited Create(ARefLifeTime); //FCriticalSection := TGMCriticalSection.Create; //end; constructor TGMGdiCompatibleDC.Create(const AGdiObj: THandle; const ADcCompatible: HDC; const ARefLifeTime: Boolean); begin //Assert(AGdiObj = 0); inherited Create(ARefLifeTime); FCriticalSection := TGMCriticalSection.Create; FDC := CreateCompatibleDC(ADcCompatible); GMAPICheckObj('CreateCompatibleDC', '', GetLastError, FDC <> 0, Self); //FGdiObject := AGdiObj; if AGdiObj <> 0 then {FPrevObject :=} DeleteObject(SelectObject(FDC, AGdiObj)); end; destructor TGMGdiCompatibleDC.Destroy; begin //if (FDC <> 0) and (FPrevObject <> 0) and (FGdiObject <> 0) and //(GetCurrentObject(FDC, GetObjectType(FGdiObject)) = FGdiObject) then SelectObject(FDC, FPrevObject); //FPrevObject := 0; if FDC <> 0 then DeleteDC(FDC); inherited Destroy; end; function TGMGdiCompatibleDC.GetHandle: THandle; begin Result := FDC; end; { ------------------------ } { ---- TGMGdiBitmapDC ---- } { ------------------------ } //destructor TGMGdiBitmapDC.Destroy; //begin //inherited; //end; constructor TGMGdiBitmapDC.Create(const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FCriticalSection := TGMCriticalSection.Create; end; constructor TGMGdiBitmapDC.CreateCompatible(const ADcCompatible: HDC; const ASize: TPoint; const ARefLifeTime: Boolean); begin //inherited Create(ARefLifeTime); FDC := TGMGdiCompatibleDC.Create(0, ADcCompatible, True); FBitmap := TGMGdiBitmap.CreateCompatibleBmp(FDC.Handle, ADcCompatible, ASize, True); end; constructor TGMGdiBitmapDC.CreateFromBmpData(const ADcCompatible: HDC; const ABmpData: TBitmap; const ARefLifeTime: Boolean); begin //inherited Create(ARefLifeTime); FDC := TGMGdiCompatibleDC.Create(0, ADcCompatible, True); FBitmap := TGMGdiBitmap.CreateFromBmpData(FDC.Handle, ABmpData, True); end; constructor TGMGdiBitmapDC.CreateFromData(const ADcCompatible: HDC; const ASize: TPoint; const APlanes, ABitCount: LongInt; const ADataBits: Pointer; const ARefLifeTime: Boolean); begin //inherited Create(ARefLifeTime); FDC := TGMGdiCompatibleDC.Create(0, ADcCompatible, True); FBitmap := TGMGdiBitmap.CreateFromData(FDC.Handle, ASize, APlanes, ABitCount, ADataBits, True); end; constructor TGMGdiBitmapDC.CreateFromRes(const ADcCompatible: HDC; const AResName: PGMChar; const AInstance: THandle; const ACheckLoad: Boolean; const ARefLifeTime: Boolean); begin //inherited Create(ARefLifeTime); FDC := TGMGdiCompatibleDC.Create(0, ADcCompatible, True); FBitmap := TGMGdiBitmap.CreateFromRes(FDC.Handle, AResName, AInstance, ACheckLoad, True); end; function TGMGdiBitmapDC.Obj: TGMGdiBitmapDC; begin Result := Self; end; function TGMGdiBitmapDC.GetHandle: THandle; begin if FDC = nil then Result := 0 else Result := FDC.Handle; end; { ---------------------------- } { ---- TGMGdiDIBitmapedDC ---- } { ---------------------------- } constructor TGMGdiDIBitmapedDC.Create(const ADcCompatible: HDC; const ASize: TPoint; const ABitsPerPixel: Integer; const ARefLifeTime: Boolean); begin inherited Create(ARefLifeTime); FDC := TGMGdiCompatibleDC.Create(0, ADcCompatible, True); FBitmap := TGMGdiDIBitmap.Create(FDC.Handle, ASize, ABitsPerPixel, True); end; //procedure TGMGdiDIBitmapedDC.DetachBitmap; //begin // //end; function TGMGdiDIBitmapedDC.GetHandle: THandle; begin if FDC = nil then Result := 0 else Result := FDC.Handle; end; { ----------------------- } { ---- TGMGdiClipRgn ---- } { ----------------------- } constructor TGMGdiClipRgn.Create(const ADC: HDC; const ARgn: HRGN; const ARefLifeTime: Boolean); //var Clip: LongInt; begin inherited Create(ARefLifeTime); if (ADC = 0) {or (Rgn = 0)} then Exit; FOrgRgn := TGMGdiRegion.CreateRect(0, cNullRect, True); case GetClipRgn(ADC, FOrgRgn.Handle) of 0: FOrgRgn := nil; // <- Free FOrgRgn, restore default (NULL) Region in destructor Low(LongInt) .. -1: GMApiCheckObj('GetClipRgn', '', GetLastError, False, Self); // else -> success, restore FOrgRgn in destructor end; {Clip := GetClipRgn(ADC, FOrgRgn.Handle); if Clip = 0 then FOrgRgn := nil else if Clip < 0 then GMApiCheckObj(False, Self, 'GetClipRgn');} GMApiCheckObj('SelectClipRgn', '', GetLastError, SelectClipRgn(ADC, ARgn) <> RGN_ERROR, Self); //GMApiCheckObj(ExtSelectClipRgn(ADC, Rgn, RGN_COPY) <> RGN_ERROR, Self, 'ExtSelectClipRgn'); FDC := ADC; // <- skipped on exception, prevent restore in destructor end; destructor TGMGdiClipRgn.Destroy; begin if FDC <> 0 then if (FOrgRgn <> nil) {and (FOrgRgn.Handle <> 0)} then SelectClipRgn(FDC, FOrgRgn.Handle) else SelectClipRgn(FDC, 0); inherited Destroy; end; { ---------------------- } { ---- TGMGdiRegion ---- } { ---------------------- } constructor TGMGdiRegion.CreateRect(const ADC: HDC; const ARect: TRect; const ARefLifeTime: Boolean); begin with ARect do inherited Create(ADC, CreateRectRgn(Left, Top, Right, Bottom), ARefLifeTime); GMAPICheckObj('CreateRectRgn', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiRegion.CreateRoundRect(const ADC: HDC; const ARect: TRect; const ARounding: TPoint; const ARefLifeTime: Boolean); begin // // CreateRoundRectRgn is one pixel too small .. with ARect do inherited Create(ADC, CreateRoundRectRgn(Left, Top, Right+1, Bottom+1, ARounding.x, ARounding.y), ARefLifeTime); GMAPICheckObj('CreateRoundRectRgn', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiRegion.CreatePolygon(const ADC: HDC; const APoints: array of TPoint; const AFilleMode: Integer; const ARefLifeTime: Boolean); begin inherited Create(ADC, CreatePolygonRgn( {$IFDEF JEDIAPI}@APoints[Low(APoints)] {$ELSE} {$IFDEF FPC}(@APoints[Low(APoints)])^ {$ELSE} APoints[Low(APoints)] {$ENDIF} {$ENDIF} , Length(APoints), AFilleMode), ARefLifeTime); //{$IFDEF FPC} //inherited Create(ADC, CreatePolygonRgn(PPoint(@APoints[Low(APoints)])^, Length(APoints), AFilleMode), ARefLifeTime); //{$ELSE} //inherited Create(ADC, CreatePolygonRgn({$IFDEF JEDIAPI}@{$ENDIF}APoints[Low(APoints)], Length(APoints), AFilleMode), ARefLifeTime); //{$ENDIF} GMAPICheckObj('CreatePolygonRgn', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiRegion.CreateElipse(const ADC: HDC; const ABounds: TRect; const ARefLifeTime: Boolean); begin with ABounds do inherited Create(ADC, CreateEllipticRgn(Left, Top, Right, Bottom), ARefLifeTime); GMAPICheckObj('CreateEllipticRgn', '', GetLastError, FGdiObject <> 0, Self); end; constructor TGMGdiRegion.CreatefromWindow(const ADC: HDC; const AWnd: HWnd; const ARefLifeTime: Boolean); //var Rgn: HRgn; begin CreateRect(ADC, cNullRect, ARefLifeTime); GetWindowRgn(AWnd, Handle); end; { ----------------------- } { ---- TGMGdiPalette ---- } { ----------------------- } constructor TGMGdiPalette.Create(const ADC: HDC; const ALogPalette: TLogPalette; const ARefLifeTime: Boolean); begin {$IFDEF FPC} inherited Create(ADC, CreatePalette(PLogPalette(@ALogPalette)^), ARefLifeTime); {$ELSE} inherited Create(ADC, CreatePalette(ALogPalette), ARefLifeTime); {$ENDIF} //FGdiObject := CreatePalette(ALogPalette); GMAPICheckObj('CreatePalette', '', GetLastError, FGdiObject <> 0, Self); end; { --------------------------------- } { ---- TGMGdiTextColorSelector ---- } { --------------------------------- } constructor TGMGdiTextColorSelector.Create(const ADC: HDC; const ATextColor, ATextBkColor: COLORREF; const ARefLifeTime: Boolean = True); begin inherited Create(ARefLifeTime); FDC := ADC; FTextColor := ATextColor; FTextBkColor := ATextBkColor; if FDC = 0 then Exit; if FTextColor <> clrTransparent then FPrevTextColor := SetTextColor(ADC, GMRGBColor(FTextColor)); if FTextBkColor = clrTransparent then FPrevTextBkMode := SetBkMode(ADC, TRANSPARENT) else begin FPrevTextBkMode := SetBkMode(FDC, OPAQUE); FPrevBkColor := SetBkColor(ADC, GMRGBColor(FTextBkColor)); end; end; destructor TGMGdiTextColorSelector.Destroy; begin // Only restore if our AColor is still the current ?!? if FDC <> 0 then begin if (FPrevTextColor <> CLR_INVALID) and (GetTextColor(FDC) = FTextColor) then SetTextColor(FDC, FPrevTextColor); if (FTextBkColor <> clrTransparent) and (FPrevBkColor <> CLR_INVALID) and (GetBkColor(FDC) = FTextBkColor) then SetBkColor(FDC, FPrevBkColor); if FPrevTextBkMode > 0 then SetBkMode(FDC, FPrevTextBkMode); end; inherited Destroy; end; { ---------------------------- } { ---- TGMGdiDCKeeperBase ---- } { ---------------------------- } constructor TGMGdiDCKeeperBase.Create(const ADC: HDC; const ARefLifeTime: Boolean = True); begin inherited Create(ARefLifeTime); if ADC <> 0 then FDC := ADC; end; function TGMGdiDCKeeperBase.GetHandle: THandle; begin Result := FDC; end; { ----------------------------- } { ---- TGMGdiDCStateKeeper ---- } { ----------------------------- } constructor TGMGdiDCStateKeeper.Create(const ADC: HDC; const ARefLifeTime: Boolean = True); begin inherited Create(ADC, ARefLifeTime); if ADC = 0 then Exit; FDCState := SaveDC(ADC); GMAPICheckObj('SaveDC', '', GetLastError, FDCState <> 0, Self); end; destructor TGMGdiDCStateKeeper.Destroy; begin if (FDC <> 0) and (FDCState <> 0) then RestoreDC(FDC, FDCState); inherited Destroy; end; { ------------------------- } { ---- TGMGdiROPKeeper ---- } { ------------------------- } constructor TGMGdiROPKeeper.Create(const ADC: HDC; const AROP: Integer; const ARefLifeTime: Boolean); begin inherited Create(ADC, ARefLifeTime); if ADC = 0 then Exit; FROP := SetROP2(ADC, AROP); GMApiCheckObj('TGMGdiROPKeeper.Create - SetROP2', '', GetLastError, FROP <> 0, Self); end; destructor TGMGdiROPKeeper.Destroy; begin if (FDC <> 0) and (FROP <> 0) then SetROP2(FDC, FROP); inherited Destroy; end; { ----------------------------- } { ---- TGMGdiClipRgnKeeper ---- } { ----------------------------- } constructor TGMGdiClipRgnKeeper.Create(const ADC: HDC; const AAdditionalRgn: HRGN; const ACombineMode: LongInt; const ARefLifeTime: Boolean); begin inherited Create(ADC, ARefLifeTime); if ADC = 0 then Exit; FOldClipRgn := TGMGdiRegion.CreateRect(0, cNullRect, True); case GetClipRgn(FDC, FOldClipRgn.Handle) of 0: FOldClipRgn := TGMHandleObj.Create(0, True); // <- will remove the clipping region when restored -1: FOldClipRgn := nil; // <- error, dont restore clipping region //1: Success end; //Clip := GetDeviceCaps(ADC, SHADEBLENDCAPS); // CLIPCAPS TECHNOLOGY //if WindowFromDC(ADC) <> 0 then ExtSelectClipRgn(ADC, AreaRgn.Handle, RGN_AND) else // with RSurface do IntersectClipRect(ADC, Left, top, Right, Bottom); //ExtSelectClipRgn(ADC, AreaRgn.Handle, RGN_AND); if AAdditionalRgn <> 0 then ExtSelectClipRgn(FDC, AAdditionalRgn, ACombineMode); //if AAdditionalRgn <> 0 then SelectClipRgn(FDC, AAdditionalRgn); end; destructor TGMGdiClipRgnKeeper.Destroy; begin if (FDC <> 0) and (FOldClipRgn <> nil) then SelectClipRgn(FDC, FOldClipRgn.Handle); // (FOldClipRgn.Handle <> 0) inherited Destroy; end; { --------------------------- } { ---- TGMCursorWithPlus ---- } { --------------------------- } constructor TGMCursorWithPlus.Create(const ACursor: MakeIntResource; const ARefLifeTime: Boolean); const cPlusSz = 9; cFrm = 0; // 1 var iconInfo: TIconInfo; bmpMask, bmpColor, dcSrc, dcAlpha, bmpAlpha: IGMGetHandle; imgSz, maskSz: TPoint; pen, brush: IUnknown; rPlus: TRect; x, y: LongInt; ppxColor: PDword; bmpAlphaHdr: TBitmapV5Header; aplphaBmpBits: Pointer; // pxColor: COLORREF; begin inherited Create(ARefLifeTime); try //FillByte(iconInfo, SizeOf(iconInfo), 0); iconInfo := Default(TIconInfo); GMApiCheckObj('GetIconInfo', '', GetLastError, GetIconInfo(LoadCursor(0, ACursor), iconInfo), Self); bmpMask := TGMGdiObject.Create(0, iconInfo.hbmMask); bmpColor := TGMGdiObject.Create(0, iconInfo.hbmColor); maskSz := GMBitmapSize(bmpMask); imgSz := GMBitmapSize(bmpColor); aplphaBmpBits := nil; if (imgSz.x = 0) or (imgSz.y = 0) then raise EAbort.Create('Zero cursor image size'); // // Create a cursor with partial tranparency see: http://support.microsoft.com/kb/318876/en-us // //FillByte(bmpAlphaHdr, SizeOf(bmpAlphaHdr), 0); bmpAlphaHdr := Default(TBitmapV5Header); bmpAlphaHdr.bV5Size := SizeOf(bmpAlphaHdr); bmpAlphaHdr.bV5Width := imgSz.x; bmpAlphaHdr.bV5Height := imgSz.y; bmpAlphaHdr.bV5Planes := 1; bmpAlphaHdr.bV5BitCount := 32; bmpAlphaHdr.bV5Compression := BI_BITFIELDS; bmpAlphaHdr.bV5RedMask := $00FF0000; bmpAlphaHdr.bV5GreenMask := $0000FF00; bmpAlphaHdr.bV5BlueMask := $000000FF; bmpAlphaHdr.bV5AlphaMask := $FF000000; bmpAlpha := TGMGdiObject.Create(0, CreateDIBSection(0, PBitmapInfo(@bmpAlphaHdr){$IFNDEF JEDIAPI}^{$ENDIF}, DIB_RGB_COLORS, aplphaBmpBits, 0, 0)); if aplphaBmpBits = nil then raise EAbort.Create('Alpha bitmap bits pointer is <nil>'); dcAlpha := TGMGdiCompatibleDC.Create(bmpAlpha.Handle); rPlus := GMRect(imgSz.x - cPlusSz - cFrm, imgSz.y - cPlusSz - cFrm, imgSz.x - cFrm, imgSz.y - cFrm); dcSrc := TGMGdiCompatibleDC.Create(bmpColor.Handle); BitBlt(dcAlpha.Handle, 0, 0, imgSz.x, imgSz.y, dcSrc.Handle, 0, 0, SRCCOPY); dcSrc := nil; brush := TGMGdiBrush.Create(dcAlpha.Handle, clWhite); pen := TGMGdiPen.Create(dcAlpha.Handle, clBlack); with rPlus do begin Rectangle(dcAlpha.Handle, Left, Top, Right, Bottom); MoveToEx(dcAlpha.Handle, Left + 2, (Top + Bottom) shr 1, nil); LineTo(dcAlpha.Handle, Right - 2, (Top + Bottom) shr 1); MoveToEx(dcAlpha.Handle, (Left + Right) shr 1, Top + 2, nil); LineTo(dcAlpha.Handle, (Left + Right) shr 1, Bottom - 2); end; for x:=rPlus.Left to rPlus.Right-1 do // for y:=rPlus.Top to rPlus.Bottom-1 do for y:=cFrm to cPlusSz+cFrm-1 do // <- the bitmap is bottom up! begin // NOTE: SetPixel does not work with alpha values! We need to directly set the bits! ppxColor := GMAddPtr(aplphaBmpBits, ((y * imgSz.x) + x) * 4); ppxColor^ := ppxColor^ or $ff000000; end; dcAlpha := nil; //iconInfo.hbmMask := bmpMask.Handle; iconInfo.hbmColor := bmpAlpha.Handle; FHandle := CreateIconIndirect(iconInfo); GMApiCheckObj('CreateIconIndirect', '', GetLastError, FHandle <> 0, Self); FDoDestroyCursor := True; except // FDoDestroyCursor := False; FHandle := LoadCursor(0, ACursor); end; end; destructor TGMCursorWithPlus.Destroy; begin if (FHandle <> 0) and FDoDestroyCursor then DestroyCursor(FHandle); inherited Destroy; end; function TGMCursorWithPlus.GetHandle: THandle; begin Result := FHandle; end; { ---------------------------- } { ---- TGMImageCollection ---- } { ---------------------------- } constructor TGMImageCollection.Create(const ACompatibleDc: HDC; const ARefLifeTime: Boolean); begin //inherited Create(ARefLifeTime); FDcCompatible := ACompatibleDc; end; constructor TGMImageCollection.Create(const AResBmpName: PGMChar; const AInstance: THandle; const ASplitWidth: Integer; ATransparentColor: COLORREF; const ADcCompatible: HDC; const ALightnessDelta, ADisabledLightnessDelta: LongInt; const ARefLifeTime: Boolean); var bmp: IGMGetHandle; begin Create(ADcCompatible, ARefLifeTime); bmp := TGMGdiBitmap.CreateFromRes(0, AResBmpName, AInstance); AddBitmap(bmp.Handle, ASplitWidth, ATransparentColor, ALightnessDelta, ADisabledLightnessDelta); end; function TGMImageCollection.Obj: TGMImageCollection; begin Result := Self; end; procedure TGMImageCollection.EnlargeBitmaps(const ASizeDelta: TPoint); var oldSize: TPoint; newDC: IGMGetHandle; begin oldSize := FBmpSize; //if FBkgndMaskDC = nil then oldSize := cNullPoint else oldSize := GMBitmapSize(FBkgndMaskDC.Obj.FBitmap); //newSize := GMPoint(oldSize.x + ASizeDelta.x, Max(oldSize.y, ASizeDelta.y)); FBmpSize := GMPoint(FBmpSize.x + ASizeDelta.x, Max(FBmpSize.y, ASizeDelta.y)); if FBmpSize = oldSize then Exit; newDC := TGMGdiBitmapDC.CreateCompatible(FDcCompatible, FBmpSize); //newDC := TGMGdiDIBitmapedDC.Create(FDcCompatible, FBmpSize, 32); if FImagesDC <> nil then BitBlt(newDC.Handle, 0, 0, oldSize.x, oldSize.y, FImagesDC.Handle, 0, 0, SRCCOPY); FImagesDC := newDC; newDC := TGMGdiBitmapDC.CreateFromData(FDcCompatible, FBmpSize, 1, 1, nil); if FBkgndMaskDC <> nil then BitBlt(newDC.Handle, 0, 0, oldSize.x, oldSize.y, FBkgndMaskDC.Handle, 0, 0, SRCCOPY); FBkgndMaskDC := newDC; newDC := TGMGdiBitmapDC.CreateCompatible(FDcCompatible, FBmpSize); if FDisabledImgDC <> nil then BitBlt(newDC.Handle, 0, 0, oldSize.x, oldSize.y, FDisabledImgDC.Handle, 0, 0, SRCCOPY); FDisabledImgDC := newDC; end; procedure TGMImageCollection.BuildDisabledImg(const AXOffset: Integer; const ASize: TPoint); begin if (FImagesDC = nil) or (FDisabledImgDC = nil) then Exit; BitBlt(FDisabledImgDC.Handle, AXOffset, cImgCollectionYOffs, ASize.x, ASize.y, FImagesDC.Handle, AXOffset, cImgCollectionYOffs, SRCCOPY); // No need to mask the disabled image again after grayscaling the image. The grayscaling will leave masked pixels (black pixels) intact! GMGrayScaleDCArea(FDisabledImgDC.Handle, GMRect(AXOffset, cImgCollectionYOffs, AXOffset + ASize.x, cImgCollectionYOffs + ASize.y)); end; procedure TGMImageCollection.AddIcon(const AIcon: HIcon; const ALightnessDelta: LongInt); var xOffs: LongInt; iconSz: TPoint; // iconInfo: TIconInfo; begin if AIcon = 0 then Exit; iconSz := GMIconSize(AIcon); if (iconSz.x <= 0) or (iconSz.y <= 0) then Exit; EnlargeBitmaps(iconSz); if Length(FImageDescs) <= 0 then xOffs := 0 else xOffs := FImageDescs[High(FImageDescs)].XOffset + FImageDescs[High(FImageDescs)].Size.x; if FImagesDC <> nil then begin DrawIconEx(FImagesDC.Handle, xOffs, cImgCollectionYOffs, AIcon, iconSz.x, iconSz.y, 0, 0, DI_IMAGE); if ALightnessDelta <> 0 then GMChangeDCAreaLightness(FImagesDC.Handle, GMRect(xOffs, cImgCollectionYOffs, xOffs + iconSz.x, cImgCollectionYOffs + iconSz.y), ALightnessDelta); end; if FBkgndMaskDC <> nil then DrawIconEx(FBkgndMaskDC.Handle, xOffs, cImgCollectionYOffs, AIcon, iconSz.x, iconSz.y, 0, 0, DI_MASK); BuildDisabledImg(xOffs, iconSz); SetLength(FImageDescs, Length(FImageDescs)+1); FImageDescs[High(FImageDescs)].XOffset := xOffs; FImageDescs[High(FImageDescs)].Size := iconSz; end; procedure TGMImageCollection.AddBitmap(const ABitmap: HBitmap; ASplitWidth: LongInt; ATransparentColor: COLORREF; const ALightnessDelta, ADisabledLightnessDelta: LongInt); var bmpSz: TPoint; xPos, xOffs: LongInt; bmpDC: IGMGetHandle; procedure AddBmpPart(const ABmpDC: HDC; const x, y, w, h: LongInt; const ATransparentColor: COLORREF); var imgMask: IGMGetHandle; oldBmpBkgndColor: COLORREF; begin // Build the background mask oldBmpBkgndColor := SetBkColor(ABmpDC, ATransparentColor); BitBlt(FBkgndMaskDC.Handle, xOffs + x, cImgCollectionYOffs, w, h, ABmpDC, x, y, SRCCOPY); SetBkColor(ABmpDC, oldBmpBkgndColor); imgMask := TGMGdiBitmapDC.CreateFromData(FDcCompatible, GMPoint(w, h), 1, 1, nil); // Build the image mask as the inverse of the background mask BitBlt(imgMask.Handle, 0, 0, w, h, FBkgndMaskDC.Handle, xOffs + x, cImgCollectionYOffs, NOTSRCCOPY); // Copy the image BitBlt(FImagesDC.Handle, xOffs + x, cImgCollectionYOffs, w, h, ABmpDC, x, y, SRCCOPY); // Mask out the transparent pixels in the image using the image mask BitBlt(FImagesDC.Handle, xOffs + x, cImgCollectionYOffs, w, h, imgMask.Handle, 0, 0, SRCAND); BuildDisabledImg(xOffs + x, GMPoint(w, h)); if (ADisabledLightnessDelta <> 0) and (FDisabledImgDC <> nil) then GMChangeDCAreaLightness(FDisabledImgDC.Handle, GMRect(xOffs + x, 0, w + xOffs + x, h), ADisabledLightnessDelta); end; begin if ABitmap = 0 then Exit; bmpSz := GMBitmapSize(ABitmap); if (bmpSz.x <= 0) or (bmpSz.y <= 0) then Exit; EnlargeBitmaps(bmpSz); if ASplitWidth = 0 then ASplitWidth := bmpSz.y else if ASplitWidth < 0 then ASplitWidth := bmpSz.x; if Length(FImageDescs) <= 0 then xOffs := 0 else xOffs := FImageDescs[High(FImageDescs)].XOffset + FImageDescs[High(FImageDescs)].Size.x; bmpDC := TGMGdiCompatibleDC.Create(ABitmap, FDcCompatible, True); if ALightnessDelta <> 0 then GMChangeDCAreaLightness(bmpDC.Handle, GMRect(cNullPoint, bmpSz), ALightnessDelta); if ATransparentColor = clrAutoTransparent then ATransparentColor := GMFindMajorityColor(bmpDC.Handle, GMRect(cNullPoint, bmpSz)); xPos := 0; while xPos + ASplitWidth <= bmpSz.x do begin AddBmpPart(bmpDC.Handle, xPos, 0, ASplitWidth, bmpSz.y, ATransparentColor); SetLength(FImageDescs, Length(FImageDescs)+1); FImageDescs[High(FImageDescs)].XOffset := xOffs + xPos; FImageDescs[High(FImageDescs)].Size := GMPoint(ASplitWidth, bmpSz.y); Inc(xPos, ASplitWidth); end; end; procedure TGMImageCollection.DrawImage(const AImageIndex: LongInt; const ADestDC: HDC; const ADstRect: TRect; const ADisabled: Boolean); var imgDesc: PGMImgCollectionDesc; dstSize: TPoint; dcPaintResult, srcDC: IGMGetHandle; begin if (FImagesDC = nil) or not GMIsInRange(AImageIndex, Low(FImageDescs), High(FImageDescs)) then Exit; dstSize := GMRectSize(ADstRect); imgDesc := @FImageDescs[AImageIndex]; // Get original background dcPaintResult := TGMGdiBitmapDC.CreateCompatible(ADestDC, imgDesc.Size, True); //dcPaintResult := TGMGdiDIBitmapedDC.Create(ADestDC, imgDesc.Size, 24, True); SetStretchBltMode(dcPaintResult.Handle, HALFTONE); StretchBlt(dcPaintResult.Handle, 0, 0, imgDesc.Size.x, imgDesc.Size.y, ADestDC, ADstRect.left, ADstRect.Top, dstSize.x, dstSize.y, SRCCOPY); // Mask the background BitBlt(dcPaintResult.Handle, 0, 0, imgDesc.Size.x, imgDesc.Size.y, FBkgndMaskDC.Handle, imgDesc.XOffset, cImgCollectionYOffs, SRCAND); // Combine masked background with masked image if ADisabled then srcDC := FDisabledImgDC else srcDC := FImagesDC; if srcDC <> nil then BitBlt(dcPaintResult.Handle, 0, 0, imgDesc.Size.x, imgDesc.Size.y, srcDC.Handle, imgDesc.XOffset, cImgCollectionYOffs, SRCPAINT); // Draw the Result back to original device context StretchBlt(ADestDC, ADstRect.left, ADstRect.Top, dstSize.x, dstSize.y, dcPaintResult.Handle, 0, 0, imgDesc.Size.x, imgDesc.Size.y, SRCCOPY); end; //initialization //vUICalcMemDC := TGMGdiCompatibleDC.Create(0, True); //vCsUICalcMemDC := TGMCriticalSection.Create; end.