799 lines
21 KiB
ObjectPascal
799 lines
21 KiB
ObjectPascal
{ lclutils unit
|
|
|
|
Copyright (C) 2005-2017 Lagunov Aleksey alexs75@yandex.ru and Lazarus team
|
|
original conception from rx library for Delphi (c)
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version with the following modification:
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
permission to link this library with independent modules to produce an
|
|
executable, regardless of the license terms of these independent modules,and
|
|
to copy and distribute the resulting executable under terms of your choice,
|
|
provided that you also meet, for each linked independent module, the terms
|
|
and conditions of the license of that module. An independent module is a
|
|
module which is not derived from or based on this library. If you modify
|
|
this library, you may extend this exception to your version of the library,
|
|
but you are not obligated to do so. If you do not wish to do so, delete this
|
|
exception statement from your version.
|
|
|
|
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. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
|
|
unit rxlclutils;
|
|
|
|
{$I rx.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF WIN32}
|
|
windows,
|
|
{$ENDIF}
|
|
Classes, SysUtils, Graphics, Controls, Forms, LResources
|
|
;
|
|
|
|
|
|
type
|
|
TTextOrientation = (toHorizontal, toVertical90, toHorizontal180, toVertical270, toHorizontal360);
|
|
|
|
{ TRxPageMargin }
|
|
|
|
TRxPageMargin = class(TPersistent)
|
|
private
|
|
FBottom: integer;
|
|
FLeft: integer;
|
|
FRight: integer;
|
|
FTop: integer;
|
|
protected
|
|
procedure AssignTo(Dest: TPersistent); override;
|
|
public
|
|
constructor Create;
|
|
published
|
|
property Left:integer read FLeft write FLeft default 20;
|
|
property Top:integer read FTop write FTop default 20;
|
|
property Right:integer read FRight write FRight default 20;
|
|
property Bottom:integer read FBottom write FBottom default 20;
|
|
end;
|
|
|
|
function WidthOf(R: TRect): Integer; inline;
|
|
function HeightOf(R: TRect): Integer; inline;
|
|
|
|
procedure RxFrame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor;
|
|
Width: Integer);
|
|
function DrawButtonFrame(Canvas: TCanvas; const Client: TRect;
|
|
IsDown, IsFlat: Boolean): TRect;
|
|
function DrawButtonFrameXP(Canvas: TCanvas; const Client: TRect;
|
|
IsDown, IsFlat: Boolean): TRect;
|
|
|
|
//Code from TAChartUtils
|
|
procedure RotateLabel(Canvas: TCanvas; x, y: Integer; const St: String; RotDegree: Integer);
|
|
procedure OutTextXY90(Canvas:TCanvas; X,Y:integer; Text:string; Orientation:TTextOrientation);
|
|
|
|
function IsForegroundTask: Boolean;
|
|
function ValidParentForm(Control: TControl): TCustomForm;
|
|
function CreateArrowBitmap:TBitmap;
|
|
function CreateResBitmap(const AResName:string):TBitmap;
|
|
function LoadLazResBitmapImage(const ResName: string): TBitmap;
|
|
|
|
{functions from DBGrid}
|
|
function GetWorkingCanvas(const Canvas: TCanvas): TCanvas;
|
|
procedure FreeWorkingCanvas(canvas: TCanvas);
|
|
|
|
{
|
|
function AllocMemo(Size: Longint): Pointer;
|
|
function ReallocMemo(fpBlock: Pointer; Size: Longint): Pointer;
|
|
procedure FreeMemo(var fpBlock: Pointer);
|
|
}
|
|
|
|
procedure RaiseIndexOutOfBounds(Control: TControl; Items:TStrings; Index: integer);
|
|
|
|
procedure WriteTextHeader(ACanvas: TCanvas; ARect: TRect; const Text: string; Alignment: TAlignment);
|
|
|
|
{$IFDEF WIN32}
|
|
type
|
|
PCursorOrIcon = ^TCursorOrIcon;
|
|
TCursorOrIcon = packed record
|
|
Reserved: Word;
|
|
wType: Word;
|
|
Count: Word;
|
|
end;
|
|
|
|
PIconRec = ^TIconRec;
|
|
TIconRec = packed record
|
|
Width: Byte;
|
|
Height: Byte;
|
|
Colors: Word;
|
|
Reserved1: Word;
|
|
Reserved2: Word;
|
|
DIBSize: Longint;
|
|
DIBOffset: Longint;
|
|
end;
|
|
|
|
procedure ReadIcon(Stream: TStream; var Icon: HICON; ImageCount: Integer;
|
|
StartOffset: Integer; const RequestedSize: TPoint; var IconSize: TPoint);
|
|
procedure OutOfResources;
|
|
{$ENDIF}
|
|
|
|
implementation
|
|
uses LCLProc, LCLIntf, LCLType, LCLStrConsts, Grids, math;
|
|
|
|
{$IFNDEF RX_USE_LAZARUS_RESOURCE}
|
|
{$R rx_lcl.res}
|
|
{$ENDIF}
|
|
|
|
{ TRxPageMargin }
|
|
|
|
procedure TRxPageMargin.AssignTo(Dest: TPersistent);
|
|
begin
|
|
if (Dest is TRxPageMargin) then
|
|
begin
|
|
TRxPageMargin(Dest).FBottom:=FBottom;
|
|
TRxPageMargin(Dest).FLeft:=FLeft;
|
|
TRxPageMargin(Dest).FRight:=FRight;
|
|
TRxPageMargin(Dest).FTop:=FTop;
|
|
end
|
|
else
|
|
inherited AssignTo(Dest);
|
|
end;
|
|
|
|
constructor TRxPageMargin.Create;
|
|
begin
|
|
inherited Create;
|
|
FBottom:=20;
|
|
FLeft:=20;
|
|
FRight:=20;
|
|
FTop:=20;
|
|
end;
|
|
|
|
function WidthOf(R: TRect): Integer;
|
|
begin
|
|
Result := R.Right - R.Left;
|
|
end;
|
|
|
|
function HeightOf(R: TRect): Integer;
|
|
begin
|
|
Result := R.Bottom - R.Top;
|
|
end;
|
|
|
|
procedure RxFrame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor;
|
|
Width: Integer);
|
|
|
|
procedure DoRect;
|
|
var
|
|
TopRight, BottomLeft: TPoint;
|
|
begin
|
|
TopRight.X := Rect.Right;
|
|
TopRight.Y := Rect.Top;
|
|
BottomLeft.X := Rect.Left;
|
|
BottomLeft.Y := Rect.Bottom;
|
|
Canvas.Pen.Color := TopColor;
|
|
Canvas.PolyLine([BottomLeft, Rect.TopLeft, TopRight]);
|
|
Canvas.Pen.Color := BottomColor;
|
|
Dec(BottomLeft.X);
|
|
Canvas.PolyLine([TopRight, Rect.BottomRight, BottomLeft]);
|
|
end;
|
|
|
|
begin
|
|
Canvas.Pen.Width := 1;
|
|
Dec(Rect.Bottom); Dec(Rect.Right);
|
|
while Width > 0 do
|
|
begin
|
|
Dec(Width);
|
|
DoRect;
|
|
InflateRect(Rect, -1, -1);
|
|
end;
|
|
Inc(Rect.Bottom); Inc(Rect.Right);
|
|
end;
|
|
|
|
function DrawButtonFrame(Canvas: TCanvas; const Client: TRect;
|
|
IsDown, IsFlat: Boolean): TRect;
|
|
begin
|
|
Result := Client;
|
|
if IsDown then
|
|
begin
|
|
RxFrame3D(Canvas, Result, clWindowFrame, clBtnHighlight, 1);
|
|
if not IsFlat then
|
|
RxFrame3D(Canvas, Result, clBtnShadow, clBtnFace, 1);
|
|
end
|
|
else
|
|
begin
|
|
if IsFlat then
|
|
RxFrame3D(Canvas, Result, clBtnHighlight, clBtnShadow, 1)
|
|
else
|
|
begin
|
|
RxFrame3D(Canvas, Result, clBtnHighlight, clWindowFrame, 1);
|
|
RxFrame3D(Canvas, Result, clBtnFace, clBtnShadow, 1);
|
|
end;
|
|
end;
|
|
InflateRect(Result, -1, -1);
|
|
end;
|
|
|
|
function DrawButtonFrameXP(Canvas: TCanvas; const Client: TRect; IsDown,
|
|
IsFlat: Boolean): TRect;
|
|
begin
|
|
Result := Client;
|
|
Canvas.Brush.Color := $00EFD3C6;
|
|
Canvas.FillRect(Client);
|
|
RxFrame3D(Canvas, Result, $00C66931, $00C66931, 1);
|
|
end;
|
|
|
|
{$IFDEF WIN32}
|
|
type
|
|
PCheckTaskInfo = ^TCheckTaskInfo;
|
|
TCheckTaskInfo = packed record
|
|
FocusWnd: HWnd;
|
|
Found: Boolean;
|
|
end;
|
|
//function CheckTaskWindow(Window: HWnd; Data: Longint): WordBool; stdcall;
|
|
function CheckTaskWindow(Window:HWND; Data:LPARAM):WINBOOL;stdcall;
|
|
begin
|
|
Result := True;
|
|
if PCheckTaskInfo(Data)^.FocusWnd = Window then begin
|
|
Result := False;
|
|
PCheckTaskInfo(Data)^.Found := True;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function IsForegroundTask: Boolean;
|
|
{$IFDEF WIN32}
|
|
var
|
|
Info: TCheckTaskInfo;
|
|
{$ENDIF}
|
|
begin
|
|
{$IFDEF WIN32}
|
|
Info.FocusWnd := GetActiveWindow;
|
|
Info.Found := False;
|
|
EnumThreadWindows(GetCurrentThreadID, @CheckTaskWindow, Longint(@Info));
|
|
Result := Info.Found;
|
|
{$ELSE}
|
|
Result:=true;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function ValidParentForm(Control: TControl): TCustomForm;
|
|
begin
|
|
Result := GetParentForm(Control);
|
|
if Result = nil then
|
|
raise EInvalidOperation.CreateFmt('ParentRequired %s', [Control.Name]);
|
|
end;
|
|
|
|
procedure RotateLabel(Canvas: TCanvas; x, y: Integer; const St: String; RotDegree: Integer);
|
|
var
|
|
L:integer;
|
|
begin
|
|
L:=Canvas.Font.Orientation;
|
|
|
|
SetBkMode(Canvas.Handle, TRANSPARENT);
|
|
|
|
Canvas.Font.Orientation:=RotDegree * 10;
|
|
Canvas.TextOut(X, Y, St);
|
|
|
|
{ DrawText(ACanvas.Handle, PChar(Text), Length(Text), DrawRect,
|
|
ALIGN_FLAGS_HEADER[Alignment] or DT_WORDBREAK
|
|
);}
|
|
|
|
Canvas.Font.Orientation:=L;
|
|
end;
|
|
|
|
|
|
procedure OutTextXY90(Canvas:TCanvas; X,Y:integer; Text:string; Orientation:TTextOrientation);
|
|
{$IFDEF OLD_STYLE_TEXT_ROTATE}
|
|
var
|
|
W,H, i,j:integer;
|
|
Bmp:TBitmap;
|
|
begin
|
|
if Orientation = toHorizontal then
|
|
Canvas.TextOut(X, Y, Text)
|
|
else
|
|
begin
|
|
W:=Canvas.TextWidth(Text);
|
|
H:=Canvas.TextHeight(Text);
|
|
Bmp:=TBitMap.Create;
|
|
try
|
|
Bmp.Width:=W;
|
|
Bmp.Height:=H;
|
|
Bmp.Canvas.Brush.Style:=bsSolid;
|
|
Bmp.Canvas.Brush.Color:=clWhite;
|
|
Bmp.Canvas.FillRect(Rect(0,0,W,H));
|
|
Bmp.Canvas.Font:=Canvas.Font;
|
|
Bmp.Canvas.TextOut(0, 0, Text);
|
|
Canvas.Lock;
|
|
if Orientation = toVertical90 then
|
|
begin
|
|
for i:=0 to W-1 do
|
|
for j:=0 to H-1 do
|
|
if Bmp.Canvas.Pixels[i,j]<>clWhite then
|
|
Canvas.Pixels[(H-j)+X,i+Y]:=Bmp.Canvas.Pixels[i,j];
|
|
end
|
|
else
|
|
if Orientation = toVertical270 then
|
|
begin
|
|
for i:=0 to W-1 do
|
|
for j:=0 to H-1 do
|
|
if Bmp.Canvas.Pixels[i,j]<>clWhite then
|
|
Canvas.Pixels[j+X,(W-i)+Y]:=Bmp.Canvas.Pixels[i,j];
|
|
end
|
|
else
|
|
if Orientation = toHorizontal180 then
|
|
begin
|
|
for i:=0 to W-1 do
|
|
for j:=0 to H-1 do
|
|
if Bmp.Canvas.Pixels[i,j]<>clWhite then
|
|
Canvas.Pixels[i+X,(H-j)+Y]:=Bmp.Canvas.Pixels[i,j];
|
|
end
|
|
else
|
|
if Orientation = toHorizontal360 then
|
|
begin
|
|
for i:=0 to W-1 do
|
|
for j:=0 to H-1 do
|
|
if Bmp.Canvas.Pixels[i,j]<>clWhite then
|
|
Canvas.Pixels[(W-i)+X,j+Y]:=Bmp.Canvas.Pixels[i,j];
|
|
end;
|
|
Canvas.Unlock;
|
|
finally
|
|
Bmp.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
{$ELSE}
|
|
const
|
|
TextAngle: array [TTextOrientation] of integer =
|
|
(0 {toHorizontal}, 90 {toVertical90},
|
|
180 {toHorizontal180}, 270 {toVertical270}, 0 {toHorizontal360});
|
|
var
|
|
W, H:integer;
|
|
begin
|
|
W:=0;
|
|
H:=0;
|
|
case Orientation of
|
|
toVertical90:
|
|
begin
|
|
H:=Canvas.TextWidth(Text);
|
|
end;
|
|
toVertical270:
|
|
begin
|
|
W:=Canvas.TextHeight(Text);
|
|
end;
|
|
toHorizontal180:
|
|
begin
|
|
H:=Canvas.TextHeight(Text);
|
|
W:=Canvas.TextWidth(Text);
|
|
end;
|
|
end;
|
|
RotateLabel(Canvas, X+W, Y+H, Text, TextAngle[Orientation]);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{
|
|
function AllocMemo(Size: Longint): Pointer;
|
|
begin
|
|
if Size > 0 then
|
|
Result := GlobalAllocPtr(HeapAllocFlags or GMEM_ZEROINIT, Size)
|
|
else Result := nil;
|
|
end;
|
|
|
|
function ReallocMemo(fpBlock: Pointer; Size: Longint): Pointer;
|
|
begin
|
|
Result := GlobalReallocPtr(fpBlock, Size,
|
|
HeapAllocFlags or GMEM_ZEROINIT);
|
|
end;
|
|
|
|
procedure FreeMemo(var fpBlock: Pointer);
|
|
begin
|
|
if fpBlock <> nil then begin
|
|
GlobalFreePtr(fpBlock);
|
|
fpBlock := nil;
|
|
end;
|
|
end;
|
|
}
|
|
{$IFDEF WIN32}
|
|
function CreateIcon(hInstance: HINST; nWidth, nHeight: Integer;
|
|
cPlanes, cBitsPixel: Byte; lpbANDbits, lpbXORbits: Pointer): HICON; stdcall; external user32 name 'CreateIcon';
|
|
|
|
procedure GDIError;
|
|
var
|
|
ErrorCode: Integer;
|
|
Buf: array [Byte] of Char;
|
|
begin
|
|
ErrorCode := GetLastError;
|
|
if (ErrorCode <> 0) and (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil,
|
|
ErrorCode, LOCALE_USER_DEFAULT, Buf, sizeof(Buf), nil) <> 0) then
|
|
raise EOutOfResources.Create(Buf)
|
|
else
|
|
OutOfResources;
|
|
end;
|
|
|
|
function DupBits(Src: HBITMAP; Size: TPoint; Mono: Boolean): HBITMAP;
|
|
var
|
|
DC, Mem1, Mem2: HDC;
|
|
Old1, Old2: HBITMAP;
|
|
Bitmap: Windows.TBitmap;
|
|
begin
|
|
Mem1 := CreateCompatibleDC(0);
|
|
Mem2 := CreateCompatibleDC(0);
|
|
|
|
try
|
|
GetObject(Src, SizeOf(Bitmap), @Bitmap);
|
|
if Mono then
|
|
Result := CreateBitmap(Size.X, Size.Y, 1, 1, nil)
|
|
else
|
|
begin
|
|
DC := GetDC(0);
|
|
if DC = 0 then GDIError;
|
|
try
|
|
Result := CreateCompatibleBitmap(DC, Size.X, Size.Y);
|
|
if Result = 0 then GDIError;
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
end;
|
|
|
|
if Result <> 0 then
|
|
begin
|
|
Old1 := SelectObject(Mem1, Src);
|
|
Old2 := SelectObject(Mem2, Result);
|
|
|
|
StretchBlt(Mem2, 0, 0, Size.X, Size.Y, Mem1, 0, 0, Bitmap.bmWidth,
|
|
Bitmap.bmHeight, SrcCopy);
|
|
if Old1 <> 0 then SelectObject(Mem1, Old1);
|
|
if Old2 <> 0 then SelectObject(Mem2, Old2);
|
|
end;
|
|
finally
|
|
DeleteDC(Mem1);
|
|
DeleteDC(Mem2);
|
|
end;
|
|
end;
|
|
|
|
function GDICheck(Value: Integer): Integer;
|
|
begin
|
|
if Value = 0 then GDIError;
|
|
Result := Value;
|
|
end;
|
|
|
|
function GetDInColors(BitCount: Word): Integer;
|
|
begin
|
|
case BitCount of
|
|
1, 4, 8: Result := 1 shl BitCount;
|
|
else
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Longint): Longint;
|
|
begin
|
|
Dec(Alignment);
|
|
Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
|
|
Result := Result div 8;
|
|
end;
|
|
|
|
procedure TwoBitsFromDIB(var BI: TBitmapInfoHeader; var XorBits, AndBits: HBITMAP;
|
|
const IconSize: TPoint);
|
|
type
|
|
PLongArray = ^TLongArray;
|
|
TLongArray = array[0..1] of Longint;
|
|
var
|
|
Temp: HBITMAP;
|
|
NumColors: Integer;
|
|
DC: HDC;
|
|
Bits: Pointer;
|
|
Colors: PLongArray;
|
|
begin
|
|
with BI do
|
|
begin
|
|
biHeight := biHeight shr 1; { Size in record is doubled }
|
|
biSizeImage := BytesPerScanline(biWidth, biBitCount, 32) * biHeight;
|
|
NumColors := GetDInColors(biBitCount);
|
|
end;
|
|
DC := GetDC(0);
|
|
if DC = 0 then OutOfResources;
|
|
try
|
|
Bits := Pointer(Longint(@BI) + SizeOf(BI) + NumColors * SizeOf(TRGBQuad));
|
|
Temp := GDICheck(CreateDIBitmap(DC, BI, CBM_INIT, Bits, PBitmapInfo(@BI)^, DIB_RGB_COLORS));
|
|
try
|
|
XorBits := DupBits(Temp, IconSize, False);
|
|
finally
|
|
DeleteObject(Temp);
|
|
end;
|
|
with BI do
|
|
begin
|
|
Inc(Longint(Bits), biSizeImage);
|
|
biBitCount := 1;
|
|
biSizeImage := BytesPerScanline(biWidth, biBitCount, 32) * biHeight;
|
|
biClrUsed := 2;
|
|
biClrImportant := 2;
|
|
end;
|
|
Colors := Pointer(Longint(@BI) + SizeOf(BI));
|
|
Colors^[0] := 0;
|
|
Colors^[1] := $FFFFFF;
|
|
Temp := GDICheck(CreateDIBitmap(DC, BI, CBM_INIT, Bits, PBitmapInfo(@BI)^, DIB_RGB_COLORS));
|
|
try
|
|
AndBits := DupBits(Temp, IconSize, True);
|
|
finally
|
|
DeleteObject(Temp);
|
|
end;
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
end;
|
|
|
|
procedure ReadIcon(Stream: TStream; var Icon: HICON; ImageCount: Integer;
|
|
StartOffset: Integer; const RequestedSize: TPoint; var IconSize: TPoint);
|
|
type
|
|
PIconRecArray = ^TIconRecArray;
|
|
TIconRecArray = array[0..300] of TIconRec;
|
|
var
|
|
List: PIconRecArray;
|
|
HeaderLen, Length: Integer;
|
|
BitsPerPixel: Word;
|
|
Colors, BestColor, C1, N, Index: Integer;
|
|
DC: HDC;
|
|
BI: PBitmapInfoHeader;
|
|
ResData: Pointer;
|
|
XorBits, AndBits: HBITMAP;
|
|
XorInfo, AndInfo: Windows.TBitmap;
|
|
XorMem, AndMem: Pointer;
|
|
XorLen, AndLen: Integer;
|
|
|
|
function AdjustColor(I: Integer): Integer;
|
|
begin
|
|
if I = 0 then
|
|
Result := MaxInt
|
|
else
|
|
Result := I;
|
|
end;
|
|
|
|
function BetterSize(const Old, New: TIconRec): Boolean;
|
|
var
|
|
NewX, NewY, OldX, OldY: Integer;
|
|
begin
|
|
NewX := New.Width - IconSize.X;
|
|
NewY := New.Height - IconSize.Y;
|
|
OldX := Old.Width - IconSize.X;
|
|
OldY := Old.Height - IconSize.Y;
|
|
Result := (Abs(NewX) <= Abs(OldX)) and ((NewX <= 0) or (NewX <= OldX)) and
|
|
(Abs(NewY) <= Abs(OldY)) and ((NewY <= 0) or (NewY <= OldY));
|
|
end;
|
|
|
|
begin
|
|
HeaderLen := SizeOf(TIconRec) * ImageCount;
|
|
List := AllocMem(HeaderLen);
|
|
try
|
|
Stream.Read(List^, HeaderLen);
|
|
if (RequestedSize.X or RequestedSize.Y) = 0 then
|
|
begin
|
|
IconSize.X := GetSystemMetrics(SM_CXICON);
|
|
IconSize.Y := GetSystemMetrics(SM_CYICON);
|
|
end
|
|
else
|
|
IconSize := RequestedSize;
|
|
DC := GetDC(0);
|
|
if DC = 0 then OutOfResources;
|
|
try
|
|
BitsPerPixel := GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL);
|
|
if BitsPerPixel > 8 then
|
|
Colors := MaxInt
|
|
else
|
|
Colors := 1 shl BitsPerPixel;
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
|
|
{ Find the image that most closely matches (<=) the current screen color
|
|
depth and the requested image size. }
|
|
Index := 0;
|
|
BestColor := AdjustColor(List^[0].Colors);
|
|
for N := 1 to ImageCount-1 do
|
|
begin
|
|
C1 := AdjustColor(List^[N].Colors);
|
|
if (C1 <= Colors) and (C1 >= BestColor) and
|
|
BetterSize(List^[Index], List^[N]) then
|
|
begin
|
|
Index := N;
|
|
BestColor := C1;
|
|
end;
|
|
end;
|
|
|
|
with List^[Index] do
|
|
begin
|
|
IconSize.X := Width;
|
|
IconSize.Y := Height;
|
|
BI := AllocMem(DIBSize);
|
|
try
|
|
Stream.Seek(DIBOffset - (HeaderLen + StartOffset), 1);
|
|
Stream.Read(BI^, DIBSize);
|
|
TwoBitsFromDIB(BI^, XorBits, AndBits, IconSize);
|
|
GetObject(AndBits, SizeOf(Windows.TBitmap), @AndInfo);
|
|
GetObject(XorBits, SizeOf(Windows.TBitmap), @XorInfo);
|
|
with AndInfo do
|
|
AndLen := bmWidthBytes * bmHeight * bmPlanes;
|
|
with XorInfo do
|
|
XorLen := bmWidthBytes * bmHeight * bmPlanes;
|
|
Length := AndLen + XorLen;
|
|
ResData := AllocMem(Length);
|
|
try
|
|
AndMem := ResData;
|
|
with AndInfo do
|
|
XorMem := Pointer(Longint(ResData) + AndLen);
|
|
GetBitmapBits(AndBits, AndLen, AndMem);
|
|
GetBitmapBits(XorBits, XorLen, XorMem);
|
|
DeleteObject(XorBits);
|
|
DeleteObject(AndBits);
|
|
Icon := CreateIcon(HInstance, IconSize.X, IconSize.Y,
|
|
XorInfo.bmPlanes, XorInfo.bmBitsPixel, AndMem, XorMem);
|
|
if Icon = 0 then GDIError;
|
|
finally
|
|
FreeMem(ResData, Length);
|
|
end;
|
|
finally
|
|
FreeMem(BI, DIBSize);
|
|
end;
|
|
end;
|
|
finally
|
|
FreeMem(List, HeaderLen);
|
|
end;
|
|
end;
|
|
|
|
procedure OutOfResources;
|
|
begin
|
|
raise Exception.Create('SOutOfResources');
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function CreateArrowBitmap:TBitmap;
|
|
begin
|
|
{$IFNDEF RX_USE_LAZARUS_RESOURCE}
|
|
Result:=CreateResBitmap('rxbtn_downarrow');
|
|
(* Result := TBitmap.Create;
|
|
try
|
|
try
|
|
C := TPortableNetworkGraphic.Create;
|
|
C.LoadFromResourceName(hInstance, 'rxbtn_downarrow');
|
|
Result.Assign(C);
|
|
finally
|
|
C.Free;
|
|
end;
|
|
except
|
|
Result.Free;
|
|
raise;
|
|
end; *)
|
|
{$ELSE}
|
|
Result:=LoadLazResBitmapImage('rxbtn_downarrow')
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function CreateResBitmap(const AResName: string): TBitmap;
|
|
var
|
|
C : TCustomBitmap;
|
|
begin
|
|
Result := TBitmap.Create;
|
|
try
|
|
try
|
|
C := TPortableNetworkGraphic.Create;
|
|
C.LoadFromResourceName(hInstance, AResName);
|
|
Result.Assign(C);
|
|
finally
|
|
C.Free;
|
|
end;
|
|
except
|
|
Result.Free;
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
//Code from DBGrid
|
|
function LoadLazResBitmapImage(const ResName: string): TBitmap;
|
|
var
|
|
C: TCustomBitmap;
|
|
begin
|
|
C := CreateBitmapFromLazarusResource(ResName);
|
|
if C<>nil then
|
|
begin
|
|
Result := TBitmap.Create;
|
|
Result.Assign(C);
|
|
C.Free;
|
|
end
|
|
else
|
|
Result:=nil;
|
|
end;
|
|
|
|
function GetWorkingCanvas(const Canvas: TCanvas): TCanvas;
|
|
var
|
|
DC: HDC;
|
|
begin
|
|
if (Canvas=nil) or (not Canvas.HandleAllocated) then
|
|
begin
|
|
DC := GetDC(0);
|
|
Result := TCanvas.Create;
|
|
Result.Handle := DC;
|
|
end
|
|
else
|
|
Result := Canvas;
|
|
end;
|
|
|
|
|
|
procedure FreeWorkingCanvas(canvas: TCanvas);
|
|
begin
|
|
ReleaseDC(0, Canvas.Handle);
|
|
Canvas.Free;
|
|
end;
|
|
|
|
procedure RaiseIndexOutOfBounds(Control: TControl; Items:TStrings; Index: integer);
|
|
begin
|
|
raise Exception.CreateFmt(rsIndexOutOfBounds,
|
|
[Control.Name, Index, Items.Count - 1]);
|
|
end;
|
|
|
|
const
|
|
ALIGN_FLAGS_HEADER: array[TAlignment] of integer =
|
|
(DT_LEFT or {DT_EXPANDTABS or} DT_NOPREFIX,
|
|
DT_RIGHT or {DT_EXPANDTABS or }DT_NOPREFIX,
|
|
DT_CENTER or {DT_EXPANDTABS or }DT_NOPREFIX);
|
|
|
|
procedure WriteTextHeader(ACanvas: TCanvas; ARect: TRect; const Text: string; Alignment: TAlignment);
|
|
var
|
|
DrawRect: TRect;
|
|
W, CnvW: integer;
|
|
begin
|
|
(*
|
|
dec(ARect.Right, constCellPadding);
|
|
case Canvas.TextStyle.Alignment of
|
|
Classes.taLeftJustify: Inc(ARect.Left, constCellPadding);
|
|
Classes.taRightJustify: Dec(ARect.Right, 1);
|
|
end;
|
|
case Canvas.TextStyle.Layout of
|
|
tlTop: Inc(ARect.Top, constCellPadding);
|
|
tlBottom: Dec(ARect.Bottom, constCellPadding);
|
|
end;
|
|
|
|
if ARect.Right<ARect.Left then
|
|
ARect.Right:=ARect.Left;
|
|
if ARect.Left>ARect.Right then
|
|
ARect.Left:=ARect.Right;
|
|
if ARect.Bottom<ARect.Top then
|
|
ARect.Bottom:=ARect.Top;
|
|
if ARect.Top>ARect.Bottom then
|
|
ARect.Top:=ARect.Bottom;
|
|
|
|
if (ARect.Left<>ARect.Right) and (ARect.Top<>ARect.Bottom) then
|
|
*)
|
|
|
|
|
|
DrawRect := Rect(ARect.Left + constCellPadding, ARect.Top + constCellPadding, ARect.Right - constCellPadding, ARect.Bottom - constCellPadding);
|
|
|
|
CnvW := Max(DrawRect.Right - DrawRect.Left, 1);
|
|
W := (ACanvas.TextWidth(Text) div CnvW) + 1;
|
|
|
|
DrawRect.Top := ((ARect.Top + ARect.Bottom) div 2) - W * ACanvas.TextHeight('Wg') div 2;
|
|
if DrawRect.Top < ARect.Top + 1 then
|
|
DrawRect.Top := ARect.Top + 1;
|
|
|
|
SetBkMode(ACanvas.Handle, TRANSPARENT);
|
|
DrawText(ACanvas.Handle, PChar(Text), Length(Text), DrawRect,
|
|
// DT_VCENTER or DT_WORDBREAK or DT_CENTER
|
|
ALIGN_FLAGS_HEADER[Alignment] {or DT_VCENTER or DT_END_ELLIPSIS } or DT_WORDBREAK
|
|
);
|
|
end;
|
|
|
|
initialization
|
|
{$IFDEF RX_USE_LAZARUS_RESOURCE}
|
|
LazarusResources.Add('rxbtn_downarrow','XPM',[
|
|
'/* XPM */'#13#10'static char * btn_downarrow_xpm[] = {'#13#10'"5 3 2 1",'#13
|
|
+#10'" '#9'c None",'#13#10'".'#9'c #000000",'#13#10'".....",'#13#10'" ... ",'
|
|
+#13#10'" . "};'#13#10]);
|
|
{$ENDIF}
|
|
|
|
end.
|
|
|
|
|