lazarus-ccr/components/orpheus/ovcmisc.pas

1116 lines
33 KiB
ObjectPascal

{*********************************************************}
{* OVCMISC.PAS 4.06 *}
{*********************************************************}
{* ***** BEGIN LICENSE BLOCK ***** *}
{* Version: MPL 1.1 *}
{* *}
{* The contents of this file are subject to the Mozilla Public License *}
{* Version 1.1 (the "License"); you may not use this file except in *}
{* compliance with the License. You may obtain a copy of the License at *}
{* http://www.mozilla.org/MPL/ *}
{* *}
{* Software distributed under the License is distributed on an "AS IS" basis, *}
{* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *}
{* for the specific language governing rights and limitations under the *}
{* License. *}
{* *}
{* The Original Code is TurboPower Orpheus *}
{* *}
{* The Initial Developer of the Original Code is TurboPower Software *}
{* *}
{* Portions created by TurboPower Software Inc. are Copyright (C) 1995-2002 *}
{* TurboPower Software Inc. All Rights Reserved. *}
{* *}
{* Contributor(s): *}
{* *}
{* ***** END LICENSE BLOCK ***** *}
(*Changes)
10/20/01- Hdc changed to TOvcHdc for BCB Compatibility
10/20/01- HWnd changed to TOvcHWnd for BCB Compatibility
*)
{$I OVC.INC}
{$B-} {Complete Boolean Evaluation}
{$I+} {Input/Output-Checking}
{$P+} {Open Parameters}
{$T-} {Typed @ Operator}
{.W-} {Windows Stack Frame}
{$X+} {Extended Syntax}
unit ovcmisc;
{-Miscellaneous functions and procedures}
interface
uses
{$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, MyMisc, {$ENDIF}
Buttons, Classes, Controls, ExtCtrls, Forms, Graphics,
SysUtils, {$IFNDEF LCL} Consts, {$ELSE} LclStrConsts, {$ENDIF} OvcData;
{ Hdc needs to be an Integer for BCB compatibility }
{$IFDEF CBuilder}
type
TOvcHdc = Integer;
TOvcHWND = Cardinal;
{$ELSE}
type
TOvcHdc = HDC;
TOvcHWND = HWND;
{$ENDIF}
{$IFNDEF LCL}
function LoadBaseBitmap(lpBitmapName : PAnsiChar) : HBITMAP;
{-load and return the handle to bitmap resource}
function LoadBaseCursor(lpCursorName : PAnsiChar) : HCURSOR;
{-load and return the handle to cursor resource}
{$ENDIF}
function CompStruct(const S1, S2; Size : Cardinal) : Integer;
{-compare two fixed size structures}
function DefaultEpoch : Integer;
{-return the current century}
function DrawButtonFrame(Canvas : TCanvas; const Client : TRect;
IsDown, IsFlat : Boolean; Style : TButtonStyle) : TRect;
{-produce a button similar to DrawFrameControl}
procedure FixRealPrim(P : PAnsiChar; DC : AnsiChar);
{-get a PChar string representing a real ready for Val()}
function GetDisplayString(Canvas : TCanvas; const S : string;
MinChars, MaxWidth : Integer) : string;
{-given a string, a minimum number of chars to display, and a max width,
find the string that can be displayed in that width - add ellipsis to
the end if necessary and possible}
function GetLeftButton: Byte;
{-return the mapped left button}
{ - HWnd changed to TOvcHWnd for BCB Compatibility }
function GetNextDlgItem(Ctrl : TOvcHWnd{hWnd}) : hWnd;
{-get handle of next control in the same form}
procedure GetRGB(Clr : TColor; var IR, IG, IB : Byte);
{-return component parts of the rgb value}
function GetShiftFlags : Byte;
{-get current shift flags, the high order bit is set if the key is down}
function CreateRotatedFont(F : TFont; Angle : Integer) : hFont;
{-create a rotated font based on the font object F}
function GetTopTextMargin(Font : TFont; BorderStyle : TBorderStyle;
Height : Integer; Ctl3D : Boolean) : Integer;
{-return the pixel top margin size}
function ExtractWord(N : Integer; const S : string; WordDelims : TCharSet) : string;
{-return the Nth word from S}
function IsForegroundTask : Boolean;
{-returns true if this task is currently in the foreground}
function TrimLeft(const S : string) : string;
{-return a string with leading white space removed}
function TrimRight(const S : string) : string;
{-return a string with trailing white space removed}
function QuotedStr(const S : string) : string;
{-return a quoted string string with internal quotes escaped}
function WordCount(const S : string; const WordDelims : TCharSet) : Integer;
{-return the word count given a set of word delimiters}
function WordPosition(const N : Integer; const S : string; const WordDelims : TCharSet) : Integer;
{-return start position of N'th word in S}
function PtrDiff(const P1, P2) : Word;
{-return the difference between P1 and P2}
procedure PtrInc(var P; Delta : Word);
{-increase P by Delta}
procedure PtrDec(var P; Delta : Word);
{-decrease P by Delta}
procedure FixTextBuffer(InBuf, OutBuf : PChar; OutSize : Integer);
{-replace orphan linefeeds with cr/lf pairs}
{ - Hdc changed to TOvcHdc for BCB Compatibility }
procedure TransStretchBlt(DstDC: TOvcHdc{HDC}; DstX, DstY, DstW, DstH: Integer;
SrcDC: TOvcHdc{HDC}; SrcX, SrcY, SrcW, SrcH: Integer;
MaskDC: TOvcHdc{HDC};
MaskX, MaskY : Integer);
function MaxL(A, B : LongInt) : LongInt;
function MinL(A, B : LongInt) : LongInt;
function MinI(X, Y : Integer) : Integer;
{-return the minimum of two integers}
function MaxI(X, Y : Integer) : Integer;
{-return the maximum of two integers}
{function GenerateComponentName(PF : TCustomForm; const Root : string) : string;}
function GenerateComponentName(PF : TWinControl; const Root : string) : string;
{-return a component name unique for this form}
function PartialCompare(const S1, S2 : string) : Boolean;
{-compare minimum length of S1 and S2 strings}
function PathEllipsis(const S : string; MaxWidth : Integer) : string;
function CreateDisabledBitmap(FOriginal : TBitmap; OutlineColor : TColor) : TBitmap;
procedure CopyParentImage(Control : TControl; Dest : TCanvas);
procedure DrawTransparentBitmap(Dest : TCanvas; X, Y, W, H : Integer;
Rect : TRect; Bitmap : TBitmap; TransparentColor : TColor);
function WidthOf(const R : TRect) : Integer;
{returnd R.Right - R.Left}
function HeightOf(const R : TRect) : Integer;
{returnd R.Bottom - R.Top}
procedure DebugOutput(const S : string);
{use OutputDebugString()}
implementation
uses
OvcBase, OvcStr;
{$IFNDEF LCL}
function LoadBaseBitmap(lpBitmapName : PAnsiChar) : HBITMAP;
begin
Result := LoadBitmap(FindClassHInstance(TOvcCustomControlEx), lpBitmapName);
end;
function LoadBaseCursor(lpCursorName : PAnsiChar) : HCURSOR;
begin
Result := LoadCursor(FindClassHInstance(TOvcCustomControlEx), lpCursorName);
end;
{$ENDIF}
{$IFDEF NoAsm}
function CompStruct(const S1, S2; Size : Cardinal) : Integer;
// Since CompStruct currently only used elsewhere to determine if
// two structures are different, just use CompareMem and don't
// worry about whether "greater than" or "less than".
begin
if CompareMem(@S1, @S2, Size) then {Structures identical?}
Result := 0
else {Structures not identical, so just return as though S1 > S2}
Result := 1;
end;
{$ELSE}
function CompStruct(const S1, S2; Size : Cardinal) : Integer; register;
{-compare two fixed size structures}
asm
push esi
push edi
mov esi, eax {pointer to S1}
mov edi, edx {pointer to S2}
xor eax, eax {eax holds temporary result (Equal)}
or ecx, ecx {size is already in ecx}
jz @@CSDone {make sure size isn't zero}
cld {go forward}
repe cmpsb {compare until no match or ecx = 0}
je @@CSDone {if equal, result is already in eax}
inc eax {prepare for greater}
ja @@CSDone {S1 greater? return +1}
mov eax, -1 {else S1 less, return -1}
@@CSDone:
pop edi
pop esi
end;
{$ENDIF}
procedure FixRealPrim(P : PAnsiChar; DC : AnsiChar);
{-Get a string representing a real ready for Val()}
var
DotPos : Cardinal;
EPos : Cardinal;
Len : Word;
Found : Boolean;
EFound : Boolean;
begin
TrimAllSpacesPChar(P);
Len := StrLen(P);
if Len > 0 then begin
if P[Len-1] = DC then begin
Dec(Len);
P[Len] := #0;
TrimAllSpacesPChar(P);
end;
{Val doesn't accept alternate decimal point chars}
Found := StrChPos(P, DC, DotPos);
{replace with '.'}
if Found and (DotPos > 0) then
P[DotPos] := '.'
else
Found := StrChPos(P, pmDecimalPt, DotPos);
if Found then begin
{check for 'nnnn.'}
if LongInt(DotPos) = Len-1 then begin
P[Len] := '0';
Inc(Len);
P[Len] := #0;
end;
{check for '.nnnn'}
if DotPos = 0 then begin
StrChInsertPrim(P, '0', 0);
Inc(Len);
Inc(DotPos);
end;
{check for '-.nnnn'}
if (Len > 1) and (P^ = '-') and (DotPos = 1) then begin
StrChInsertPrim(P, '0', 1);
Inc(DotPos);
end;
end;
{fix up numbers with exponents}
EFound := StrChPos(P, 'E', EPos);
if EFound and (EPos > 0) then begin
if not Found then begin
StrChInsertPrim(P, '.', EPos);
DotPos := EPos;
Inc(EPos);
end;
if EPos-DotPos < 12 then
StrStInsertPrim(P, '00000', EPos);
end;
{remove blanks before and after '.' }
if Found then begin
while (DotPos > 0) and (P[DotPos-1] = ' ') do begin
StrStDeletePrim(P, DotPos-1, 1);
Dec(DotPos);
end;
while P[DotPos+1] = ' ' do
StrStDeletePrim(P, DotPos+1, 1);
end;
end else begin
{empty string = '0'}
P[0] := '0';
P[1] := #0;
end;
end;
function GetLeftButton: Byte;
const
RLButton : array[Boolean] of Word = (VK_LBUTTON, VK_RBUTTON);
begin
Result := RLButton[GetSystemMetrics(SM_SWAPBUTTON) <> 0];
end;
{ - HWnd changed to TOvcHWnd for BCB Compatibility }
function GetNextDlgItem(Ctrl : TOvcHWnd{hWnd}) : hWnd;
{-Get handle of next control in the same form}
begin
{asking for previous returns next}
Result := GetNextWindow(Ctrl, GW_HWNDPREV);
if Result = 0 then begin
{asking for last returns first}
Result := GetWindow(Ctrl, GW_HWNDLAST);
if Result = 0 then
Result := Ctrl;
end;
end;
procedure GetRGB(Clr : TColor; var IR, IG, IB : Byte);
begin
if (Clr < 0) then begin
Clr := Clr + MaxLongInt + 1;
Clr := GetSysColor(Clr);
end;
IR := GetRValue(Clr);
IG := GetGValue(Clr);
IB := GetBValue(Clr);
end;
function GetShiftFlags : Byte;
{-get current shift flags, the high order bit is set if the key is down}
begin
Result := (Ord(GetKeyState(VK_CONTROL) < 0) * ss_Ctrl) +
(Ord(GetKeyState(VK_SHIFT ) < 0) * ss_Shift) +
(Ord(GetKeyState(VK_ALT ) < 0) * ss_Alt);
end;
function CreateRotatedFont(F : TFont; Angle : Integer) : hFont;
{-create a rotated font based on the font object F}
var
LF : TLogFont;
begin
FillChar(LF, SizeOf(LF), #0);
with LF do begin
lfHeight := F.Height;
lfWidth := 0;
lfEscapement := Angle*10;
lfOrientation := 0;
if fsBold in F.Style then
lfWeight := FW_BOLD
else
lfWeight := FW_NORMAL;
lfItalic := Byte(fsItalic in F.Style);
lfUnderline := Byte(fsUnderline in F.Style);
lfStrikeOut := Byte(fsStrikeOut in F.Style);
lfCharSet := DEFAULT_CHARSET;
StrPCopy(lfFaceName, F.Name);
lfQuality := DEFAULT_QUALITY;
{everything else as default}
lfOutPrecision := OUT_DEFAULT_PRECIS;
lfClipPrecision := CLIP_DEFAULT_PRECIS;
case F.Pitch of
fpVariable : lfPitchAndFamily := VARIABLE_PITCH;
fpFixed : lfPitchAndFamily := FIXED_PITCH;
else
lfPitchAndFamily := DEFAULT_PITCH;
end;
end;
Result := CreateFontIndirect(LF);
end;
function GetTopTextMargin(Font : TFont; BorderStyle : TBorderStyle;
Height : Integer; Ctl3D : Boolean) : Integer;
{-return the pixel top margin size}
var
I : Integer;
DC : hDC;
Metrics : TTextMetric;
SaveFont : hFont;
SysMetrics : TTextMetric;
begin
DC := GetDC(0);
try
GetTextMetrics(DC, SysMetrics);
SaveFont := SelectObject(DC, Font.Handle);
GetTextMetrics(DC, Metrics);
SelectObject(DC, SaveFont);
finally
ReleaseDC(0, DC);
end;
I := SysMetrics.tmHeight;
if I > Metrics.tmHeight then
I := Metrics.tmHeight;
if NewStyleControls then begin
if BorderStyle = bsNone then begin
Result := 0;
if I >= Height-2 then
Result := (Height-I-2) div 2 - Ord(Odd(Height-I));
end else if Ctl3D then begin
Result := 1;
if I >= Height-4 then
Result := (Height-I-4) div 2 - 1;
end else begin
Result := 1;
if I >= Height-4 then
Result := (Height-I-4) div 2 - Ord(Odd(Height-I));
end;
end else begin
Result := (Height-Metrics.tmHeight-1) div 2;
if I > Height-2 then begin
Dec(Result, 2);
if BorderStyle = bsNone then
Inc(Result, 1);
end;
end;
end;
function PtrDiff(const P1, P2) : Word;
{-return the difference between P1 and P2}
begin
{P1 and P2 are assumed to point within the same buffer}
Result := PAnsiChar(P1) - PAnsiChar(P2);
end;
procedure PtrInc(var P; Delta : Word);
{-increase P by Delta}
begin
Inc(PAnsiChar(P), Delta);
end;
procedure PtrDec(var P; Delta : Word);
{-increase P by Delta}
begin
Dec(PAnsiChar(P), Delta);
end;
{$IFDEF NoAsm}
function MinI(X, Y : Integer) : Integer;
begin
if X < Y then
Result := X
else
Result := Y;
end;
function MaxI(X, Y : Integer) : Integer;
begin
if X >= Y then
Result := X
else
Result := Y;
end;
{$ELSE}
function MinI(X, Y : Integer) : Integer;
asm
cmp eax, edx
jle @@Exit
mov eax, edx
@@Exit:
end;
function MaxI(X, Y : Integer) : Integer;
asm
cmp eax, edx
jge @@Exit
mov eax, edx
@@Exit:
end;
{$ENDIF}
function MaxL(A, B : LongInt) : LongInt;
begin
if (A < B) then
Result := B
else
Result := A;
end;
function MinL(A, B : LongInt) : LongInt;
begin
if (A < B) then
Result := A
else
Result := B;
end;
function TrimLeft(const S : string) : string;
var
I, L : Integer;
begin
L := Length(S);
I := 1;
while (I <= L) and (S[I] <= ' ') do
Inc(I);
Result := Copy(S, I, Length(S)-I+1);
end;
function TrimRight(const S : string) : string;
var
I : Integer;
begin
I := Length(S);
while (I > 0) and (S[I] <= ' ') do
Dec(I);
Result := Copy(S, 1, I);
end;
function QuotedStr(const S: string): string;
var
I : Integer;
begin
Result := S;
for I := Length(Result) downto 1 do
if Result[I] = '''' then Insert('''', Result, I);
Result := '''' + Result + '''';
end;
function WordCount(const S : string; const WordDelims : TCharSet) : Integer;
var
SLen, I : Integer;
begin
Result := 0;
I := 1;
SLen := Length(S);
while I <= SLen do begin
while (I <= SLen) and (S[I] in WordDelims) do
Inc(I);
if I <= SLen then
Inc(Result);
while (I <= SLen) and not(S[I] in WordDelims) do
Inc(I);
end;
end;
function ExtractWord(N : Integer; const S : string; WordDelims : TCharSet) : string;
var
I : Word;
Len : Integer;
begin
Len := 0;
I := WordPosition(N, S, WordDelims);
if I <> 0 then
{ find the end of the current word }
while (I <= Length(S)) and not(S[I] in WordDelims) do begin
{ add the I'th character to result }
Inc(Len);
SetLength(Result, Len);
Result[Len] := S[I];
Inc(I);
end;
SetLength(Result, Len);
end;
function WordPosition(const N : Integer; const S : string; const WordDelims : TCharSet) : Integer;
var
Count, I : Integer;
begin
Count := 0;
I := 1;
Result := 0;
while (I <= Length(S)) and (Count <> N) do begin
{skip over delimiters}
while (I <= Length(S)) and (S[I] in WordDelims) do
Inc(I);
{if we're not beyond end of S, we're at the start of a word}
if I <= Length(S) then
Inc(Count);
{if not finished, find the end of the current word}
if Count <> N then
while (I <= Length(S)) and not (S[I] in WordDelims) do
Inc(I)
else
Result := I;
end;
end;
function DrawButtonFrame(Canvas : TCanvas; const Client : TRect;
IsDown, IsFlat : Boolean; Style : TButtonStyle) : TRect;
var
NewStyle : Boolean;
begin
Result := Client;
NewStyle := (Style = bsNew) or (NewStyleControls and (Style = bsAutoDetect));
if IsDown then begin
if NewStyle then begin
Frame3D(Canvas, Result, clWindowFrame, clBtnHighlight, 1);
if not IsFlat then
Frame3D(Canvas, Result, clBtnShadow, clBtnFace, 1);
end else begin
if IsFlat then
Frame3D(Canvas, Result, clWindowFrame, clBtnHighlight, 1)
else begin
Frame3D(Canvas, Result, clWindowFrame, clWindowFrame, 1);
Canvas.Pen.Color := clBtnShadow;
Canvas.PolyLine([Point(Result.Left, Result.Bottom - 1),
Point(Result.Left, Result.Top), Point(Result.Right, Result.Top)]);
end;
end;
end else begin
if NewStyle then begin
if IsFlat then
Frame3D(Canvas, Result, clBtnHighlight, clBtnShadow, 1)
else begin
Frame3D(Canvas, Result, clBtnHighlight, clWindowFrame, 1);
Frame3D(Canvas, Result, clBtnFace, clBtnShadow, 1);
end;
end else begin
if IsFlat then
Frame3D(Canvas, Result, clBtnHighlight, clWindowFrame, 1)
else begin
Frame3D(Canvas, Result, clWindowFrame, clWindowFrame, 1);
Frame3D(Canvas, Result, clBtnHighlight, clBtnShadow, 1);
end;
end;
end;
InflateRect(Result, -1, -1);
end;
function GetDisplayString(Canvas : TCanvas; const S : string;
MinChars, MaxWidth : Integer) : string;
var
iDots, EllipsisWidth, Extent, Len, Width : Integer;
ShowEllipsis : Boolean;
begin
{be sure that the Canvas Font is set before entering this routine}
EllipsisWidth := Canvas.TextWidth('...');
Len := Length(S);
Result := S;
Extent := Canvas.TextWidth(Result);
ShowEllipsis := False;
Width := MaxWidth;
while (Extent > Width) do begin
ShowEllipsis := True;
Width := MaxWidth - EllipsisWidth;
if Len > MinChars then begin
Delete(Result, Len, 1);
dec(Len);
end else
break;
Extent := Canvas.TextWidth(Result);
end;
if ShowEllipsis then begin
Result := Result + '...';
inc(Len, 3);
Extent := Canvas.TextWidth(Result);
iDots := 3;
while (iDots > 0) and (Extent > MaxWidth) do begin
Delete(Result, Len, 1);
Dec(Len);
Extent := Canvas.TextWidth(Result);
Dec(iDots);
end;
end;
end;
type
PCheckTaskInfo = ^TCheckTaskInfo;
TCheckTaskInfo = packed record
FocusWnd: HWnd;
Found: Boolean;
end;
{ - HWnd changed to TOvcHWnd for BCB Compatibility }
function CheckTaskWindow(Window: TOvcHWnd{HWnd};
Data: Longint): WordBool; stdcall;
begin
Result := True;
if PCheckTaskInfo(Data)^.FocusWnd = Window then begin
Result := False;
PCheckTaskInfo(Data)^.Found := True;
end;
end;
function IsForegroundTask : Boolean;
var
Info : TCheckTaskInfo;
begin
Info.FocusWnd := GetActiveWindow;
Info.Found := False;
{$IFNDEF DARWIN}
EnumThreadWindows(GetCurrentThreadID, @CheckTaskWindow, Longint(@Info));
{$ELSE}
EnumThreadWindows(LongWord(GetCurrentThreadID), @CheckTaskWindow, Longint(@Info));
{$ENDIF}
Result := Info.Found;
end;
procedure FixTextBuffer(InBuf, OutBuf : PChar; OutSize : Integer);
var
I, P : Integer;
begin
P := 0;
for I := 0 to StrLen(InBuf) do begin
if (InBuf[I] = #10) and ((I = 0) or (InBuf[I-1] <> #13)) then begin
OutBuf[P] := #13;
Inc(P);
end;
OutBuf[P] := InBuf[I];
{is outbuf full?}
if P = OutSize-1 then begin
{if so, terminate and exit}
OutBuf[OutSize] := #0;
Break;
end;
Inc(P);
end;
end;
{ - Hdc changed to TOvcHdc for BCB Compatibility }
procedure TransStretchBlt(DstDC: TOvcHdc{HDC}; DstX, DstY, DstW, DstH: Integer;
SrcDC: TOvcHdc{HDC}; SrcX, SrcY, SrcW, SrcH: Integer;
MaskDC: TOvcHdc{HDC};
MaskX, MaskY : Integer);
var
MemDC : HDC;
MemBmp : HBITMAP;
Save : THandle;
crText, crBack : TColorRef;
SystemPalette16, SavePal : HPALETTE;
begin
SavePal := 0;
MemDC := CreateCompatibleDC(0);
try
MemBmp := CreateCompatibleBitmap(SrcDC, SrcW, SrcH);
Save := SelectObject(MemDC, MemBmp);
SystemPalette16 := GetStockObject(DEFAULT_PALETTE);
SavePal := SelectPalette(SrcDC, SystemPalette16, False);
SelectPalette(SrcDC, SavePal, False);
if SavePal <> 0 then
SavePal := SelectPalette(MemDC, SavePal, True)
else
SavePal := SelectPalette(MemDC, SystemPalette16, True);
RealizePalette(MemDC);
StretchBlt(MemDC, 0, 0, SrcW, SrcH, MaskDC, MaskX, MaskY,
SrcW, SrcH, SrcCopy);
StretchBlt(MemDC, 0, 0, SrcW, SrcH, SrcDC, SrcX, SrcY, SrcW, SrcH,
SrcErase);
crText := SetTextColor(DstDC, $0);
crBack := SetBkColor(DstDC, $FFFFFF);
StretchBlt(DstDC, DstX, DstY, DstW, DstH, MaskDC, MaskX, MaskY,
SrcW, SrcH, SrcAnd);
StretchBlt(DstDC, DstX, DstY, DstW, DstH, MemDC, 0, 0,
SrcW, SrcH, SrcInvert);
SetTextColor(DstDC, crText);
SetBkColor(DstDC, crBack);
if Save <> 0 then
SelectObject(MemDC, Save);
DeleteObject(MemBmp);
finally
if SavePal <> 0 then
SelectPalette(MemDC, SavePal, False);
DeleteDC(MemDC);
end;
end;
function DefaultEpoch : Integer;
var
ThisYear : Word;
ThisMonth : Word;
ThisDay : Word;
begin
DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay);
Result := (ThisYear div 100) * 100;
end;
{function GenerateComponentName(PF : TCustomForm; const Root : string) : string;}
function GenerateComponentName(PF : TWinControl; const Root : string) : string;
var
I : Integer;
begin
if not IsValidIdent(Root) then
raise EComponentError.CreateFmt('''''%s'''' is not a valid component name',
[Root]);
I := 0;
repeat
Inc(I);
Result := Root + IntToStr(I);
until (PF.FindComponent(Result) = nil);
end;
function PartialCompare(const S1, S2 : string) : Boolean;
var
L : Integer;
begin
{and empty string matches nothing}
Result := False;
L := MinI(Length(S1), Length(S2));
if L > 0 then
Result := AnsiUpperCase(Copy(S1, 1, L)) = AnsiUpperCase(Copy(S2, 1, L));
end;
function PathEllipsis(const S : string; MaxWidth : Integer) : string;
{ PathEllipsis function. Trims a path down to the }
{ specified number of pixels. For example, }
{ 'd:\program files\my stuff\some long document.txt' }
{ becomes 'd:\...\some long...' or a variation thereof }
{ depending on the value of MaxWidth. }
var
R : TRect;
BM : TBitmap;
NCM : TNonClientMetrics;
begin
if MaxWidth = 0 then begin
Result := S;
Exit;
end;
NCM.cbSize := SizeOf(NCM);
SystemParametersInfo(
SPI_GETNONCLIENTMETRICS, NCM.cbSize, @NCM, 0);
BM := TBitmap.Create;
try
BM.Canvas.Font.Handle := CreateFontIndirect(NCM.lfMenuFont);
if BM.Canvas.TextWidth(S) < MaxWidth then begin
Result := S;
Exit;
end;
Result := ExtractFilePath(S);
Delete(Result, Length(Result), 1);
while BM.Canvas.TextWidth(Result + '\...\' + ExtractFileName(S)) > MaxWidth do begin
{ Start trimming the path, working backwards }
Result := ExtractFilePath(Result);
Delete(Result, Length(Result), 1);
{ Only drive letter left so break out of loop. }
if Length(Result) = 2 then
Break;
end;
{ Add the filename back onto the modified path. }
Result := Result + '\...\' + ExtractFileName(S);
{ Still too long? }
if BM.Canvas.TextWidth(Result) > MaxWidth then begin
R := Rect(0, 0, MaxWidth, 0);
DrawText(BM.Canvas.Handle, PChar(Result), -1,
R, DT_SINGLELINE or DT_END_ELLIPSIS or DT_MODIFYSTRING or DT_CALCRECT);
end;
finally
BM.Free;
end;
end;
function CreateDisabledBitmap(FOriginal : TBitmap; OutlineColor : TColor) : TBitmap;
{-create TBitmap object with disabled glyph}
const
ROP_DSPDxax = $00E20746;
var
MonoBmp : TBitmap;
IRect : TRect;
begin
IRect := Rect(0, 0, FOriginal.Width, FOriginal.Height);
Result := TBitmap.Create;
try
Result.Width := FOriginal.Width;
Result.Height := FOriginal.Height;
MonoBmp := TBitmap.Create;
try
with MonoBmp do begin
Assign(FOriginal);
HandleType := bmDDB;
Canvas.Brush.Color := OutlineColor;
if Monochrome then begin
Canvas.Font.Color := clWhite;
Monochrome := False;
Canvas.Brush.Color := clWhite;
end;
Monochrome := True;
end;
with Result.Canvas do begin
Brush.Color := clBtnFace;
FillRect(IRect);
Brush.Color := clBtnHighlight;
SetTextColor(Handle, clBlack);
SetBkColor(Handle, clWhite);
BitBlt(Handle, 1, 1, WidthOf(IRect), HeightOf(IRect),
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
Brush.Color := clBtnShadow;
SetTextColor(Handle, clBlack);
SetBkColor(Handle, clWhite);
BitBlt(Handle, 0, 0, WidthOf(IRect), HeightOf(IRect),
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
end;
finally
MonoBmp.Free;
end;
except
Result.Free;
raise;
end;
end;
type
TParentControl = class(TWinControl);
procedure CopyParentImage(Control : TControl; Dest : TCanvas);
var
I : Integer;
Count : Integer;
X, Y : Integer;
OldDC : Integer;
DC : hDC;
R : TRect;
SelfR : TRect;
CtlR : TRect;
begin
if Control.Parent = nil then
Exit;
Count := Control.Parent.ControlCount;
DC := Dest.Handle;
SelfR := Bounds(Control.Left, Control.Top, Control.Width, Control.Height);
X := -Control.Left; Y := -Control.Top;
{copy parent control image}
OldDC := SaveDC(DC);
SetViewportOrgEx(DC, X, Y, nil);
IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth, Control.Parent.ClientHeight);
TParentControl(Control.Parent).PaintWindow(DC);
RestoreDC(DC, OldDC);
{copy images of graphic controls}
for I := 0 to Count - 1 do begin
if (Control.Parent.Controls[I] <> nil) and
not (Control.Parent.Controls[I] is TWinControl) then begin
if Control.Parent.Controls[I] = Control then
Break;
with Control.Parent.Controls[I] do begin
CtlR := Bounds(Left, Top, Width, Height);
if Bool(IntersectRect(R, SelfR, CtlR)) and Visible then begin
OldDC := SaveDC(DC);
SetViewportOrgEx(DC, Left + X, Top + Y, nil);
IntersectClipRect(DC, 0, 0, Width, Height);
Perform(WM_PAINT, DC, 0);
RestoreDC(DC, OldDC);
end;
end;
end;
end;
end;
{ - Hdc changed to TOvcHdc for BCB Compatibility }
procedure DrawTransparentBitmapPrim(DC : TOvcHdc{HDC}; Bitmap : HBitmap;
xStart, yStart, Width, Height : Integer; Rect : TRect;
TransparentColor : TColorRef);
{-draw transparent bitmap}
var
{$IFNDEF LCL}
BM : Windows.TBitmap;
{$ELSE}
BM : LclType.tagBITMAP;
{$ENDIF}
cColor : TColorRef;
bmAndBack : hBitmap;
bmAndObject : hBitmap;
bmAndMem : hBitmap;
bmSave : hBitmap;
bmBackOld : hBitmap;
bmObjectOld : hBitmap;
bmMemOld : hBitmap;
bmSaveOld : hBitmap;
hdcMem : hDC;
hdcBack : hDC;
hdcObject : hDC;
hdcTemp : hDC;
hdcSave : hDC;
ptSize : TPoint;
ptRealSize : TPoint;
ptBitSize : TPoint;
ptOrigin : TPoint;
begin
hdcTemp := CreateCompatibleDC(DC);
SelectObject(hdcTemp, Bitmap);
GetObject(Bitmap, SizeOf(BM), @BM);
ptRealSize.x := MinL(Rect.Right - Rect.Left, BM.bmWidth - Rect.Left);
ptRealSize.y := MinL(Rect.Bottom - Rect.Top, BM.bmHeight - Rect.Top);
DPtoLP(hdcTemp, ptRealSize, 1);
ptOrigin.x := Rect.Left;
ptOrigin.y := Rect.Top;
{convert from device to logical points}
DPtoLP(hdcTemp, ptOrigin, 1);
{get width of bitmap}
ptBitSize.x := BM.bmWidth;
{get height of bitmap}
ptBitSize.y := BM.bmHeight;
DPtoLP(hdcTemp, ptBitSize, 1);
if (ptRealSize.x = 0) or (ptRealSize.y = 0) then begin
ptSize := ptBitSize;
ptRealSize := ptSize;
end else
ptSize := ptRealSize;
if (Width = 0) or (Height = 0) then begin
Width := ptSize.x;
Height := ptSize.y;
end;
{create DCs to hold temporary data}
hdcBack := CreateCompatibleDC(DC);
hdcObject := CreateCompatibleDC(DC);
hdcMem := CreateCompatibleDC(DC);
hdcSave := CreateCompatibleDC(DC);
{create a bitmap for each DC}
{monochrome DC}
bmAndBack := CreateBitmap(ptSize.x, ptSize.y, 1, 1, nil);
bmAndObject := CreateBitmap(ptSize.x, ptSize.y, 1, 1, nil);
bmAndMem := CreateCompatibleBitmap(DC, MaxL(ptSize.x, Width), MaxL(ptSize.y, Height));
bmSave := CreateCompatibleBitmap(DC, ptBitSize.x, ptBitSize.y);
{select a bitmap object to store pixel data}
bmBackOld := SelectObject(hdcBack, bmAndBack);
bmObjectOld := SelectObject(hdcObject, bmAndObject);
bmMemOld := SelectObject(hdcMem, bmAndMem);
bmSaveOld := SelectObject(hdcSave, bmSave);
SetMapMode(hdcTemp, GetMapMode(DC));
{save the bitmap sent here, it will be overwritten}
BitBlt(hdcSave, 0, 0, ptBitSize.x, ptBitSize.y, hdcTemp, 0, 0, SRCCOPY);
{set the background color of the source DC to the color,}
{contained in the parts of the bitmap that should be transparent}
cColor := SetBkColor(hdcTemp, TransparentColor);
{create the object mask for the bitmap by performing a BitBlt()}
{from the source bitmap to a monochrome bitmap}
BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, ptOrigin.x, ptOrigin.y, SRCCOPY);
{set the background color of the source DC back to the original color}
SetBkColor(hdcTemp, cColor);
{create the inverse of the object mask}
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
{copy the background of the main DC to the destination}
BitBlt(hdcMem, 0, 0, Width, Height, DC, xStart, yStart, SRCCOPY);
{mask out the places where the bitmap will be placed}
StretchBlt(hdcMem, 0, 0, Width, Height, hdcObject, 0, 0, ptSize.x, ptSize.y, SRCAND);
{mask out the transparent colored pixels on the bitmap}
BitBlt(hdcTemp, ptOrigin.x, ptOrigin.y, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
{XOR the bitmap with the background on the destination DC}
StretchBlt(hdcMem, 0, 0, Width, Height, hdcTemp, ptOrigin.x, ptOrigin.y, ptSize.x, ptSize.y, SRCPAINT);
{copy the destination to the screen}
BitBlt(DC, xStart, yStart, MaxL(ptRealSize.x, Width), MaxL(ptRealSize.y, Height), hdcMem, 0, 0, SRCCOPY);
{place the original bitmap back into the bitmap sent}
BitBlt(hdcTemp, 0, 0, ptBitSize.x, ptBitSize.y, hdcSave, 0, 0, SRCCOPY);
{delete the memory bitmaps}
DeleteObject(SelectObject(hdcBack, bmBackOld));
DeleteObject(SelectObject(hdcObject, bmObjectOld));
DeleteObject(SelectObject(hdcMem, bmMemOld));
DeleteObject(SelectObject(hdcSave, bmSaveOld));
{delete the memory DCs}
DeleteDC(hdcMem);
DeleteDC(hdcBack);
DeleteDC(hdcObject);
DeleteDC(hdcSave);
DeleteDC(hdcTemp);
end;
procedure DrawTransparentBitmap(Dest : TCanvas; X, Y, W, H : Integer;
Rect : TRect; Bitmap : TBitmap; TransparentColor : TColor);
var
MemImage : TBitmap;
R : TRect;
begin
MemImage := TBitmap.Create;
try
R := Bounds(0, 0, Bitmap.Width, Bitmap.Height);
if TransparentColor = clNone then begin
if (WidthOf(Rect) <> 0) and (HeightOf(Rect) <> 0) then
R := Rect;
MemImage.Width := WidthOf(R);
MemImage.Height := HeightOf(R);
MemImage.Canvas.CopyRect(Bounds(0, 0, MemImage.Width, MemImage.Height),
Bitmap.Canvas, R);
if (W = 0) or (H = 0) then
Dest.Draw(X, Y, MemImage)
else
Dest.StretchDraw(Bounds(X, Y, W, H), MemImage);
end else begin
MemImage.Width := WidthOf(R);
MemImage.Height := HeightOf(R);
MemImage.Canvas.CopyRect(R, Bitmap.Canvas, R);
if TransparentColor = clDefault then
TransparentColor := MemImage.Canvas.Pixels[0, MemImage.Height - 1];
DrawTransparentBitmapPrim(Dest.Handle, MemImage.Handle, X, Y, W, H,
Rect, ColorToRGB(TransparentColor and not $02000000));
end;
finally
MemImage.Free;
end;
end;
function WidthOf(const R : TRect) : Integer;
begin
Result := R.Right - R.Left;
end;
function HeightOf(const R : TRect) : Integer;
begin
Result := R.Bottom - R.Top;
end;
procedure DebugOutput(const S : string);
begin
OutputDebugString(PChar(S));
OutputDebugString(#13#10);
end;
end.