initial implementation of TWinControl.SetShape for gtk, qt, win32 + example

git-svn-id: trunk@13874 -
This commit is contained in:
paul 2008-01-25 06:56:57 +00:00
parent 737152c95a
commit f1d8f78b0c
19 changed files with 628 additions and 7 deletions

6
.gitattributes vendored
View File

@ -1780,6 +1780,12 @@ examples/scrollbar.lpi svneol=native#text/plain
examples/scrollbar.pp svneol=native#text/pascal examples/scrollbar.pp svneol=native#text/pascal
examples/selection.pp svneol=native#text/pascal examples/selection.pp svneol=native#text/pascal
examples/selectionform.pp svneol=native#text/pascal examples/selectionform.pp svneol=native#text/pascal
examples/shapedcontrols/manifest.rc svneol=native#text/plain
examples/shapedcontrols/project1.lpi svneol=native#text/plain
examples/shapedcontrols/project1.lpr -text svneol=native#test/pascal
examples/shapedcontrols/unit1.lfm svneol=native#text/plain
examples/shapedcontrols/unit1.lrs -text svneol=native#test/pascal
examples/shapedcontrols/unit1.pas -text svneol=native#test/pascal
examples/speedtest.lpi svneol=native#text/plain examples/speedtest.lpi svneol=native#text/plain
examples/speedtest.pp svneol=native#text/pascal examples/speedtest.pp svneol=native#text/pascal
examples/sprites/playground.lfm svneol=native#text/plain examples/sprites/playground.lfm svneol=native#text/plain

View File

@ -0,0 +1,25 @@
#define RT_MANIFEST 24
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2
#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST MOVEABLE PURE
{
"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>"
"<assembly xmlns=""urn:schemas-microsoft-com:asm.v1"" manifestVersion=""1.0"">"
"<assemblyIdentity version=""1.0.0.0"" processorArchitecture=""*"" name=""CompanyName.ProductName.YourApp"" type=""win32""/>"
"<description>Your application description here.</description>"
"<dependency>"
"<dependentAssembly>"
"<assemblyIdentity type=""win32"" name=""Microsoft.Windows.Common-Controls"" version=""6.0.0.0"" processorArchitecture=""*"" publicKeyToken=""6595b64144ccf1df"" language=""*""/>"
"</dependentAssembly>"
"</dependency>"
"<trustInfo xmlns=""urn:schemas-microsoft-com:asm.v3"">"
"<security>"
"<requestedPrivileges>"
"<requestedExecutionLevel level=""asInvoker"" uiAccess=""false""/>"
"</requestedPrivileges>"
"</security>"
"</trustInfo>"
"</assembly>"
}

View File

