procedure TAnimatedCursorImage.AssignTo(Dest: TPersistent);
var
I: Integer;
begin
if Dest is TIcon then
begin
if IconCount > 0 then
Dest.Assign(Icons[0])
else
Dest.Assign(nil);
end
else
if Dest is TBitmap then
begin
if IconCount > 0 then
AssignToBitmap(TBitmap(Dest), TBitmap(Dest).Canvas.Brush.Color,
True, False)
else
Dest.Assign(nil);
end
else
if Dest is TIconList then
begin
TIconList(Dest).begin
Update;
try
TIconList(Dest).Clear;
for I := 0 to IconCount - 1do
TIconList(Dest).Add(Icons);
finally
TIconList(Dest).EndUpdate;
end;
end
else
inherited AssignTo(Dest);
end;
function TAnimatedCursorImage.ReadCreateIcon(Stream: TStream;
ASize: Longint;
var HotSpot: TPoint;
var IsIcon: Boolean): TIcon;
type
PIconRecArray = ^TIconRecArray;
TIconRecArray = array[0..300] of TIconRec;
var
List: PIconRecArray;
Mem: TMemoryStream;
HeaderLen, I: Integer;
BI: PBitmapInfoHeader;
begin
Result := nil;
Mem := TMemoryStream.Create;
try
Mem.SetSize(ASize);
Mem.CopyFrom(Stream, Mem.Size);
HotSpot := Point(0, 0);
IsIcon := PCursorOrIcon(Mem.Memory)^.wType = RC3_ICON;
if PCursorOrIcon(Mem.Memory)^.wType = RC3_CURSOR then
PCursorOrIcon(Mem.Memory)^.wType := RC3_ICON;
if PCursorOrIcon(Mem.Memory)^.wType = RC3_ICON then
begin
{ determinate original icon color }
HeaderLen := PCursorOrIcon(Mem.Memory)^.Count * SizeOf(TIconRec);
GetMem(List, HeaderLen);
try
Mem.Position := SizeOf(TCursorOrIcon);
Mem.Read(List^, HeaderLen);
for I := 0 to PCursorOrIcon(Mem.Memory)^.Count - 1do
iFrame := 0;
iRate := 0;
iSeq := 0;
{ Make sure it's a RIFF ANI file }
if not ReadTag(Stream, @Tag) or (Tag.ckID <> FOURCC_RIFF) then
RiffReadError;
if (Stream.Read(Tag.ckID, SizeOf(Tag.ckID)) < SizeOf(Tag.ckID)) or
(Tag.ckID <> FOURCC_ACON) then
RiffReadError;
NewImage;
{ look for 'anih', 'rate', 'seq ', and 'icon' chunks }
while ReadTag(Stream, @Tag)do
begin
if Tag.ckID = FOURCC_anih then
begin
if not ReadChunk(Stream, @Tag, @FHeader) then
Break;
if ((FHeader.fl and AF_ICON) <> AF_ICON) or
(FHeader.cFrames = 0) then
RiffReadError;
for I := 0 to FHeader.cSteps - 1do
begin
{ If we find a rate chunk, read it into its preallocated space }
if not ReadChunkN(Stream, @Tag, @Temp, SizeOf(Longint)) then
Break;
if iRate < FIcons.Count then
TIconFrame(FIcons[iRate]).FJiffRate := Temp;
Inc(iRate);
end
else
if Tag.ckID = FOURCC_seq then
begin
{ If we find a seq chunk, read it into its preallocated space }
if not ReadChunkN(Stream, @Tag, @Temp, SizeOf(Longint)) then
Break;
if iSeq < FIcons.Count then
TIconFrame(FIcons[iSeq]).FSeq := Temp;
Inc(iSeq);
end
else
if Tag.ckID = FOURCC_LIST then
begin
cbChunk := PadUp(Tag.ckSize);
{ See if this list is the 'fram' list of icon chunks }
cbRead := Stream.Read(Tag.ckID, SizeOf(Tag.ckID));
if cbRead < SizeOf(Tag.ckID) then
Break;
Dec(cbChunk, cbRead);
if (Tag.ckID = FOURCC_fram) then
begin
while (cbChunk >= SizeOf(Tag))do
begin
if not ReadTag(Stream, @Tag) then
Break;
Dec(cbChunk, SizeOf(Tag));
if (Tag.ckID = FOURCC_icon) then
begin
{ Ok, load the icon/cursor bits }
Icon := ReadCreateIcon(Stream, Tag.ckSize, HotSpot, IsIcon);
if Icon = nil then
Break;
bFound := False;
for I := 0 to FIcons.Count - 1do
begin
{ Unknown chunk in fram list, just ignore it }
SkipChunk(Stream, @Tag);
end;
Dec(cbChunk, PadUp(Tag.ckSize));
end;
end
else
if (Tag.ckID = FOURCC_INFO) then
begin
{ now look for INAM and IART chunks }
while (cbChunk >= SizeOf(Tag))do
begin
if not ReadTag(Stream, @Tag) then
Break;
Dec(cbChunk, SizeOf(Tag));
if Tag.ckID = FOURCC_INAM then
begin
if (cbChunk < Tag.ckSize) or not
ReadChunkN(Stream, @Tag, @FTitle, SizeOf(TANINAME) - 1) then
Break;
Dec(cbChunk, PadUp(Tag.ckSize));
end
else
if Tag.ckID = FOURCC_IART then
begin
if (cbChunk < Tag.ckSize) or not
ReadChunkN(Stream, @Tag, @FCreator, SizeOf(TANINAME) - 1) then
Break;
Dec(cbChunk, PadUp(Tag.ckSize));
end
else
begin
if not SkipChunk(Stream, @Tag) then
Break;
Dec(cbChunk, PadUp(Tag.ckSize));
end;
end;
end
else
begin
{ Not the fram list or the INFO list. Skip the rest of this
chunk. (Don't forget that we have already skipped one dword) }
Tag.ckSize := cbChunk;
SkipChunk(Stream, @Tag);
end;
end
else
begin
{ We're not interested in this chunk, skip it. }
if not SkipChunk(Stream, @Tag) then
Break;
end;
end;
{ while }
{ Update the frame count incase we coalesced some frames while reading
in the file. }
for I := FIcons.Count - 1do
wnto 0do
begin
if TIconFrame(FIcons).FIcon = nil then
begin
TIconFrame(FIcons).Free;
FIcons.Delete(I);
end;
end;
FHeader.cFrames := FIcons.Count;
if FHeader.cFrames = 0 then
RiffReadError;
end;
procedure TAnimatedCursorImage.ReadStream(Size: Longint;
Stream: TStream);
var
Data: TMemoryStream;
begin
Data := TMemoryStream.Create;
try
Data.SetSize(Size);
Stream.ReadBuffer(Data.Memory^, Size);
if Size > 0 then
begin
Data.Position := 0;
ReadAniStream(Data);
end;
finally
Data.Free;
end;
end;
procedure TAnimatedCursorImage.WriteStream(Stream: TStream;
WriteSize: Boolean);
begin
NotImplemented;
end;
procedure TAnimatedCursorImage.LoadFromStream(Stream: TStream);
begin
procedure THackBitmap.Draw(ACanvas: TCanvas;
const Rect: TRect);
begin
if not Empty then
Canvas.Lock;
try
inherited Draw(ACanvas, Rect);
finally
if not Empty then
Canvas.Unlock;
end;
end;
type
THack = class(TBitmap);
var
Hooked: Boolean = False;
procedure HookBitmap;
var
Index: Integer;
begin
if Hooked then
Exit;
Index := FindVirtualMethodIndex(THack, @THack.Draw);
SetVirtualMethodAddress(TBitmap, Index, @THackBitmap.Draw);
Hooked := True;
end;
{$ENDIF RX_D3}
{ TRxImageControl }
constructor TRxImageControl.Create(AOwner: TComponent);
begin
procedure TRxImageControl.DoPaintControl;
var
DC: HDC;
begin
{$IFDEF RX_D3}
if GetCurrentThreadID = MainThreadID then
begin
Repaint;
Exit;
end;
{$ENDIF}
DC := GetDC(Parent.Handle);
try
IntersectClipRect(DC, Left, Top, Left + Width, Top + Height);
MoveWindowOrg(DC, Left, Top);
Perform(WM_PAINT, DC, 0);
finally
ReleaseDC(Parent.Handle, DC);
end;
end;
function TRxImageControl.DoPaletteChange: Boolean;
var
ParentForm: TCustomForm;
Tmp: TGraphic;
begin
Result := False;
Tmp := FGraphic;
if Visible and (not (csLoading in ComponentState)) and (Tmp <> nil)
{$IFDEF RX_D3} and (Tmp.PaletteModified) {$ENDIF} then
begin
if (GetPalette <> 0) then
begin
ParentForm := GetParentForm(Self);
if Assigned(ParentForm) and ParentForm.Active and ParentForm.HandleAllocated then
procedure TAnimatedImage.DoPaintImage;
var
BmpIndex: Integer;
SrcRect, DstRect: TRect;
{Origin: TPoint;}
begin
if (not Active) and (FInactiveGlyph >= 0) and
(FInactiveGlyph < FNumGlyphs) then
BmpIndex := FInactiveGlyph
else
BmpIndex := FGlyphNum;
{ copy image from parent and back-level controls }
if not FOpaque then
CopyParentImage(Self, Canvas);
if (FImageWidth > 0) and (FImageHeight > 0) then
begin
if Orientation = goHorizontal then
SrcRect := Bounds(BmpIndex * FImageWidth, 0, FImageWidth, FImageHeight)
else
{if Orientation = goVertical then
}
SrcRect := Bounds(0, BmpIndex * FImageHeight, FImageWidth, FImageHeight);
if Stretch then
DstRect := ClientRect
else
if Center then
DstRect := Bounds((ClientWidth - FImageWidth) div 2,
(ClientHeight - FImageHeight) div 2, FImageWidth, FImageHeight)
else
DstRect := Rect(0, 0, FImageWidth, FImageHeight);
with DstRectdo