LCL: High-DPI ImageList: imglist fixes

git-svn-id: branches/HiDPIImageList@57054 -
This commit is contained in:
ondrej 2018-01-11 13:16:27 +00:00
parent ba1c5e5fd4
commit ad9612efd5
2 changed files with 121 additions and 60 deletions

View File

@ -122,7 +122,7 @@ type
function Add(Image, Mask: TCustomBitmap): Integer;
procedure InternalInsert(AIndex: Integer; AData: PRGBAQuad); overload;
procedure InternalMove(ACurIndex, ANewIndex: Cardinal; AIgnoreCurrent: Boolean);
procedure InternalReplace(AIndex: Integer; AImage, AMask: HBitmap);
procedure InternalReplace(AIndex: Integer; AData: PRGBAQuad);
function InternalSetData(AIndex: Integer; AData: PRGBAQuad): PRGBAQuad;
procedure CheckIndex(AIndex: Integer; AForInsert: Boolean = False);
@ -190,6 +190,8 @@ type
destructor Destroy; override;
public
function FindBestToScaleFrom(const ATargetWidth: Integer): Integer;
procedure Delete(const AIndex: Integer);
procedure Clear;
property ImageLists[const AImageWidth: Integer]: TCustomImageListResolution read GetImageLists;
property Items[const AIndex: Integer]: TCustomImageListResolution read GetItems; default;
@ -246,6 +248,9 @@ type
function GetHeightForImagePPI(AImageWidth, APPI: Integer): Integer;
function GetCount: Integer;
function GetSizeForImagePPI(AImageWidth, APPI: Integer): TSize;
function GetBestIconIndexForSize(AIcon: TCustomIcon; AWidth: Integer): Integer;
function GetResolutionByIndex(AIndex: Integer): TCustomImageListResolution;
function GetResolutionCount: Integer;
protected
function GetResolution(AImageWidth: Integer): TCustomImageListResolution;
function GetResolutionClass: TCustomImageListResolutionClass; virtual;
@ -311,13 +316,15 @@ type
procedure Move(ACurIndex, ANewIndex: Integer);
procedure Overlay(AIndex: Integer; Overlay: TOverlay);
property HasOverlays: boolean read fHasOverlays;
procedure Replace(AIndex: Integer; AImage, AMask: TCustomBitmap);
procedure ReplaceMasked(Index: Integer; NewImage: TCustomBitmap; MaskColor: TColor);
procedure Replace(AIndex: Integer; AImage, AMask: TCustomBitmap; const AAllResolutions: Boolean = True);
procedure ReplaceIcon(AIndex: Integer; AIcon: TCustomIcon);
procedure ReplaceMasked(Index: Integer; NewImage: TCustomBitmap; MaskColor: TColor; const AAllResolutions: Boolean = True);
procedure RegisterChanges(Value: TChangeLink);
procedure StretchDraw(Canvas: TCanvas; Index: Integer; ARect: TRect; Enabled: Boolean = True);
procedure UnRegisterChanges(Value: TChangeLink);
procedure RegisterResolutions(const AResolutionWidths: array of Integer);
procedure DeleteResolution(const AWidth: Integer);
public
property AllocBy: Integer read FAllocBy write FAllocBy default 4;
property BlendColor: TColor read FBlendColor write FBlendColor default clNone;
@ -334,7 +341,9 @@ type
property Reference[AImageWidth: Integer]: TWSCustomImageListReference read GetReference;
property ReferenceForImagePPI[AImageWidth, APPI: Integer]: TWSCustomImageListReference read GetReferenceForImagePPI;
property Resolution[AImageWidth: Integer]: TCustomImageListResolution read GetResolution;
property ResolutionByIndex[AIndex: Integer]: TCustomImageListResolution read GetResolutionByIndex;
property ResolutionForImagePPI[AImageWidth, APPI: Integer]: TCustomImageListResolution read GetResolutionForImagePPI;
property ResolutionCount: Integer read GetResolutionCount;
function Resolutions: TCustomImageListResolutionEnumerator;
function ResolutionsDesc: TCustomImageListResolutionEnumerator;
property ShareImages: Boolean read FShareImages write SetShareImages default False;

View File