@ -0,0 +1,160 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<PathDelim Value="\"/>
<Version Value="6"/>
<General>
<MainUnit Value="0"/>
<TargetFileExt Value=".exe"/>
<UseXPManifest Value="True"/>
<ActiveEditorIndexAtStart Value="1"/>
</General>
<VersionInfo>
<ProjectVersion Value=""/>
</VersionInfo>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<RequiredPackages Count="1">
<Item1>
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="3">
<Unit0>
<Filename Value="project1.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="project1"/>
<CursorPos X="21" Y="12"/>
<TopLine Value="1"/>
<EditorIndex Value="1"/>
<UsageCount Value="20"/>
<Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="unit1.pas"/>
<ComponentName Value="Form1"/>
<IsPartOfProject Value="True"/>
<ResourceFilename Value="unit1.lrs"/>
<UnitName Value="Unit1"/>
<CursorPos X="38" Y="54"/>
<TopLine Value="34"/>
<EditorIndex Value="0"/>
<UsageCount Value="20"/>
<Loaded Value="True"/>
</Unit1>
<Unit2>
<Filename Value="..\..\lcl\include\wincontrol.inc"/>
<CursorPos X="70" Y="4369"/>
<TopLine Value="4363"/>
<UsageCount Value="10"/>
</Unit2>
</Units>
<JumpHistory Count="17" HistoryIndex="16">
<Position1>
<Filename Value="unit1.pas"/>
<Caret Line="24" Column="16" TopLine="1"/>
</Position1>
<Position2>
<Filename Value="unit1.pas"/>
<Caret Line="16" Column="45" TopLine="1"/>
</Position2>
<Position3>
<Filename Value="unit1.pas"/>
<Caret Line="38" Column="5" TopLine="4"/>
</Position3>
<Position4>
<Filename Value="unit1.pas"/>
<Caret Line="17" Column="43" TopLine="9"/>
</Position4>
<Position5>
<Filename Value="unit1.pas"/>
<Caret Line="38" Column="1" TopLine="20"/>
</Position5>
<Position6>
<Filename Value="unit1.pas"/>
<Caret Line="45" Column="1" TopLine="27"/>
</Position6>
<Position7>
<Filename Value="unit1.pas"/>
<Caret Line="46" Column="1" TopLine="28"/>
</Position7>
<Position8>
<Filename Value="unit1.pas"/>
<Caret Line="47" Column="1" TopLine="28"/>
</Position8>
<Position9>
<Filename Value="unit1.pas"/>
<Caret Line="48" Column="1" TopLine="28"/>
</Position9>
<Position10>
<Filename Value="unit1.pas"/>
<Caret Line="50" Column="1" TopLine="28"/>
</Position10>
<Position11>
<Filename Value="unit1.pas"/>
<Caret Line="51" Column="1" TopLine="28"/>
</Position11>
<Position12>
<Filename Value="unit1.pas"/>
<Caret Line="52" Column="1" TopLine="28"/>
</Position12>
<Position13>
<Filename Value="unit1.pas"/>
<Caret Line="53" Column="1" TopLine="28"/>
</Position13>
<Position14>
<Filename Value="unit1.pas"/>
<Caret Line="55" Column="1" TopLine="28"/>
</Position14>
<Position15>
<Filename Value="unit1.pas"/>
<Caret Line="54" Column="13" TopLine="28"/>
</Position15>
<Position16>
<Filename Value="unit1.pas"/>
<Caret Line="17" Column="20" TopLine="8"/>
</Position16>
<Position17>
<Filename Value="unit1.pas"/>
<Caret Line="41" Column="40" TopLine="28"/>
</Position17>
</JumpHistory>
</ProjectOptions>
<CompilerOptions>
<Version Value="5"/>
<PathDelim Value="\"/>
<CodeGeneration>
<Generate Value="Faster"/>
</CodeGeneration>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="2">
<Item1>
<Name Value="ECodetoolError"/>
</Item1>
<Item2>
<Name Value="EFOpenError"/>
</Item2>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,20 @@
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms
{ you can add units after this }, Unit1;
{$IFDEF WINDOWS}{$R manifest.rc}{$ENDIF}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@ -0,0 +1,23 @@
object Form1: TForm1
Left = 460
Height = 146
Top = 327
Width = 300
HorzScrollBar.Page = 299
VertScrollBar.Page = 145
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsSingle
Caption = 'Form1'
ClientHeight = 146
ClientWidth = 300
OnCreate = FormCreate
object Button1: TButton
Left = 24
Height = 57
Top = 40
Width = 248
Caption = 'Shaped button. Press to make window shaped.'
OnClick = Button1Click
TabOrder = 0
end
end

View File

@ -0,0 +1,11 @@
{ Ýòî - ôàéë ðåñóðñîâ, àâòîìàòè÷åñêè ñîçäàííûé lazarus }
LazarusResources.Add('TForm1','FORMDATA',[
'TPF0'#6'TForm1'#5'Form1'#4'Left'#3#204#1#6'Height'#3#146#0#3'Top'#3'G'#1#5'W'
+'idth'#3','#1#18'HorzScrollBar.Page'#3'+'#1#18'VertScrollBar.Page'#3#145#0#11
+'BorderIcons'#11#12'biSystemMenu'#10'biMinimize'#0#11'BorderStyle'#7#8'bsSin'
+'gle'#7'Caption'#6#5'Form1'#12'ClientHeight'#3#146#0#11'ClientWidth'#3','#1#8
+'OnCreate'#7#10'FormCreate'#0#7'TButton'#7'Button1'#4'Left'#2#24#6'Height'#2
+'9'#3'Top'#2'('#5'Width'#3#248#0#7'Caption'#6'+Shaped button. Press to make '
+'window shaped.'#7'OnClick'#7#12'Button1Click'#8'TabOrder'#2#0#0#0#0
]);

