* Added CentrED+ code (thanks to StaticZ for his awesome work!)

This commit is contained in:
2015-05-01 12:23:03 +02:00
parent 2e62fd570a
commit 34637d40ce
97 changed files with 22628 additions and 4243 deletions

222
Client/GUI/AeroGlass.pas Normal file
View File

@@ -0,0 +1,222 @@
unit AeroGlass;
{$mode delphi}
//{$mode objfpc}{$H+}
interface
uses
//Windows, Forms, Graphics;
// os
Windows, UxTheme, ShellAPI, Win32Proc, Win32Extra,
// rtl
Classes, SysUtils,
// lcl
Forms, Controls, Graphics, Themes;//, LCLProc, LCLType;
type
_MARGINS = packed record
cxLeftWidth : Integer;
cxRightWidth : Integer;
cyTopHeight : Integer;
cyBottomHeight : Integer;
end;
PMargins = ^_MARGINS;
TMargins = _MARGINS;
DwmIsCompositionEnabledFunc = function(pfEnabled: PBoolean): HRESULT; stdcall;
DwmExtendFrameIntoClientAreaFunc = function(destWnd: HWND; const pMarInset: PMargins): HRESULT; stdcall;
SetLayeredWindowAttributesFunc = function(destWnd: HWND; cKey: TColor; bAlpha: Byte; dwFlags: DWord): BOOL; stdcall;
const
WS_EX_LAYERED = $80000;
LWA_COLORKEY = 1;
procedure GlassFormEx(frm: TForm; tmpMargins: TMargins; cBlurColorKey: TColor = clFuchsia);
procedure GlassForm(frm: TForm; cBlurColorKey: TColor = clFuchsia);
function WindowsAeroGlassCompatible: Boolean;
function CreateBitmap32(DC: HDC; W, H: Integer; var BitmapBits: Pointer): HBITMAP;
procedure DrawAlphaText(wnd: hwnd; DC: HDC; x,y: integer; txt: WideString);
implementation
// =============================================================================
// == Преобразование формы в AeroGlass
// =============================================================================
function WindowsAeroGlassCompatible: Boolean;
var
osVinfo: TOSVERSIONINFO;
begin
ZeroMemory(@osVinfo, SizeOf(osVinfo));
OsVinfo.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);
if (
(GetVersionEx(osVInfo) = True) and
(osVinfo.dwPlatformId = VER_PLATFORM_WIN32_NT) and
(osVinfo.dwMajorVersion >= 6)
)
then Result:=True
else Result:=False;
end;
procedure GlassFormEx(frm: TForm; tmpMargins: TMargins; cBlurColorKey: TColor = clFuchsia);
var
hDwmDLL: Cardinal;
fDwmIsCompositionEnabled: DwmIsCompositionEnabledFunc;
fDwmExtendFrameIntoClientArea: DwmExtendFrameIntoClientAreaFunc;
fSetLayeredWindowAttributesFunc: SetLayeredWindowAttributesFunc;
bCmpEnable: Boolean;
mgn: TMargins;
begin
{ Continue if Windows version is compatible }
if WindowsAeroGlassCompatible then begin
{ Continue if 'dwmapi' library is loaded }
hDwmDLL := LoadLibrary('dwmapi.dll');
if hDwmDLL <> 0 then begin
{ Get values }
@fDwmIsCompositionEnabled := GetProcAddress(hDwmDLL, 'DwmIsCompositionEnabled');
@fDwmExtendFrameIntoClientArea := GetProcAddress(hDwmDLL, 'DwmExtendFrameIntoClientArea');
@fSetLayeredWindowAttributesFunc := GetProcAddress(GetModulehandle(user32), 'SetLayeredWindowAttributes');
{ Continue if values are <> nil }
if (
(@fDwmIsCompositionEnabled <> nil) and
(@fDwmExtendFrameIntoClientArea <> nil) and
(@fSetLayeredWindowAttributesFunc <> nil)
)
then begin
{ Continue if composition is enabled }
fDwmIsCompositionEnabled(@bCmpEnable);
if bCmpEnable = True then begin
{ Set Form Color same as cBlurColorKey }
frm.Color := cBlurColorKey;
{ ... }
SetWindowLong(frm.Handle, GWL_EXSTYLE, GetWindowLong(frm.Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
{ ... }
fSetLayeredWindowAttributesFunc(frm.Handle, cBlurColorKey, 0, LWA_COLORKEY);
{ Set margins }
ZeroMemory(@mgn, SizeOf(mgn));
mgn.cxLeftWidth := tmpMargins.cxLeftWidth;
mgn.cxRightWidth := tmpMargins.cxRightWidth;
mgn.cyTopHeight := tmpMargins.cyTopHeight;
mgn.cyBottomHeight := tmpMargins.cyBottomHeight;
{ Extend Form }
fDwmExtendFrameIntoClientArea(frm.Handle,@mgn);
end;
end;
{ Free loaded 'dwmapi' library }
FreeLibrary(hDWMDLL);
end;
end;
end;
procedure GlassForm(frm: TForm; cBlurColorKey: TColor = clFuchsia);
var
tmpMargins: TMargins;
begin
{ If all margins are -1 the whole form will be aero glass}
tmpMargins.cxLeftWidth := 8;
tmpMargins.cxRightWidth := 8;
tmpMargins.cyBottomHeight := 25;
tmpMargins.cyTopHeight := 4;
{ FormName ; Margins ; TransparentColor }
GlassFormEx(frm, tmpMargins, cBlurColorKey);
end;
// =============================================================================
// == Вывод текста и изображений на форме AeroGlass
// =============================================================================
function CreateBitmap32(DC: HDC; W, H: Integer; var BitmapBits: Pointer): HBITMAP;
var
bi: BITMAPINFO;
begin
ZeroMemory(@bi, sizeof(BITMAPINFO));
with bi.bmiHeader do
begin
biSize := sizeof(BITMAPINFOHEADER);
biWidth := W;
biHeight := -H;
biCompression := BI_RGB;
biBitCount := 32;
biPlanes := 1;
biXPelsPerMeter := 0;
biYPelsPerMeter := 0;
biClrUsed := 0;
biClrImportant := 0;
end;
Result := CreateDIBSection(DC, bi, DIB_RGB_COLORS, BitmapBits, 0, 0);
end;
type
TDTTOpts = record
dwSize: Longword;
dwFlags: Longword;
crText: Longword;
crBorder: Longword;
crShadow: Longword;
eTextShadowType: Integer;
ptShadowOffset: TPoint;
iBorderSize: Integer;
iFontPropId: Integer;
iColorPropId: Integer;
iStateId: Integer;
fApplyOverlay: Integer;
iGlowSize: Integer;
pfnDrawTextCallback: Pointer;
lParam: Integer;
end;
var
hTheme: THandle;
procedure DrawAlphaText(wnd: hwnd; DC: HDC; x,y: integer; txt: WideString);
var
tr: trect;
txtOptions: TDTTOPTS;
hBmp: HBITMAP;
hBmpDC: HDC;
hFnt: HFont;
p: pointer;
ts: SIZE;
begin
hTheme := OpenThemeData(wnd, 'window');
hBmpDC := CreateCompatibleDC(0);
hFnt := CreateFont(-MulDiv(10, GetDeviceCaps(hBmpDC, LOGPIXELSY), 72), 0, 0, 0, FW_BOLD {FW_NORMAL}, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, 'arial');
SelectObject(hBmpDC, hFnt);
GetTextExtentPointW(hBmpDC, PWideChar(txt), length(txt), ts);
SetRect(tr, 0, 0, ts.cx + 5, ts.cy + 5);
hBmp := CreateBitmap32(hBmpDC, tr.Right, tr.Bottom, p);
SelectObject(hBmpDC, hBmp);
ZeroMemory(@txtOptions, sizeof(TDTTOPTS));
txtOptions.dwSize := sizeof(TDTTOPTS);
txtOptions.dwFlags := DTT_COMPOSITED or DTT_GLOWSIZE or DTT_TEXTCOLOR;
txtOptions.iGlowSize := 5;
txtOptions.crText := $00FF0000;
DrawThemeTextEx(hTheme, hBmpDC, 0, 0, PWideChar(txt), length(txt), DT_SINGLELINE or DT_vCENTER, @tr, @txtOptions);
BitBlt(dc, x, y, tr.Right, tr.Bottom, hBmpDC, 0, 0, SRCCOPY);
DeleteObject(hBmpDC);
DeleteObject(hBmp);
DeleteObject(hFnt);
CloseThemeData(hTheme);
end;
end.

368
Client/GUI/GlowLabel.pas Normal file
View File

@@ -0,0 +1,368 @@
unit GlowLabel;
{******************************************************************}
{ GlowLabel }
{ }
{ home page : http://www.winningcubed.de }
{ email : martin.walter@winningcubed.de }
{ }
{ date : 15-04-2007 }
{ }
{ version : 1.0 }
{ }
{ Use of this file is permitted for commercial and non-commercial }
{ use, as long as the author is credited. }
{ This file (c) 2007 Martin Walter }
{ }
{ This Software is distributed on an "AS IS" basis, WITHOUT }
{ WARRANTY OF ANY KIND, either express or implied. }
{ }
{ *****************************************************************}
interface
uses
Windows, Classes, StdCtrls {$IFDEF USETNT}, TntStdCtrls{$ENDIF};
type
TCustomGlowLabel = class({$IFDEF USETNT}TTntCustomLabel{$ELSE}TCustomLabel{$ENDIF})
private
FGlow: Boolean;
FGlowSize: Integer;
FOldGlowSize: Integer;
FBoundsWithGlow: Boolean;
procedure SetGlow(const Value: Boolean);
procedure SetGlowSize(const Value: Integer);
function IsGlow: Boolean;
function GetExpansion(GlowSize: Integer): Integer;
protected
procedure DoDrawText(var Rect: TRect; Flags: Longint); override;
procedure AdjustBounds; override;
property Glow: Boolean read FGlow write SetGlow;
property GlowSize: Integer read FGlowSize write SetGlowSize;
public
constructor Create(AOwner: TComponent); override;
end;
TGlowLabel = class(TCustomGlowLabel)
published
property Align;
property Alignment;
property Anchors;
property AutoSize;
property BiDiMode;
property Caption;
property Color nodefault;
property Constraints;
property DragCursor;
property DragKind;
property DragMode;
property EllipsisPosition;
property Enabled;
property FocusControl;
property Font;
property Glow;
property GlowSize;
property ParentBiDiMode;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowAccelChar;
property ShowHint;
property Transparent;
property Layout;
property Visible;
property WordWrap;
property OnClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnMouseActivate;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseEnter;
property OnMouseLeave;
property OnStartDock;
property OnStartDrag;
end;
procedure Register;
implementation
uses
Controls, Forms, Graphics, SysUtils, Math, DwmApi, Themes, UxTheme;
function StrScanW(const Str: PWideChar; Chr: WideChar): PWideChar;
begin
Result := Str;
while Result^ <> Chr do
begin
if Result^ = #0 then
begin
Result := nil;
Exit;
end;
Inc(Result);
end;
end;
function LastDelimiterW(const Delimiters, S: WideString): Integer;
var
P: PWideChar;
begin
Result := Length(S);
P := PWideChar(Delimiters);
while Result > 0 do
begin
if (S[Result] <> #0) and (StrScanW(P, S[Result]) <> nil) then
Exit;
Dec(Result);
end;
end;
{ TGlowCustomLabel }
procedure TCustomGlowLabel.AdjustBounds;
const
WordWraps: array[Boolean] of Word = (0, DT_WORDBREAK);
var
DC: HDC;
Rect, Bounds, CalcRect: TRect;
AAlignment: TAlignment;
Expand: Integer;
DoSetBounds: Boolean;
begin
DoSetBounds := False;
Bounds := BoundsRect;
Rect := Bounds;
if (IsGlow and (csReading in ComponentState)) then
begin
FBoundsWithGlow := True;
FOldGlowSize := FGlowSize;
end;
if FBoundsWithGlow then
begin
Expand := GetExpansion(FOldGlowSize);
Inc(Rect.Left, Expand);
Inc(Rect.Top, Expand);
Dec(Rect.Right, Expand);
Dec(Rect.Bottom, Expand);
FBoundsWithGlow := False;
DoSetBounds := True;
end;
if not ((csReading in ComponentState) or
(csLoading in ComponentState)) and
AutoSize then
begin
DC := GetDC(0);
Canvas.Handle := DC;
CalcRect.Left := 0;
CalcRect.Top := 0;
DoDrawText(CalcRect, (DT_EXPANDTABS or DT_CALCRECT) or WordWraps[WordWrap]);
Canvas.Handle := 0;
ReleaseDC(0, DC);
AAlignment := Alignment;
if UseRightToLeftAlignment then
ChangeBiDiModeAlignment(AAlignment);
if AAlignment = taRightJustify then
Rect.Left := Rect.Right - CalcRect.Right;
Rect.Right := Rect.Left + CalcRect.Right;
Rect.Bottom := Rect.Top + CalcRect.Bottom;
DoSetBounds := True;
end;
if IsGlow then
begin
FBoundsWithGlow := True;
Expand := GetExpansion(FGlowSize);
Dec(Rect.Left, Expand);
Dec(Rect.Top, Expand);
Inc(Rect.Right, Expand);
Inc(Rect.Bottom, Expand);
FOldGlowSize := FGlowSize;
DoSetBounds := True;
end;
if DoSetBounds then
SetBounds(Rect.Left, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
end;
constructor TCustomGlowLabel.Create(AOwner: TComponent);
begin
inherited;
FGlow := False;
FGlowSize := 10;
FOldGlowSize := 0;
FBoundsWithGlow := False;
end;
procedure TCustomGlowLabel.DoDrawText(var Rect: TRect; Flags: Integer);
procedure DoDrawThemeTextEx(DC: HDC; const Text: WideString; TextLen: Integer;
var TextRect: TRect; TextFlags: Cardinal);
var
Options: TDTTOpts;
begin
FillChar(Options, SizeOf(Options), 0);
Options.dwSize := SizeOf(Options);
Options.dwFlags := DTT_TEXTCOLOR or DTT_COMPOSITED;
if IsGlow then
begin
Options.dwFlags := Options.dwFlags or DTT_GLOWSIZE;
Options.iGlowSize := FGlowSize;
end;
Options.crText := ColorToRGB(Canvas.Font.Color);
with ThemeServices.GetElementDetails(teEditTextNormal) do
DrawThemeTextEx(ThemeServices.Theme[teEdit], DC, Part, State,
PWideChar(Text), TextLen, TextFlags, @TextRect, Options);
end;
procedure DrawText(DC: HDC; const Text: WideString; TextLen: Integer;
var TextRect: TRect; TextFlags: Cardinal);
var
LForm: TCustomForm;
PaintOnGlass: Boolean;
Expand: Integer;
begin
PaintOnGlass := ThemeServices.ThemesEnabled and DwmCompositionEnabled and
not (csDesigning in ComponentState);
if PaintOnGlass then
begin
LForm := GetParentForm(Self);
PaintOnGlass := (LForm <> nil) and LForm.GlassFrame.FrameExtended and
LForm.GlassFrame.IntersectsControl(Self);
end;
if IsGlow and (Flags and DT_CALCRECT = 0) then
begin
Expand := GetExpansion(FGlowSize);
case Alignment of
taLeftJustify: OffsetRect(TextRect, Expand, 0);
taRightJustify: OffsetRect(TextRect, -Expand, 0);
end;
case Layout of
tlTop: OffsetRect(TextRect, 0, Expand);
tlBottom: OffsetRect(TextRect, 0, -Expand);
end;
end;
if PaintOnGlass and (Flags and DT_CALCRECT = 0) then
DoDrawThemeTextEx(DC, Text, TextLen, TextRect, TextFlags)
else
Windows.DrawTextW(DC, PWideChar(Text), TextLen, TextRect, TextFlags);
end;
const
EllipsisStr = '...';
Ellipsis: array[TEllipsisPosition] of Longint = (0, DT_PATH_ELLIPSIS,
DT_END_ELLIPSIS, DT_WORD_ELLIPSIS);
var
Text, DText: WideString;
NewRect: TRect;
Height, Delim: Integer;
begin
Text := Caption;
if (Flags and DT_CALCRECT <> 0) and ((Text = '') or ShowAccelChar and
(Text[1] = '&') and (Text[2] = #0)) then
Text := Text + ' ';
if not ShowAccelChar then
Flags := Flags or DT_NOPREFIX;
Flags := DrawTextBiDiModeFlags(Flags);
Canvas.Font := Font;
if (EllipsisPosition <> epNone) and not AutoSize then
begin
DText := Text;
Flags := Flags and not DT_EXPANDTABS;
Flags := Flags or Ellipsis[EllipsisPosition];
if WordWrap and (EllipsisPosition in [epEndEllipsis, epWordEllipsis]) then
begin
repeat
NewRect := Rect;
Dec(NewRect.Right, Canvas.TextWidth(EllipsisStr));
Windows.DrawTextW(Canvas.Handle, PWideChar(DText), Length(DText), NewRect, Flags or DT_CALCRECT);
Height := NewRect.Bottom - NewRect.Top;
if (Height > ClientHeight) and (Height > Canvas.Font.Height) then
begin
Delim := LastDelimiterW(' '#9, Text);
if Delim = 0 then
Delim := Length(Text);
Dec(Delim);
Text := Copy(Text, 1, Delim);
DText := Text + EllipsisStr;
if Text = '' then
Break;
end else
Break;
until False;
end;
if Text <> '' then
Text := DText;
end;
if not Enabled then
begin
OffsetRect(Rect, 1, 1);
Canvas.Font.Color := clBtnHighlight;
DrawText(Canvas.Handle, Text, Length(Text), Rect, Flags);
OffsetRect(Rect, -1, -1);
Canvas.Font.Color := clBtnShadow;
DrawText(Canvas.Handle, Text, Length(Text), Rect, Flags);
end
else
DrawText(Canvas.Handle, Text, Length(Text), Rect, Flags);
end;
function TCustomGlowLabel.GetExpansion(GlowSize: Integer): Integer;
begin
Result := Ceil(GlowSize / 2) + 1;
end;
function TCustomGlowLabel.IsGlow: Boolean;
begin
Result := FGlow and (FGlowSize > 0);
end;
procedure TCustomGlowLabel.SetGlow(const Value: Boolean);
begin
if FGlow <> Value then
begin
FGlow := Value;
AdjustBounds;
Invalidate;
end;
end;
procedure TCustomGlowLabel.SetGlowSize(const Value: Integer);
begin
if FGlowSize <> Value then
begin
FGlowSize := Value;
AdjustBounds;
Invalidate;
end;
end;
procedure Register;
begin
RegisterComponents('MWK', [TGlowLabel]);
end;
end.

703
Client/GUI/VirtualList.pas Normal file
View File

@@ -0,0 +1,703 @@
unit VirtualList;
{$mode delphi}{$H+}
interface
uses
Windows, Forms, Controls, StdCtrls, Graphics, Classes, SysUtils, VirtualTrees,
Logging, LMessages, ShellAPI, LCLIntf, Math;
type
{$Z4} INPUTTYPE = (INPUT_MOUSE = $00, INPUT_KEYBOARD = $01, INPUT_HARDWARE = $02);
{$Z4} KEYEVENTF = (KEYEVENTF_EXTENDEDKEY = $01, KEYEVENTF_KEYUP = $02, KEYEVENTF_SCANCODE = $04, KEYEVENTF_UNICODE = $08);
TKEYINPUT = record
itype: INPUTTYPE;
// tagKEYBDINPUT
wVk: WORD;
wScan: WORD;
dwFlags: KEYEVENTF;
time: DWORD;
dwExtraInfo: ULONG_PTR;
end;
PVirtualItem = ^TVirtualItem;
TVirtualItem = record
NextItem: PVirtualItem;
Node: PVirtualNode;
Column: Word;
Selected: Boolean;
end;
TVirtualList = class(TVirtualDrawTree)
private
HintCanvas: TCanvas;
TileColumn: Word;
FirstItem: PVirtualItem;
LastItem: PVirtualItem;
LastSelected: PVirtualItem;
ClearAll: Boolean;
FSelectionCount: DWord;
FTilesCount: DWord;
function GetSelected(Item: PVirtualItem): Boolean;
procedure SetSelected(Item: PVirtualItem; Value: Boolean);
function GetFocusedNode(): PVirtualItem;
procedure SetFocusedNode(Item: PVirtualItem);
public
constructor Create(AOwner: TComponent); override;
procedure UpdateHintCanvas(newCanvas: TCanvas);
procedure DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: TRect); override;
procedure UpdateTileColumn(count: Word; Forse: Boolean = False);
//function AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode; override;
function AddChild(ParentItem: PVirtualNode; UserData: Pointer = nil): PVirtualNode; override;
function AddItem(ParentItem: PVirtualItem; UserData: Pointer = nil): PVirtualItem;
function GetFirst(ConsiderChildrenAbove: Boolean = False): PVirtualItem;
function GetNext(Item: PVirtualItem; ConsiderChildrenAbove: Boolean = False): PVirtualItem;
function GetLast(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualItem;
function GetItemAt(Node: PVirtualNode; Column: TColumnIndex): PVirtualItem;
function GetNodeData(Item: PVirtualItem): Pointer;
procedure Clear; override;
function GetFirstSelected(ConsiderChildrenAbove: Boolean = False): PVirtualItem;
function GetNextSelected(Item: PVirtualItem; ConsiderChildrenAbove: Boolean = False): PVirtualItem;
property Selected[Item: PVirtualItem]: Boolean read GetSelected write SetSelected;
procedure ClearSelection;
procedure DeleteSelectedNodes; override;
property FocusedNode: PVirtualItem read GetFocusedNode write SetFocusedNode;
procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
procedure PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: Integer); override;
procedure DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; const R: TRect); override;
procedure HandleMouseDblClick(var Message: TLMMouse; const HitInfo: THitInfo); override;
procedure HandleMouseDown(var Message: TLMMouse; var HitInfo: THitInfo); override;
procedure HandleMouseUp(var Message: TLMMouse; const HitInfo: THitInfo); override;
property SelectedCount: Dword read FSelectionCount;
property TilesCount: Dword read FTilesCount;
end;
function SendInput(nInputs:UINT; pInputs:POINTER; cbSize:INTEGER):UINT; stdcall; external 'User32.dll' name 'SendInput';
Implementation
//----------------------------------------------------------------------------------------------------------------------
constructor TVirtualList.Create(AOwner: TComponent);
var
Pvdt: TVirtualDrawTree;
column: TVirtualTreeColumn;
c: Integer;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.Create START');
if not (AOwner is TVirtualDrawTree) then begin
Logger.Send([lcClient, lcDebug], 'TVirtualTree.Create(AOwner: TVirtualDrawTree) must get argument TVirtualDrawTree');
Assert(not (AOwner is TVirtualDrawTree), 'TVirtualTree.Create(AOwner: TVirtualDrawTree) must get argument TVirtualDrawTree');
Abort;
Halt;
end;
inherited Create(AOwner.Owner);
Pvdt := TVirtualDrawTree(AOwner);
Self.Parent := Pvdt.Parent;
FSelectionCount := 0;
FTilesCount:= 0;
TileColumn := 1;
ClearAll := True;
// Копирование свойств
Self.AnchorSideTop.Control := Pvdt.AnchorSideTop.Control;
Self.AnchorSideTop.Side := Pvdt.AnchorSideTop.Side;
Self.AnchorSideLeft.Control := Pvdt.AnchorSideLeft.Control;
Self.AnchorSideLeft.Side := Pvdt.AnchorSideLeft.Side;
Self.AnchorSideRight.Control := Pvdt.AnchorSideRight.Control;
Self.AnchorSideRight.Side := Pvdt.AnchorSideRight.Side;
Self.AnchorSideBottom.Control := Pvdt.AnchorSideBottom.Control;
Self.AnchorSideBottom.Side := Pvdt.AnchorSideBottom.Side;
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.Create 0');
Self.Left := Pvdt.Left;
Self.Height := Pvdt.Height;
Self.Hint := Pvdt.Hint;
Self.Top := Pvdt.Top;
Self.Width := Pvdt.Width;
Self.Anchors := Pvdt.Anchors;
Self.BorderSpacing.Top := Pvdt.BorderSpacing.Top;
Self.BorderSpacing.Left := Pvdt.BorderSpacing.Left;
Self.BorderSpacing.Right := Pvdt.BorderSpacing.Right;
Self.BorderSpacing.Bottom := Pvdt.BorderSpacing.Bottom;
Self.BiDiMode := Pvdt.BiDiMode;
Self.Tag := Pvdt.Tag;
Self.Color := Pvdt.Color;
Self.Colors.DropMarkColor := Pvdt.Colors.DropMarkColor;
Self.Colors.DropTargetColor := Pvdt.Colors.DropTargetColor;
Self.Colors.DropTargetBorderColor := Pvdt.Colors.DropTargetBorderColor;
Self.Colors.BorderColor := Pvdt.Colors.BorderColor;
Self.Colors.GridLineColor := Pvdt.Colors.GridLineColor;
Self.Colors.TreeLineColor := Pvdt.Colors.TreeLineColor;
Self.Colors.FocusedSelectionColor := Pvdt.Colors.FocusedSelectionColor;
Self.Colors.FocusedSelectionBorderColor := Pvdt.Colors.FocusedSelectionBorderColor;
Self.Colors.SelectionRectangleBlendColor := Pvdt.Colors.SelectionRectangleBlendColor;
Self.Colors.UnfocusedSelectionColor := Pvdt.Colors.UnfocusedSelectionColor;
Self.Colors.UnfocusedSelectionBorderColor := Pvdt.Colors.UnfocusedSelectionBorderColor;
Self.Constraints.MinHeight := Pvdt.Constraints.MinHeight;
Self.Constraints.MinWidth := Pvdt.Constraints.MinWidth;
Self.Constraints.MaxHeight := Pvdt.Constraints.MaxHeight;
Self.Constraints.MaxWidth := Pvdt.Constraints.MaxWidth;
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.Create 0___');
// Self.DefaultNodeHeight := Pvdt.DefaultNodeHeight;
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.Create 0&&&');
Self.DragKind := PVdt.DragKind;
Self.DragMode := Pvdt.DragMode;
Self.DragOperations := Pvdt.DragOperations;
Self.DragType := Pvdt.DragType;
Self.DrawSelectionMode := Pvdt.DrawSelectionMode;
Self.Font.Height := Pvdt.Font.Height;
Self.Font.Name := Pvdt.Font.Name;
Self.Font.Color := Pvdt.Font.Color;
Self.Font.Style := Pvdt.Font.Style;
Self.Font.Underline := Pvdt.Font.Underline;
Self.Font.Orientation := Pvdt.Font.Orientation;
Self.Font.Size := Pvdt.Font.Size;
Self.Font.Pitch := Pvdt.Font.Pitch;
Self.Font.Quality := Pvdt.Font.Quality;
Self.Header.AutoSizeIndex := Pvdt.Header.AutoSizeIndex;
Self.Header.DefaultHeight := Pvdt.Header.DefaultHeight;
Self.Header.MainColumn := Pvdt.Header.MainColumn;
Self.Header.Options := Pvdt.Header.Options;
Self.Header.ParentFont := Pvdt.Header.ParentFont;
Self.Header.Style := Pvdt.Header.Style;
Self.HintMode := Pvdt.HintMode;
Self.ParentFont := Pvdt.ParentFont;
Self.ParentShowHint := Pvdt.ParentShowHint;
Self.PopupMenu := Pvdt.PopupMenu;
Self.ScrollBarOptions.AlwaysVisible := Pvdt.ScrollBarOptions.AlwaysVisible;
Self.ScrollBarOptions.ScrollBars := Pvdt.ScrollBarOptions.ScrollBars;
Self.ShowHint := Pvdt.ShowHint;
Self.TabOrder := Pvdt.TabOrder;
Self.TreeOptions.AutoOptions := Pvdt.TreeOptions.AutoOptions;
Self.TreeOptions.MiscOptions := Pvdt.TreeOptions.MiscOptions;
Self.TreeOptions.PaintOptions := Pvdt.TreeOptions.PaintOptions;
Self.TreeOptions.SelectionOptions := Pvdt.TreeOptions.SelectionOptions;
// Копирование событий
Self.OnChange := Pvdt.OnChange;
Self.OnClick := Pvdt.OnClick;
Self.OnDrawHint := Pvdt.OnDrawHint;
Self.OnDrawNode := Pvdt.OnDrawNode;
Self.OnEnter := Pvdt.OnEnter;
Self.OnGetHintSize := Pvdt.OnGetHintSize;
Self.OnKeyDown := Pvdt.OnKeyDown;
Self.OnKeyPress := Pvdt.OnKeyPress;
Self.OnMouseDown := Pvdt.OnMouseDown;
Self.OnMouseMove := Pvdt.OnMouseMove;
Self.OnScroll := Pvdt.OnScroll;
Self.OnDragAllowed := Pvdt.OnDragAllowed;
Self.OnDragDrop := Pvdt.OnDragDrop;
Self.OnDragOver := Pvdt.OnDragOver;
// Копирование колонок
for c := 0 to Pvdt.Header.Columns.Count-1 do begin
column := Self.Header.Columns.Add;
column.Options := Pvdt.Header.Columns[c].Options;
column.Position := Pvdt.Header.Columns[c].Position;
column.MaxWidth := Pvdt.Header.Columns[c].MaxWidth;
column.MinWidth := Pvdt.Header.Columns[c].MinWidth;
column.Width := Pvdt.Header.Columns[c].Width;
column.Spacing := Pvdt.Header.Columns[c].Spacing;
column.Margin := Pvdt.Header.Columns[c].Margin;
column.Style := Pvdt.Header.Columns[c].Style;
column.Text := Pvdt.Header.Columns[c].Text;
end;
Pvdt.Destroy;
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.Create DONE');
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TVirtualList.UpdateHintCanvas(newCanvas: TCanvas);
begin
// Для перерисовки тултипа нужна его канва, достать ее можно только при получении
// сообщения CM_HINTSHOW (см CMHintShow), но так как все нужные свойства закрыты
// единственным способом ее получения является обработчик события OnDrawHint
Self.HintCanvas := newCanvas;
end;
procedure TVirtualList.DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: TRect);
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.DoGetHintSize %d', [Column]);
inherited DoGetHintSize(Node, Column, R);
if (Self.HintCanvas <> nil) then begin
//Self.HintCanvas.Brush.Color := clRed;
Self.HintCanvas.Brush.Style := bsSolid;
Self.HintCanvas.FillRect(0,0,Self.HintCanvas.Width, Self.HintCanvas.Height);
inherited DoDrawHint(Self.HintCanvas, Node, R, Column);
end;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TVirtualList.UpdateTileColumn(count: Word; Forse: Boolean = False);
var
data, RawData, NodeDat: PByte;
n, c: DWord;
node: PVirtualNode;
item: PVirtualItem;
begin
if (not Forse and ((Self.TileColumn = count) or (Self.Header.Columns.Count <= count)))
then Exit;
getmem(RawData, NodeDataSize * RootNodeCount + NodeDataSize div Self.TileColumn * count);
data := RawData;
node := inherited GetFirst(False);
while node <> nil do begin
Move(inherited GetNodeData(node)^, data^, NodeDataSize);
inc(data, NodeDataSize);
node := inherited GetNext(node, False);
end;
SetRoundMode(rmUp);
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.UpdateTileColumn %d %d %d', [Self.RootNodeCount, Self.TileColumn, count]);
//nodes := Round(Self.RootNodeCount * Self.TileColumn / count);
SetRoundMode(rmNearest);
Self.ClearAll := False;
inherited Clear;
Self.NodeDataSize := Self.NodeDataSize div Self.TileColumn * count;
Self.ClearAll := True;
Self.TileColumn := count;
item := Self.FirstItem;
data := RawData;
//if (item <> nil) then
n:=0;
while item <> nil do begin
if (item^.NextItem = nil)
then Break;
node := inherited AddChild(nil);
NodeDat := inherited GetNodeData(node);
Move(data^, NodeDat^, Self.NodeDataSize);
inc(data, Self.NodeDataSize);
for c:=0 to Self.TileColumn - 1 do begin
if (item^.NextItem = nil)
then Break;
item^.Node := node;
item^.Column := c;
item := item^.NextItem;
end;
inc(n, +1);
end;
freemem(RawData);
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.UpdateTileColumn %s', ['Done']);
end;
function TVirtualList.AddChild(ParentItem: PVirtualNode; UserData: Pointer = nil): PVirtualNode;
begin
Result := PVirtualNode(Self.AddItem(PVirtualItem(Parent), UserData));
end;
function TVirtualList.AddItem(ParentItem: PVirtualItem; UserData: Pointer = nil): PVirtualItem;
var
item: PVirtualItem;
begin
// Logger.Send([lcClient, lcDebug], 'TVirtualTree.AddChild %s', ['Start']);
getmem(item, SizeOf(TVirtualItem));
item^.NextItem:=nil;
item^.Selected:=False;
if ((Self.LastItem = nil) or (Self.LastItem^.Column = Self.TileColumn - 1))
then begin
item^.Node := inherited AddChild(nil);
item^.Column := 0;
if (Self.FirstItem = nil)
then Self.FirstItem := item;
end else begin
item^.Node := Self.LastItem^.Node;
item^.Column := Self.LastItem^.Column + 1;
end;
if (Self.LastItem <> nil)
then Self.LastItem^.NextItem := item;
Self.LastItem := item;
Result := item;
inc(FTilesCount, +1);
// Logger.Send([lcClient, lcDebug], 'TVirtualTree.AddChild %s', ['Done']);
end;
function TVirtualList.GetFirst(ConsiderChildrenAbove: Boolean = False): PVirtualItem;
begin
Result := Self.FirstItem;
end;
function TVirtualList.GetNext(Item: PVirtualItem; ConsiderChildrenAbove: Boolean = False): PVirtualItem;
begin
Result := Item^.NextItem;
end;
function TVirtualList.GetLast(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualItem;
begin
Result := Self.LastItem;
end;
function TVirtualList.GetItemAt(Node: PVirtualNode; Column: TColumnIndex): PVirtualItem;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.GetItemAt %s', ['Start']);
if (Column < 0) or (Column >= Self.Header.Columns.Count) then begin
Result := nil;
Exit;
end;
Result := Self.FirstItem;
while (Result <> nil) and ((Result^.Node <> Node) or (Result^.Column <> Word(Self.Header.Columns[Column].Tag)))
do Result := Result^.NextItem;
end;
function TVirtualList.GetNodeData(Item: PVirtualItem): Pointer;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.GetNodeData %s', ['Start']);
Result := inherited GetNodeData(Item^.Node) + (Item^.Column * NodeDataSize div Self.TileColumn);
end;
procedure TVirtualList.Clear;
var
item: PVirtualItem;
next: PVirtualItem;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.Clear %s', ['Called']);
// Злоябучий паскаль автоматически вызывает чистку при изменении NodeDataSize, что не всегда нужно...
if (Self.ClearAll) and (Self.FirstItem <> nil) then begin
next := Self.FirstItem;
while (next <> nil) do begin
item := next;
next := next^.NextItem;
freemem(item);
end;
Self.FirstItem:=nil;
Self.LastItem:=nil;
end;
inherited;
FTilesCount := 0;
FSelectionCount := 0;
end;
//----------------------------------------------------------------------------------------------------------------------
function TVirtualList.GetFirstSelected(ConsiderChildrenAbove: Boolean = False): PVirtualItem;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.GetFirstSelected %s', ['']);
Result := Self.FirstItem;
while ((Result <> nil) and (not Result^.Selected)) do begin
Result := Result^.NextItem;
end;
end;
function TVirtualList.GetNextSelected(Item: PVirtualItem; ConsiderChildrenAbove: Boolean = False): PVirtualItem;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.GetNextSelected %s', ['']);
Result := Item^.NextItem;
while ((Result <> nil) and (not Result^.Selected)) do begin
Result := Result^.NextItem;
end;
end;
function TVirtualList.GetSelected(Item: PVirtualItem): Boolean;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.GetSelected %s', ['']);
Result := Item^.Selected;
end;
procedure TVirtualList.SetSelected(Item: PVirtualItem; Value: Boolean);
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.SetSelected %s', ['']);
if (Item^.Selected = Value)
then Exit;
Item^.Selected := Value;
if not Value
then Dec(FSelectionCount)
else begin
Inc(FSelectionCount);
Self.LastSelected := Item;
end;
// TODO: Обновить отображение выделения
end;
procedure TVirtualList.ClearSelection;
var
item: PVirtualItem;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.ClearSelection %s', ['']);
item := Self.FirstItem;
while (item <> nil) do begin
Self.SetSelected(item, False);
item := item^.NextItem;
end;
FSelectionCount := 0;
inherited ClearSelection;
end;
procedure TVirtualList.DeleteSelectedNodes;
var
item, next, prev: PVirtualItem;
node: PVirtualNode;
data, RawData: PByte;
size: Word;
c: Word;
begin
if (Self.GetFirstSelected() = nil)
then Exit;
size := NodeDataSize div Self.TileColumn;
getmem(RawData, NodeDataSize * RootNodeCount);
data := RawData;
prev := nil;
item := Self.FirstItem;
while (item <> nil) do begin
if (item^.Selected) then begin
next := item^.NextItem;
Dec(FTilesCount);
freemem(item);
if (prev <> nil) then begin
prev^.NextItem := next;
end else begin
Self.FirstItem := next;
end;
if (next = nil) then begin
Self.LastItem := prev;
end;
item := next;
end else begin
Move((inherited GetNodeData(item^.Node) + (size * item^.Column))^, data^, size);
inc(data, size);
prev := item;
item := item^.NextItem;
end;
end;
data := RawData;
item := Self.FirstItem;
node := inherited GetFirst();
while (node <> nil) do begin
Move(data^, inherited GetNodeData(node)^, NodeDataSize);
Inc(data, NodeDataSize);
for c := 0 to Self.TileColumn - 1 do
if item <> nil then begin
item^.Node := node;
item^.Column := c;
item := item^.NextItem;
end else Break;
if (item = nil)
then Break;
node := inherited GetNext(node);
end;
if (Self.LastItem = nil)
then inherited Clear
else begin
item := Self.LastItem^.NextItem;
while (item <> nil) do begin
if (item^.Node <> Self.LastItem^.Node) then begin
node := item^.Node;
while (node <> nil) do begin
inherited DeleteNode(node, False);
node := inherited GetNext(node);
end;
Break;
end;
item := item^.NextItem;
end;
end;
freemem(RawData);
Self.LastSelected := nil;
FSelectionCount := 0;
end;
//----------------------------------------------------------------------------------------------------------------------
function TVirtualList.GetFocusedNode(): PVirtualItem;
var
node: PVirtualNode;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.GetFocusedNode %s', ['']);
node := inherited FocusedNode;
Result := Self.FirstItem;
while ((Result <> nil) and (Result^.Node <> node))
do Result := Result^.NextItem;
end;
procedure TVirtualList.SetFocusedNode(Item: PVirtualItem);
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.SetFocusedNode %s', ['']);
inherited FocusedNode := Item^.Node;
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TVirtualList.DoPaintNode(var PaintInfo: TVTPaintInfo);
var
item: PVirtualItem;
node: PVirtualNode;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.DoPaintNode %s', ['Start']);
item := Self.FirstItem;//^.NextItem;
while ((item <> nil) and ((item^.Node^.Index <> PaintInfo.Node^.Index) or (item^.Column <> Word(Self.Header.Columns[PaintInfo.Column].Tag))))
do item := item^.NextItem;
if (item <> nil) then begin
node := PaintInfo.Node;
PaintInfo.Node := PVirtualNode(item);
inherited DoPaintNode(PaintInfo);
PaintInfo.Node := node;
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.DoPaintNode %s', ['Done']);
if (item^.Selected and (item = Self.LastSelected))
then PaintInfo.Canvas.Pen.Color := Colors.FocusedSelectionBorderColor
else if item^.Selected
then PaintInfo.Canvas.Pen.Color := Colors.UnfocusedSelectionBorderColor
else PaintInfo.Canvas.Pen.Color := Colors.BorderColor;
//PaintInfo.Canvas.Pen.Color := clRed;
PaintInfo.Canvas.Pen.Style := psDot;//psSolid;
PaintInfo.Canvas.Pen.Width := 1;
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.DoPaintNode [%d,%d,%d,%d] [%d,%d]', [PaintInfo.CellRect.Left, PaintInfo.CellRect.Top,
//PaintInfo.CellRect.Right - PaintInfo.CellRect.Left, PaintInfo.CellRect.Bottom - PaintInfo.CellRect.Top, PaintInfo.Canvas.Width, PaintInfo.Canvas.Height]);
PaintInfo.Canvas.Line(PaintInfo.CellRect.Left+1,PaintInfo.CellRect.Bottom-1,PaintInfo.CellRect.Right-1,PaintInfo.CellRect.Bottom-1);
PaintInfo.Canvas.Line(PaintInfo.CellRect.Right-1,PaintInfo.CellRect.Top+1,PaintInfo.CellRect.Left+1,PaintInfo.CellRect.Top+1);
if Self.TileColumn > 1 then begin
PaintInfo.Canvas.Line(PaintInfo.CellRect.Left+1,PaintInfo.CellRect.Top+1,PaintInfo.CellRect.Left+1,PaintInfo.CellRect.Bottom-1);
PaintInfo.Canvas.Line(PaintInfo.CellRect.Right-1,PaintInfo.CellRect.Bottom-1,PaintInfo.CellRect.Right-1,PaintInfo.CellRect.Top+1);
end;
PaintInfo.Canvas.Pen.Color := Color;
PaintInfo.Canvas.Pen.Style := psSolid;
PaintInfo.Canvas.Line(PaintInfo.CellRect.Left,PaintInfo.CellRect.Bottom,PaintInfo.CellRect.Right,PaintInfo.CellRect.Bottom);
PaintInfo.Canvas.Line(PaintInfo.CellRect.Right,PaintInfo.CellRect.Top,PaintInfo.CellRect.Left,PaintInfo.CellRect.Top);
if Self.TileColumn > 1 then begin
PaintInfo.Canvas.Line(PaintInfo.CellRect.Left,PaintInfo.CellRect.Top,PaintInfo.CellRect.Left,PaintInfo.CellRect.Bottom);
PaintInfo.Canvas.Line(PaintInfo.CellRect.Right,PaintInfo.CellRect.Bottom,PaintInfo.CellRect.Right,PaintInfo.CellRect.Top);
PaintInfo.Canvas.Pixels[PaintInfo.CellRect.Left+1,PaintInfo.CellRect.Top+1] := Color;
PaintInfo.Canvas.Pixels[PaintInfo.CellRect.Left+1,PaintInfo.CellRect.Bottom-1] := Color;
PaintInfo.Canvas.Pixels[PaintInfo.CellRect.Right-1,PaintInfo.CellRect.Bottom-1] := Color;
PaintInfo.Canvas.Pixels[PaintInfo.CellRect.Right-1,PaintInfo.CellRect.Top+1] := Color;
end;
//PaintInfo.Canvas.Rectangle(PaintInfo.CellRect);
//PaintInfo.Canvas.Line(Rect(1,1,PaintInfo.Canvas.Width-2, PaintInfo.Canvas.Height-2));
//PaintInfo.Canvas.Rectangle(Rect(1,1,PaintInfo.Canvas.Width-2, PaintInfo.Canvas.Height-2));
//PaintInfo.Canvas.Line(1,1,PaintInfo.Canvas.Width-2,PaintInfo.Canvas.Height-2);
//PaintInfo.Canvas.Line(1,1,1,PaintInfo.Canvas.Height-2);
//PaintInfo.Canvas.Line(1,PaintInfo.Canvas.Height-2,PaintInfo.Canvas.Width-2,PaintInfo.Canvas.Height-2);
//PaintInfo.Canvas.Line(PaintInfo.Canvas.Width-4,PaintInfo.Canvas.Height-2,PaintInfo.Canvas.Width-4,1);
//PaintInfo.Canvas.Line(0,PaintInfo.Canvas.Width,0,0);
end;
end;
procedure TVirtualList.PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: Integer);
var
item: PVirtualItem;
begin
inherited PrepareCell(PaintInfo, WindowOrgX, MaxWidth);
item := Self.GetItemAt(PaintInfo.Node, PaintInfo.Column);
if (item = nil)
then Exit;
if (item^.Selected and (item = Self.LastSelected))
then PaintInfo.Canvas.Brush.Color := Colors.FocusedSelectionColor
else if item^.Selected
then PaintInfo.Canvas.Brush.Color := Colors.UnfocusedSelectionColor
else PaintInfo.Canvas.Brush.Color := Colors.GridLineColor;
PaintInfo.Canvas.Brush.Style := bsSolid;
PaintInfo.Canvas.FillRect(0,0,PaintInfo.Canvas.Width, PaintInfo.Canvas.Height);
end;
procedure TVirtualList.DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; const R: TRect);
begin
end;
//----------------------------------------------------------------------------------------------------------------------
procedure TVirtualList.HandleMouseDblClick(var Message: TLMMouse; const HitInfo: THitInfo);
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.HandleMouseDblClick %s', ['Start']);
inherited HandleMouseDblClick(Message, HitInfo);
end;
procedure TVirtualList.HandleMouseDown(var Message: TLMMouse; var HitInfo: THitInfo);
var
ShiftState: TShiftState;
HitItem: PVirtualItem;
item: PVirtualItem;
kinput: TKEYINPUT;
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.HandleMouseDown %s', ['Start']);
HitItem := Self.GetItemAt(HitInfo.HitNode, HitInfo.HitColumn);
if (HitItem = nil) then begin
inherited HandleMouseDown(Message, HitInfo);
Exit;
end;
ShiftState := KeysToShiftState(Message.Keys) * [ssShift, ssCtrl, ssAlt];
if not (ssAlt in ShiftState) then begin
if (not (ssCtrl in ShiftState)) and (not (ssShift in ShiftState)) then begin
if (not HitItem^.Selected)
then Self.ClearSelection;
Self.SetSelected(HitItem, True);
end else if not (ssShift in ShiftState) then begin
Self.SetSelected(HitItem, not HitItem^.Selected);
end else begin
if not (ssCtrl in ShiftState)
then Self.ClearSelection;
if Self.LastSelected = nil
then Self.LastSelected := Self.FirstItem;
if Self.LastSelected^.Node^.Index < HitItem^.Node^.Index then begin
item := Self.LastSelected;
HitItem := HitItem;
end else begin
item := HitItem;
HitItem := Self.LastSelected;
end;
while item <> HitItem^.NextItem do begin
Self.SetSelected(item, True);
item := item^.NextItem;
end;
end;
end;
// Вызываем перерисовку контрола (тутбы потом понормальному сделать...)
if (Self.Focused) then begin
Self.Parent.SetFocus;
Self.SetFocus;
end;
inherited HandleMouseDown(Message, HitInfo);
// Чтоже я творю-то...
if (ShiftState = []) then begin
kinput.itype := INPUT_KEYBOARD;
kinput.wVk := $11; // VK_CONTROL
SendInput(1, @kinput, sizeof(TKEYINPUT));
BeginDrag(TRUE);
kinput.dwFlags := KEYEVENTF_KEYUP;
SendInput(1, @kinput, sizeof(TKEYINPUT));
end;
end;
procedure TVirtualList.HandleMouseUp(var Message: TLMMouse; const HitInfo: THitInfo);
begin
//Logger.Send([lcClient, lcDebug], 'TVirtualTree.HandleMouseUp %s', ['Start']);
inherited HandleMouseUp(Message, HitInfo);
end;
//----------------------------------------------------------------------------------------------------------------------
end.