fixed glyph display issue and Luiz Americo Pereira Camara

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@534 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
eugene1
2008-08-25 13:07:22 +00:00
parent 7296df02a0
commit c469f3a322
12 changed files with 521 additions and 1457 deletions

View File

@ -1,475 +1,333 @@
unit urotatebitmap;
unit uRotateBitmap;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Graphics, Buttons, LCLType,
IntfGraphics, fpImage, LCLIntf, Types;
Classes, SysUtils, Graphics, Buttons, LCLType, IntfGraphics, Types;
type
TRotateDirection = (rdRight, rdNormal, rdLeft);
TRotatedBitmap = class( TObject )
private
FNormalImage, FRotatedImage : TLazIntfImage;
FRotateTo : TRotateDirection;
function GetBitmap : TBitmap;
procedure SetRotateTo(const Value : TRotateDirection);
procedure DoRotate;
protected
function GetWidth : Integer;
function GetHeight : Integer;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Free;
procedure LoadBitmap(var b : TBitmap);
//property Bitmap : TBitmap read GetBitmap;
property Image : TLazIntfImage read FRotatedImage;
property RotateDirection : TRotateDirection read FRotateTo write SetRotateTo;
procedure Draw(X,Y: Integer;var b : TBitmap); virtual;
procedure Draw(X,Y: Integer;var b : TLazIntfImage); virtual;
procedure Draw(X,Y: Integer;var b : TBitmap;
TransparentColor : TColor); virtual;
procedure Draw(X,Y: Integer;var b : TLazIntfImage;
TransparentColor : TFPColor); virtual;
property Width : Integer read GetWidth;
property Height : Integer read GetHeight;
end;
TRotateDirection = (rdNormal, rdRight, rdLeft);
TRotatedGlyph = class(TRotatedBitmap)
private
FNormalGlyphBitmap : TBitmap;
FNormalGlyph : TButtonGlyph;
FTransparentColor : TColor;
FButtonState : TButtonState;
function GetGlyph : TBitmap;
procedure SetGlyph(Value: TBitmap);
procedure SetButtonState(Value: TButtonState);
procedure SetTransparentColor(Value: TColor);
public
constructor Create; override;
destructor Destroy; override;
procedure Draw(X,Y: Integer;var b : TBitmap;
TransparentColor : TColor); override;
procedure Draw(X, Y: Integer; var b: TLazIntfImage;
TransparentColor: TFPColor); override;
procedure Update;
property State : TButtonState read FButtonState write SetButtonState;
property Glyph : TBitmap read GetGlyph write SetGlyph;
property TransparentColor: TColor read FTransparentColor write SetTransparentColor;
end;
{ TCustomRotatedBitmap }
TRotatedText = class(TRotatedBitmap)
private
FBitmap : TBitmap;
FText : String;
procedure SetText(const Value: String);
function GetCanvas : TCanvas;
procedure PaintText;
public
constructor Create; override;
destructor Destroy; override;
procedure Update;
property Text : String read FText write SetText;
property Canvas : TCanvas read GetCanvas;
procedure Draw(X,Y: Integer;var b : TBitmap); override;
procedure Draw(X,Y: Integer;var b : TLazIntfImage); override;
end;
TCustomRotatedBitmap = class
private
FActiveBitmap: TBitmap;
FDirection: TRotateDirection;
FNormalBitmap: TBitmap;
FRotatedBitmap: TBitmap;
FTransparent: Boolean;
FActiveBitmapNeedsUpdate: Boolean;
function GetBitmap : TBitmap;
function GetEmpty: Boolean;
procedure NormalBitmapChanged(Sender: TObject);
procedure SetBitmap(const AValue: TBitmap);
procedure SetDirection(const AValue: TRotateDirection);
procedure SetTransparent(const AValue: Boolean);
procedure UpdateActiveBitmap; virtual;
protected
procedure NotifyBitmapChange; virtual;
function GetWidth: Integer; virtual;
function GetHeight: Integer; virtual;
property Bitmap: TBitmap read GetBitmap write SetBitmap;
property Transparent: Boolean read FTransparent write SetTransparent;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Draw(Canvas: TCanvas; X, Y: Integer); virtual;
function IsBitmapStored : Boolean;
property Direction: TRotateDirection read FDirection write SetDirection;
property Empty: Boolean read GetEmpty;
property Width: Integer read GetWidth;
property Height: Integer read GetHeight;
end;
operator := (const b : TBitmap) : TLazIntfImage;
operator := (const i : TLazIntfImage) : TBitmap;
{ TRotatedBitmap }
TRotatedBitmap = class (TCustomRotatedBitmap)
public
property Bitmap;
property Transparent;
end;
{ TRotatedGlyph }
TRotatedGlyph = class (TCustomRotatedBitmap)
private
FGlyph : TButtonGlyph;
FButtonState : TButtonState;
FOnChange: TNotifyEvent;
procedure SetButtonState(Value: TButtonState);
procedure UpdateActiveBitmap; override;
protected
procedure NotifyBitmapChange; override;
public
constructor Create; override;
destructor Destroy; override;
procedure Draw(Canvas: TCanvas; X, Y: Integer); override;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property State: TButtonState read FButtonState write SetButtonState;
property Bitmap;
property Transparent;
end;
{ TRotatedText }
TRotatedText = class (TCustomRotatedBitmap)
private
FText : String;
procedure SetFont(const AValue: TFont);
procedure SetText(const Value: String);
procedure UpdateText;
protected
public
constructor Create; override;
property Font: TFont write SetFont;
property Text: String read FText write SetText;
end;
function CreateRotatedBitmap(SrcImage: TRasterImage; Direction: TRotateDirection): TBitmap;
implementation
uses
LCLProc;
LCLProc;
function CreateRotatedBitmap(SrcImage: TRasterImage; Direction: TRotateDirection): TBitmap;
var
px, py, nx, ny : Integer;
RotateImg, NormalImg: TLazIntfImage;
ImageHandle, MaskHandle: HBITMAP;
begin
NormalImg := SrcImage.CreateIntfImage;
RotateImg := TLazIntfImage.Create(NormalImg.Height, NormalImg.Width);
RotateImg.DataDescription := GetDescriptionFromDevice(0, NormalImg.Height, NormalImg.Width);
for px := 0 to NormalImg.Width - 1 do
for py := 0 to NormalImg.Height - 1 do
begin
if Direction = rdRight then
begin
nx := RotateImg.Width - 1 - py;
ny := px;
end else begin
nx := py;
ny := RotateImg.Height - 1 - px;
end;
RotateImg.Colors[nx, ny] := NormalImg.Colors[px, py];
end;
Result := TBitmap.Create;
//todo: Set mask manually and than create the mask handle here
//LoadFromIntfImage always create a mask leading to wrong display
RotateImg.CreateBitmaps(ImageHandle, MaskHandle, True);
Result.SetHandles(ImageHandle, MaskHandle);
if SrcImage.MaskHandleAllocated then
begin
//Calling TransparentMode and than TransparentColor creates the mask twice
//Set TransparentColor and call Mask
Result.TransparentColor := SrcImage.TransparentColor;
Result.Mask(SrcImage.TransparentColor);
end;
RotateImg.Free;
NormalImg.Free;
end;
{ TCustomRotatedBitmap }
function TCustomRotatedBitmap.GetBitmap: TBitmap;
begin
Result := FNormalBitmap;
end;
function TCustomRotatedBitmap.GetEmpty: Boolean;
begin
Result := (FNormalBitmap.Width = 0) or (FNormalBitmap.Height = 0);
end;
procedure TCustomRotatedBitmap.NormalBitmapChanged(Sender: TObject);
begin
FActiveBitmapNeedsUpdate := True;
NotifyBitmapChange;
end;
procedure TCustomRotatedBitmap.SetBitmap(const AValue: TBitmap);
begin
FNormalBitmap.Assign(AValue);
FActiveBitmapNeedsUpdate := True;
end;
procedure TCustomRotatedBitmap.SetDirection(const AValue: TRotateDirection);
begin
if FDirection = AValue then
Exit;
FDirection := AValue;
FActiveBitmapNeedsUpdate := True;
end;
procedure TCustomRotatedBitmap.SetTransparent(const AValue: Boolean);
begin
if FTransparent = AValue then exit;
FTransparent := AValue;
FActiveBitmap.Transparent := FTransparent;
end;
procedure TCustomRotatedBitmap.UpdateActiveBitmap;
begin
FreeAndNil(FRotatedBitmap);
if FDirection = rdNormal then
FActiveBitmap := FNormalBitmap
else
begin
FRotatedBitmap := CreateRotatedBitmap(FNormalBitmap, FDirection);
FActiveBitmap := FRotatedBitmap;
end;
FActiveBitmap.Transparent := FTransparent;
FActiveBitmapNeedsUpdate := False;
end;
procedure TCustomRotatedBitmap.NotifyBitmapChange;
begin
end;
function TCustomRotatedBitmap.GetWidth: Integer;
begin
if FActiveBitmapNeedsUpdate then
UpdateActiveBitmap;
Result := FActiveBitmap.Width;
end;
function TCustomRotatedBitmap.GetHeight: Integer;
begin
if FActiveBitmapNeedsUpdate then
UpdateActiveBitmap;
Result := FActiveBitmap.Height;
end;
constructor TCustomRotatedBitmap.Create;
begin
FDirection := rdNormal;
FNormalBitmap := TBitmap.Create;
FNormalBitmap.OnChange := @NormalBitmapChanged;
FActiveBitmap := FNormalBitmap;
end;
destructor TCustomRotatedBitmap.Destroy;
begin
FNormalBitmap.Destroy;
FRotatedBitmap.Free;
end;
procedure TCustomRotatedBitmap.Draw(Canvas: TCanvas; X, Y: Integer);
begin
if FActiveBitmapNeedsUpdate then
UpdateActiveBitmap;
Canvas.Draw(X, Y, FActiveBitmap);
end;
function TCustomRotatedBitmap.IsBitmapStored : Boolean;
begin
Result := (not FActiveBitmap.Empty)
and (FActiveBitmap.Width>0) and (FActiveBitmap.Height>0);
end;
{ TRotatedGlyph }
procedure TRotatedGlyph.SetButtonState(Value: TButtonState);
begin
FButtonState := Value;
end;
procedure TRotatedGlyph.UpdateActiveBitmap;
begin
inherited UpdateActiveBitmap;
FGlyph.Glyph := FActiveBitmap;
end;
procedure TRotatedGlyph.NotifyBitmapChange;
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
constructor TRotatedGlyph.Create;
begin
inherited;
FNormalGlyph := TButtonGlyph.Create;
//FNormalGlyph.SetTransparentMode(gtmTransparent);
FTransparentColor:=clFuchsia;
FNormalGlyphBitmap := TBitmap.Create;
FButtonState := bsUp;
inherited Create;
FGlyph := TButtonGlyph.Create;
end;
destructor TRotatedGlyph.Destroy;
begin
DebugLn('TRotatedGlyph.Destroy');
DebugLn('FNormalGlyph.Free Assigned: %s',[BoolToStr(Assigned(FNormalGlyph),true)]);
if Assigned(FNormalGlyph) then FNormalGlyph.Free;
DebugLn('FNormalGlyphBitmap.Free Assigned: %s',[BoolToStr(Assigned(FNormalGlyphBitmap),true)]);
if Assigned(FNormalGlyphBitmap) then FNormalGlyphBitmap.Free;
DebugLn('Inherited');
inherited;
FGlyph.Destroy;
inherited Destroy;
end;
procedure TRotatedGlyph.SetTransparentColor(Value: TColor);
begin
FTransparentColor:=Value;
Update;
end;
function TRotatedGlyph.GetGlyph : TBitmap;
begin
Result := FNormalGlyphBitmap;
end;
procedure TRotatedGlyph.SetGlyph(Value: TBitmap);
begin
FNormalGlyphBitmap.Assign(Value);
//FNormalGlyph.Glyph.TransparentMode:=tmFixed;
//FNormalGlyph.Glyph.Transparent:=true;
Update;
end;
procedure TRotatedGlyph.SetButtonState(Value: TButtonState);
begin
FButtonState:=Value;
Update;
end;
procedure TRotatedGlyph.Update;
procedure TRotatedGlyph.Draw(Canvas: TCanvas; X, Y: Integer);
var
TempBitmap : TBitmap;
SrcIntf, TrgIntf : TLazIntfImage;
i, j : Integer;
R: TRect;
P: TPoint;
begin
TempBitmap := TBitmap.Create;
TempBitmap.Width:=FNormalGlyphBitmap.Width;
TempBitmap.Height:=FNormalGlyphBitmap.Height;
TempBitmap.Canvas.Brush.Color:=clNone;
TempBitmap.Canvas.FillRect(0,0,TempBitmap.Width,TempBitmap.Height);
SrcIntf := FNormalGlyphBitmap;
TrgIntf := TempBitmap;
{TmpIntf.DataDescription := GetDescriptionFromDevice(0);
TmpIntf.SetSize(TempBitmap.Width, TempBitmap.Height);
}
for i := 0 to TempBitmap.Width-1 do
for j := 0 to TempBitmap.Height-1 do
if SrcIntf.Colors[i,j] <> TColorToFPColor(FTransparentColor) then
TrgIntf.Colors[i,j] := SrcIntf.Colors[i,j];
{FNormalGlyph.Draw(TempBitmap.Canvas,Rect(0,0,TempBitmap.Width,TempBitmap.Height),
Point(0,0), FButtonState, true, 0);
}
TempBitmap.Free;
TempBitmap := TrgIntf;
LoadBitmap(TempBitmap);
TempBitmap.Free;
TrgIntf.Free;
SrcIntf.Free;
if FActiveBitmapNeedsUpdate then
UpdateActiveBitmap;
R := Rect(0, 0, FActiveBitmap.Width, FActiveBitmap.Height);
P := Point(X, Y);
FGlyph.Draw(Canvas, R, P, FButtonState, Transparent, 0);
end;
procedure TRotatedGlyph.Draw(X,Y: Integer;var b : TBitmap;
TransparentColor : TColor);
var
Temp : TLazIntfImage;
{ TRotatedText }
procedure TRotatedText.SetText(const Value: String);
begin
Temp := b;
b.Free;
Draw(X,Y,Temp, TColorToFPColor(TransparentColor));
b := Temp;
Temp.Free;
if Value = FText then
Exit;
FText := Value;
UpdateText;
end;
procedure TRotatedGlyph.Draw(X, Y: Integer; var b: TLazIntfImage;
TransparentColor: TFPColor);
var
TempBitmap,Trg : TBitmap;
procedure TRotatedText.SetFont(const AValue: TFont);
begin
Trg := TBitmap.Create;
FNormalBitmap.Canvas.Font := AValue;
UpdateText;
end;
//First Rotate the Glyph then Draw it with an other State
inherited Draw(X,Y,b,TransparentColor);
TempBitmap := b;
b.Free;
Trg.Width:=b.Width;
Trg.Height:=b.Height;
FNormalGlyph.Glyph.Assign(TempBitmap);
FNormalGlyph.Draw(Trg.Canvas,Rect(0,0,Trg.Width,Trg.Height),
Point(0,0), FButtonState, true, 0);
b := Trg;
Trg.Free;
TempBitmap.Free;
procedure TRotatedText.UpdateText;
var
TextSize : TSize;
begin
//todo: handle font
with FNormalBitmap, Canvas do
begin
TextSize := TextExtent(FText);
{$if defined(LCLWin32) or defined (LCLQt)}
//win32 and Qt does not comput correct text extent when Italic style is set.
//gtk1/2 does not support Italic at all
if fsItalic in Font.Style then
Inc(TextSize.cx, 4);
{$endif}
SetSize(TextSize.cx, TextSize.cy);
if Font.Color <> clFuchsia then
Brush.Color := clFuchsia
else
Brush.Color := clWhite;
FillRect(0, 0, FNormalBitmap.Width, FNormalBitmap.Height);
TextOut(0, 0, FText);
Mask(Brush.Color);
end;
//FActiveBitmapNeedsUpdate := True;
end;
constructor TRotatedText.Create;
begin
inherited;
FBitmap := TBitmap.Create;
FText:='X';
SetText('');
end;
destructor TRotatedText.Destroy;
begin
FBitmap.Free;
inherited;
end;
procedure TRotatedText.Update;
begin
PaintText;
end;
procedure TRotatedText.SetText(const Value: String);
begin
if FText <> Value then
begin
FText:=Value;
PaintText;
end;
end;
function TRotatedText.GetCanvas : TCanvas;
begin
Result := FBitmap.Canvas;
end;
procedure TRotatedText.PaintText;
var
TextSize : TSize;
begin
TextSize := FBitmap.Canvas.TextExtent(FText);
{$ifdef LCLWin32}
//win32 does not comput correct text extent when Italic style is set.
//small workaround to this bug
//not sure if other widgetsets alsoa have this bug. Enable it only for win32 for now
if fsItalic in FBitmap.Canvas.Font.Style then
Inc(TextSize.cx, 4);
{$endif}
FBitmap.SetSize(TextSize.cx, TextSize.cy);
//check to allow Text with Fuchsia color
if FBitmap.Canvas.Font.Color = clFuchsia then
FBitmap.Canvas.Brush.Color := clWhite
else
FBitmap.Canvas.Brush.Color := clFuchsia;
FBitmap.Canvas.FillRect(0,0, FBitmap.Width, FBitmap.Height);
FBitmap.Canvas.TextOut(0,0, FText);
Inherited LoadBitmap(FBitmap);
end;
procedure TRotatedText.Draw(X,Y: Integer;var b : TBitmap);
begin
Inherited Draw(X,Y,b,FBitmap.Canvas.Brush.Color);
end;
procedure TRotatedText.Draw(X,Y: Integer;var b : TLazIntfImage);
begin
Inherited Draw(X,Y,b,TColorToFPColor(FBitmap.Canvas.Brush.Color));
end;
operator := (const b : TBitmap) : TLazIntfImage;
begin
Result := TLazIntfImage.Create(0,0);
Result.LoadFromBitmap(b.Handle,b.MaskHandle);
end;
operator := (const i : TLazIntfImage) : TBitmap;
begin
Result := TBitmap.Create;
Result.LoadFromIntfImage(i);
end;
constructor TRotatedBitmap.Create;
begin
//inherited;
FRotateTo:=rdNormal;
end;
destructor TRotatedBitmap.Destroy;
begin
DebugLn('Destroy');
if Assigned(FNormalImage) then FNormalImage.Free;
if Assigned(FRotatedImage) then FRotatedImage.Free;
end;
procedure TRotatedBitmap.Free;
begin
inherited;
//if Self<>nil then
//Self.Destroy;
end;
function TRotatedBitmap.GetBitmap : TBitmap;
var
TempIntf : TLazIntfImage;
begin
if FRotateTo = rdNormal then
TempIntf := FNormalImage
else
TempIntf := FRotatedImage;
if Assigned(TempIntf) then
Result := TempIntf;
end;
procedure TRotatedBitmap.SetRotateTo(const Value : TRotateDirection);
begin
//WriteLn(FRotateTo<>Value);
if FRotateTo<>Value then
begin
//WriteLn('SetRotateTo');
FRotateTo:=Value;
DoRotate;
end;
end;
procedure TRotatedBitmap.LoadBitmap(var b : TBitmap);
begin
if FNormalImage <> nil then FNormalImage.Free;
if FRotatedImage = nil then begin
FRotatedImage := TLazIntfImage.Create(0,0);
FRotatedImage.DataDescription := GetDescriptionFromDevice(0);
end;
DebugLn('Assigned: B',BoolToStr(Assigned(FNormalImage),true));
FNormalImage := b;
//FNormalImage := TLazIntfImage.Create(0,0);
DebugLn('Assigned: A',BoolToStr(Assigned(FNormalImage),true));
if FRotateTo <> rdNormal then DoRotate;
end;
procedure TRotatedBitmap.DoRotate;
var
px, py, iw, ih, nx, ny : Integer;
CurColor: TFPColor;
begin
if FRotateTo=rdNormal then Exit;
{if Assigned(FRotatedImage) then
FRotatedImage.Free;
FRotatedImage := TLazIntfImage.Create(0,0);
FRotatedImage.DataDescription := GetDescriptionFromDevice(0);
}
FRotatedImage.SetSize({FNormalImage.Width,FNormalImage.Height}
FNormalImage.Height,FNormalImage.Width);
FRotatedImage.FillPixels(colWhite);
//WriteLn(FRotatedImage.Width, ' ', FRotatedImage.Height);
for px := 0 to FNormalImage.Width-1 do
for py := 0 to FNormalImage.Height-1 do
begin
if FRotateTo = rdRight then
begin
nx := FRotatedImage.Width-1-py;
ny := px;
end else begin
nx := py;
ny := FRotatedImage.Height-1-px;
end;
//WriteLn(nx, ' ', ny, ' ', px, ' ', py);
CurColor := FNormalImage.Colors[px,py];
FRotatedImage.Colors[nx,ny]:= CurColor;
end;
end;
procedure TRotatedBitmap.Draw(X,Y: Integer;var b : TBitmap);
begin
Draw(X,Y,b,clNone);
end;
procedure TRotatedBitmap.Draw(X,Y: Integer;var b : TLazIntfImage);
begin
Draw(X,Y,b,TColorToFPColor(clNone));
end;
procedure TRotatedBitmap.Draw(X,Y: Integer;var b : TBitmap; TransparentColor : TColor);
var
TempIntfImage : TLazIntfImage;
begin
TempIntfImage := b;
b.Free;
Draw(X,Y, TempIntfImage, TColorToFPColor(TransparentColor));
b := TempIntfImage;
TempIntfImage.Free;
end;
procedure TRotatedBitmap.Draw(X,Y: Integer;var b : TLazIntfImage; TransparentColor : TFPColor);
var
px, py : Integer;
TempIntf : TLazIntfImage;
begin
if FRotateTo = rdNormal then
TempIntf := FNormalImage
else
TempIntf := FRotatedImage;
//WriteLn(Assigned(FNormalImage));
//WriteLn(Assigned(FRotatedImage));
for px := 0 to TempIntf.Width-1 do
for py := 0 to TempIntf.Height-1 do
if (TempIntf.Colors[px,py] <> TransparentColor)
AND ((X+px) < b.Width) AND ((Y+py) < b.Height)
AND ((X+px) >= 0) AND ((Y+py) >= 0) then
begin
//WriteLn(px, ' ', py);
b.Colors[X+px,Y+py]:=TempIntf.Colors[px,py];
end;
end;
function TRotatedBitmap.GetWidth : Integer;
begin
Result := -1;
if (FRotateTo = rdNormal) AND Assigned(FNormalImage) then
Result := FNormalImage.Width
else if Assigned(FRotatedImage) then
Result := FRotatedImage.Width;
end;
function TRotatedBitmap.GetHeight : Integer;
begin
Result := -1;
if (FRotateTo = rdNormal) AND Assigned(FNormalImage) then
Result := FNormalImage.Height
else if Assigned(FRotatedImage) then
Result := FRotatedImage.Height;
inherited Create;
Transparent := True;
end;
end.