View File

@ -0,0 +1,74 @@
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
procedure ShapeControl(AControl: TWinControl);
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShapeControl(Self);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Handle;
ShapeControl(Button1);
end;
procedure TForm1.ShapeControl(AControl: TWinControl);
var
ABitmap: TBitmap;
Points: array of TPoint;
begin
ABitmap := TBitmap.Create;
ABitmap.Monochrome := True;
ABitmap.Width := AControl.Width;
ABitmap.Height := AControl.Height;
SetLength(Points, 6);
Points[0] := Point(0, ABitmap.Height div 2);
Points[1] := Point(10, 0);
Points[2] := Point(ABitmap.Width - 10, 0);
Points[3] := Point(ABitmap.Width, ABitmap.Height div 2);
Points[4] := Point(ABitmap.Width - 10, ABitmap.Height);
Points[5] := Point(10, ABitmap.Height);
with ABitmap.Canvas do
begin
Brush.Color := clBlack; // transparent color
FillRect(0, 0, ABitmap.Width, ABitmap.Height);
Brush.Color := clWhite; // mask color
Polygon(Points);
end;
AControl.SetShape(ABitmap);
ABitmap.Free;
end;
initialization
{$I unit1.lrs}
end.

View File

@ -1793,6 +1793,7 @@ type
RepeatCount: integer; SystemKey: boolean): boolean; dynamic; RepeatCount: integer; SystemKey: boolean): boolean; dynamic;
procedure PaintTo(DC: HDC; X, Y: Integer); virtual; overload; procedure PaintTo(DC: HDC; X, Y: Integer); virtual; overload;
procedure PaintTo(ACanvas: TCanvas; X, Y: Integer); overload; procedure PaintTo(ACanvas: TCanvas; X, Y: Integer); overload;
procedure SetShape(AShape: TBitmap);
end; end;

View File

@ -4368,6 +4368,18 @@ begin
PaintTo(ACanvas.Handle, X, Y); PaintTo(ACanvas.Handle, X, Y);
end; end;
procedure TWinControl.SetShape(AShape: TBitmap);
begin
if not HandleAllocated then
Exit;
if (AShape <> nil) and (AShape.Width = Width) and (AShape.Height = Height) then
TWSWinControlClass(WidgetSetClass).SetShape(Self, AShape.Handle)
else
if AShape = nil then
TWSWinControlClass(WidgetSetClass).SetShape(Self, 0)
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
TWinControl ControlAtPos TWinControl ControlAtPos
Params: const Pos : TPoint Params: const Pos : TPoint

View File

