mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-20 11:39:29 +02:00
1616 lines
48 KiB
PHP
1616 lines
48 KiB
PHP
{%MainUnit ../imglist.pp}
|
|
|
|
{******************************************************************************
|
|
TCustomImageList
|
|
******************************************************************************
|
|
|
|
*****************************************************************************
|
|
This file is part of the Lazarus Component Library (LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
}
|
|
|
|
type
|
|
TImageListSignature = array[0..1] of char;
|
|
TCustomIconAccess = class(TCustomIcon);
|
|
|
|
const
|
|
SIG_LAZ1 = #1#0;
|
|
SIG_LAZ2 = 'li';
|
|
SIG_LAZ3 = 'Li';
|
|
SIG_D3 = 'IL';
|
|
|
|
const
|
|
EffectMap: array[Boolean] of TGraphicsDrawEffect = (
|
|
gdeDisabled,
|
|
gdeNormal
|
|
);
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: CopyImage
|
|
Params: Destination, Source: the destination/source canvas
|
|
DestinationRect: the rectangle where the image is copied to
|
|
SourceRect: the rectangle containing the part to be copied
|
|
Returns: Nothing
|
|
|
|
Internal routine to copy a rectangle from a source canvas to a rectangle on
|
|
the destination canvas
|
|
------------------------------------------------------------------------------}
|
|
procedure CopyImage(Destination, Source: TCanvas; DestinationRect, SourceRect: TRect);
|
|
begin
|
|
Destination.CopyRect(
|
|
DestinationRect,
|
|
Source,
|
|
SourceRect
|
|
);
|
|
end;
|
|
|
|
{ TCustomImageList }
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: TCustomImageList.Add
|
|
Params: Image: a bitmap image
|
|
Mask: a bitmap which defines the transparent parts of Image
|
|
Returns: The index of the added image, -1 if unsuccesful.
|
|
|
|
Adds one or more (bitmap width / imagelist width) bitmaps to the list.
|
|
If Mask is nil, the image has no transparent parts.
|
|
|
|
The image is copied. To add it directly use AddDirect.
|
|
------------------------------------------------------------------------------}
|
|
|
|
function TCustomImageList.Add(Image, Mask: TCustomBitmap): Integer;
|
|
begin
|
|
Result := Count;
|
|
Insert(Result, Image, Mask);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: TCustomImageList.AddIcon
|
|
Params: Image: the Icon to be added;
|
|
Returns: The index of the added icon, -1 if unsuccesfull.
|
|
|
|
Adds an icon to the list.
|
|
------------------------------------------------------------------------------}
|
|
function TCustomImageList.AddIcon(Image: TCustomIcon): Integer;
|
|
begin
|
|
Result := Count;
|
|
InsertIcon(Result, Image);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.AddImages
|
|
Params: Value: An imagelist containing images to be added
|
|
Returns: Nothing
|
|
|
|
Adds images from another imagelist to the list.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.AddImages(AValue: TCustomImageList);
|
|
var
|
|
n: Integer;
|
|
p: PRGBAQuad;
|
|
DataSize: Integer;
|
|
OldCount: Integer;
|
|
begin
|
|
if (AValue = nil) or (AValue=Self) or (AValue.FCount = 0) then exit;
|
|
|
|
AllocData(FCount + AValue.FCount);
|
|
if (AValue.FWidth = FWidth) and (AValue.FHeight = FHeight)
|
|
then begin
|
|
DataSize := FWidth * FHeight * SizeOf(FData[0]);
|
|
System.Move(AVAlue.FData[0], FData[FCount], AValue.FCount * DataSize);
|
|
OldCount := FCount;
|
|
Inc(FCount, AValue.FCount);
|
|
if HandleAllocated
|
|
then begin
|
|
p := @FData[OldCount];
|
|
for n := OldCount to FCount - 1 do
|
|
begin
|
|
TWSCustomImageListClass(WidgetSetClass).Insert(Self, n, p);
|
|
Inc(PByte(p), DataSize);
|
|
end;
|
|
end;
|
|
end
|
|
else begin
|
|
// ToDo:
|
|
raise Exception.Create('TCustomImageList.AddImages not implemented yet for other Width/Height');
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: TCustomImageList.AddMasked
|
|
Params: Image: A bitmap to be added
|
|
MaskColor: The color acting as transparant color
|
|
Returns: The index of the added icon, -1 if unsuccesfull.
|
|
|
|
Adds one or more (bitmap width / imagelist width) bitmaps to the list.
|
|
Every occurrence of MaskColor will be converted to transparent.
|
|
------------------------------------------------------------------------------}
|
|
function TCustomImageList.AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
|
|
begin
|
|
try
|
|
Result := Count;
|
|
InsertMasked(Result, Image, MaskColor);
|
|
except
|
|
on E: Exception do
|
|
begin
|
|
DebugLn('TCustomImageList.AddMasked ',E.Message);
|
|
Result := -1; // Ignore exceptions, just return -1
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function TCustomImageList.AddLazarusResource(const ResourceName: string
|
|
): integer;
|
|
|
|
Load TBitmap from lazarus resources and add it.
|
|
------------------------------------------------------------------------------}
|
|
function TCustomImageList.AddLazarusResource(const ResourceName: string; MaskColor: TColor): integer;
|
|
var
|
|
Bmp: TCustomBitmap;
|
|
begin
|
|
Bmp := CreateBitmapFromLazarusResource(ResourceName);
|
|
if MaskColor <> clNone then
|
|
begin
|
|
Bmp.TransparentColor := MaskColor;
|
|
Bmp.Transparent := True;
|
|
end;
|
|
Result := Add(Bmp, nil);
|
|
Bmp.Free;
|
|
end;
|
|
|
|
function TCustomImageList.AddResourceName(Instance: THandle; const ResourceName: string; MaskColor: TColor): integer;
|
|
var
|
|
Grp: TGraphic;
|
|
Bmp: TCustomBitmap absolute Grp;
|
|
begin
|
|
Grp := CreateGraphicFromResourceName(Instance, ResourceName);
|
|
if Grp is TCustomBitmap then
|
|
begin
|
|
if MaskColor <> clNone then
|
|
begin
|
|
Bmp.TransparentColor := MaskColor;
|
|
Bmp.Transparent := True;
|
|
end;
|
|
Result := Add(Bmp, nil);
|
|
end
|
|
else
|
|
Result := AddIcon(Grp as TCustomIcon);
|
|
Grp.Free;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.AllocData
|
|
Params: ACount: the amount of images
|
|
Returns: Nothing
|
|
|
|
Allocates data for ACount images
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.AllocData(ACount: Integer);
|
|
var
|
|
n: Integer;
|
|
begin
|
|
if FAllocCount >= ACount
|
|
then Exit;
|
|
|
|
// calculate number of blocks, add an extra block for the remainder.
|
|
n := ACount mod FAllocBy;
|
|
if n <> 0
|
|
then Inc(ACount, FAllocBy - n);
|
|
|
|
SetLength(FData, ACount * FWidth * FHeight * SizeOf(FData[0]));
|
|
|
|
Inc(FAllocCount, ACount);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.InternalInsert
|
|
Params: AIndex: Index to insert images
|
|
AImage, AMask: handles of Image and Mask
|
|
AWidth, AHeight: Width and Height of AImage and AMask
|
|
Returns: Nothing
|
|
|
|
Insert bitmap (with split if necessary) into position AIndex with shifting other
|
|
images
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.InternalInsert(AIndex: Integer; AImage, AMask: HBitmap;
|
|
AWidth, AHeight: Integer);
|
|
var
|
|
RawImg: TRawImage;
|
|
R: TRect;
|
|
ImgData: PRGBAQuad;
|
|
i, ACount: Integer;
|
|
begin
|
|
CheckIndex(AIndex, True);
|
|
if (AIndex < 0) then
|
|
AIndex := 0;
|
|
|
|
ACount := AWidth div Width;
|
|
if ACount = 0 then
|
|
ACount := 1;
|
|
Inc(FCount, ACount);
|
|
AllocData(FCount);
|
|
if AIndex < FCount - ACount then
|
|
begin
|
|
for i := 0 to ACount - 1 do
|
|
InternalMove(FCount - i - 1, AIndex + i, True);
|
|
end;
|
|
|
|
R := Rect(0, 0, FWidth, FHeight);
|
|
for i := 0 to ACount - 1 do
|
|
begin
|
|
RawImage_FromBitmap(RawImg, AImage, AMask, @R);
|
|
ImgData := InternalSetImage(AIndex + i, RawImg);
|
|
if HandleAllocated
|
|
then TWSCustomImageListClass(WidgetSetClass).Insert(Self, AIndex + i, ImgData);
|
|
inc(R.Left, FWidth);
|
|
inc(R.Right, FWidth);
|
|
end;
|
|
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
|
|
procedure TCustomImageList.InternalInsert(AIndex: Integer; ARawImage: TRawImage);
|
|
var
|
|
RawImg: TRawImage;
|
|
R: TRect;
|
|
ImgData: PRGBAQuad;
|
|
i, ACount: Integer;
|
|
begin
|
|
CheckIndex(AIndex, True);
|
|
if (AIndex < 0) then
|
|
AIndex := 0;
|
|
|
|
ACount := ARawImage.Description.Width div Width;
|
|
if ACount = 0 then
|
|
ACount := 1;
|
|
Inc(FCount, ACount);
|
|
AllocData(FCount);
|
|
if AIndex < FCount - ACount then
|
|
begin
|
|
for i := 0 to ACount - 1 do
|
|
InternalMove(FCount - i - 1, AIndex + i, True);
|
|
end;
|
|
|
|
R := Rect(0, 0, FWidth, FHeight);
|
|
for i := 0 to ACount - 1 do
|
|
begin
|
|
ARawImage.ExtractRect(R, RawImg);
|
|
ImgData := InternalSetImage(AIndex + i, RawImg);
|
|
if HandleAllocated
|
|
then TWSCustomImageListClass(WidgetSetClass).Insert(Self, AIndex + i, ImgData);
|
|
inc(R.Left, FWidth);
|
|
inc(R.Right, FWidth);
|
|
end;
|
|
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Assign
|
|
Params: Source: Source data
|
|
Returns: Nothing
|
|
|
|
Very simple assign with stream exchange
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Assign(Source: TPersistent);
|
|
Var
|
|
ImgSrc : TCustomImageList;
|
|
begin
|
|
if (Source=Self) then exit;
|
|
if Source is TCustomImageList then
|
|
begin
|
|
ImgSrc := TCustomImageList(Source);
|
|
BeginUpdate;
|
|
try
|
|
SetWidthHeight(ImgSrc.Width,ImgSrc.Height);
|
|
Clear;
|
|
AddImages(ImgSrc);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end
|
|
else inherited Assign(Source);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.AssignTo
|
|
Params: Dest: the destination to assign to
|
|
Returns: Nothing
|
|
|
|
Very simple assign with stream exchange
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.AssignTo(Dest: TPersistent);
|
|
begin
|
|
if Dest is TCustomImageList then
|
|
TCustomImageList(Dest).Assign(Self)
|
|
else
|
|
inherited AssignTo(Dest);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.BeginUpdate
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Lock the change event for updating.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.BeginUpdate;
|
|
begin
|
|
inc(FUpdateCount);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Change
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Fires the change event.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Change;
|
|
begin
|
|
if (not FChanged) or (FUpdateCount > 0) then exit;
|
|
NotifyChangeLink;
|
|
if Assigned(FOnChange) then FOnChange(Self);
|
|
FChanged := false;
|
|
end;
|
|
|
|
procedure TCustomImageList.CheckIndex(AIndex: Integer; AForInsert: Boolean);
|
|
// aviod exceptionframe generation
|
|
procedure Error;
|
|
begin
|
|
raise EInvalidOperation.Create(SInvalidIndex);
|
|
end;
|
|
begin
|
|
if AForInsert
|
|
then begin
|
|
if AIndex > FCount then Error;
|
|
end
|
|
else begin
|
|
if AIndex >= FCount then Error;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Clear
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Clears the list.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Clear;
|
|
begin
|
|
if FCount = 0 then Exit;
|
|
if HandleAllocated
|
|
then TWSCustomImageListClass(WidgetSetClass).Clear(Self);
|
|
{$ifdef windows}
|
|
DestroyReference; //Issue #0029905: images added after clear aren't shown if width or height changed
|
|
{$endif}
|
|
SetLength(FData, 0);
|
|
FAllocCount := 0;
|
|
ClearOverlays;
|
|
|
|
FChanged := True;
|
|
FCount := 0;
|
|
Change;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Create
|
|
Params: AOwner: the owner of the class
|
|
Returns: Nothing
|
|
|
|
Constructor for the class.
|
|
------------------------------------------------------------------------------}
|
|
constructor TCustomImageList.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FHeight := 16;
|
|
FWidth := 16;
|
|
|
|
Initialize;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.CreateSize
|
|
Params: AHeight: The height of an image
|
|
AWidth: The width of an image
|
|
Returns: Nothing
|
|
|
|
Runtime constructor for the class with a given width and height.
|
|
------------------------------------------------------------------------------}
|
|
{.$ifdef IMGLIST_KEEP_EXTRA}
|
|
constructor TCustomImageList.CreateSize(AWidth, AHeight: Integer);
|
|
begin
|
|
inherited Create(nil);
|
|
FHeight := AHeight;
|
|
FWidth := AWidth;
|
|
Initialize;
|
|
end;
|
|
{.$endif}
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.DefineProperties
|
|
Params: Filer: A filer for our properties
|
|
Returns: Nothing
|
|
|
|
Defines the images
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.DefineProperties(Filer: TFiler);
|
|
|
|
function DoWrite: Boolean;
|
|
begin
|
|
if (Filer.Ancestor <> nil) and (Filer.Ancestor is TCustomImageList) then
|
|
Result := not Equals(Filer.Ancestor)
|
|
else
|
|
Result := Count > 0;
|
|
end;
|
|
|
|
begin
|
|
inherited DefineProperties(Filer);
|
|
Filer.DefineBinaryProperty('Bitmap', @ReadData, @WriteData, DoWrite);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Delete
|
|
Params: Index: the index of the image to be deleted.
|
|
Returns: Nothing
|
|
|
|
Deletes the image identified by Index. An index of -1 deletes all
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Delete(AIndex: Integer);
|
|
begin
|
|
if AIndex = -1
|
|
then begin
|
|
Clear;
|
|
Exit;
|
|
end;
|
|
|
|
CheckIndex(AIndex);
|
|
|
|
InternalMove(AIndex, FCount - 1, True);
|
|
Dec(FCount);
|
|
if HandleAllocated
|
|
then TWSCustomImageListClass(WidgetSetClass).Delete(Self, AIndex);
|
|
// TODO: adjust allocated data
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Destroy
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Destructor for the class.
|
|
------------------------------------------------------------------------------}
|
|
destructor TCustomImageList.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
while FChangeLinkList.Count>0 do
|
|
UnregisterChanges(TChangeLink(FChangeLinkList[0]));
|
|
FreeThenNil(FChangeLinkList);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Draw
|
|
Params: Canvas: the canvas to draw on
|
|
X, Y: co-ordinates of the top, left corner of thetarget location
|
|
Index: index of the image to be drawn
|
|
Enabled: True, draws the image
|
|
False, draws the image disabled (embossed)
|
|
Returns: Nothing
|
|
|
|
Draws the requested image on the given canvas.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Draw(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
AEnabled: Boolean);
|
|
begin
|
|
Draw(ACanvas, AX, AY, AIndex, EffectMap[AEnabled]);
|
|
end;
|
|
|
|
procedure TCustomImageList.Draw(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
ADrawEffect: TGraphicsDrawEffect);
|
|
begin
|
|
Draw(ACanvas, AX, AY, AIndex, DrawingStyle, ImageType, ADrawEffect);
|
|
end;
|
|
|
|
procedure TCustomImageList.Draw(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
ADrawingStyle: TDrawingStyle; AImageType: TImageType; AEnabled: Boolean);
|
|
begin
|
|
Draw(ACanvas, AX, AY, AIndex, ADrawingStyle, AImageType, EffectMap[AEnabled]);
|
|
end;
|
|
|
|
procedure TCustomImageList.Draw(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
ADrawingStyle: TDrawingStyle; AImageType: TImageType;
|
|
ADrawEffect: TGraphicsDrawEffect);
|
|
begin
|
|
if (AIndex < 0) or (AIndex >= FCount) then Exit;
|
|
|
|
ReferenceNeeded;
|
|
TWSCustomImageListClass(WidgetSetClass).Draw(Self, AIndex, ACanvas, Rect(AX, AY, FWidth, FHeight),
|
|
BkColor, BlendColor, ADrawEffect, ADrawingStyle, AImageType);
|
|
end;
|
|
|
|
procedure TCustomImageList.DrawOverlay(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
AOverlay: TOverlay; AEnabled: Boolean = True);
|
|
begin
|
|
DrawOverlay(ACanvas, AX, AY, AIndex, AOverlay, EffectMap[AEnabled]);
|
|
end;
|
|
|
|
procedure TCustomImageList.DrawOverlay(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
AOverlay: TOverlay; ADrawEffect: TGraphicsDrawEffect);
|
|
begin
|
|
DrawOverlay(ACanvas, AX, AY, AIndex, AOverlay, DrawingStyle, ImageType, ADrawEffect);
|
|
end;
|
|
|
|
procedure TCustomImageList.DrawOverlay(ACanvas: TCanvas; AX, AY, AIndex: Integer;
|
|
AOverlay: TOverlay; ADrawingStyle: TDrawingStyle; AImageType: TImageType;
|
|
ADrawEffect: TGraphicsDrawEffect);
|
|
var
|
|
OverlayIndex: Integer;
|
|
begin
|
|
if (AIndex < 0) or (AIndex >= FCount) then Exit;
|
|
|
|
ReferenceNeeded;
|
|
TWSCustomImageListClass(WidgetSetClass).Draw(Self, AIndex, ACanvas, Rect(AX, AY, FWidth, FHeight),
|
|
BkColor, BlendColor, ADrawEffect, ADrawingStyle, AImageType);
|
|
|
|
OverlayIndex := FOverlays[AOverlay];
|
|
if (OverlayIndex < 0) or (OverlayIndex >= FCount) then Exit;
|
|
|
|
TWSCustomImageListClass(WidgetSetClass).Draw(Self, OverlayIndex, ACanvas, Rect(AX, AY, FWidth, FHeight),
|
|
clNone, BlendColor, ADrawEffect, ADrawingStyle, AImageType);
|
|
end;
|
|
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.EndUpdate
|
|
Params: none
|
|
Returns: Nothing
|
|
|
|
Decrements te update lock. When zero, changes are notified when necesary
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.EndUpdate;
|
|
begin
|
|
if FUpdateCount<=0 then
|
|
RaiseGDBException('');
|
|
dec(FUpdateCount);
|
|
Change;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.FillDescription
|
|
Params: Desc: the description to fill
|
|
Returns: Nothing
|
|
|
|
Fills the description with the default info of the imagedata
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.FillDescription(out ADesc: TRawImageDescription);
|
|
begin
|
|
ADesc.Init;
|
|
ADesc.Format := ricfRGBA;
|
|
ADesc.PaletteColorCount := 0;
|
|
ADesc.MaskBitsPerPixel := 0;
|
|
ADesc.Depth := 32;
|
|
ADesc.Width := FWidth;
|
|
ADesc.Height := FHeight;
|
|
ADesc.BitOrder := riboBitsInOrder;
|
|
ADesc.ByteOrder := riboMSBFirst;
|
|
ADesc.LineOrder := riloTopToBottom;
|
|
ADesc.BitsPerPixel := 32;
|
|
ADesc.LineEnd := rileDWordBoundary;
|
|
ADesc.RedPrec := 8; // red precision. bits for red
|
|
ADesc.RedShift := 8;
|
|
ADesc.GreenPrec := 8;
|
|
ADesc.GreenShift := 16;
|
|
ADesc.BluePrec := 8;
|
|
ADesc.BlueShift := 24;
|
|
ADesc.AlphaPrec := 8;
|
|
ADesc.AlphaShift := 0;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.GetBitmap
|
|
Params: Index: the index of the requested image
|
|
Image: a bitmap as a container for the bitmap
|
|
Returns: Nothing
|
|
|
|
Creates a copy of the index'th image.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.GetBitmap(Index: Integer; Image: TCustomBitmap);
|
|
begin
|
|
GetBitmap(Index, Image, gdeNormal);
|
|
end;
|
|
|
|
procedure TCustomImageList.GetFullBitmap(Image: TCustomBitmap; AEffect: TGraphicsDrawEffect = gdeNormal);
|
|
var
|
|
RawImg: TRawImage;
|
|
ListImg, DeviceImg: TLazIntfImage;
|
|
ImgHandle, MskHandle: HBitmap;
|
|
begin
|
|
if (FCount = 0) or (Image = nil) then Exit;
|
|
|
|
GetFullRawImage(RawImg);
|
|
|
|
RawImg.PerformEffect(AEffect, True);
|
|
|
|
MskHandle := 0;
|
|
if not CreateCompatibleBitmaps(RawImg, ImgHandle, MskHandle, True)
|
|
then begin
|
|
// bummer, the widgetset doesn't support our 32bit format, try device
|
|
ListImg := TLazIntfImage.Create(RawImg, False);
|
|
DeviceImg := TLazIntfImage.Create(0,0,[]);
|
|
DeviceImg.DataDescription := GetDescriptionFromDevice(0, Width, Height * Count);
|
|
DeviceImg.CopyPixels(ListImg);
|
|
DeviceImg.GetRawImage(RawImg);
|
|
RawImage_CreateBitmaps(RawImg, ImgHandle, MskHandle);
|
|
DeviceImg.Free;
|
|
ListImg.Free;
|
|
end;
|
|
Image.SetHandles(ImgHandle, MskHandle);
|
|
|
|
RawImg.FreeData;
|
|
end;
|
|
|
|
procedure TCustomImageList.GetBitmap(Index: Integer; Image: TCustomBitmap;
|
|
AEffect: TGraphicsDrawEffect);
|
|
var
|
|
RawImg: TRawImage;
|
|
ListImg, DeviceImg: TLazIntfImage;
|
|
ImgHandle, MskHandle: HBitmap;
|
|
begin
|
|
if (FCount = 0) or (Image = nil) then Exit;
|
|
|
|
GetRawImage(Index, RawImg);
|
|
|
|
RawImg.PerformEffect(AEffect, True);
|
|
|
|
MskHandle := 0;
|
|
if not CreateCompatibleBitmaps(RawImg, ImgHandle, MskHandle, True)
|
|
then begin
|
|
// bummer, the widgetset doesn't support our 32bit format, try device
|
|
ListImg := TLazIntfImage.Create(RawImg, False);
|
|
DeviceImg := TLazIntfImage.Create(0,0,[]);
|
|
DeviceImg.DataDescription := GetDescriptionFromDevice(0, FWidth, FHeight);
|
|
DeviceImg.CopyPixels(ListImg);
|
|
DeviceImg.GetRawImage(RawImg);
|
|
RawImage_CreateBitmaps(RawImg, ImgHandle, MskHandle);
|
|
DeviceImg.Free;
|
|
ListImg.Free;
|
|
end;
|
|
Image.SetHandles(ImgHandle, MskHandle);
|
|
|
|
RawImg.FreeData;
|
|
end;
|
|
|
|
procedure TCustomImageList.GetFullRawImage(out Image: TRawImage);
|
|
begin
|
|
Image.Init;
|
|
|
|
if (FCount = 0) then Exit;
|
|
FillDescription(Image.Description);
|
|
Image.Description.Height := Height * Count;
|
|
Image.DataSize := Width * Height * Count * SizeOf(FData[0]);
|
|
Image.Data := PByte(FData);
|
|
end;
|
|
|
|
procedure TCustomImageList.GetIcon(Index: Integer; Image: TIcon; AEffect: TGraphicsDrawEffect);
|
|
var
|
|
RawImg: TRawImage;
|
|
ListImg, DeviceImg: TLazIntfImage;
|
|
IconInfo: TIconInfo;
|
|
begin
|
|
if (FCount = 0) or (Image = nil) then Exit;
|
|
|
|
GetRawImage(Index, RawImg);
|
|
RawImg.PerformEffect(AEffect, True);
|
|
|
|
IconInfo.fIcon := True;
|
|
IconInfo.hbmMask := 0;
|
|
if not CreateCompatibleBitmaps(RawImg, IconInfo.hbmColor, IconInfo.hbmMask, True)
|
|
then begin
|
|
// bummer, the widgetset doesn't support our 32bit format, try device
|
|
ListImg := TLazIntfImage.Create(RawImg, False);
|
|
DeviceImg := TLazIntfImage.Create(0,0,[]);
|
|
DeviceImg.DataDescription := GetDescriptionFromDevice(0, FWidth, FHeight);
|
|
DeviceImg.CopyPixels(ListImg);
|
|
DeviceImg.GetRawImage(RawImg);
|
|
RawImage_CreateBitmaps(RawImg, IconInfo.hbmColor, IconInfo.hbmMask);
|
|
DeviceImg.Free;
|
|
ListImg.Free;
|
|
end;
|
|
Image.Handle := CreateIconIndirect(@IconInfo);
|
|
|
|
RawImg.FreeData;
|
|
end;
|
|
|
|
procedure TCustomImageList.GetIcon(Index: Integer; Image: TIcon);
|
|
begin
|
|
GetIcon(Index, Image, gdeNormal);
|
|
end;
|
|
|
|
procedure TCustomImageList.GetRawImage(Index: Integer; out Image: TRawImage);
|
|
begin
|
|
Image.Init;
|
|
|
|
if (FCount = 0) then Exit;
|
|
CheckIndex(Index);
|
|
FillDescription(Image.Description);
|
|
if Index >= 0 then
|
|
begin
|
|
Image.DataSize := FWidth * FHeight * SizeOf(FData[0]);
|
|
Image.Data := @FData[Index * FWidth * FHeight];
|
|
end;
|
|
end;
|
|
|
|
function TCustomImageList.GetReference: TWSCustomImageListReference;
|
|
begin
|
|
if not FReference.Allocated then ReferenceNeeded;
|
|
Result := FReference;
|
|
end;
|
|
|
|
function TCustomImageList.GetReferenceHandle: THandle;
|
|
begin
|
|
Result := FReference.Handle;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: TCustomImageList.GetHotspot
|
|
Params: None
|
|
Returns: The co-ordinates for the hotspot of the drag image
|
|
|
|
Returns the co-ordinates for the hotspot of the drag image.
|
|
------------------------------------------------------------------------------}
|
|
function TCustomImageList.GetHotSpot: TPoint;
|
|
begin
|
|
Result := Point(0, 0);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Initialize
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Initializes the internal bitmap structures and the changelink list.
|
|
It is used by the Create and CreateSize constructors
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Initialize;
|
|
begin
|
|
FChangeLinkList := TList.Create;
|
|
FAllocBy := 4;
|
|
FAllocCount := 0;
|
|
FBlendColor := clNone;
|
|
FBkColor := clNone;
|
|
FDrawingStyle := dsNormal;
|
|
ClearOverlays;
|
|
|
|
if (Height < 1) or (Height > 32768) or (Width < 1)
|
|
then raise EInvalidOperation.Create(SInvalidImageSize);
|
|
end;
|
|
|
|
procedure TCustomImageList.SetWidthHeight(NewWidth, NewHeight: integer);
|
|
begin
|
|
if (FHeight=NewHeight) and (FWidth=NewWidth) then exit;
|
|
FHeight := NewHeight;
|
|
FWidth := NewWidth;
|
|
Clear;
|
|
end;
|
|
|
|
procedure TCustomImageList.ClearOverlays;
|
|
var
|
|
I: TOverlay;
|
|
begin
|
|
for I := Low(TOverlay) to High(TOverlay) do
|
|
FOverlays[I] := -1;
|
|
end;
|
|
|
|
class procedure TCustomImageList.WSRegisterClass;
|
|
begin
|
|
inherited WSRegisterClass;
|
|
RegisterCustomImageList;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Insert
|
|
Params: Index: the index of the inserted image
|
|
Image: a bitmap image
|
|
Mask: a bitmap which defines the transparent parts of Image
|
|
Returns: Nothing
|
|
|
|
Inserts one or more (bitmap width / imagelist width) bitmaps into the list
|
|
at the index'th position. If Mask is nil, the image has no transparent parts.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Insert(AIndex: Integer; AImage, AMask: TCustomBitmap);
|
|
var
|
|
msk: THandle;
|
|
begin
|
|
if AImage = nil then Exit;
|
|
|
|
if AMask = nil
|
|
then begin
|
|
if AImage.Masked
|
|
then msk := AImage.MaskHandle
|
|
else msk := 0;
|
|
end
|
|
else msk := AMask.Handle;
|
|
|
|
InternalInsert(AIndex, AImage.Handle, msk, AImage.Width, AImage.Height);
|
|
end;
|
|
|
|
procedure TCustomImageList.InsertIcon(AIndex: Integer; AIcon: TCustomIcon);
|
|
var
|
|
IconIndex: Integer;
|
|
Image: TIconImage;
|
|
begin
|
|
if AIcon = nil then Exit;
|
|
IconIndex := AIcon.GetBestIndexForSize(Size(Width, Height));
|
|
if IconIndex = -1 then Exit;
|
|
Image := TSharedIcon(TCustomIconAccess(AIcon).FSharedImage).Images[IconIndex];
|
|
if Image.Handle = 0 then
|
|
InternalInsert(AIndex, Image.RawImage)
|
|
else
|
|
InternalInsert(AIndex, Image.Handle, Image.MaskHandle, Image.Width, Image.Height);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.InsertMasked
|
|
Params: Index: the index of the inserted image
|
|
AImage: A bitmap to be inserted
|
|
MaskColor: The color acting as transparant color
|
|
Returns: Nothing
|
|
|
|
Adds one or more (bitmap width / imagelist width) bitmaps to the list.
|
|
Every occurrence of MaskColor will be converted to transparent.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.InsertMasked(Index: Integer; AImage: TCustomBitmap;
|
|
MaskColor: TColor);
|
|
var
|
|
RawImg: TRawImage;
|
|
SourceImage, MaskedImage: TLazIntfImage;
|
|
MaskedDescription, DeviceDescription: TRawImageDescription;
|
|
begin
|
|
if AImage = nil then Exit;
|
|
SourceImage := TLazIntfImage.Create(AImage.RawImage, False);
|
|
try
|
|
MaskedImage := TLazIntfImage.Create(0,0,[]);
|
|
try
|
|
MaskedImage.DataDescription := SourceImage.DataDescription;
|
|
if MaskedImage.DataDescription.MaskBitsPerPixel = 0 then
|
|
begin
|
|
MaskedDescription := MaskedImage.DataDescription;
|
|
DeviceDescription := GetDescriptionFromDevice(0, 0, 0);
|
|
MaskedDescription.MaskBitsPerPixel := DeviceDescription.MaskBitsPerPixel;
|
|
MaskedDescription.MaskBitOrder := DeviceDescription.MaskBitOrder;
|
|
MaskedDescription.MaskLineEnd := DeviceDescription.MaskLineEnd;
|
|
MaskedDescription.MaskShift := DeviceDescription.MaskShift;
|
|
MaskedImage.DataDescription := MaskedDescription;
|
|
end;
|
|
MaskedImage.CopyPixels(SourceImage);
|
|
MaskedImage.Mask(TColorToFPColor(ColorToRGB(MaskColor)));
|
|
MaskedImage.GetRawImage(RawImg);
|
|
InternalInsert(Index, RawImg);
|
|
finally
|
|
MaskedImage.Free;
|
|
end;
|
|
finally
|
|
SourceImage.Free;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.InternalMove
|
|
Params: CurIndex: the index of the image to be moved
|
|
NewIndex: the new index of the image
|
|
Returns: Nothing
|
|
|
|
Moves an image from the CurIndex'th location to NewIndex'th location
|
|
without notifying the widgetset
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.InternalMove(ACurIndex, ANewIndex: Cardinal; AIgnoreCurrent: Boolean);
|
|
var
|
|
ImgSize, DataSize: Cardinal;
|
|
p: Pointer;
|
|
begin
|
|
ImgSize := FWidth * FHeight;
|
|
DataSize := ImgSize * SizeOf(FData[0]);
|
|
|
|
if not AIgnoreCurrent
|
|
then begin
|
|
// store current
|
|
p := GetMem(DataSize);
|
|
System.Move(FData[ACurIndex * ImgSize], p^, DataSize);
|
|
end;
|
|
|
|
// move all one up
|
|
if ACurIndex < ANewIndex
|
|
then System.Move(FData[(ACurIndex + 1) * ImgSize], FData[ACurIndex * ImgSize], DataSize * Cardinal(ANewIndex - ACurIndex))
|
|
else System.Move(FData[ANewIndex * ImgSize], FData[(ANewIndex + 1) * ImgSize], DataSize * Cardinal(ACurIndex - ANewIndex));
|
|
|
|
if not AIgnoreCurrent
|
|
then begin
|
|
// restore current
|
|
System.Move(p^, FData[ANewIndex * ImgSize], DataSize);
|
|
FreeMem(p);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomImageList.InternalReplace(AIndex: Integer; AImage,
|
|
AMask: HBitmap);
|
|
var
|
|
RawImage: TRawImage;
|
|
R: TRect;
|
|
ImgData: PRGBAQuad;
|
|
begin
|
|
if (AIndex < 0) then AIndex := 0;
|
|
CheckIndex(AIndex);
|
|
|
|
R := Rect(0, 0, FWidth, FHeight);
|
|
RawImage_FromBitmap(RawImage, AImage, AMask, @R);
|
|
ImgData := InternalSetImage(AIndex, RawImage);
|
|
if HandleAllocated
|
|
then TWSCustomImageListClass(WidgetSetClass).Replace(Self, AIndex, ImgData);
|
|
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.InternalSetImage
|
|
Params: AIndex: the index of the location where the image should be set
|
|
AImage: the new image
|
|
Returns: Pointer to the updated image data
|
|
|
|
Copies the imagedata into the FData array and then frees the image.
|
|
------------------------------------------------------------------------------}
|
|
function TCustomImageList.InternalSetImage(AIndex: Integer; AImage: TRawImage): PRGBAQuad;
|
|
var
|
|
Desc: TRawImageDescription absolute AImage.Description;
|
|
|
|
RawImg: TRawImage;
|
|
SrcImg, DstImg: TLazIntfImage;
|
|
SrcHasAlpha, KeepAlpha: Boolean;
|
|
|
|
begin
|
|
SrcHasAlpha := AImage.Description.AlphaPrec > 0;
|
|
KeepAlpha := SrcHasAlpha;
|
|
if not SrcHasAlpha and (Desc.BitsPerPixel = 32) and (Desc.Depth = 24) and
|
|
(AImage.Mask <> nil) and (Desc.MaskBitsPerPixel > 0)
|
|
then begin
|
|
// Try to squeeze Aplha channel in some unused bits
|
|
if (Desc.RedShift >= 8)
|
|
and (Desc.GreenShift >= 8)
|
|
and (Desc.BlueShift >= 8)
|
|
then begin
|
|
// there is room at the lsb side
|
|
Desc.AlphaPrec := 8;
|
|
Desc.AlphaShift := 0;
|
|
Desc.Depth := 32;
|
|
SrcHasAlpha := True;
|
|
end
|
|
else if (Desc.RedShift < 24)
|
|
and (Desc.GreenShift < 24)
|
|
and (Desc.BlueShift < 24)
|
|
then begin
|
|
// there is room at the msb side
|
|
Desc.AlphaPrec := 8;
|
|
Desc.AlphaShift := 24;
|
|
Desc.Depth := 32;
|
|
SrcHasAlpha := True;
|
|
end;
|
|
end;
|
|
|
|
SrcImg := TLazIntfImage.Create(AImage, True);
|
|
if SrcHasAlpha
|
|
then SrcImg.AlphaFromMask(KeepAlpha);
|
|
|
|
RawImg.Init;
|
|
FillDescription(RawImg.Description);
|
|
Result := @FData[AIndex * FWidth * FHeight];
|
|
RawImg.DataSize := FWidth * FHeight * SizeOf(FData[0]);
|
|
RawImg.Data := PByte(Result);
|
|
if not SrcHasAlpha
|
|
then begin
|
|
// Add maskdata to store copied mask, so an alpha can be created
|
|
RawImg.Description.MaskBitsPerPixel := 1;
|
|
RawImg.Description.MaskBitOrder := riboReversedBits;
|
|
RawImg.Description.MaskLineEnd := rileByteBoundary;
|
|
RawImg.Description.MaskShift := 0;
|
|
RawImg.MaskSize := RawImg.Description.MaskBytesPerLine * PtrUInt(FHeight);
|
|
RawImg.Mask := GetMem(RawImg.MaskSize);
|
|
end;
|
|
|
|
DstImg := TLazIntfImage.Create(RawImg, False);
|
|
DstImg.CopyPixels(SrcImg);
|
|
if not SrcHasAlpha
|
|
then begin
|
|
DstImg.AlphaFromMask;
|
|
FreeMem(RawImg.Mask);
|
|
RawImg.Mask := nil;
|
|
RawImg.MaskSize := 0;
|
|
end;
|
|
|
|
DstImg.Free;
|
|
SrcImg.Free;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Move
|
|
Params: CurIndex: the index of the image to be moved
|
|
NewIndex: the new index of the image
|
|
Returns: Nothing
|
|
|
|
Moves an image from the CurIndex'th location to NewIndex'th location
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.Move(ACurIndex, ANewIndex: Integer);
|
|
begin
|
|
if ACurIndex = ANewIndex then Exit;
|
|
CheckIndex(ACurIndex);
|
|
CheckIndex(ANewIndex);
|
|
|
|
if ACurIndex < 0 then ACurIndex := 0;
|
|
if ANewIndex < 0 then ANewIndex := 0;
|
|
|
|
InternalMove(ACurIndex, ANewIndex, False);
|
|
if HandleAllocated
|
|
then TWSCustomImageListClass(WidgetSetClass).Move(Self, ACurIndex, ANewIndex);
|
|
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.NotifyChangeLink
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Internal function to notify the subscribed objects of a change
|
|
of the imagelist.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.NotifyChangeLink;
|
|
var
|
|
nIndex: Integer;
|
|
begin
|
|
if FChangeLinkList <> nil then
|
|
with FChangeLinkList do
|
|
for nIndex := 0 to Count - 1 do TChangeLink(Items[nIndex]).Change
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.WriteData
|
|
Params: AStream: The stream to write the data to
|
|
Returns: Nothing
|
|
|
|
Writes the imagelist data to stream
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.WriteData(AStream: TStream);
|
|
var
|
|
Signature: TImageListSignature;
|
|
begin
|
|
//Write signature
|
|
Signature:=SIG_LAZ3;
|
|
AStream.Write(Signature,SizeOf(Signature));
|
|
|
|
//Count of image
|
|
WriteLRSInteger(AStream,Count);
|
|
WriteLRSInteger(AStream,Width);
|
|
WriteLRSInteger(AStream,Height);
|
|
|
|
//images
|
|
if Count > 0 then
|
|
AStream.Write(FData[0], FWidth * FHeight * FCount * SizeOf(FData[0]));
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.ReadData
|
|
Params: AStream: The stream to read the data from
|
|
Returns: Nothing
|
|
|
|
Reads the imagelist data from stream
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.ReadData(AStream: TStream);
|
|
var
|
|
Signature: TImageListSignature;
|
|
StreamPos: TStreamSeekType;
|
|
|
|
procedure DoReadLaz1;
|
|
var
|
|
i, NewCount, Size: Integer;
|
|
bmp: TBitmap;
|
|
begin
|
|
// provided for compatability for earlier lazarus streams
|
|
NewCount := AStream.ReadWord;
|
|
for i := 0 to NewCount - 1 do
|
|
begin
|
|
bmp := TBitMap.Create;
|
|
Size:=ReadLRSInteger(AStream);
|
|
bmp.LoadFromStream(AStream, Size);
|
|
bmp.Transparent := True;
|
|
Add(bmp, nil);
|
|
bmp.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure DoReadLaz2;
|
|
var
|
|
i, NewCount, Size: cardinal;
|
|
bmp: TCustomBitmap;
|
|
Sig: array[0..1] of char;
|
|
begin
|
|
NewCount := ReadLRSCardinal(AStream);
|
|
Width := ReadLRSCardinal(AStream);
|
|
Height := ReadLRSCardinal(AStream);
|
|
for i := 0 to NewCount - 1 do
|
|
begin
|
|
Size := ReadLRSCardinal(AStream);
|
|
bmp := nil;
|
|
// Before our TBitmap can have bpm, xpm, png or other content
|
|
// We need to look at signature before loading
|
|
if Size > 2 then
|
|
begin
|
|
AStream.Read(Sig[0], 2);
|
|
if Sig = 'BM' then
|
|
bmp := TBitmap.Create
|
|
else
|
|
if Sig = '/*' then
|
|
bmp := TPixmap.Create
|
|
else
|
|
if Sig = '%P' then
|
|
bmp := TPortableNetworkGraphic.Create
|
|
else
|
|
raise EInvalidGraphicOperation.Create(rsInvalidStreamFormat);
|
|
AStream.Position := AStream.Position - 2;
|
|
end;
|
|
bmp.LoadFromStream(AStream, Size);
|
|
Add(bmp, nil);
|
|
bmp.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure DoReadLaz3;
|
|
begin
|
|
FCount := ReadLRSCardinal(AStream);
|
|
FWidth := ReadLRSCardinal(AStream);
|
|
FHeight := ReadLRSCardinal(AStream);
|
|
|
|
AllocData(FCount);
|
|
if FCount > 0 then
|
|
AStream.ReadBuffer(FData[0], FWidth * FHeight * FCount * SizeOf(FData[0])) ;
|
|
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
|
|
procedure CreateImagesFromRawImage(IntfImage: TLazIntfImage;
|
|
NewCount: integer);
|
|
var
|
|
RawImage, SubRawImage: TRawImage;
|
|
ImgHandle, MaskHandle: HBitmap;
|
|
Row: Integer;
|
|
Col: Integer;
|
|
ImgRect: TRect;
|
|
Res: Boolean;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
IntfImage.GetRawImage(RawImage);
|
|
SubRawImage.Init;
|
|
|
|
for Row := 0 to (IntfImage.Height div Height) - 1 do
|
|
begin
|
|
if NewCount <= 0 then Break;
|
|
for Col := 0 to (IntfImage.Width div Width) - 1 do
|
|
begin
|
|
if NewCount <= 0 then Break;
|
|
|
|
ImgRect := Bounds(Col*Width,Row*Height,Width,Height);
|
|
RawImage.ExtractRect(ImgRect, SubRawImage);
|
|
Res := RawImage_CreateBitmaps(SubRawImage, ImgHandle, MaskHandle);
|
|
SubRawImage.FreeData;
|
|
if not Res
|
|
then raise EInvalidGraphicOperation.Create('TCustomImageList.CreateImagesFromRawImage Create bitmaps');
|
|
|
|
InternalInsert(Count, ImgHandle, MaskHandle, Width, Height);
|
|
DeleteObject(ImgHandle);
|
|
DeleteObject(MaskHandle);
|
|
//DebugLn('CreateImagesFromRawImage B ',Img.Width,',',Img.Height,' ',Count);
|
|
Dec(NewCount);
|
|
end;
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure ReadDelphiImageAndMask(HasMask: boolean; NewCount: integer);
|
|
var
|
|
IntfImage: TLazIntfImage;
|
|
ImgReader: TFPReaderBMP;
|
|
MaskIntfImage: TLazIntfImageMask;
|
|
begin
|
|
IntfImage:=nil;
|
|
MaskIntfImage:=nil;
|
|
ImgReader:=nil;
|
|
try
|
|
IntfImage:=TLazIntfImage.Create(0,0,[]);
|
|
IntfImage.DataDescription := GetDescriptionFromDevice(0, 0, 0);
|
|
// read the image bmp stream into the IntfImage
|
|
ImgReader:=TFPReaderBMP.Create;
|
|
IntfImage.LoadFromStream(AStream,ImgReader);
|
|
if HasMask then begin
|
|
// create the mask bmp directly into the RawImage
|
|
MaskIntfImage:=TLazIntfImageMask.CreateWithImage(IntfImage);
|
|
MaskIntfImage.LoadFromStream(AStream,ImgReader);
|
|
end;
|
|
|
|
CreateImagesFromRawImage(IntfImage,NewCount);
|
|
finally
|
|
// clean up
|
|
ImgReader.Free;
|
|
IntfImage.Free;
|
|
MaskIntfImage.Free;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF SaveDelphiImgListStream}
|
|
procedure SaveImgListStreamToFile;
|
|
var
|
|
CurStreamPos: TStreamSeekType;
|
|
fs: TFileStream;
|
|
i: Integer;
|
|
Filename: string;
|
|
begin
|
|
i:=0;
|
|
repeat
|
|
inc(i);
|
|
Filename:='TCustomImageList'+IntToStr(i)+'.stream';
|
|
until not FileExistsUTF8(Filename);
|
|
CurStreamPos := AStream.Position;
|
|
DebugLn('TCustomImageList.ReadData Saving stream to ',Filename);
|
|
fs:=TFileStream.Create(UTF8ToSys(Filename),fmCreate);
|
|
AStream.Position:=StreamPos;
|
|
fs.CopyFrom(AStream,AStream.Size-AStream.Position);
|
|
fs.Free;
|
|
AStream.Position:=CurStreamPos;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
var
|
|
HasMask: Boolean;
|
|
NewCount: Integer;
|
|
Size: integer;
|
|
begin
|
|
BeginUpdate; // avoid multiple changed calls
|
|
try
|
|
Clear;
|
|
|
|
StreamPos := AStream.Position; // check stream signature
|
|
AStream.Read(Signature, SizeOf(Signature));
|
|
|
|
if Signature = SIG_LAZ3
|
|
then begin
|
|
DoReadLaz3;
|
|
Exit;
|
|
end;
|
|
|
|
if Signature = SIG_LAZ2
|
|
then begin
|
|
DoReadLaz2;
|
|
Exit;
|
|
end;
|
|
|
|
if Signature = SIG_LAZ1
|
|
then begin
|
|
DoReadLaz1;
|
|
Exit;
|
|
end;
|
|
|
|
// Delphi streams
|
|
|
|
{$IFDEF SaveDelphiImgListStream}
|
|
SaveImgListStreamToFile;
|
|
{$ENDIF}
|
|
|
|
if Signature = SIG_D3
|
|
then begin
|
|
AStream.ReadWord; //Skip ?
|
|
NewCount := ReadLRSWord(AStream);
|
|
//DebugLn('NewCount=',NewCount);
|
|
AStream.ReadWord; //Skip Capacity
|
|
AStream.ReadWord; //Skip Grow
|
|
FWidth := ReadLRSWord(AStream);
|
|
//DebugLn('NewWidth=',FWidth);
|
|
FHeight := ReadLRSWord(AStream);
|
|
//DebugLn('NewHeight=',FHeight);
|
|
FBKColor := TColor(ReadLRSInteger(AStream));
|
|
// corrent colors - they are stored in windows values
|
|
if TColorRef(FBKColor) = CLR_NONE then
|
|
FBKColor := clNone
|
|
else
|
|
if TColorRef(FBKColor) = CLR_DEFAULT then
|
|
FBKColor := clDefault;
|
|
HasMask := (ReadLRSWord(AStream) and 1) = 1;
|
|
AStream.ReadDWord; //Skip ?
|
|
AStream.ReadDWord; //Skip ?
|
|
|
|
ReadDelphiImageAndMask(HasMask,NewCount);
|
|
end
|
|
else begin
|
|
// D2 has no signature, so restore original position
|
|
AStream.Position := StreamPos;
|
|
Size:=ReadLRSInteger(AStream);
|
|
NewCount:=ReadLRSInteger(AStream);
|
|
|
|
ReadDelphiImageAndMask(false,NewCount);
|
|
AStream.Position := StreamPos+Size;
|
|
end;
|
|
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TCustomImageList.Equals(Obj: TObject): boolean;
|
|
var
|
|
SrcList: TCustomImageList;
|
|
CurStream: TMemoryStream;
|
|
SrcStream: TMemoryStream;
|
|
begin
|
|
if Obj is TCustomImageList then begin
|
|
SrcList:=TCustomImageList(Obj);
|
|
Result:=false;
|
|
if SrcList.Count<>Count then exit;
|
|
if Count=0 then exit(true);
|
|
CurStream:=TMemoryStream.Create;
|
|
SrcStream:=TMemoryStream.Create;
|
|
try
|
|
WriteData(CurStream);
|
|
SrcList.WriteData(SrcStream);
|
|
Result:=CompareMemStreams(CurStream,SrcStream);
|
|
finally
|
|
SrcStream.Free;
|
|
CurStream.Free;
|
|
end;
|
|
end else
|
|
{$IF FPC_FULLVERSION>20402}
|
|
Result:=inherited Equals(Obj);
|
|
{$ELSE}
|
|
Result:=false;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TCustomImageList.Overlay(AIndex: Integer; Overlay: TOverlay);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
FOverlays[Overlay] := AIndex;
|
|
if AIndex>=0 then
|
|
fHasOverlays:=true
|
|
else if fHasOverlays then begin
|
|
fHasOverlays:=false;
|
|
for i:=Low(TOverlay) to high(TOverlay) do
|
|
begin
|
|
if FOverlays[i]<0 then continue;
|
|
fHasOverlays:=true;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.RegisterChanges
|
|
Params: Value: a reference to changelink object
|
|
Returns: Nothing
|
|
|
|
Registers an object to get notified of a change of the imagelist.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.RegisterChanges(Value: TChangeLink);
|
|
begin
|
|
if (Value <> nil) and (FChangeLinkList.IndexOf(Value) = -1)
|
|
then begin
|
|
Value.Sender := Self;
|
|
FChangeLinkList.Add(Value);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.Replace
|
|
Params: Index: the index of the replaceded image
|
|
Image: a bitmap image
|
|
Mask: a bitmap which defines the transparent parts of Image
|
|
Returns: Nothing.
|
|
|
|
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);
|
|
var
|
|
msk: THandle;
|
|
begin
|
|
if AImage = nil then Exit;
|
|
|
|
if AMask = nil
|
|
then msk := 0
|
|
else msk := AMask.Handle;
|
|
InternalReplace(AIndex, AImage.Handle, msk);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.ReplaceMasked
|
|
Params: Index: the index of the replaceded image
|
|
Image: A bitmap image
|
|
MaskColor: The color acting as transparant color
|
|
Returns: Nothing
|
|
|
|
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);
|
|
var
|
|
Bmp: TBitmap;
|
|
begin
|
|
if NewImage = nil then Exit;
|
|
|
|
Bmp := TBitmap.Create;
|
|
with Bmp do
|
|
begin
|
|
Assign(NewImage);
|
|
TransparentColor := MaskColor;
|
|
Transparent := True;
|
|
end;
|
|
|
|
if Bmp.Masked
|
|
then InternalReplace(Index, Bmp.Handle, Bmp.MaskHandle)
|
|
else InternalReplace(Index, Bmp.Handle, 0);
|
|
Bmp.Free;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.SetBkColor
|
|
Params: Value: The background color
|
|
Returns: Nothing
|
|
|
|
Sets the backgroundcolor for the transparen parts.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.SetBkColor(const Value: TColor);
|
|
begin
|
|
if FBkColor <> Value
|
|
then begin
|
|
FBkColor := Value;
|
|
FChanged := true;
|
|
Change;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomImageList.SetDrawingStyle(const AValue: TDrawingStyle);
|
|
begin
|
|
if FDrawingStyle=AValue then exit;
|
|
FDrawingStyle:=AValue;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.SetHeight
|
|
Params: Value: the height of an image
|
|
Returns: Nothing
|
|
|
|
Sets the height of an image. If the height differs from the original height,
|
|
the list contents wil be deleted.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.SetHeight(const Value: Integer);
|
|
begin
|
|
SetWidthHeight(Width,Value);
|
|
end;
|
|
|
|
procedure TCustomImageList.SetMasked(const AValue: boolean);
|
|
begin
|
|
if FMasked=AValue then exit;
|
|
FMasked:=AValue;
|
|
end;
|
|
|
|
procedure TCustomImageList.SetShareImages(const AValue: Boolean);
|
|
begin
|
|
if FShareImages=AValue then exit;
|
|
FShareImages:=AValue;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.SetWidth
|
|
Params: Value: the width of an image
|
|
Returns: Nothing
|
|
|
|
Sets the width of an image. If the width differs from the original width,
|
|
the list contents wil be deleted.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.SetWidth(const Value: Integer);
|
|
begin
|
|
SetWidthHeight(Value,Height);
|
|
end;
|
|
|
|
procedure TCustomImageList.StretchDraw(Canvas: TCanvas; Index: Integer;
|
|
ARect: TRect; Enabled: Boolean);
|
|
var
|
|
bmp: TBitmap;
|
|
begin
|
|
if (FCount = 0) or (Index >= FCount) then Exit;
|
|
|
|
// ToDo: accelerate
|
|
// temp workaround
|
|
bmp := TBitmap.Create;
|
|
GetBitmap(Index, bmp);
|
|
Canvas.StretchDraw(ARect, bmp);
|
|
bmp.Free;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.UnRegisterChanges
|
|
Params: Value: a reference to changelink object
|
|
Returns: Nothing
|
|
|
|
Unregisters an object for notifications.
|
|
------------------------------------------------------------------------------}
|
|
procedure TCustomImageList.UnRegisterChanges(Value: TChangeLink);
|
|
begin
|
|
if (FChangeLinkList<>nil) and (Value.Sender=Self) then
|
|
FChangeLinkList.Remove(Value);
|
|
Value.Sender:=nil;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TCustomImageList.WSCreateHandle
|
|
Params: AParams: ignored
|
|
Returns: Handle to created imagelist
|
|
|
|
Instructs the widgtset to create an imagelist
|
|
------------------------------------------------------------------------------}
|
|
function TCustomImageList.WSCreateReference(AParams: TCreateParams): PWSReference;
|
|
var
|
|
ilc: TWSCustomImageListClass;
|
|
dt: PRGBAQuad;
|
|
begin
|
|
ilc := TWSCustomImageListClass(WidgetSetClass);
|
|
if FCount = 0 then
|
|
dt := nil
|
|
else
|
|
dt := @FData[0];
|
|
FReference := ilc.CreateReference(Self, FCount, FAllocBy, FWidth, FHeight, dt);
|
|
Result := @FReference;
|
|
end;
|
|
|
|
{******************************************************************************
|
|
TChangeLink
|
|
******************************************************************************}
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TChangeLink.Change
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Fires the OnChange event.
|
|
------------------------------------------------------------------------------}
|
|
procedure TChangeLink.Change;
|
|
begin
|
|
if Assigned(FOnChange) then FOnChange(Sender)
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: TChangeLink.Destroy
|
|
Params: None
|
|
Returns: Nothing
|
|
|
|
Destructor for the class.
|
|
------------------------------------------------------------------------------}
|
|
destructor TChangeLink.Destroy;
|
|
begin
|
|
if Sender <> nil
|
|
then Sender.UnRegisterChanges(Self);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
// included by imglist.pp
|