@ -57,7 +57,7 @@ begin
FImgList := AImgList;
FDesc := ADesc;
if ADesc then
FCurrent := FImgList.Count
FCurrent := FImgList.FData.Count
else
FCurrent := -1;
end;
@ -510,7 +510,7 @@ begin
end;
procedure TCustomImageListResolution.InternalReplace(AIndex: Integer;
AImage, AMask: HBitmap);
AData: PRGBAQuad);
var
RawImage: TRawImage;
R: TRect;
@ -522,23 +522,7 @@ begin
if (AIndex < 0) then AIndex := 0;
CheckIndex(AIndex);
R := Rect(0, 0, FWidth, FHeight);
RawImage_FromBitmap(RawImage, AImage, AMask, @R);
LI := TLazIntfImage.Create(RawImage, True);
SetLength(TargetData, FWidth * FHeight * SizeOf(TRGBAQuad));
ImgData := @TargetData[0];
for Y := 0 to FHeight-1 do
for X := 0 to FWidth-1 do
begin
ImgData^.Alpha := Byte(LI.Colors[x, y].alpha);
ImgData^.Red := Byte(LI.Colors[x, y].red);
ImgData^.Green := Byte(LI.Colors[x, y].green);
ImgData^.Blue := Byte(LI.Colors[x, y].blue);
Inc(ImgData);
end;
LI.Free;
ImgData := InternalSetData(AIndex, @TargetData[0]);
ImgData := InternalSetData(AIndex, AData);
if HandleAllocated
then TWSCustomImageListResolutionClass(WidgetSetClass).Replace(Self, AIndex, ImgData);
end;
@ -867,6 +851,16 @@ begin
FResolutionClass := AResolutionClass;
end;
procedure TCustomImageListResolutions.Clear;
begin
FList.Clear;
end;
procedure TCustomImageListResolutions.Delete(const AIndex: Integer);
begin
FList.Delete(AIndex);
end;
destructor TCustomImageListResolutions.Destroy;
begin
FList.Free;
@ -1213,8 +1207,7 @@ procedure TCustomImageList.Clear;
var
R: TCustomImageListResolution;
begin
for R in Resolutions do
R.Clear;
FData.Clear;
ClearOverlays;
FChanged := True;
@ -1300,6 +1293,14 @@ begin
Change;
end;
procedure TCustomImageList.DeleteResolution(const AWidth: Integer);
var
I: Integer;
begin
if FData.Find(AWidth, I) then
FData.Delete(I);
end;
{------------------------------------------------------------------------------
Method: TCustomImageList.Destroy
Params: None
@ -1531,11 +1532,22 @@ begin
Result := FData.ImageLists[AImageWidth];
end;
function TCustomImageList.GetResolutionByIndex(
AIndex: Integer): TCustomImageListResolution;
begin
Result := FData[AIndex];
end;
function TCustomImageList.GetResolutionClass: TCustomImageListResolutionClass;
begin
Result := TCustomImageListResolution;
end;
function TCustomImageList.GetResolutionCount: Integer;
begin
Result := FData.Count;
end;
{------------------------------------------------------------------------------
Function: TCustomImageList.GetHotspot
Params: None
@ -1613,29 +1625,8 @@ begin
end;
procedure TCustomImageList.InsertIcon(AIndex: Integer; AIcon: TCustomIcon);
function GetBestIndexForSize(AWidth: Integer): Integer;
var
MaxWidth, MaxWidthI: Integer;
begin
MaxWidth := 0;
for Result := 0 to AIcon.Count-1 do // first try to find the smallest (but bigger) multiple
begin
AIcon.Current := Result;
if (AIcon.Width mod AWidth = 0) then
Exit;
if AIcon.Width>MaxWidth then
begin
MaxWidth := AIcon.Width;
MaxWidthI := Result;
end;
end;
Result := MaxWidthI; // just pickup the biggest image
end;
var
R: TCustomImageListResolution;
BmpFree: Boolean;
ScBmp: TRGBAQuadArray;
msk: HBITMAP;
begin
@ -1644,7 +1635,7 @@ begin
R := GetResolution(FWidth); // create default resolution if needed - do not create all icon resolutions
for R in Resolutions do
begin
AIcon.Current := GetBestIndexForSize(R.Width);
AIcon.Current := GetBestIconIndexForSize(AIcon, R.Width);
if AIcon.Masked then
msk := AIcon.MaskHandle
else
@ -1979,6 +1970,28 @@ begin
{$ENDIF}
end;
function TCustomImageList.GetBestIconIndexForSize(AIcon: TCustomIcon;
AWidth: Integer): Integer;
var
MaxWidth, MaxWidthI: Integer;
begin
MaxWidth := 0;
for Result := 0 to AIcon.Count-1 do // first try to find the smallest (but bigger) multiple
begin
AIcon.Current := Result;
if (AIcon.Width mod AWidth = 0) then
Exit;
if AIcon.Width>MaxWidth then
begin
MaxWidth := AIcon.Width;
MaxWidthI := Result;
end;
end;
Result := MaxWidthI; // just pickup the biggest image
end;
procedure TCustomImageList.Overlay(AIndex: Integer; Overlay: TOverlay);
var
i: Integer;
@ -2032,16 +2045,54 @@ end;
Replaces the index'th image with the image given. If Mask is nil,
the image has no transparent parts.
------------------------------------------------------------------------------}
procedure TCustomImageList.Replace(AIndex: Integer; AImage, AMask: TCustomBitmap);
procedure TCustomImageList.Replace(AIndex: Integer; AImage,
AMask: TCustomBitmap; const AAllResolutions: Boolean);
var
msk: THandle;
R: TCustomImageListResolution;
Data: TRGBAQuadArray;
procedure _Replace;
begin
ScaleImage(AImage, AMask, R.Width, R.Height, Data);
R.InternalReplace(AIndex, @Data[0]);
end;
begin
if AImage = nil then Exit;
if AMask = nil
then msk := 0
else msk := AMask.Handle;
GetResolution(AImage.Width).InternalReplace(AIndex, AImage.BitmapHandle, msk);
if AAllResolutions then
begin
for R in Resolutions do
_Replace;
end else
begin
R := GetResolution(AImage.Width);
_Replace;
end;
end;
procedure TCustomImageList.ReplaceIcon(AIndex: Integer; AIcon: TCustomIcon);
var
R: TCustomImageListResolution;
ScBmp: TRGBAQuadArray;
msk: HBITMAP;
begin
if AIcon = nil then Exit;
for R in Resolutions do
begin
AIcon.Current := GetBestIconIndexForSize(AIcon, R.Width);
if AIcon.Masked then
msk := AIcon.MaskHandle
else
msk := 0;
ScaleImage(AIcon.BitmapHandle, msk,
AIcon.Width, AIcon.Height, R.Width, R.Height, ScBmp);
R.InternalReplace(AIndex, @ScBmp[0]);
end;
end;
{------------------------------------------------------------------------------
@ -2054,26 +2105,27 @@ end;
Replaces the index'th image with the image given.
Every occurrence of MaskColor will be converted to transparent.
------------------------------------------------------------------------------}
procedure TCustomImageList.ReplaceMasked(Index: Integer; NewImage: TCustomBitmap; MaskColor: TColor);
procedure TCustomImageList.ReplaceMasked(Index: Integer;
NewImage: TCustomBitmap; MaskColor: TColor; const AAllResolutions: Boolean);
var
Bmp: TBitmap;
R: TCustomImageListResolution;
Data: TRGBAQuadArray;
begin
if NewImage = nil then Exit;
Bmp := TBitmap.Create;
with Bmp do
begin
Assign(NewImage);
TransparentColor := MaskColor;
Transparent := True;
end;
try
Bmp.Assign(NewImage);
Bmp.TransparentColor := MaskColor;
Bmp.Transparent := True;
R := GetResolution(NewImage.Width);
if Bmp.Masked
then R.InternalReplace(Index, Bmp.Handle, Bmp.MaskHandle)
else R.InternalReplace(Index, Bmp.Handle, 0);
Bmp.Free;
R := GetResolution(NewImage.Width);
ScaleImage(Bmp, nil, R.Width, R.Height, Data);
R.InternalReplace(Index, @Data[0]);
finally
Bmp.Free;
end;
end;
{------------------------------------------------------------------------------