@ -94,6 +94,7 @@ type
class procedure SetSize(const AWinControl: TWinControl; const AWidth, AHeight: Integer); override; class procedure SetSize(const AWinControl: TWinControl; const AWidth, AHeight: Integer); override;
class procedure SetPos(const AWinControl: TWinControl; const ALeft, ATop: Integer); override; class procedure SetPos(const AWinControl: TWinControl; const ALeft, ATop: Integer); override;
class procedure SetText(const AWinControl: TWinControl; const AText: string); override; class procedure SetText(const AWinControl: TWinControl; const AText: string); override;
class procedure SetShape(const AWinControl: TWinControl; const AShape: HBITMAP); override;
class procedure PaintTo(const AWinControl: TWinControl; ADC: HDC; X, Y: Integer); override; class procedure PaintTo(const AWinControl: TWinControl; ADC: HDC; X, Y: Integer); override;
class procedure ShowHide(const AWinControl: TWinControl); override; class procedure ShowHide(const AWinControl: TWinControl); override;
@ -664,6 +665,30 @@ begin
Assert(False, Format('trace: [TGtkWidgetSet.SetLabel] %s --> END', [AWinControl.ClassName])); Assert(False, Format('trace: [TGtkWidgetSet.SetLabel] %s --> END', [AWinControl.ClassName]));
end; end;
class procedure TGtkWSWinControl.SetShape(const AWinControl: TWinControl;
const AShape: HBITMAP);
var
GtkWidget: PGtkWidget;
GdkBitmap: PGDKBitmap;
begin
if not WSCheckHandleAllocated(AWinControl, 'SetShape') then
Exit;
GtkWidget := PGtkWidget(AWinControl.Handle);
if AShape <> 0 then
begin
if GtkWidgetset.IsValidGDIObjectType(AShape, gdiBitmap) then
GdkBitmap := PGdiObject(AShape)^.GDIBitmapObject
else
GdkBitmap := nil;
end
else
GdkBitmap := nil;
gtk_widget_shape_combine_mask(GtkWidget, GdkBitmap, 0, 0);
end;
{ {
Paint control to X, Y point of device context. Paint control to X, Y point of device context.
} }

View File

@ -35,7 +35,7 @@ uses
SysUtils, Classes, LCLProc, LCLType, Controls, LMessages, InterfaceBase, SysUtils, Classes, LCLProc, LCLType, Controls, LMessages, InterfaceBase,
Graphics, Dialogs,Forms, Math, Graphics, Dialogs,Forms, Math,
WSDialogs, WSLCLClasses, WSControls, WSForms, WSProc, WSDialogs, WSLCLClasses, WSControls, WSForms, WSProc,
gtkInt, gtkProc, gtkWSControls, gtkDef, gtkExtra, gtkGlobals, GtkWSPrivate; GtkInt, GtkProc, GtkDef, GtkExtra, GtkGlobals, GtkWSControls, GtkWSPrivate;
type type

View File

@ -113,13 +113,15 @@ type
constructor Create(Adata: PByte; width: Integer; height: Integer; format: QImageFormat; const ADataOwner: Boolean = False); overload; constructor Create(Adata: PByte; width: Integer; height: Integer; format: QImageFormat; const ADataOwner: Boolean = False); overload;
destructor Destroy; override; destructor Destroy; override;
function AsIcon(AMode: QIconMode = QIconNormal; AState: QIconState = QIconOff): QIconH; function AsIcon(AMode: QIconMode = QIconNormal; AState: QIconState = QIconOff): QIconH;
function AsPixmap: QPixmapH; function AsPixmap(flags: QtImageConversionFlags = QtAutoColor): QPixmapH;
function AsBitmap(flags: QtImageConversionFlags = QtAutoColor): QBitmapH;
procedure CopyFrom(AImage: QImageH; x, y, w, h: integer); procedure CopyFrom(AImage: QImageH; x, y, w, h: integer);
public public
function height: Integer; function height: Integer;
function width: Integer; function width: Integer;
function bits: PByte; function bits: PByte;
function numBytes: Integer; function numBytes: Integer;
procedure invertPixels(InvertMode: QImageInvertMode = QImageInvertRgb);
end; end;
{ TQtFont } { TQtFont }
@ -836,10 +838,16 @@ begin
QPixmap_destroy(APixmap); QPixmap_destroy(APixmap);
end; end;
function TQtImage.AsPixmap: QPixmapH; function TQtImage.AsPixmap(flags: QtImageConversionFlags = QtAutoColor): QPixmapH;
begin begin
Result := QPixmap_create(); Result := QPixmap_create();
QPixmap_fromImage(Result, Handle); QPixmap_fromImage(Result, Handle, flags);
end;
function TQtImage.AsBitmap(flags: QtImageConversionFlags = QtAutoColor): QBitmapH;
begin
Result := QBitmap_create();
QBitmap_fromImage(Result, Handle, flags);
end; end;
procedure TQtImage.CopyFrom(AImage: QImageH; x, y, w, h: integer); procedure TQtImage.CopyFrom(AImage: QImageH; x, y, w, h: integer);
@ -887,6 +895,11 @@ begin
Result := QImage_numBytes(Handle); Result := QImage_numBytes(Handle);
end; end;
procedure TQtImage.invertPixels(InvertMode: QImageInvertMode = QImageInvertRgb);
begin
QImage_invertPixels(Handle, InvertMode);
end;
{ TQtFont } { TQtFont }
function TQtFont.GetMetrics: TQtFontMetrics; function TQtFont.GetMetrics: TQtFontMetrics;

