Componentes.Terceros.jvcl/official/3.00/archive/JvClxUtils.pas

683 lines
18 KiB
ObjectPascal

{-----------------------------------------------------------------------------
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/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvClxUtils.pas released on 2003-10-25.
The Initial Developer of the Original Code is Marcel Bestebroer
Portions created by Andreas Hausladen are Copyright (C) 2003 Andreas Hausladen,
[Andreas dott Hausladen att gmx dott de] and André Snepvangers
All Rights Reserved.
Contributor(s):
Last Modified: 2003-10-31
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Known Issues:
-----------------------------------------------------------------------------}
{$I jvcl.inc}
unit JvClxUtils;
interface
uses
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF MSWINDOWS}
{$IFDEF LINUX}
Libc,
{$ENDIF LINUX}
{$IFDEF VCL}
Graphics,
{$ENDIF VCL}
{$IFDEF VisualCLX}
Qt, QTypes, Types, QGraphics,
{$ENDIF VisualCLX}
SysUtils, Classes;
{$IFDEF LINUX}
type
TColorRef = Integer;
{$ENDIF LINUX}
{$IFDEF VisualCLX}
const
VK_UP = Key_Up;
VK_DOWN = Key_Down;
VK_RIGHT = Key_Right;
VK_LEFT = Key_Left;
VK_ESCAPE = Key_Escape;
VK_TAB = Key_Tab;
VK_SPACE = Key_Space;
VK_ENTER = Key_Enter;
VK_RETURN = Key_Return;
VK_BACKTAB = Key_Backtab;
VK_BACKSPACE = Key_Backspace;
VK_PRIOR = Key_Prior;
VK_NEXT = Key_Next;
VK_HOME = Key_Home;
VK_END = Key_End;
VK_ADD = Key_Plus;
VK_SUBTRACT = Key_Minus;
function GetSysColor(Color: Integer): TColorRef;
procedure SetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement);
procedure GetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement);
function IsWindowVisible(Handle: QWidgetH): Boolean;
function IsWindowEnabled(Handle: QWidgetH): Boolean;
procedure EnableWindow(Handle: QWidgetH; Value: Boolean);
procedure SwitchToThisWindow(Handle: QWidgetH; Restore: Boolean);
procedure SetFocus(Handle: QWidgetH);
function RGB(Red, Green, Blue: Integer): TColorRef;
function GetBValue(Col: TColorRef): Integer;
function GetGValue(Col: TColorRef): Integer;
function GetRValue(Col: TColorRef): Integer;
{$IFDEF LINUX}
function GetTickCount: Cardinal;
function MakeIntResource(Value: Integer): PChar;
{$ENDIF LINUX}
type
TSysMetrics =
(
SM_CXSCREEN, SM_CYSCREEN,
SM_CXVSCROLL, SM_CYVSCROLL,
SM_CXSMICON, SM_CXICON,
SM_CXBORDER, SM_CYBORDER,
SM_CXFRAME, SM_CYFRAME
);
// limited implementation of
function GetSystemMetrics(PropItem: TSysMetrics): Integer;
function TruncatePath(const FilePath: string; Canvas: TCanvas; MaxLen: Integer): string;
function TruncateName(const Name: String; Canvas: TCanvas; MaxLen: Integer): string;
const
// constants for Canvas.TextRect converted from enummeration
AlignLeft = 1; // $0001
AlignRight = 2; // $0002
AlignHCenter = 4; // $0004
AlignTop = 8; // $0008
AlignBottom = 16; // $0010
AlignVCenter = 32; // $0020
AlignCenter = 36; // $0024
SingleLine = 64; // $0040
DontClip = 128; // $0080
ExpandTabs = 256; // $0100
ShowPrefix = 512; // $0200
WordBreak = 1024; // $0400
ModifyString = 2048; // $0800 // not supported by TextRect but by ClxDrawText
DontPrint = 4096; // $1000
ClipPath = 8192; // $2000 // not supported by TextRect but by ClxDrawText
ClipName = 16384; // $4000 // not supported by TextRect but by ClxDrawText
CalcRect = 32768; // $8000 // not supported by TextRect but by ClxDrawText
pf24bit = pf32bit;
{$ENDIF VisualCLX}
const
DT_ELLIPSIS = DT_END_ELLIPSIS;
{$IFDEF LINUX}
const
{ ClxDrawText() Format Flags }
DT_TOP = 0; // default
DT_LEFT = 0; // default
DT_CENTER = 1;
DT_RIGHT = 2;
DT_VCENTER = 4;
DT_BOTTOM = 8;
DT_WORDBREAK = $10;
DT_SINGLELINE = $20;
DT_EXPANDTABS = $40;
//DT_TABSTOP = $80;
DT_NOCLIP = $100;
//DT_EXTERNALLEADING = $200;
DT_CALCRECT = $400;
DT_NOPREFIX = $800;
//DT_INTERNAL = $1000;
//DT_HIDEPREFIX = $00100000;
//DT_PREFIXONLY = $00200000;
//DT_EDITCONTROL = $2000;
DT_PATH_ELLIPSIS = $4000;
DT_END_ELLIPSIS = $8000;
DT_ELLIPSIS = DT_END_ELLIPSIS;
DT_MODIFYSTRING = $10000;
// DT_RTLREADING = $20000;
// DT_WORD_ELLIPSIS = $40000;
{ ClxExtTextOut() Format Flags }
ETO_OPAQUE = 2;
ETO_CLIPPED = 4;
//ETO_GLYPH_INDEX = $10;
ETO_RTLREADING = $80; // ignored
//ETO_NUMERICSLOCAL = $400;
//ETO_NUMERICSLATIN = $800;
//ETO_IGNORELANGUAGE = $1000;
//ETO_PDY = $2000;
{ ShowWindow() Commands }
SW_HIDE = 0;
SW_SHOWNORMAL = 1;
SW_NORMAL = 1;
SW_SHOWMINIMIZED = 2;
SW_SHOWMAXIMIZED = 3;
SW_MAXIMIZE = 3;
SW_SHOWNOACTIVATE = 4;
SW_SHOW = 5;
SW_MINIMIZE = 6;
SW_SHOWMINNOACTIVE = 7;
SW_SHOWNA = 8;
SW_RESTORE = 9;
SW_SHOWDEFAULT = 10;
SW_MAX = 10;
{$ENDIF LINUX}
function ClxDrawText(Canvas: TCanvas; var Caption: string; var R: TRect;
Flags: Integer): Integer;
function ClxDrawTextW(Canvas: TCanvas; var Caption: WideString; var R: TRect;
Flags: Integer): Integer;
function ClxExtTextOut(Canvas: TCanvas; X, Y: Integer; Flags: Integer;
Rect: PRect; const Text: string; lpDx: Pointer): Boolean;
function ClxExtTextOutW(Canvas: TCanvas; X, Y: Integer; Flags: Integer;
Rect: PRect; const Text: WideString; lpDx: Pointer): Boolean;
implementation
{$IFDEF VisualCLX}
var
SysColorPalette: TPalette = nil;
function GetSysColor(Color: Integer): TColorRef;
begin
if not Assigned(SysColorPalette) then
SysColorPalette := TPalette.Create;
Result := TColorRef(SysColorPalette.GetColor(Color));
end;
procedure EnableWindow(Handle: QWidgetH; Value: Boolean);
begin
QWidget_setEnabled(Handle, Value);
end;
procedure SetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement);
begin
with W.rcNormalPosition do
QWidget_setGeometry(Handle, Left, Top, Right - Left, Bottom - Top);
case W.ShowCmd of
SW_MINIMIZE, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE:
QWidget_showMinimized(Handle);
SW_MAXIMIZE:
QWidget_showMaximized(Handle);
SW_HIDE:
QWidget_hide(Handle);
else
QWidget_showNormal(Handle);
end;
end;
procedure GetWindowPlacement(Handle: QWidgetH; W: PWindowPlacement);
var
R : TRect;
begin
QWidget_geometry(Handle, @R);
W.rcNormalPosition.Left := R.Left;
W.rcNormalPosition.Top := R.Top;
W.rcNormalPosition.Right := R.Right;
W.rcNormalPosition.Bottom := R.Left;
if QWidget_isMinimized(Handle) then
W.showCmd := SW_SHOWMINIMIZED
else
if QWidget_isMaximized(Handle) then
W.showCmd := SW_SHOWMAXIMIZED
else
if not QWidget_isVisible(Handle) then
W.showCmd := SW_HIDE
else
W.showCmd := SW_SHOWNORMAL;
end;
function IsWindowVisible(Handle: QWidgetH): Boolean;
begin
Result := QWidget_isVisible(Handle);
end;
function IsWindowEnabled(Handle: QWidgetH): Boolean;
begin
Result := QWidget_isEnabled(Handle);
end;
procedure SetFocus(Handle: QWidgetH);
begin
QWidget_setFocus(Handle);
end;
procedure SetForegroundWindow(Handle: QWidgetH);
begin
QWidget_raise(Handle);
end;
procedure SwitchToThisWindow(Handle: QWidgetH; Restore: Boolean);
begin
if Restore then
QWidget_Show(Handle);
QWidget_setActiveWindow(Handle);
end;
// limited implementation of
function GetSystemMetrics(PropItem: TSysMetrics): Integer;
var
Size: TSize;
begin
case PropItem of
SM_CXVSCROLL:
begin
QStyle_scrollBarExtent(QApplication_style, @Size);
Result := Size.cx;
end;
SM_CYVSCROLL:
begin
QStyle_scrollBarExtent(QApplication_style, @Size);
Result := Size.cy;
end;
SM_CXSMICON:
Result := 16;
SM_CXICON:
Result := 32;
SM_CXSCREEN:
Result := QWidget_width(QApplication_desktop);
SM_CYSCREEN:
Result := QWidget_height(QApplication_desktop);
SM_CXBORDER, SM_CYBORDER:
Result := QClxStyle_defaultFrameWidth(QClxStyleH(QApplication_style)); // (probably) wrong ?
SM_CXFRAME, SM_CYFRAME:
Result := QClxStyle_defaultFrameWidth(QClxStyleH(QApplication_style)); // or this one
else
Result := 0;
end;
end;
function RGB(Red, Green, Blue: Integer): TColorRef;
begin
Result := (Blue shl 16) or (Green shl 8) or Red;
end;
function GetBValue(Col: TColorRef): Integer;
begin
Result := (Col shr 16) and $FF;
end;
function GetGValue(Col: TColorRef): Integer;
begin
Result := (Col shr 8) and $FF;
end;
function GetRValue(Col: TColorRef): Integer;
begin
Result := Col and $FF;
end;
{$IFDEF LINUX}
function GetTickCount: Cardinal;
var
Info: TSysInfo;
TimeVal: TTimeVal;
begin
sysinfo(Info);
gettimeofday(TimeVal, nil);
Result := Cardinal((Int64(Info.uptime) * 1000) + Round(TimeVal.tv_usec / 1000));
end;
function MakeIntResource(Value: Integer): PChar;
begin
Result := PChar(Value and $0000ffff);
end;
{$ENDIF LINUX}
const
cEllipsis = '...';
function TruncatePath(const FilePath: string; Canvas: TCanvas; MaxLen: Integer): string;
var
Paths: TStringList;
K, I, Start: Integer;
CurPath: string;
begin
if Canvas.TextWidth(FilePath) <= MaxLen then
Result := FilePath
else
begin // FilePath too long
Paths := TStringList.Create;
try
Paths.Delimiter := PathDelim;
Paths.DelimitedText := FilePath; // splits the filepath
if Length(Paths[0]) = 0 then
Start := 1
else
Start := 0;
for K := Start to Paths.Count - 2 do
begin
CurPath := Paths[K];
if Length(CurPath) > 2 then // this excludes ~ ..
begin
Paths[K] := cEllipsis; // replace with ellipsis
I := 1;
while Canvas.TextWidth(Paths.DelimitedText) <= MaxLen do
begin
Paths[K] := Copy(CurPath, I, MaxInt) + cEllipsis; // add a character
Inc(I);
end;
if I <> 1 then
begin
// remove last added character
Paths[K] := Copy(Paths[K], 2, MaxInt);
Result := Paths.DelimitedText ; // something /.../P../bin/file.tst
Exit; // ready
end;
end
end;
// not succeeded.
// replace /.../.../.../<filename> with .../<filename>
// before starting to minimize filename
for K := Paths.Count - 2 downto 1 do
Paths.Delete(K);
Paths[0] := cEllipsis;
if Canvas.TextWidth(Paths.DelimitedText) > MaxLen then
begin
CurPath := Paths[1];
Paths[1] := cEllipsis; // replace with ellipsis
I := 1 ;
while Canvas.TextWidth(Paths.DelimitedText) <= MaxLen do
begin
Paths[1] := Copy(CurPath, I, MaxInt) + cEllipsis;
Inc(I);
end;
if I <> 1 then
Paths[1] := Copy(Paths[1], 2, MaxInt);
end;
Result := Paths.DelimitedText; // will be something .../Progr...
finally
Paths.Free;
end;
end;
end;
function TruncateName(const Name: String; Canvas: TCanvas; MaxLen: Integer): string;
var
I: Integer;
begin
if Canvas.TextWidth(Name) <= MaxLen then
Result := Name
else
begin
Result := cEllipsis; // replace with ellipsis
I := 1;
while Canvas.TextWidth(Result) <= MaxLen do
begin
Result := Copy(Name, I, MaxInt) + cEllipsis; // add a character
Inc(I);
end;
if I <> 1 then
// remove last added character
Delete(Result, 1, 1);
end;
end;
{$ENDIF VisualCLX}
type
TOpenCanvas = class(TCanvas);
function ClxDrawText(Canvas: TCanvas; var Caption: string; var R: TRect;
Flags: Integer): Integer;
{$IFNDEF VCL}
var
W: WideString;
{$ENDIF VCL}
begin
{$IFDEF VCL}
TOpenCanvas(Canvas).Changing;
Result := DrawText(Canvas.Handle, PChar(Caption), Length(Caption), R, Flags);
TOpenCanvas(Canvas).Changed;
{$ELSE}
W := Caption;
Result := ClxDrawTextW(Canvas, W, R, Flags);
if Flags and DT_MODIFYSTRING <> 0 then
Caption := W;
{$ENDIF VCL}
end;
function ClxDrawTextW(Canvas: TCanvas; var Caption: WideString; var R: TRect;
Flags: Integer): Integer;
{$IFDEF VisualCLX}
var
Flgs: Word;
Text: string;
{$ENDIF VisualCLX}
begin
{$IFDEF VCL}
TOpenCanvas(Canvas).Changing;
Result := DrawTextW(Canvas.Handle, PWideChar(Caption), Length(Caption), R, Flags);
TOpenCanvas(Canvas).Changed;
{$ENDIF VCL}
{$IFDEF VisualCLX}
Text := Caption;
with Canvas do
begin
Flgs := 0;
if Flags and DT_SINGLELINE <> 0 then
Flgs := SingleLine;
if Flags and DT_WORDBREAK <> 0 then
Flgs := Flgs or WordBreak;
if Flags and DT_EXPANDTABS <> 0 then
Flgs := Flgs or ExpandTabs;
if Flags and DT_NOPREFIX = 0 then
Flgs := Flgs or ShowPrefix;
if Flags and DT_RIGHT <> 0 then
Flgs := Flgs or AlignRight
else
if Flags and DT_CENTER <> 0 then
Flgs := Flgs or AlignHCenter
else
Flgs := Flgs or AlignLeft ; // default
// vertical alignment
if Flags and DT_BOTTOM <> 0 then
Flgs := Flgs or AlignTop
else
if Flags and DT_VCENTER <> 0 then
Flgs := Flgs or AlignVCenter
else
Flgs := Flgs or AlignTop; // default
if Flags and DT_ELLIPSIS <> 0 then
Text := TruncateName(Text, Canvas, R.Right - R.Left)
else
if Flags and DT_PATH_ELLIPSIS <> 0 then
Text := TruncatePath(Text, Canvas, R.Right - R.Left)
else
if Flags and DT_CALCRECT <> 0 then
begin
TextExtent(Caption, R, Flgs);
Result := R.Bottom - R.Top;
Exit;
end;
Canvas.TextRect(R, R.Left, R.Top, Text, Flgs);
if Flags and DT_MODIFYSTRING <> 0 then
Caption := Text;
end;
Result := 1;
{$ENDIF VisualCLX}
end;
function ClxExtTextOut(Canvas: TCanvas; X, Y: Integer; Flags: Integer; Rect: PRect;
const Text: string; lpDx: Pointer): Boolean;
begin
{$IFDEF VCL}
TOpenCanvas(Canvas).Changing;
Result := ExtTextOut(Canvas.Handle, X, Y, Flags, Rect, PChar(Text),
Length(Text), lpDx);
TOpenCanvas(Canvas).Changed;
{$ELSE}
Result := ClxExtTextOutW(Canvas, X, Y, Flags, Rect, WideString(Text), lpDx);
{$ENDIF VCL}
end;
function ClxExtTextOutW(Canvas: TCanvas; X, Y: Integer; Flags: Integer;
Rect: PRect; const Text: WideString; lpDx: Pointer): Boolean;
{$IFDEF VisualCLX}
{ TODO missing feature: horizontal text alignment }
var
RecallBrush: TBrush;
RecallPenPos: TPoint;
WS: WideString;
Index, Width: Integer;
Dx: PInteger;
R, CellRect: TRect;
TextLen: Integer;
{$ENDIF VisualCLX}
begin
{$IFDEF VCL}
TOpenCanvas(Canvas).Changing;
Result := ExtTextOutW(Canvas.Handle, X, Y, Flags, Rect, PWideChar(Text),
Length(Text), lpDx);
TOpenCanvas(Canvas).Changed;
{$ENDIF VCL}
{$IFDEF VisualCLX}
Canvas.Start;
try
with Canvas do
begin
Result := False;
if (Text = '') then
Exit;
if (Flags and ETO_CLIPPED <> 0) and (Rect = nil) then
Flags := Flags and not ETO_CLIPPED;
RecallPenPos := PenPos;
Result := True;
RecallBrush := nil;
try
if Flags and ETO_OPAQUE <> 0 then
begin
if Brush.Style <> bsSolid then
begin
RecallBrush := TBrush.Create;
RecallBrush.Assign(Brush);
Brush.Style := bsSolid;
end;
if Rect <> nil then
FillRect(Rect^);
end
else
if Brush.Style = bsSolid then
begin
RecallBrush := TBrush.Create;
RecallBrush.Assign(Brush);
Brush.Style := bsClear;
end;
if lpDx = nil then
begin
if (Flags and ETO_CLIPPED <> 0) then
TextRect(Rect^, X, Y, Text)
else
TextOut(X, Y, Text);
end
else
begin
// put each char in its cell
TextLen := Length(Text);
if (Flags and ETO_OPAQUE <> 0) and (Rect = nil) then
begin
Dx := lpDx;
Width := 0;
for Index := 1 to TextLen do
begin
Inc(Width, Dx^);
Inc(Dx);
end;
R.Left := X;
R.Right := X + Width;
R.Top := Y;
R.Bottom := Y + TextHeight(Text);
FillRect(R);
end;
Dx := lpDx;
SetLength(WS, 1);
for Index := 1 to TextLen do
begin
if (Rect <> nil) and (X >= Rect^.Right) then
Break;
WS[1] := Text[Index];
if Flags and ETO_CLIPPED <> 0 then
begin
CellRect.Left := X;
CellRect.Right := X + Dx^;
CellRect.Top := Rect^.Top;
CellRect.Bottom := Rect^.Bottom;
if CellRect.Right > Rect^.Right then
CellRect.Right := Rect^.Right;
TextRect(R, X, Y, WS);
end
else
TextOut(X, Y, WS);
if Index = TextLen then
Break;
Inc(X, Dx^);
Inc(Dx);
end;
end;
finally
if Assigned(RecallBrush) then
begin
Brush.Assign(RecallBrush);
RecallBrush.Free;
end;
end;
PenPos := RecallPenPos;
end;
finally
Canvas.Stop;
end;
{$ENDIF VisualCLX}
end;
{$IFDEF VisualCLX}
initialization
finalization
FreeAndNil(SysColorPalette);
{$ENDIF VisualCLX}
end.