mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-03 16:38:17 +02:00

- register more picture extensions (.cur, .icns) - add simple implementation to TCustomIcon.UpdateCurrentView git-svn-id: trunk@15613 -
771 lines
20 KiB
PHP
771 lines
20 KiB
PHP
{%MainUnit ../graphics.pp}
|
|
|
|
{******************************************************************************
|
|
TCustomIcon
|
|
******************************************************************************
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
|
|
const
|
|
IconSignature: array [0..3] of char = #0#0#1#0;
|
|
CursorSignature: array [0..3] of char = #0#0#2#0;
|
|
|
|
type
|
|
TIconHeader = {packed} record // packed it not needed
|
|
idReserved: Word; // 0
|
|
idType: Word; // 1 - Icon, 2 - Cursor
|
|
idCount: Word; // number of icons in file
|
|
end;
|
|
|
|
TIconDirEntry = {packed} record // packing not needed
|
|
bWidth: Byte; // a value of 0 means 256
|
|
bHeight: Byte; // a value of 0 means 256
|
|
bColorCount: Byte; // number of entires in pallette table below
|
|
bReserved: Byte; // not used = 0
|
|
case Byte of
|
|
1: (
|
|
// icon
|
|
wPlanes: Word; // number of planes, should be 0 or 1
|
|
wBpp: Word; // bits per pixel
|
|
// common
|
|
dwBytesInRes: Longint; // total number bytes in images including pallette
|
|
// data: XOR, AND and bitmap info header
|
|
dwImageOffset: Longint; // pos of image as offset from the beginning of file
|
|
);
|
|
2:(
|
|
// cursor
|
|
wXHotSpot: Word;
|
|
wYHotSpot: Word;
|
|
);
|
|
end;
|
|
|
|
PIconDirEntry = ^TIconDirEntry;
|
|
|
|
|
|
function TestStreamIsIcon(const AStream: TStream): boolean;
|
|
var
|
|
Signature: array[0..3] of char;
|
|
ReadSize: Integer;
|
|
OldPosition: TStreamSeekType;
|
|
begin
|
|
OldPosition:=AStream.Position;
|
|
ReadSize:=AStream.Read(Signature, SizeOf(Signature));
|
|
Result:=(ReadSize=SizeOf(Signature)) and CompareMem(@Signature,@IconSignature,4);
|
|
AStream.Position:=OldPosition;
|
|
end;
|
|
|
|
function TestStreamIsCursor(const AStream: TStream): boolean;
|
|
var
|
|
Signature: array[0..3] of char;
|
|
ReadSize: Integer;
|
|
OldPosition: TStreamSeekType;
|
|
begin
|
|
OldPosition:=AStream.Position;
|
|
ReadSize:=AStream.Read(Signature, SizeOf(Signature));
|
|
Result:=(ReadSize=SizeOf(Signature)) and CompareMem(@Signature,@CursorSignature,4);
|
|
AStream.Position:=OldPosition;
|
|
end;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
{ TSharedIcon }
|
|
|
|
procedure TSharedIcon.FreeHandle;
|
|
begin
|
|
if FHandle = 0 then Exit;
|
|
|
|
DestroyIcon(FHandle);
|
|
FHandle := 0;
|
|
end;
|
|
|
|
class function TSharedIcon.GetImagesClass: TIconImageClass;
|
|
begin
|
|
Result := TIconImage;
|
|
end;
|
|
|
|
procedure TSharedIcon.Add(AIconImage: TIconImage);
|
|
begin
|
|
FImages.Add(AIconImage);
|
|
end;
|
|
|
|
constructor TSharedIcon.Create;
|
|
begin
|
|
inherited Create;
|
|
FImages := TFPList.Create;
|
|
end;
|
|
|
|
procedure TSharedIcon.Delete(Aindex: Integer);
|
|
var
|
|
Image: TIconImage;
|
|
begin
|
|
Image := TIconImage(FImages[Aindex]);
|
|
FImages.Delete(AIndex);
|
|
Image.Free;
|
|
end;
|
|
|
|
destructor TSharedIcon.Destroy;
|
|
begin
|
|
Clear;
|
|
FreeAndNil(FImages);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSharedIcon.Clear;
|
|
var
|
|
n: Integer;
|
|
begin
|
|
for n := 0 to FImages.Count - 1 do
|
|
TObject(FImages[n]).Free;
|
|
end;
|
|
|
|
function TSharedIcon.GetIndex(AFormat: TPixelFormat; AHeight, AWidth: Word): Integer;
|
|
var
|
|
//List: TFPList;
|
|
Image: TIconImage;
|
|
begin
|
|
for Result := 0 to FImages.Count -1 do
|
|
begin
|
|
Image := TIconImage(FImages[Result]);
|
|
if Image.PixelFormat <> AFormat then Continue;
|
|
if Image.Height <> AHeight then Continue;
|
|
if Image.Width <> AWidth then Continue;
|
|
// found
|
|
Exit;
|
|
end;
|
|
Result := -1;
|
|
end;
|
|
|
|
function TSharedIcon.Count: Integer;
|
|
begin
|
|
Result := FImages.Count;
|
|
end;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
{ TIconImage }
|
|
|
|
constructor TIconImage.Create(AFormat: TPixelFormat; AHeight, AWidth: Word);
|
|
begin
|
|
inherited Create;
|
|
FHeight := AHeight;
|
|
FWidth := AWidth;
|
|
FPixelFormat := AFormat;
|
|
end;
|
|
|
|
constructor TIconImage.Create(const AImage: TRawImage);
|
|
begin
|
|
inherited Create;
|
|
FImage := AImage;
|
|
FHeight := FImage.Description.Height;
|
|
FWidth := FImage.Description.Width;
|
|
|
|
case FImage.Description.Depth of
|
|
1: FPixelFormat := pf1Bit;
|
|
4: FPixelFormat := pf4Bit;
|
|
8: FPixelFormat := pf8Bit;
|
|
15: FPixelFormat := pf15Bit;
|
|
16: FPixelFormat := pf16Bit;
|
|
24: FPixelFormat := pf24Bit;
|
|
32: FPixelFormat := pf32Bit;
|
|
else
|
|
FPixelFormat := pfCustom;
|
|
end;
|
|
end;
|
|
|
|
destructor TIconImage.Destroy;
|
|
begin
|
|
if FHandle <> 0
|
|
then DeleteObject(FHandle);
|
|
FHandle := 0;
|
|
if FMaskHandle <> 0
|
|
then DeleteObject(FMaskHandle);
|
|
FMaskHandle := 0;
|
|
if FPalette <> 0
|
|
then DeleteObject(FPalette);
|
|
FPalette := 0;
|
|
FImage.FreeData;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TIconImage.GetPalette: HPALETTE;
|
|
begin
|
|
// TODO: implement
|
|
Result := FPalette
|
|
end;
|
|
|
|
function TIconImage.ReleaseHandle: HBITMAP;
|
|
begin
|
|
Result := Handle;
|
|
FHandle := 0;
|
|
end;
|
|
|
|
function TIconImage.ReleaseMaskHandle: HBITMAP;
|
|
begin
|
|
Result := MaskHandle;
|
|
FMaskHandle := 0;
|
|
end;
|
|
|
|
function TIconImage.ReleasePalette: HPALETTE;
|
|
begin
|
|
Result := Palette;
|
|
FPalette := 0;
|
|
end;
|
|
|
|
function TIconImage.UpdateHandles(ABitmap, AMask: HBITMAP): Boolean;
|
|
begin
|
|
Result := False;
|
|
|
|
if FHandle <> ABitmap
|
|
then begin
|
|
if FHandle <> 0
|
|
then DeleteObject(FHandle);
|
|
FHandle := ABitmap;
|
|
Result := True;
|
|
end;
|
|
|
|
if FMaskHandle <> AMask
|
|
then begin
|
|
if FMaskHandle <> 0
|
|
then DeleteObject(FMaskHandle);
|
|
FMaskHandle := AMask;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
{ TCustomIcon }
|
|
|
|
procedure TCustomIcon.Add(AFormat: TPixelFormat; AHeight, AWidth: Word);
|
|
begin
|
|
if GetIndex(AFormat, AHeight, AWidth) <> -1
|
|
then raise EInvalidGraphicOperation.Create(rsDuplicateIconFormat);
|
|
|
|
UnshareImage(True);
|
|
if TSharedIcon(FSharedImage).FImages.Add(TIconImage.Create(AFormat, AHeight, AWidth)) = 0
|
|
then begin
|
|
// First added
|
|
FCurrent := 0;
|
|
UpdateCurrentView;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomIcon.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TCustomIcon then
|
|
FCurrent := TCustomIcon(Source).Current;
|
|
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TCustomIcon.Clear;
|
|
begin
|
|
if not Empty then
|
|
begin
|
|
FreeSaveStream;
|
|
FSharedImage.Release;
|
|
FSharedImage := GetSharedImageClass.Create;
|
|
FSharedImage.Reference;
|
|
FCurrent := -1;
|
|
Changed(Self);
|
|
end;
|
|
end;
|
|
|
|
function TCustomIcon.BitmapHandleAllocated: boolean;
|
|
begin
|
|
Result := (FCurrent <> -1) and (TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).FHandle <> 0);
|
|
end;
|
|
|
|
constructor TCustomIcon.Create;
|
|
begin
|
|
inherited Create;
|
|
FCurrent := -1;
|
|
end;
|
|
|
|
procedure TCustomIcon.Delete(Aindex: Integer);
|
|
begin
|
|
UnshareImage(True);
|
|
TSharedIcon(FSharedImage).Delete(AIndex);
|
|
if FCurrent = AIndex
|
|
then begin
|
|
FCurrent := -1;
|
|
UpdateCurrentView;
|
|
end
|
|
else if FCurrent > AIndex
|
|
then begin
|
|
Dec(FCurrent);
|
|
end;
|
|
end;
|
|
|
|
function TCustomIcon.GetCount: Integer;
|
|
begin
|
|
Result := TSharedIcon(FSharedImage).Count;
|
|
end;
|
|
|
|
procedure TCustomIcon.GetDescription(Aindex: Integer; out AFormat: TPixelFormat; out AHeight, AWidth: Word);
|
|
var
|
|
Image: TIconImage;
|
|
begin
|
|
Image := TIconImage(TSharedIcon(FSharedImage).FImages[Aindex]);
|
|
AFormat := Image.PixelFormat;
|
|
AHeight := Image.Height;
|
|
AWidth := Image.Width;
|
|
end;
|
|
|
|
class function TCustomIcon.GetFileExtensions: string;
|
|
begin
|
|
Result:='ico';
|
|
end;
|
|
|
|
function TCustomIcon.GetBitmapHandle: HBITMAP;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := 0
|
|
else begin
|
|
BitmapHandleNeeded;
|
|
Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).Handle;
|
|
end;
|
|
end;
|
|
|
|
function TCustomIcon.GetIndex(AFormat: TPixelFormat; AHeight, AWidth: Word): Integer;
|
|
begin
|
|
Result := TSharedIcon(FSharedImage).GetIndex(AFormat, AHeight, AWidth);
|
|
end;
|
|
|
|
function TCustomIcon.GetMaskHandle: HBITMAP;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := 0
|
|
else begin
|
|
MaskHandleNeeded;
|
|
Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).MaskHandle;
|
|
end;
|
|
end;
|
|
|
|
function TCustomIcon.GetPalette: HPALETTE;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := 0
|
|
else begin
|
|
PaletteNeeded;
|
|
Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).Palette;
|
|
end;
|
|
end;
|
|
|
|
function TCustomIcon.GetPixelFormat: TPixelFormat;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := pfCustom
|
|
else Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).PixelFormat;
|
|
end;
|
|
|
|
function TCustomIcon.GetRawImage: PRawImage;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := nil
|
|
else Result := @TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).FImage;
|
|
end;
|
|
|
|
function TCustomIcon.GetRawImageDescription: PRawImageDescription;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := nil
|
|
else Result := @TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).FImage.Description;
|
|
end;
|
|
|
|
class function TCustomIcon.GetSharedImageClass: TSharedRasterImageClass;
|
|
begin
|
|
Result := TSharedIcon;
|
|
end;
|
|
|
|
procedure TCustomIcon.HandleNeeded;
|
|
begin
|
|
{$IFDEF VerboseLCLTodos}{$note TODO implement some WSclass call}{$ENDIF}
|
|
end;
|
|
|
|
function TCustomIcon.InternalReleaseBitmapHandle: HBITMAP;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := 0
|
|
else Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).ReleaseHandle;
|
|
end;
|
|
|
|
function TCustomIcon.InternalReleaseMaskHandle: HBITMAP;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := 0
|
|
else Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).ReleaseMaskHandle;
|
|
end;
|
|
|
|
function TCustomIcon.InternalReleasePalette: HPALETTE;
|
|
begin
|
|
if FCurrent = -1
|
|
then Result := 0
|
|
else Result := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).ReleasePalette;
|
|
end;
|
|
|
|
function TCustomIcon.LazarusResourceTypeValid(const ResourceType: string): boolean;
|
|
var
|
|
ResType: String;
|
|
begin
|
|
if Length(ResourceType) < 3 then Exit(False);
|
|
|
|
ResType := UpperCase(ResourceType);
|
|
case ResType[1] of
|
|
'I': begin
|
|
Result := (ResType = 'ICO') or (ResType = 'ICON');
|
|
end;
|
|
else
|
|
Result := inherited LazarusResourceTypeValid(ResType);
|
|
end;
|
|
end;
|
|
|
|
function TCustomIcon.MaskHandleAllocated: boolean;
|
|
begin
|
|
Result := (FCurrent <> -1) and (TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).FMaskHandle <> 0);
|
|
end;
|
|
|
|
procedure TCustomIcon.MaskHandleNeeded;
|
|
begin
|
|
// Created by bitmaphandle
|
|
BitmapHandleNeeded;
|
|
end;
|
|
|
|
function TCustomIcon.PaletteAllocated: boolean;
|
|
begin
|
|
Result := (FCurrent <> -1) and (TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]).FPalette <> 0);
|
|
end;
|
|
|
|
procedure TCustomIcon.PaletteNeeded;
|
|
begin
|
|
// nothing to do, handled by image itself
|
|
end;
|
|
|
|
procedure TCustomIcon.ReadData(Stream: TStream);
|
|
var
|
|
Signature: array [0..3] of Char;
|
|
Size: longint absolute Signature;
|
|
Position: Int64;
|
|
begin
|
|
// Check it the stream is prefixed with a size.
|
|
// Delphi doesn't, while we do.
|
|
|
|
Position := Stream.Position;
|
|
Stream.Read(Signature, SizeOf(Signature));
|
|
if Cardinal(Signature) = Cardinal(IconSignature)
|
|
then begin
|
|
// Assume Icon - stream without explicit size
|
|
Stream.Position := Position;
|
|
LoadFromStream(Stream);
|
|
end
|
|
else begin
|
|
LoadFromStream(Stream, LEtoN(Size));
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomIcon.ReadStream(AStream: TMemoryStream; ASize: Longint);
|
|
var
|
|
Header: TIconHeader;
|
|
StreamStart: Int64;
|
|
IconDir: array of TIconDirEntry;
|
|
n: Integer;
|
|
MaxWidth, MaxHeight, MaxDepth: Word;
|
|
BestIndex: Word;
|
|
IconImage: TIconImage;
|
|
IntfImage: TLazIntfImage;
|
|
PNGSig: array[0..7] of Byte;
|
|
PNGReader: TLazReaderPNG;
|
|
DIBReader: TLazReaderDIB;
|
|
ImgReader: TFPCustomImageReader;
|
|
LazReader: ILazImageReader;
|
|
RawImage: TRawImage;
|
|
Depth: Byte;
|
|
|
|
begin
|
|
StreamStart := AStream.Position;
|
|
AStream.Read(Header, SizeOf(Header));
|
|
|
|
{$ifdef FPC_BIG_ENDIAN}
|
|
// adjust header
|
|
Header.idType := LEtoN(Header.idType);
|
|
Header.idCount := LEtoN(Header.idCount);
|
|
{$endif}
|
|
|
|
if (Header.idType <> 1) and (Header.idType <> 2)
|
|
then raise EInvalidGraphic.Create('Stream is not an Icon type');
|
|
|
|
if Header.idCount = 0
|
|
then begin
|
|
AStream.Seek(StreamStart + ASize, soBeginning);
|
|
FCurrent := -1;
|
|
Exit;
|
|
end;
|
|
|
|
SetLength(IconDir, Header.idCount);
|
|
AStream.Read(IconDir[0], Header.idCount * SizeOf(IconDir[0]));
|
|
|
|
// Adjust all entries and find best (atm the order: max width, max height, max depth)
|
|
MaxWidth := 0;
|
|
MaxHeight := 0;
|
|
MaxDepth := 0;
|
|
BestIndex := 0;
|
|
PNGReader := nil;
|
|
DIBReader := nil;
|
|
IntfImage := nil;
|
|
try
|
|
for n := 0 to Header.idCount - 1 do
|
|
begin
|
|
{$ifdef FPC_BIG_ENDIAN}
|
|
// adjust entry
|
|
IconDir[n].wXHotSpot := LEtoN(IconDir[n].wXHotSpot);
|
|
IconDir[n].wYHotSpot := LEtoN(IconDir[n].wYHotSpot);
|
|
IconDir[n].dwBytesInRes := LEtoN(IconDir[n].dwBytesInRes);
|
|
IconDir[n].dwImageOffset := LEtoN(IconDir[n].dwImageOffset);
|
|
{$endif}
|
|
|
|
AStream.Seek(StreamStart + IconDir[n].dwImageOffset, soBeginning);
|
|
|
|
ImgReader := nil;
|
|
if (IconDir[n].bWidth = 0) or (IconDir[n].bHeight = 0)
|
|
then begin
|
|
// PNG or DIB image
|
|
// Vista icons are PNG in this case, but there exist also "old style" icons
|
|
// with DIB image
|
|
|
|
// don't use PNGReader.CheckContents(AStream) since it uses internally
|
|
// an exception for checking, which is not "nice" when debugging.
|
|
AStream.Read(PNGSig, SizeOf(PNGSig));
|
|
AStream.Seek(StreamStart + IconDir[n].dwImageOffset, soBeginning);
|
|
|
|
if QWord(PNGComn.Signature) = QWord(PNGSig)
|
|
then begin
|
|
if PNGReader = nil
|
|
then PNGReader := TLazReaderPNG.Create;
|
|
ImgReader := PNGReader;
|
|
end;
|
|
end;
|
|
|
|
if ImgReader = nil
|
|
then begin
|
|
// DIB image
|
|
if DIBReader = nil
|
|
then DIBReader := TLazReaderIconDIB.Create;
|
|
ImgReader := DIBReader;
|
|
end;
|
|
|
|
// create or reset intfimage
|
|
if IntfImage = nil
|
|
then IntfImage := TLazIntfImage.Create(0,0)
|
|
else IntfImage.SetSize(0,0);
|
|
|
|
if Supports(ImgReader, ILazImageReader, LazReader)
|
|
then LazReader.UpdateDescription := True
|
|
else IntfImage.DataDescription := QueryDescription([riqfRGB, riqfAlpha, riqfMask]); // fallback to default
|
|
ImgReader.ImageRead(AStream, IntfImage);
|
|
|
|
// update best image index
|
|
if IntfImage.Height > MaxHeight
|
|
then begin
|
|
MaxHeight := IntfImage.Height;
|
|
BestIndex := n;
|
|
end;
|
|
|
|
if (IntfImage.Height = MaxHeight)
|
|
and (IntfImage.Width > MaxWidth)
|
|
then begin
|
|
MaxWidth := IntfImage.Width;
|
|
BestIndex := n;
|
|
end;
|
|
|
|
if (IntfImage.Height = MaxHeight)
|
|
and (IntfImage.Width = MaxWidth)
|
|
then begin
|
|
// new icons have bpp in direntry, older not.
|
|
// So use it only for png (which itself is alway at bpp=32)
|
|
if (IconDir[n].bWidth = 0) or (IconDir[n].bHeight = 0)
|
|
then Depth := IconDir[n].wBpp
|
|
else Depth := IntfImage.DataDescription.Depth;
|
|
|
|
if Depth > MaxDepth
|
|
then begin
|
|
MaxDepth := Depth;
|
|
BestIndex := n;
|
|
end;
|
|
end;
|
|
|
|
// Add image
|
|
IntfImage.GetRawImage(RawImage, True);
|
|
if not IntfImage.HasMask
|
|
then RawImage.Description.MaskBitsPerPixel := 0;
|
|
with TSharedIcon(FSharedImage) do
|
|
begin
|
|
IconImage := GetImagesClass.Create(RawImage);
|
|
if IconImage is TCursorImageImage then
|
|
TCursorImageImage(IconImage).HotSpot := Point(IconDir[n].wXHotSpot, IconDir[n].wYHotSpot);
|
|
FImages.Add(IconImage);
|
|
end;
|
|
end;
|
|
finally
|
|
LazReader := nil;
|
|
DIBReader.Free;
|
|
PNGReader.Free;
|
|
IntfImage.Free;
|
|
end;
|
|
FCurrent := BestIndex;
|
|
end;
|
|
|
|
procedure TCustomIcon.Remove(AFormat: TPixelFormat; AHeight, AWidth: Word);
|
|
var
|
|
idx: Integer;
|
|
begin
|
|
idx := GetIndex(AFormat, AHeight, AWidth);
|
|
if idx <> -1 then Delete(idx);
|
|
end;
|
|
|
|
procedure TCustomIcon.SetCurrent(const AValue: Integer);
|
|
begin
|
|
if FCurrent = AValue then exit;
|
|
FCurrent := AValue;
|
|
UpdateCurrentView;
|
|
end;
|
|
|
|
procedure TCustomIcon.SetHandles(ABitmap, AMask: HBITMAP);
|
|
begin
|
|
{$IFDEF VerboseLCLTodos}{$note Implement me (or raise exception)}{$ENDIF}
|
|
end;
|
|
|
|
procedure TCustomIcon.SetPixelFormat(AValue: TPixelFormat);
|
|
begin
|
|
raise EInvalidGraphicOperation.Create('Cannot change format of icon image');
|
|
end;
|
|
|
|
procedure TCustomIcon.SetSize(AWidth, AHeight: integer);
|
|
begin
|
|
raise EInvalidGraphicOperation.Create('Cannot change size of icon image');
|
|
end;
|
|
|
|
procedure TCustomIcon.UnshareImage(CopyContent: boolean);
|
|
var
|
|
NewIcon, OldIcon: TSharedIcon;
|
|
n: Integer;
|
|
OldImage, NewImage: TIconImage;
|
|
begin
|
|
if FSharedImage.RefCount <= 1 then Exit;
|
|
|
|
NewIcon := GetSharedImageClass.Create as TSharedIcon;
|
|
try
|
|
NewIcon.Reference;
|
|
if CopyContent
|
|
then begin
|
|
OldIcon := FSharedImage as TSharedIcon;
|
|
for n := 0 to OldIcon.FImages.Count -1 do
|
|
begin
|
|
OldImage := TIconImage(OldIcon.FImages[n]);
|
|
NewImage := TIconImage.Create(OldImage.PixelFormat, OldImage.Height, OldImage.Width);
|
|
NewIcon.FImages.Add(NewImage);
|
|
NewImage.FImage.Description := OldImage.FImage.Description;
|
|
NewImage.FImage.DataSize := OldImage.FImage.DataSize;
|
|
if NewImage.FImage.DataSize > 0
|
|
then begin
|
|
NewImage.FImage.Data := GetMem(NewImage.FImage.DataSize);
|
|
Move(OldImage.FImage.Data^, NewImage.FImage.Data^, NewImage.FImage.DataSize);
|
|
end;
|
|
NewImage.FImage.MaskSize := OldImage.FImage.MaskSize;
|
|
if NewImage.FImage.MaskSize > 0
|
|
then begin
|
|
NewImage.FImage.Mask := GetMem(NewImage.FImage.MaskSize);
|
|
Move(OldImage.FImage.Mask^, NewImage.FImage.Mask^, NewImage.FImage.MaskSize);
|
|
end;
|
|
NewImage.FImage.PaletteSize := OldImage.FImage.PaletteSize;
|
|
if NewImage.FImage.PaletteSize > 0
|
|
then begin
|
|
NewImage.FImage.Palette := GetMem(NewImage.FImage.PaletteSize);
|
|
Move(OldImage.FImage.Palette^, NewImage.FImage.Palette^, NewImage.FImage.PaletteSize);
|
|
end;
|
|
end;
|
|
end;
|
|
FreeCanvasContext;
|
|
OldIcon := FSharedImage as TSharedIcon;
|
|
FSharedImage := NewIcon;
|
|
|
|
NewIcon := nil; // transaction sucessful
|
|
OldIcon.Release;
|
|
finally
|
|
// in case something goes wrong, keep old and free new
|
|
NewIcon.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomIcon.UpdateCurrentView;
|
|
begin
|
|
{$IFDEF VerboseLCLTodos}{$note implement me}{$ENDIF}
|
|
FreeCanvasContext;
|
|
Changed(Self);
|
|
end;
|
|
|
|
function TCustomIcon.UpdateHandles(ABitmap, AMask: HBITMAP): Boolean;
|
|
var
|
|
Image: TIconImage;
|
|
begin
|
|
if FCurrent = -1
|
|
then begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
Image := TIconImage(TSharedIcon(FSharedImage).FImages[FCurrent]);
|
|
Result := Image.UpdateHandles(ABitmap, AMask);
|
|
end;
|
|
|
|
procedure TCustomIcon.WriteStream(AStream: TMemoryStream);
|
|
begin
|
|
{$IFDEF VerboseLCLTodos}{$note implement me}{$ENDIF}
|
|
end;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
{ TIcon }
|
|
|
|
function TIcon.GetIconHandle: HICON;
|
|
begin
|
|
Result := GetHandle;
|
|
end;
|
|
|
|
function TIcon.ReleaseHandle: HICON;
|
|
begin
|
|
HandleNeeded;
|
|
Result := FSharedImage.ReleaseHandle;
|
|
end;
|
|
|
|
procedure TIcon.SetIconHandle(const AValue: HICON);
|
|
begin
|
|
SetHandle(AValue);
|
|
end;
|
|
|
|
procedure TIcon.HandleNeeded;
|
|
var
|
|
IconInfo: TIconInfo;
|
|
begin
|
|
if FSharedImage.FHandle <> 0 then Exit;
|
|
|
|
IconInfo.fIcon := True;
|
|
IconInfo.hbmMask := MaskHandle;
|
|
IconInfo.hbmColor := BitmapHandle;
|
|
FSharedImage.FHandle := WidgetSet.CreateIconIndirect(@IconInfo);
|
|
end;
|
|
|
|
|