View File

@ -139,6 +139,7 @@ type
public public
procedure Activate; procedure Activate;
procedure BringToFront; procedure BringToFront;
procedure clearMask;
procedure OffsetMousePos(APoint: PQtPoint); virtual; procedure OffsetMousePos(APoint: PQtPoint); virtual;
procedure Update(ARect: PRect = nil); virtual; procedure Update(ARect: PRect = nil); virtual;
procedure Repaint(ARect: PRect = nil); virtual; procedure Repaint(ARect: PRect = nil); virtual;
@ -179,6 +180,7 @@ type
procedure setFont(AFont: QFontH); procedure setFont(AFont: QFontH);
procedure setGeometry(ARect: TRect); overload; procedure setGeometry(ARect: TRect); overload;
procedure setMaximumSize(AWidth, AHeight: Integer); procedure setMaximumSize(AWidth, AHeight: Integer);
procedure setMask(AMask: QBitmapH);
procedure setMinimumSize(AWidth, AHeight: Integer); procedure setMinimumSize(AWidth, AHeight: Integer);
procedure setParent(parent: QWidgetH); virtual; procedure setParent(parent: QWidgetH); virtual;
procedure setText(const W: WideString); virtual; procedure setText(const W: WideString); virtual;
@ -2280,6 +2282,11 @@ begin
raiseWidget; raiseWidget;
end; end;
procedure TQtWidget.clearMask;
begin
QWidget_clearMask(Widget);
end;
procedure TQtWidget.OffsetMousePos(APoint: PQtPoint); procedure TQtWidget.OffsetMousePos(APoint: PQtPoint);
begin begin
with getClientBounds do with getClientBounds do
@ -2560,6 +2567,11 @@ begin
QWidget_setMaximumSize(Widget, AWidth, AHeight); QWidget_setMaximumSize(Widget, AWidth, AHeight);
end; end;
procedure TQtWidget.setMask(AMask: QBitmapH);
begin
QWidget_setMask(Widget, AMask);
end;
procedure TQtWidget.setMinimumSize(AWidth, AHeight: Integer); procedure TQtWidget.setMinimumSize(AWidth, AHeight: Integer);
begin begin
QWidget_setMinimumSize(Widget, AWidth, AHeight); QWidget_setMinimumSize(Widget, AWidth, AHeight);

View File

