I've tried to set TListView control's direction to RTL by following function:
procedure RTL_LV(lv:TListView);
const
LVM_FIRST = $1000;
LVM_GETHEADER = LVM_FIRST + 31;
var
header: THandle;
begin
header:= SendMessage (lv.Handle, LVM_GETHEADER, 0, 0);
SetWindowLong (header, GWL_EXSTYLE,
GetWindowLong (header, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
SetWindowLong (lv.Handle, GWL_EXSTYLE,
GetWindowLong (lv.Handle, GWL_EXSTYLE) or
WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
lv.invalidate;
end;
But I have two problems as follows when the project uses VCL Styles:
1: Vertical scrollbar not appearing without clicking on it.
2: When i change the size of the ListView columns and the horizontal scrollbar is clicked, the following error message is displayed:
Exception source: Vcl.ComCtrls.TListViewStyleHook.WMMouseMove
procedure TListViewStyleHook.WMMouseMove(var Message: TWMMouse);
var
SF: TScrollInfo;
SPos: Integer;
R: TRect;
begin
if VertSliderState = tsThumbBtnVertPressed then
begin
SF.fMask := SIF_ALL;
SF.cbSize := SizeOf(SF);
GetScrollInfo(Handle, SB_VERT, SF);
ScrollPos := ScrollPos + (SF.nMax - SF.nMin) * ((Mouse.CursorPos.Y - PrevScrollPos) / VertTrackRect.Height);
PrevScrollPos := Mouse.CursorPos.Y;
if Control is TCustomListView then
begin
PostMessage(Handle, WM_VSCROLL, Integer(SmallPoint(SB_THUMBTRACK, Round(ScrollPos))), 0);
if TCustomListView(Control).ViewStyle = vsReport then
begin
if (Abs(ScrollPos - ListPos) >= 1) or
((ScrollPos = SF.nMin) and (ListPos <> ScrollPos)) or
((ScrollPos = SF.nMax) and (ListPos <> ScrollPos)) then
begin
if TCustomListView(Control).GroupView then
begin
SPos := Round(ScrollPos - ListPos);
if SF.nPos + SPos < 0 then SPos := -SF.nPos;
end
else
begin
ListView_GetItemRect(Handle, 0, R, LVIR_BOUNDS);
SPos := Round((ScrollPos - ListPos) * R.Height);
end;
ListView_Scroll(Handle, 0, SPos);
ListPos := ScrollPos;
end;
end
else
begin
if Abs(ScrollPos - ListPos) >= 1 then
begin
ListView_Scroll(Handle, 0, Round((ScrollPos - ListPos)));
ListPos := ScrollPos;
end;
end;
end
else
PostMessage(Handle, WM_VSCROLL, Integer(SmallPoint(SB_THUMBPOSITION, Round(ScrollPos))), 0);
PaintScroll;
Handled := True;
Exit;
end;
if HorzSliderState = tsThumbBtnHorzPressed then
begin
SF.fMask := SIF_ALL;
SF.cbSize := SizeOf(SF);
GeTScrollInfo(Handle, SB_HORZ, SF);
ScrollPos := ScrollPos + (SF.nMax - SF.nMin) * ((Mouse.CursorPos.X - PrevScrollPos) / HorzTrackRect.Width);
if ScrollPos < SF.nMin then
ScrollPos := SF.nMin;
if ScrollPos > SF.nMax then
ScrollPos := SF.nMax;
PrevScrollPos := Mouse.CursorPos.X;
if Control is TCustomListView then
begin
if TCustomListView(Control).ViewStyle = vsReport then
begin
if Abs(ScrollPos - ListPos) >= 1 then
begin
ListView_Scroll(Handle, Round((ScrollPos - ListPos)), 0);
ListPos := ScrollPos;
end;
end
else
begin
if Abs(ScrollPos - ListPos) >= 0.5 then
begin
ListView_Scroll(Handle, Round((ScrollPos - ListPos)), 0);
ListPos := ScrollPos;
end;
end;
end
else
PostMessage(Handle, WM_HSCROLL, Integer(SmallPoint(SB_THUMBPOSITION, Round(ScrollPos))), 0);
PaintScroll;
Handled := True;
Exit;
end;
if (HorzSliderState <> tsThumbBtnHorzPressed) and (HorzSliderState = tsThumbBtnHorzHot) then
begin
HorzSliderState := tsThumbBtnHorzNormal;
PaintScroll;
end;
if (VertSliderState <> tsThumbBtnVertPressed) and (VertSliderState = tsThumbBtnVertHot) then
begin
VertSliderState := tsThumbBtnVertNormal;
PaintScroll;
end;
if (HorzUpState <> tsArrowBtnLeftPressed) and (HorzUpState = tsArrowBtnLeftHot) then
begin
HorzUpState := tsArrowBtnLeftNormal;
PaintScroll;
end;
if (HorzDownState <> tsArrowBtnRightPressed) and (HorzDownState =tsArrowBtnRightHot) then
begin
HorzDownState := tsArrowBtnRightNormal;
PaintScroll;
end;
if (VertUpState <> tsArrowBtnUpPressed) and (VertUpState = tsArrowBtnUpHot) then
begin
VertUpState := tsArrowBtnUpNormal;
PaintScroll;
end;
if (VertDownState <> tsArrowBtnDownPressed) and (VertDownState = tsArrowBtnDownHot) then
begin
VertDownState := tsArrowBtnDownNormal;
PaintScroll;
end;
CallDefaultProc(TMessage(Message));
if LeftButtonDown then
PaintScroll;
Handled := True;
end;
How should this problems be solved?
Thanks.
There are multiple problems with your approach. The quick answer is:
Do not do this. Instead, set the controls's BiDiMode property to bdRightToLeft. Unless I am missing something, that will get you the behavior you need and I tested it now, there are no problems with scrolling with themes this way.
There are two big problems with the way you are tying to do this:
You can't guarantee the control will keep the settings you are forcing into it. The first time the VCL needs to recreate the Window for the control, your settings will be obliterated.
You are assuming that the VCL doesn't need to account for this setting in some way. Clearly it does, because you are getting bad behavior when trying to undercut the VCL and send the style directly to the Window. If you really want to directly control the window style, you need to create your own descendant of the control class and handle everything related in the proper places-- you can't just pick any old time you want to change the control to RTL with a Windows API call (rather than the control's properties) and expect that the control will continue to work properly.
Related
I use the OnCustomDrawItem event to draw a TTreeView like this :
Here is my code :
procedure Tform1.trvArbreCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
var
vRect : TRect;
vBmp : TBitmap;
vBmpRect : TRect;
vTreeView : TTreeView;
vBarreInfo : TScrollInfo;
vDeltaX : Integer;
begin
DefaultDraw := False;
vTreeView := TTreeView(Sender);
vRect := Node.DisplayRect(False);
vBmp := TBitmap.Create();
FillChar(vBarreInfo, SizeOF(vBarreInfo), 0);
vBarreInfo.cbSize := SizeOf(vBarreInfo);
vBarreInfo.fMask := SIF_RANGE or SIF_POS;
if GetScrollInfo(trvArbre.Handle, SB_HORZ, vBarreInfo) then
begin
if vBarreInfo.nMax > vRect.Right - vRect.Left then
begin
vBmp.Width := vBarreInfo.nMax + 1;
vBmp.Height := vRect.Bottom - vRect.Top;
vDeltaX := vBarreInfo.nPos;
end
else
begin
vBmp.Width := vRect.Right - vRect.Left;
vBmp.Height := vRect.Bottom - vRect.Top;
vDeltaX := 0;
end;
end
else
begin
vBmp.Width := vRect.Right - vRect.Left;
vBmp.Height := vRect.Bottom - vRect.Top;
vDeltaX := 0;
end;
vBmpRect := Rect(0, 0, vBmp.Width, vBmp.Height);
if cdsSelected in State then
begin
vBmp.Canvas.Brush.Color := cMenuDownFond;
vBmp.Canvas.Pen .Color := cMenuDownBordure;
end
else if cdsHot in State then
begin
vBmp.Canvas.Brush.Color := cMenuSurvolFond;
vBmp.Canvas.Pen .Color := cMenuSurvolBordure;
end
else
begin
vBmp.Canvas.Brush.Color := clWhite;
vBmp.Canvas.Pen .Color := clwhite;
end;
vBmp.Canvas.Rectangle(vBmpRect);
vBmpRect.Left := vBmpRect.Left + 3;
vBmpRect.Left := vBmpRect.Left + (Node.Level * vTreeView.Indent);
if Node.StateIndex >= 0 then
begin
vTreeView.StateImages.Draw(vBmp.Canvas, vBmpRect.Left, vBmpRect.Top, Node.StateIndex);
end;
vBmpRect.Left := vBmpRect.Left + 18;
vTreeView.Images.Draw(vBmp.Canvas, vBmpRect.Left, vBmpRect.Top, Node.ImageIndex);
vBmpRect.Left := vBmpRect.Left + 18 + 3;
vBmp.Canvas.Font := vTreeView.Font;
DrawText
(
vBmp.Canvas.Handle,
PChar(Node.Text),
Length(Node.Text),
vBmpRect,
DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_NOPREFIX or DT_END_ELLIPSIS
);
BitBlt
(
Sender.Canvas.Handle,
vRect.Left,
vRect.Top,
vRect.Right - vRect.Left,
vRect.Bottom - vRect.Top,
vBmp.Canvas.Handle,
vDeltaX,
0,
SRCCOPY
);
FreeAndNil(vBmp);
end;
My problem is that the node "My last node wich is not too long" is not too long to justify the presence of the horizontal scrollbar.
When I set DefaultDraw to true I obtain :
It seems that the width of the node is computed with a font I don't use.
I tried to change the font of the canvas, to use Windows API, to use the OnAdvancedCustomDrawItem with no result.
Thanks.
I use Delphi 7. I copied ComCtrls.pas in the folder of my application. I changed procedure TCustomTreeView.CNNotify(var Message: TWMNotify);. Line 8979 from Result := Result or CDRF_SKIPDEFAULT to Result := Result or CDRF_SKIPDEFAULT; and I commented line 8980 else if FCanvasChanged then in order to simulate DefaultDraw=True and FCanvasChanged even if I set DefaultDraw to False in event et don't change font. After a lot of tests, I don't see any caveats.
When dropping this component onto the form, The TImage is not showing the map image (hexagons) Until i drag the component around on the form , Then it will show it until i stop dragging it around on the form. (this is all in desgin mode). How do i make it show all the time? not when just dragging it.
type
THexMap = Class(TScrollingWinControl)
Constructor
Constructor THexMap.Create(AOwner: Tcomponent);
begin
inherited Create(AOwner);
Width := DEFAULT_MAP_WIDTH;
Height := DEFAULT_MAP_HEIGHT;
FCanvas := timage.Create(self);
tempMap := timage.Create(self);
fcanvas.Parent := self;
tempmap.Parent := self;
fCanvas.Width := DEFAULT_MAP_WIDTH;
fCAnvas.Height := DEFAULT_MAP_WIDTH;
{ Set intial property values for component }
//create map
MakeSolidMap;
end;
MakeSolidMap
Procedure THexMap.MakeSolidMap;
var
p0 : TPoint;
looprow,Loopcol : integer;
begin
TempMap.width := ((HexColumns-1) * round((1.5 * HexRadius))) + (2 * hexRadius);
TempMap.height := ((HexRows) * (2 * rise)) + rise;
With TempMap.Canvas do
begin
{set Background color}
brush.Color := BackColor;
fillrect(rect(0,0,TempMap.Width,TempMap.Height));
{draw Hex's left to right / top to bottom}
for looprow := 1 to HexRows do
begin
for loopcol := 1 to HexColumns do
begin
{compute center coords}
p0 := ConvertCoords(Point(LoopCol,LoopRow),ptROWCOL);
{draw the hex}
DrawSolidHex(Tempmap,bsSolid,hexColor,psSolid,LineColor,P0.X,p0.Y,hexRadius,hex3d);
end;
end;
end;
end;
DrawSoildHex
procedure THexMap.DrawSolidHex(Target: timage;
FillStyle: TBrushStyle;
FillColor: TColor;
LineStyle: TPenStyle;
LineColor: TColor;
x: Integer;
y: Integer;
Radius: Integer;
button: Boolean);
var
p0,p1,p2,p3,p4,p5,p6:TPoint;
begin
p0 := Point(x,y);
{compute each point based on hex center}
p1.X := p0.X - round(Radius /2);
p1.Y := p0.Y - rise;
p2.X := p0.X + round(Radius/2);
p2.Y := p1.Y;
p3.X := p0.X + Radius;
p3.Y := p0.Y;
p4.X := p2.X;
p4.Y := p0.Y + rise;
p5.X := p1.X;
p5.Y := p4.Y;
p6.X := p0.X - Radius;
p6.Y := p0.Y;
{set color / style of lines}
target.canvas.Pen.Color := LineColor;
target.canvas.Pen.Style := LineStyle;
{set color / style of hex}
target.canvas.Brush.Color := FillColor;
Target.canvas.Brush.Style := FillStyle;
{draw the hex}
target.canvas.Polygon([p1,p2,p3,p4,p5,p6]);
{if desired, draw the boarder for the hex}
if button = true then
begin
with target.canvas do
begin
pen.Mode :=pmCopy;
pen.Color :=clWhite;
moveto(p5.X+1,p5.Y-1);
lineto(p6.X+1,p6.Y);
lineto(p1.X+1,p1.Y+1);
lineto(p2.X-1,p2.Y+1);
pen.Color :=clBlack;
lineto(p3.X-1,p3.Y);
lineto(p4.X-1,p4.Y-1);
lineto(p5.X+1,p5.Y-1);
end;
end;
invalidate;
end;
WndProc
procedure THexMap.WndProc(var Message: TMessage);
const
DISCARD_CURRENT_ORIGIN = nil;
var
R : TRect;
PS : PAINTSTRUCT;
begin
if Message.Msg = WM_PAINT then
begin
if GetUpdateRect( Handle, nil, false ) then
begin
BeginPaint( Handle, PS );
try
R := PS.rcPaint;
bitblt(fCanvas.Canvas.Handle, R.Left, R.Top, R.Width, R.Height, TempMap.Canvas.Handle, R.Left+FOffset.X, R.Top+FOffset.Y, SRCCOPY);
finally
EndPaint( Handle, PS );
end;
end
else
inherited;
end
else
inherited;
end;
Nothing shows because you have taken over painting the control by handing WM_PAINT. And in your handling of WM_PAINT you do not paint anything to the device context returned by BeginPaint. You do not call the inherited handler which would call Paint and then paint children. Hence nothing appears in your control.
It seems to me that you need to decide to either use visual controls and let the VCL paint them, or paint your control yourself. You are currently attempting to do both but achieving neither!
I cannot suggest a fix because I've really no idea what you are doing. I don't understand why you have visual controls and override the paint message handler. To go forward you'll need to pick one approach or the other.
On Windows default appearance the tabsheet caption are showed in horizontal (left to right 1) and with the VCL styles enabled they are displayed in vertical (down to top[2]). How I can fix this on Delphi XE5?
Detail: I'm using the JvgPageControl component, from JEDI-VCL 3.58.
I want to create an similar interface of DisplayFusion welcome screen [3]. Suggestions are welcome!
Images:
Thanks in advance!
The TJvgPageControl uses the same vcl style hook (TTabControlStyleHook) of the TPageControl control, so you must create a new style hook inherited from the TTabControlStyleHook and override the DrawTab method.
Check this basic implementation for the new style hook
type
TTabControlStyleHookExt = class(TTabControlStyleHook)
protected
procedure DrawTab(Canvas: TCanvas; Index: Integer); override;
end;
TCustomTabControlClass = class(TCustomTabControl);
{ TTabControlStyleHookExt }
procedure TTabControlStyleHookExt.DrawTab(Canvas: TCanvas; Index: Integer);
var
R, LayoutR, GlyphR: TRect;
ImageWidth, ImageHeight, ImageStep : Integer;
LDrawState: TThemedTab;
LDetails: TThemedElementDetails;
ThemeTextColor: TColor;
FImageIndex: Integer;
begin
if TabPosition <> tpLeft then
begin
inherited ;
exit;
end;
if (Images <> nil) and (Index < Images.Count) then
begin
ImageWidth := Images.Width;
ImageHeight := Images.Height;
ImageStep := 3;
end
else
begin
ImageWidth := 0;
ImageHeight := 0;
ImageStep := 0;
end;
R := TabRect[Index];
if R.Left < 0 then Exit;
if Index = TabIndex then
Dec(R.Left, 2)
else
Dec(R.Right, 2);
Canvas.Font.Assign(TCustomTabControlClass(Control).Font);
LayoutR := R;
if Index = TabIndex then
LDrawState := ttTabItemLeftEdgeSelected
else if (Index = HotTabIndex) and MouseInControl then
LDrawState := ttTabItemLeftEdgeHot
else
LDrawState := ttTabItemLeftEdgeNormal;
LDetails := StyleServices.GetElementDetails(LDrawState);
StyleServices.DrawElement(Canvas.Handle, LDetails, R);
{ Image }
if Control is TCustomTabControl then
FImageIndex := TCustomTabControlClass(Control).GetImageIndex(Index)
else
FImageIndex := Index;
if (Images <> nil) and (FImageIndex >= 0) and (FImageIndex < Images.Count) then
begin
GlyphR := LayoutR;
GlyphR.Bottom := GlyphR.Bottom - ImageStep;
GlyphR.Top := GlyphR.Bottom - ImageHeight;
LayoutR.Bottom := GlyphR.Top;
GlyphR.Left := GlyphR.Left + (GlyphR.Right - GlyphR.Left) div 2 - ImageWidth div 2;
if StyleServices.Available then
StyleServices.DrawIcon(Canvas.Handle, LDetails, GlyphR, Images.Handle, FImageIndex);
end;
{ Text }
if StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then
Canvas.Font.Color := ThemeTextColor;
//use the top tab style to draw the text
if Index = TabIndex then
LDetails := StyleServices.GetElementDetails(ttTabItemSelected)
else
if (Index = HotTabIndex) and MouseInControl then
LDetails := StyleServices.GetElementDetails(ttTabItemHot)
else
LDetails := StyleServices.GetElementDetails(ttTabItemNormal);
DrawControlText(Canvas, LDetails, Tabs[Index], LayoutR, DT_VCENTER or DT_CENTER or DT_SINGLELINE or DT_NOCLIP);
end;
Then register the new style hook like this
initialization
TStyleEngine.RegisterStyleHook(TJvgPageControl, TTabControlStyleHookExt);
I'm working on a PingTool and I've got a TabSheet of dynamically created buttons(anywhere from 1-150 based on user input) and I would like to be able to pass the OnClick command to all buttons on the given TabSheet. My individual button clicks successfully run my ping code, but I get a EStackOverflow message when clicking my PingAll button. Any help would be greatly appreciated. Code Excerpt below:
Code used for button creation:
begin
For x := 0 to CheckListBox1.Items.Count -1 Do
Begin
If CheckListBox1.Checked[x]=true then
begin
GLCount := (GLCount +1);
theIP :=(CheckListBox1.Items.Strings[x]);
if GLcount < 10 then begin
B := TColorButton.Create(Self);
B.Name:= ('BTN'+intToStr(GLCount+1));
B.Caption := theIP;
B.Parent := TabSheet2;
B.Height := 25;
B.Width := 97;
B.Left := 0 + GLCount * 96;
B.Top := 8;
B.BackColor := clBtnFace;
B.ForeColor := clBtnText;
B.OnClick := CustomButtonClick;
end;
CustomButtonClick Code:
Procedure TForm1.CustomButtonClick(Sender: TObject);
begin
GlobalIP:=TColorButton(Sender).caption;
IdIcmpClient1.Host := GlobalIP;
IdIcmpClient1.ReceiveTimeout := 500;
IdIcmpClient1.Ping();
case IdIcmpClient1.ReplyStatus.ReplyStatusType of
rsEcho:
TColorButton(Sender).BackColor := clGreen;
rsTimeOut:
TColorButton(Sender).BackColor := clRed;
end;
end;
PingAll Code(not working):
procedure TForm1.PingAllClick(Sender: TObject);
var
i: integer;
begin
For i := 0 to TabSheet2.ControlCount -1 do
if TabSheet2.Controls[i] is TColorButton then
begin
TColorButton(Sender).Click;
end;
end;
You are calling recurcive the method PingAllClick... look that you call TColorButton(Sender).Click instead
....
Control := tabSheet2.Controls[i]
if Control is TColorButton then
TColorButton(Control ).Click()
....
I try to create a custom Combobox control that popups a Treeview.
Everything looks fine.
But when i try to add runtime resize functionality to that control, the popup window (Treeview) just move and won't change its size.
Any suggestion would be appreciated.
Snippets for Popup Window :
On Create :
ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable, csDoubleClicks];
On Create Params :
begin
inherited CreateParams(Params);
with Params do
begin
Style := Style or WS_POPUP or WS_VSCROLL or WS_BORDER;
ExStyle := WS_EX_TOOLWINDOW;
AddBiDiModeExStyle(ExStyle);
//WindowClass.Style := CS_SAVEBITS; {this would prevent ondoubleclick event}
end;
On Mouse Move :
var
ARect, RR: TRect;
DragStyle: TDragStyle;
Procedure SetDragStyle(ds:TDragStyle; c:TCursor);
begin
FDragStyle:=ds;
Cursor:=c;
end;
begin
inherited;
FMouseMoveSelected := GetNodeAt(x, y);
if FDragged then begin
case FDragStyle of
dsSizeLeft :begin
SetWindowPos(Handle, HWND_TOP, Left+(x-FDragPos.X), Top, Width, Height,
SWP_NOACTIVATE or SWP_SHOWWINDOW);
//Left:=Left+(x-FDragPos.X); {alternate code that doesn't work either}
end;
end;
FDragPos:=Point(x,y);
end else begin
SetDragStyle(dsMove,crDefault);
ARect := GetClientRect;
RR:=ARect;
InflateRect(RR,-2,-2);
if (x>=0) and (x<=Width) and (y>=0) and (y<=Height) and (not PtInRect(RR,Point(x,y))) then begin
if (x<=RR.Left) then begin
//if (y<=RR.Top) then SetDragStyle(dsSizeTopLeft,crSizeNWSE)else
if (y>=RR.Bottom) then SetDragStyle(dsSizeBottomLeft,crSizeNESW)
else SetDragStyle(dsSizeLeft,crSizeWE);
end else if (x>=RR.Right) then begin
//if (y<=RR.Top) then SetDragStyle(dsSizeTopRight,crSizeNESW) else
if (y>=RR.Bottom) then SetDragStyle(dsSizeBottomRight,crSizeNWSE)
else SetDragStyle(dsSizeRight,crSizeWE);
end else begin
//if (y<=RR.Top) then SetDragStyle(dsSizeTop,crSizeNS) else
if (y>=RR.Bottom) then SetDragStyle(dsSizeBottom,crSizeNS)
else SetDragStyle(dsMove,crDefault);
end;
end;
end;
end;
end;
On Mouse Down :
begin
inherited;
if FDragStyle<>dsMove then begin
FDragPos:=point(x,y);
FDragged:=true;
end;
end;
On Mouse Up :
begin
inherited;
FDragged:=false;
end;
You're mixing client coordinates with screen coordinates in the SetWindowPos call. That's because you're floating a window that's not supposed to float and the VCL has no knowledge of it. When you refer to its Left, the VCL returns a coordinate relative to its parent, probably the form. Also don't change the point you saved while you started to drag during the drag (that being FDragPos):
procedure TPanel.MouseMove(Shift: TShiftState; X, Y: Integer);
var
ARect, RR: TRect;
DragStyle: TDragStyle;
Procedure SetDragStyle(ds:TDragStyle; c:TCursor);
begin
FDragStyle:=ds;
Cursor:=c;
end;
var
DragOffset: Integer;
begin
inherited;
FMouseMoveSelected := GetNodeAt(x, y);
if FDragged then begin
case FDragStyle of
dsSizeLeft:
begin
DragOffset := X - FDragPos.X;
winapi.windows.GetWindowRect(Handle, ARect);
SetWindowPos(Handle, HWND_TOP,
ARect.Left + DragOffset,
ARect.Top,
ARect.Right - ARect.Left - DragOffset,
ARect.Bottom - ARect.Top,
SWP_NOACTIVATE or SWP_SHOWWINDOW);
//Left:=Left+(x-FDragPos.X); {alternate code that doesn't work either}
end;
end;
// FDragPos:=Point(x,y); // do not change drag origin while you're dragging
end else begin
..