From 0e956295523c89d8daf18c1a3030306647b4b7c7 Mon Sep 17 00:00:00 2001 From: blikblum Date: Mon, 23 Jul 2007 14:43:56 +0000 Subject: [PATCH] * Backported changes done in main svn tree up to svn rev 143 (version 4.5.4) git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@223 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../virtualtreeview-unstable/VirtualTrees.pas | 392 ++++++++++++++++-- 1 file changed, 350 insertions(+), 42 deletions(-) diff --git a/components/virtualtreeview-unstable/VirtualTrees.pas b/components/virtualtreeview-unstable/VirtualTrees.pas index b9981c618..d3e78061e 100644 --- a/components/virtualtreeview-unstable/VirtualTrees.pas +++ b/components/virtualtreeview-unstable/VirtualTrees.pas @@ -2,7 +2,7 @@ unit VirtualTrees; {$mode delphi}{$H+} -// Version 4.5.1 +// Version 4.5.4 // // 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 @@ -26,9 +26,24 @@ unit VirtualTrees; // (C) 1999-2001 digital publishing AG. All Rights Reserved. //---------------------------------------------------------------------------------------------------------------------- // +// June 2007 +// - Bug fix: Fixed a problem with potentially large amount of nodes (larger than 2 billion) in +// TBaseVirtualTree.SetChildCount. +// - Bug fix: remove hint if any in case the tree loses the focus. +// - Improvement: TVirtualTreeColumns.HandleClick is now virtual, introduced TVTHeader.DoSetSortColumn. +// - Bug fix: compiler error due to old variable reference when enabling flat scrollbars. +// May 2007 +// - Improvement: new functions: GetPreviousSelected, GetPreviousChecked, GetCheckedCount, +// GetPreviousCutCopy, GetCutCopyCount, GetFirstLeaf, GetNextLeaf, +// GetPreviousLeaf, GetFirstLevel, GetNextLevel, GetPreviousLevel +// - Improvement: new properties: CheckedCount, CutCopyCount +// - Improvement: DoFocusChanging for finding a valid column (TBaseVirtualTree.WMKeyDown) +// March 2007 +// - Improvement: adjusted accessibility implementation to compile with pre-BDS IDEs. +// - If a column is not visible, MultiColumnAccessibility now will not include it. // January 2007 // - Improvement: added code donation from Marco Zehe (with help from Sebastian Modersohn) which implements the -// MS accessability interface for Virtual Treeview. +// MS accessibility interface for Virtual Treeview. // December 2006 // - Improvement: bidi mode implementation finished (toAutoBidiColumnOrdering introduced) // - Change: right-to-left flag removed from shorten string methods/events (not necessary) @@ -135,7 +150,7 @@ uses const {$I lclconstants.inc} - VTVersion = '4.5.1'; + VTVersion = '4.5.4'; VTTreeStreamVersion = 2; VTHeaderStreamVersion = 3; // The header needs an own stream version to indicate changes only relevant to the header. @@ -1072,7 +1087,7 @@ type procedure FixPositions; function GetColumnAndBounds(P: TPoint; var ColumnLeft, ColumnRight: Integer; Relative: Boolean = True): Integer; function GetOwner: TPersistent; override; - procedure HandleClick(P: TPoint; Button: TMouseButton; Force, DblClick: Boolean); + procedure HandleClick(P: TPoint; Button: TMouseButton; Force, DblClick: Boolean); virtual; procedure IndexChanged(OldIndex, NewIndex: Integer); procedure InitializePositionArray; procedure ReorderColumns(RTL: Boolean); @@ -1208,6 +1223,7 @@ type function CanWriteColumns: Boolean; virtual; procedure ChangeScale(M, D: Integer); virtual; function DetermineSplitterIndex(P: TPoint): Boolean; virtual; + procedure DoSetSortColumn(Value: TColumnIndex); virtual; procedure DragTo(P: TPoint); function GetColumnsClass: TVirtualTreeColumnsClass; virtual; function GetOwner: TPersistent; override; @@ -1986,10 +2002,12 @@ TBaseVirtualTree = class(TCustomControl) function FindInPositionCache(Position: Cardinal; var CurrentPos: Cardinal): PVirtualNode; overload; procedure FixupTotalCount(Node: PVirtualNode); procedure FixupTotalHeight(Node: PVirtualNode); + function GetCheckedCount: Integer; function GetCheckState(Node: PVirtualNode): TCheckState; function GetCheckType(Node: PVirtualNode): TCheckType; function GetChildCount(Node: PVirtualNode): Cardinal; function GetChildrenInitialized(Node: PVirtualNode): Boolean; + function GetCutCopyCount: Integer; function GetDisabled(Node: PVirtualNode): Boolean; function GetDragManager: IVTDragManager; function GetExpanded(Node: PVirtualNode): Boolean; @@ -2261,6 +2279,8 @@ TBaseVirtualTree = class(TCustomControl) procedure DoTimerScroll; virtual; procedure DoUpdating(State: TVTUpdateState); virtual; function DoValidateCache: Boolean; virtual; + procedure DragAndDrop(AllowedEffects: Integer; DataObject: IDataObject; + DragEffect: Integer); virtual; procedure DragCanceled; override; function DragDrop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint; var Effect: LongWord): HResult; reintroduce; virtual; @@ -2532,6 +2552,8 @@ TBaseVirtualTree = class(TCustomControl) function GetFirstChild(Node: PVirtualNode): PVirtualNode; function GetFirstCutCopy: PVirtualNode; function GetFirstInitialized: PVirtualNode; + function GetFirstLeaf: PVirtualNode; + function GetFirstLevel(NodeLevel: Cardinal): PVirtualNode; function GetFirstNoInit: PVirtualNode; function GetFirstSelected: PVirtualNode; function GetFirstVisible: PVirtualNode; @@ -2553,6 +2575,8 @@ TBaseVirtualTree = class(TCustomControl) function GetNextChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal): PVirtualNode; function GetNextCutCopy(Node: PVirtualNode): PVirtualNode; function GetNextInitialized(Node: PVirtualNode): PVirtualNode; + function GetNextLeaf(Node: PVirtualNode): PVirtualNode; + function GetNextLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; function GetNextNoInit(Node: PVirtualNode): PVirtualNode; function GetNextSelected(Node: PVirtualNode): PVirtualNode; function GetNextSibling(Node: PVirtualNode): PVirtualNode; @@ -2565,8 +2589,13 @@ TBaseVirtualTree = class(TCustomControl) function GetNodeData(Node: PVirtualNode): Pointer; function GetNodeLevel(Node: PVirtualNode): Cardinal; function GetPrevious(Node: PVirtualNode): PVirtualNode; + function GetPreviousChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal): PVirtualNode; + function GetPreviousCutCopy(Node: PVirtualNode): PVirtualNode; function GetPreviousInitialized(Node: PVirtualNode): PVirtualNode; + function GetPreviousLeaf(Node: PVirtualNode): PVirtualNode; + function GetPreviousLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; function GetPreviousNoInit(Node: PVirtualNode): PVirtualNode; + function GetPreviousSelected(Node: PVirtualNode): PVirtualNode; function GetPreviousSibling(Node: PVirtualNode): PVirtualNode; function GetPreviousVisible(Node: PVirtualNode): PVirtualNode; function GetPreviousVisibleNoInit(Node: PVirtualNode): PVirtualNode; @@ -2630,11 +2659,13 @@ TBaseVirtualTree = class(TCustomControl) property AccessibleItem: IAccessible read FAccessibleItem write FAccessibleItem; property AccessibleName: string read FAccessibleName write FAccessibleName; {$endif} + property CheckedCount: Integer read GetCheckedCount; property CheckImages: TBitmap read FCheckImages; property CheckState[Node: PVirtualNode]: TCheckState read GetCheckState write SetCheckState; property CheckType[Node: PVirtualNode]: TCheckType read GetCheckType write SetCheckType; property ChildCount[Node: PVirtualNode]: Cardinal read GetChildCount write SetChildCount; property ChildrenInitialized[Node: PVirtualNode]: Boolean read GetChildrenInitialized; + property CutCopyCount: Integer read GetCutCopyCount; property DragImage: TVTDragImage read FDragImage; property DragManager: IVTDragManager read GetDragManager; property DropTargetNode: PVirtualNode read FDropTargetNode; @@ -2924,7 +2955,8 @@ type property Colors; property Constraints; property Ctl3D; - property CustomCheckImages; + //todo: see a way to set CustomCheckImages at design time + //property CustomCheckImages; property DefaultNodeHeight; property DefaultPasteMode; property DefaultText; @@ -9936,22 +9968,7 @@ begin if csLoading in Treeview.ComponentState then FSortColumn := Value else - begin - if Value < NoColumn then - Value := NoColumn; - if Value > Columns.Count - 1 then - Value := Columns.Count - 1; - if FSortColumn <> Value then - begin - if FSortColumn > NoColumn then - Invalidate(Columns[FSortColumn]); - FSortColumn := Value; - if FSortColumn > NoColumn then - Invalidate(Columns[FSortColumn]); - if (toAutoSort in Treeview.FOptions.FAutoOptions) and (Treeview.FUpdateCount = 0) then - Treeview.SortTree(FSortColumn, FSortDirection, True); - end; - end; + DoSetSortColumn(Value); end; //---------------------------------------------------------------------------------------------------------------------- @@ -10074,6 +10091,27 @@ end; //---------------------------------------------------------------------------------------------------------------------- +procedure TVTHeader.DoSetSortColumn(Value: TColumnIndex); + +begin + if Value < NoColumn then + Value := NoColumn; + if Value > Columns.Count - 1 then + Value := Columns.Count - 1; + if FSortColumn <> Value then + begin + if FSortColumn > NoColumn then + Invalidate(Columns[FSortColumn]); + FSortColumn := Value; + if FSortColumn > NoColumn then + Invalidate(Columns[FSortColumn]); + if (toAutoSort in Treeview.FOptions.FAutoOptions) and (Treeview.FUpdateCount = 0) then + Treeview.SortTree(FSortColumn, FSortDirection, True); + end; +end; + +//---------------------------------------------------------------------------------------------------------------------- + procedure TVTHeader.DragTo(P: TPoint); // Moves the drag image to a new position, which is determined from the passed point P and the previous @@ -12284,6 +12322,16 @@ begin end; end; +procedure TBaseVirtualTree.DragAndDrop(AllowedEffects: Integer; + DataObject: IDataObject; DragEffect: Integer); +begin + {$ifdef UseExternalDragManager} + VirtualDragManager.DoDragDrop(DataObject, DragManager as IDropSource, AllowedEffects, @DragEffect); + {$else} + ActiveX.DoDragDrop(DataObject, DragManager as IDropSource, AllowedEffects, @DragEffect); + {$endif} +end; + //---------------------------------------------------------------------------------------------------------------------- procedure TBaseVirtualTree.DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: Integer; Style: TVTLineType; @@ -12457,6 +12505,22 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetCheckedCount: Integer; + +var + Node: PVirtualNode; + +begin + Result := 0; + Node := GetFirstChecked; + while Assigned(Node) do begin + Inc(Result); + Node := GetNextChecked(Node); + end; +end; + +//---------------------------------------------------------------------------------------------------------------------- + function TBaseVirtualTree.GetCheckState(Node: PVirtualNode): TCheckState; begin @@ -12492,6 +12556,21 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetCutCopyCount: Integer; + +var + Node: PVirtualNode; + +begin + Result := 0; + Node := GetFirstCutCopy; + while Assigned(Node) do begin + Inc(Result); + Node := GetNextCutCopy(Node); + end; +end; + +//---------------------------------------------------------------------------------------------------------------------- function TBaseVirtualTree.GetDisabled(Node: PVirtualNode): Boolean; begin @@ -13025,7 +13104,10 @@ begin if PeekMessage(Msg, Handle, 0, 0, PM_REMOVE) then begin if Msg.message = WM_QUIT then + begin + PostQuitMessage(Msg.WParam); Break; + end; TranslateMessage(Msg); DispatchMessage(Msg); end; @@ -13766,10 +13848,10 @@ procedure TBaseVirtualTree.SetChildCount(Node: PVirtualNode; NewChildCount: Card // routine is used. var - Count: Integer; + Remaining: Cardinal; Index: Cardinal; Child: PVirtualNode; - C: Integer; + Count: Integer; NewHeight: Integer; begin @@ -13782,18 +13864,17 @@ begin DeleteChildren(Node) else begin - Count := Integer(NewChildCount) - Integer(Node.ChildCount); - // If nothing changed then do nothing. - if Count <> 0 then + if NewChildCount <> Node.ChildCount then begin InterruptValidation; - - C := Count; NewHeight := 0; - if Count > 0 then + if NewChildCount > Node.ChildCount then begin + Remaining := NewChildCount - Node.ChildCount; + Count := Remaining; + // New nodes to add. if Assigned(Node.LastChild) then Index := Node.LastChild.Index + 1 @@ -13805,7 +13886,7 @@ begin Node.States := Node.States - [vsAllChildrenHidden, vsHeightMeasured]; // New nodes are by default always visible, so we don't need to check the visibility. - while Count > 0 do + while Remaining > 0 do begin Child := MakeNewNode; Child.Index := Index; @@ -13816,7 +13897,7 @@ begin Node.LastChild := Child; if Node.FirstChild = nil then Node.FirstChild := Child; - Dec(Count); + Dec(Remaining); Inc(Index); // The actual node height will later be computed once it is clear @@ -13828,10 +13909,10 @@ begin begin AdjustTotalHeight(Node, NewHeight, True); if FullyVisible[Node] then - Inc(Integer(FVisibleCount), C); + Inc(Integer(FVisibleCount), Count); end; - AdjustTotalCount(Node, C, True); + AdjustTotalCount(Node, Count, True); Node.ChildCount := NewChildCount; if (FUpdateCount = 0) and (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then Sort(Node, FHeader.FSortColumn, FHeader.FSortDirection, True); @@ -13841,10 +13922,11 @@ begin else begin // Nodes have to be deleted. - while Count < 0 do + Remaining := Node.ChildCount - NewChildCount; + while Remaining > 0 do begin DeleteNode(Node.LastChild); - Inc(Count); + Dec(Remaining); end; end; @@ -15749,7 +15831,10 @@ begin else NewColumn := NoColumn; // Find a column for the new/current node which can be focused. - while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, Node, FFocusedColumn, NewColumn) do + // Make the 'DoFocusChanging' for finding a valid column + // identifiable from the 'DoFocusChanging' raised later on by + // "FocusedNode := Node;" + while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, FFocusedNode, FFocusedColumn, NewColumn) do NewColumn := GetNextColumn(NewColumn); if NewColumn > InvalidColumn then begin @@ -16242,6 +16327,9 @@ var begin Logger.EnterMethod([lcMessages],'WMKillFocus'); inherited WMKillFocus(Msg); + + // Remove hint if shown currently. + Application.CancelHint; // Stop wheel panning if active. StopWheelPanning; @@ -18428,11 +18516,7 @@ begin DragEffect := DROPEFFECT_NONE; AllowedEffects := GetDragOperations; try - {$ifdef UseExternalDragManager} - virtualdragmanager.DoDragDrop(DataObject, DragManager as IDropSource, AllowedEffects, @DragEffect); - {$else} - ActiveX.DoDragDrop(DataObject, DragManager as IDropSource, AllowedEffects, @DragEffect); - {$endif} + DragAndDrop(AllowedEffects, DataObject, DragEffect); DragManager.ForceDragLeave; finally GetCursorPos(P); @@ -24931,6 +25015,36 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetFirstLeaf: PVirtualNode; + +// Returns the first node in the tree which has currently no children. +// The result is initialized if necessary. + +begin + Result := GetNextLeaf(nil); +end; + +//---------------------------------------------------------------------------------------------------------------------- + +function TBaseVirtualTree.GetFirstLevel(NodeLevel: Cardinal): PVirtualNode; + +// Returns the first node in the tree on a specific level. +// The result is initialized if necessary. + +begin + Result := GetFirstNoInit; + while Assigned(Result) and (GetNodeLevel(Result) <> NodeLevel) do + Result := GetNextNoInit(Result); + + if Assigned(Result) and (GetNodeLevel(Result) <> NodeLevel) then // i.e. there is no node with the desired level in the tree + Result := nil; + + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); +end; + +//---------------------------------------------------------------------------------------------------------------------- + function TBaseVirtualTree.GetFirstNoInit: PVirtualNode; begin @@ -25573,6 +25687,69 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetNextLeaf(Node: PVirtualNode): PVirtualNode; + +// Returns the next node in the tree which has currently no children. +// The result is initialized if necessary. + +begin + if (Node = nil) or (Node = FRoot) then + Result := FRoot.FirstChild + else + Result := GetNext(Node); + while Assigned(Result) and (vsHasChildren in Result.States) do + Result := GetNext(Result); + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); +end; + +//---------------------------------------------------------------------------------------------------------------------- + +function TBaseVirtualTree.GetNextLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; + +// Returns the next node in the tree on a specific level. +// The result is initialized if necessary. + +var + StartNodeLevel: Cardinal; + +begin + Result := nil; + + if Assigned(Node) and (Node <> FRoot) then + begin + StartNodeLevel := GetNodeLevel(Node); + + if StartNodeLevel < NodeLevel then + begin + Result := GetNext(Node); + if Assigned(Result) and (GetNodeLevel(Result) <> NodeLevel) then + Result := GetNextLevel(Result, NodeLevel); + end else if StartNodeLevel = NodeLevel then + begin + Result := Node.NextSibling; + if not Assigned(Result) then // i.e. start node was a last sibling + begin + Result := Node.Parent; + if Assigned(Result) then + begin + // go to next anchestor of the start node which has a next sibling (if exists) + while Assigned(Result) and not Assigned(Result.NextSibling) do + Result := Result.Parent; + if Assigned(Result) then + Result := GetNextLevel(Result.NextSibling, NodeLevel); + end; + end; + end else // i.e. StartNodeLevel > NodeLevel + Result := GetNextLevel(Node.Parent, NodeLevel); + end; + + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); +end; + +//---------------------------------------------------------------------------------------------------------------------- + function TBaseVirtualTree.GetNextNoInit(Node: PVirtualNode): PVirtualNode; // Optimized variant of GetNext, no initialization of nodes is performed (if a node is not initialized @@ -25998,6 +26175,49 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetPreviousChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal): PVirtualNode; + +begin + + if (Node = nil) or (Node = FRoot) then + Result := FRoot.LastChild + else + Result := GetPreviousNoInit(Node); + + while Assigned(Result) and (Result.CheckState <> State) do + Result := GetPreviousNoInit(Result); + + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); + +end; + +//---------------------------------------------------------------------------------------------------------------------- + +function TBaseVirtualTree.GetPreviousCutCopy(Node: PVirtualNode): PVirtualNode; + +// Returns the previous node in the tree which is currently marked for a clipboard operation. Since only visible nodes can +// be marked (or they are hidden after they have been marked) it is not necessary to initialize nodes to check for +// child nodes. The result, however, is initialized if necessary. + +begin + if ClipboardStates * FStates <> [] then + begin + if (Node = nil) or (Node = FRoot) then + Result := FRoot.LastChild + else + Result := GetPreviousNoInit(Node); + while Assigned(Result) and not (vsCutOrCopy in Result.States) do + Result := GetPreviousNoInit(Result); + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); + end + else + Result := nil; +end; + +//---------------------------------------------------------------------------------------------------------------------- + function TBaseVirtualTree.GetPreviousInitialized(Node: PVirtualNode): PVirtualNode; // Returns the previous node in tree which is initialized. @@ -26011,6 +26231,70 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetPreviousLeaf(Node: PVirtualNode): PVirtualNode; + +// Returns the previous node in the tree which has currently no children. +// The result is initialized if necessary. + +begin + if (Node = nil) or (Node = FRoot) then + Result := FRoot.LastChild + else + Result := GetPrevious(Node); + while Assigned(Result) and (vsHasChildren in Result.States) do + Result := GetPrevious(Result); + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); +end; + +//---------------------------------------------------------------------------------------------------------------------- + +function TBaseVirtualTree.GetPreviousLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; + +// Returns the previous node in the tree on a specific level. +// The result is initialized if necessary. + +var + StartNodeLevel: Cardinal; + +begin + Result := nil; + + if Assigned(Node) and (Node <> FRoot) then + begin + StartNodeLevel := GetNodeLevel(Node); + + if StartNodeLevel < NodeLevel then + begin + Result := Node.PrevSibling; + if Assigned(Result) then + begin + // go to last descendant of previous sibling with desired node level (if exists) + while Assigned(Result) and (GetNodeLevel(Result) < NodeLevel) do + Result := GetLastChild(Result); + if not Assigned(Result) then + Result := GetPreviousLevel(Node.PrevSibling, NodeLevel); + end else + Result := GetPreviousLevel(Node.Parent, NodeLevel); + end else if StartNodeLevel = NodeLevel then + begin + Result := Node.PrevSibling; + if not Assigned(Result) then // i.e. start node was a first sibling + begin + Result := Node.Parent; + if Assigned(Result) then + Result := GetPreviousLevel(Result, NodeLevel); + end; + end else // i.e. StartNodeLevel > NodeLevel + Result := GetPreviousLevel(Node.Parent, NodeLevel); + end; + + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); +end; + +//---------------------------------------------------------------------------------------------------------------------- + function TBaseVirtualTree.GetPreviousNoInit(Node: PVirtualNode): PVirtualNode; // Returns the previous node in the tree with regard to Node. No initialization in done, hence this @@ -26041,6 +26325,30 @@ end; //---------------------------------------------------------------------------------------------------------------------- +function TBaseVirtualTree.GetPreviousSelected(Node: PVirtualNode): PVirtualNode; + +// Returns the previous node in the tree which is currently selected. Since children of unitialized nodes cannot be +// in the current selection (because they simply do not exist yet) it is not necessary to initialize nodes here. +// The result however is initialized if necessary. + +begin + if FSelectionCount > 0 then + begin + if (Node = nil) or (Node = FRoot) then + Result := FRoot.LastChild + else + Result := GetPreviousNoInit(Node); + while Assigned(Result) and not (vsSelected in Result.States) do + Result := GetPreviousNoInit(Result); + if Assigned(Result) and not (vsInitialized in Result.States) then + InitNode(Result); + end + else + Result := nil; +end; + +//---------------------------------------------------------------------------------------------------------------------- + function TBaseVirtualTree.GetPreviousSibling(Node: PVirtualNode): PVirtualNode; // Get next sibling of Node, initialize it if necessary. @@ -28970,7 +29278,7 @@ begin // Since the position is automatically changed if it doesn't meet the range // we better read the current position back to stay synchronized. {$ifdef UseFlatScrollbars} - FScrollOffsetX := FlatSB_GetScrollPos(Handle, SB_HORZ); + FEffectiveOffsetX := FlatSB_GetScrollPos(Handle, SB_HORZ); {$else} //todo: Use get scrollinfo instead of GetScrollPos?? FEffectiveOffsetX := GetScrollPos(Handle, SB_HORZ);