@ -90,6 +90,7 @@ type
class procedure SetColor(const AWinControl: TWinControl); override; class procedure SetColor(const AWinControl: TWinControl); override;
class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); override; class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); override;
class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
class procedure SetShape(const AWinControl: TWinControl; const AShape: HBITMAP); override;
class procedure GetPreferredSize(const AWinControl: TWinControl; class procedure GetPreferredSize(const AWinControl: TWinControl;
var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override;
@ -562,6 +563,32 @@ begin
TQtWidget(AWinControl.Handle).SetTextColor(@QColor); TQtWidget(AWinControl.Handle).SetTextColor(@QColor);
end; end;
class procedure TQtWSWinControl.SetShape(const AWinControl: TWinControl;
const AShape: HBITMAP);
var
Widget: TQtWidget;
Shape: TQtImage;
AMask: QBitmapH;
begin
if not WSCheckHandleAllocated(AWinControl, 'SetShape') then
Exit;
Widget := TQtWidget(AWinControl.Handle);
if AShape <> 0 then
begin
Shape := TQtImage(AShape);
// invert white/black
Shape.invertPixels;
AMask := Shape.AsBitmap;
Widget.setMask(AMask);
QBitmap_destroy(AMask);
// invert back
Shape.invertPixels;
end
else
Widget.clearMask;
end;
class procedure TQtWSWinControl.SetBorderStyle(const AWinControl: TWinControl; class procedure TQtWSWinControl.SetBorderStyle(const AWinControl: TWinControl;
const ABorderStyle: TBorderStyle); const ABorderStyle: TBorderStyle);
var var

View File

@ -39,7 +39,7 @@ uses
// LCL // LCL
SysUtils, Classes, Controls, LCLType, Forms, SysUtils, Classes, Controls, LCLType, Forms,
// Widgetset // Widgetset
InterfaceBase, WSForms, WSLCLClasses; InterfaceBase, WSForms, WSProc, WSLCLClasses;
type type

View File

@ -28,7 +28,7 @@ interface
uses uses
Windows, Win32Extra, Classes, SysUtils, Windows, Win32Extra, Classes, SysUtils,
LMessages, LCLType, LCLProc, Controls, Forms, Menus, GraphType; LMessages, LCLType, LCLProc, Controls, Forms, Menus, GraphType, IntfGraphics;
Type Type
TEventType = (etNotify, etKey, etKeyPress, etMouseWheel, etMouseUpDown); TEventType = (etNotify, etKey, etKeyPress, etMouseWheel, etMouseUpDown);
@ -122,6 +122,7 @@ function GetBitmapBytes(AWinBmp: Windows.TBitmap; ABitmap: HBITMAP; const ARect:
procedure BlendRect(ADC: HDC; const ARect: TRect; Color: ColorRef); procedure BlendRect(ADC: HDC; const ARect: TRect; Color: ColorRef);
function GetLastErrorText(AErrorCode: Cardinal): String; function GetLastErrorText(AErrorCode: Cardinal): String;
function BitmapToRegion(hBmp: HBITMAP; cTransparentColor: COLORREF = 0; cTolerance: COLORREF = $101010): HRGN;
type type
PDisableWindowsInfo = ^TDisableWindowsInfo; PDisableWindowsInfo = ^TDisableWindowsInfo;
@ -1582,6 +1583,193 @@ begin
then LocalFree(HLOCAL(tmp)); then LocalFree(HLOCAL(tmp));
end; end;
(*
BitmapToRegion : Create a region from the "non-transparent" pixels of a bitma
Author : Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998
hBmp : Source bitmap
cTransparentColor : Color base for the "transparent" pixels (default is black)
cTolerance : Color tolerance for the "transparent" pixels
A pixel is assumed to be transparent if the value of each of its 3 components (blue, green and red) is
greater or equal to the corresponding value in cTransparentColor and is lower or equal to the
corresponding value in cTransparentColor + cTolerance
*)
function BitmapToRegion(hBmp: HBITMAP; cTransparentColor: COLORREF = 0; cTolerance: COLORREF = $101010): HRGN;
const
ALLOC_UNIT = 100;
var
AWidth, AHeight: Integer;
maxRects: DWORD;
hData: THANDLE;
pData: PRGNDATA;
lr, lg, lb, hr, hg, hb: Byte;
x, y, x0: Integer;
pr: PRect;
h: HRGN;
WinBmp: Windows.TBitmap;
P, Data: PRGBAQuad;
RS: PtrUInt;
ARawImage, DstRawImage: TRawImage;
SourceImage, DestImage: TLazIntfImage;
procedure FillDescription(out ADesc: TRawImageDescription);
begin
ADesc.Init;
ADesc.Format := ricfRGBA;
ADesc.PaletteColorCount := 0;
ADesc.MaskBitsPerPixel := 0;
ADesc.Depth := 32;
ADesc.Width := AWidth;
ADesc.Height := AHeight;
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;
begin
Result := 0;
if Windows.GetObject(hBmp, sizeof(WinBmp), @WinBmp) = 0 then
Exit;
AWidth := WinBmp.bmWidth;
AHeight := Abs(WinBmp.bmHeight);
if not RawImage_FromBitmap(ARawImage, hBmp, 0, Rect(0, 0, AWidth, AHeight)) then
Exit;
SourceImage := TLazIntfImage.Create(ARawImage, True);
DstRawImage.Init;
FillDescription(DstRawImage.Description);
DstRawImage.DataSize := AWidth * AHeight * SizeOf(TRGBAQuad);
Data := AllocMem(DstRawImage.DataSize);
DstRawImage.Data := PByte(Data);
DestImage := TLazIntfImage.Create(DstRawImage, False);
DestImage.CopyPixels(SourceImage);
SourceImage.Free;
DestImage.Free;
RS := GetBytesPerLine(AWidth, 32, rileDWordBoundary);
// For better performances, we will use the ExtCreateRegion() function to create the
// region. This function take a RGNDATA structure on entry. We will add rectangles by
// amount of ALLOC_UNIT number in this structure
maxRects := ALLOC_UNIT;
hData := GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(TRECT) * maxRects));
pData := GlobalLock(hData);
pData^.rdh.dwSize := sizeof(RGNDATAHEADER);
pData^.rdh.iType := RDH_RECTANGLES;
pData^.rdh.nCount := 0;
pData^.rdh.nRgnSize := 0;
Windows.SetRect(pData^.rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
// Keep on hand highest and lowest values for the "transparent" pixel
lr := GetRValue(cTransparentColor);
lg := GetGValue(cTransparentColor);
lb := GetBValue(cTransparentColor);
hr := min($ff, lr + GetRValue(cTolerance));
hg := min($ff, lg + GetGValue(cTolerance));
hb := min($ff, lb + GetBValue(cTolerance));
P := Data;
// Scan each bitmap row from bottom to top (the bitmap is inverted vertically)
for y := 0 to AHeight - 1 do
begin
// Scan each bitmap pixel from left to righ
x := 0;
while (x < AWidth) do
begin
// Search for a continuous range of "non transparent pixels"
x0 := x;
while (x < AWidth) do
begin
with P[x] do
if (Red >= lr) and (Red <= hr) then
begin
if (Green >= lg) and (Green <= hg) then
begin
if (Blue >= lb) and (Blue <= hb) then
break; //This pixel is "transparent"
end;
end;
inc(x);
end;
if (x > x0) then
begin
// Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region
if (pData^.rdh.nCount >= maxRects) then
begin
GlobalUnlock(hData);
maxRects := maxRects + ALLOC_UNIT;
hData := GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(TRECT) * maxRects), GMEM_MOVEABLE);
pData := GlobalLock(hData);
end;
pr := PRect(PChar(pData^.Buffer));
SetRect(pr[pData^.rdh.nCount], x0, y, x, y+1);
if (x0 < pData^.rdh.rcBound.left) then
pData^.rdh.rcBound.left := x0;
if (y < pData^.rdh.rcBound.top) then
pData^.rdh.rcBound.top := y;
if (x > pData^.rdh.rcBound.right) then
pData^.rdh.rcBound.right := x;
if (y+1 > pData^.rdh.rcBound.bottom) then
pData^.rdh.rcBound.bottom := y+1;
inc(pData^.rdh.nCount);
// On Windows98, ExtCreateRegion() may fail if the number of rectangles is to
// large (ie: > 4000). Therefore, we have to create the region by multiple steps
if (pData^.rdh.nCount = 2000) then
begin
h := Windows.ExtCreateRegion(nil, sizeof(RGNDATAHEADER) + (sizeof(TRECT) * maxRects), pData^);
if (Result <> 0) then
begin
Windows.CombineRgn(Result, Result, h, RGN_OR);
Windows.DeleteObject(h);
end
else
Result := h;
pData^.rdh.nCount := 0;
Windows.SetRect(pData^.rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
end;
end;
inc(x);
end;
// Go to next row (remember, the bitmap is inverted vertically
P := PRGBAQuad(PByte(P) + RS);
end;
// Create or extend the region with the remaining rectangle
h := Windows.ExtCreateRegion(nil, sizeof(RGNDATAHEADER) + (sizeof(TRECT) * maxRects), pData^);
if (Result <> 0) then
begin
Windows.CombineRgn(Result, Result, h, RGN_OR);
Windows.DeleteObject(h);
end
else
Result := h;
FreeMem(Data);
end;
procedure DoInitialization; procedure DoInitialization;
begin begin

View File

@ -84,6 +84,7 @@ type
class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override; class procedure SetFont(const AWinControl: TWinControl; const AFont: TFont); override;
class procedure SetText(const AWinControl: TWinControl; const AText: string); override; class procedure SetText(const AWinControl: TWinControl; const AText: string); override;
class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); override; class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); override;
class procedure SetShape(const AWinControl: TWinControl; const AShape: HBITMAP); override;
class procedure ConstraintsChange(const AWinControl: TWinControl); override; class procedure ConstraintsChange(const AWinControl: TWinControl); override;
class function CreateHandle(const AWinControl: TWinControl; class function CreateHandle(const AWinControl: TWinControl;
@ -492,6 +493,23 @@ begin
Windows.SetCursor(ACursor); Windows.SetCursor(ACursor);
end; end;
class procedure TWin32WSWinControl.SetShape(const AWinControl: TWinControl;
const AShape: HBITMAP);
var
Rgn: HRGN;
begin
if not WSCheckHandleAllocated(AWinControl, 'SetShape') then
Exit;
if AShape <> 0 then
Rgn := BitmapToRegion(AShape)
else
Rgn := 0;
SetWindowRgn(AWinControl.Handle, Rgn, True);
if Rgn <> 0 then
DeleteObject(Rgn);
end;
class procedure TWin32WSWinControl.ConstraintsChange(const AWinControl: TWinControl); class procedure TWin32WSWinControl.ConstraintsChange(const AWinControl: TWinControl);
begin begin
// TODO: implement me! // TODO: implement me!

View File

@ -35,7 +35,7 @@ uses
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
Forms, Controls, LCLType, Classes, Forms, Controls, LCLType, Classes,
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
WSForms, WSLCLClasses, Windows, SysUtils, Win32Extra, WSForms, WSProc, WSLCLClasses, Windows, SysUtils, Win32Extra,
InterfaceBase, Win32Int, Win32Proc, Win32WSControls; InterfaceBase, Win32Int, Win32Proc, Win32WSControls;
type type

View File

@ -101,6 +101,7 @@ type
class procedure SetSize(const AWinControl: TWinControl; const AWidth, AHeight: Integer); virtual; class procedure SetSize(const AWinControl: TWinControl; const AWidth, AHeight: Integer); virtual;
class procedure SetText(const AWinControl: TWinControl; const AText: String); virtual; class procedure SetText(const AWinControl: TWinControl; const AText: String); virtual;
class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); virtual; class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); virtual;
class procedure SetShape(const AWinControl: TWinControl; const AShape: HBITMAP); virtual;
{ TODO: move AdaptBounds: it is only used in winapi interfaces } { TODO: move AdaptBounds: it is only used in winapi interfaces }
class procedure AdaptBounds(const AWinControl: TWinControl; class procedure AdaptBounds(const AWinControl: TWinControl;
@ -257,6 +258,11 @@ class procedure TWSWinControl.SetCursor(const AWinControl: TWinControl; const AC
begin begin
end; end;
class procedure TWSWinControl.SetShape(const AWinControl: TWinControl;
const AShape: HBITMAP);
begin
end;
class procedure TWSWinControl.SetFont(const AWinControl: TWinControl; const AFont: TFont); class procedure TWSWinControl.SetFont(const AWinControl: TWinControl; const AFont: TFont);
begin begin
end; end;