|
@@ -1309,8 +1309,6 @@ type
|
|
|
FLayoutNode: TFresnelLayoutNode;
|
|
|
FFontDesc: TFresnelFontDesc;
|
|
|
FRendered: boolean;
|
|
|
- FRenderedBorderBox: TFresnelRect;
|
|
|
- FRenderedContentBox: TFresnelRect;
|
|
|
FScrollBarHorizontal: TPseudoElScrollBar;
|
|
|
FScrollBarVertical: TPseudoElScrollBar;
|
|
|
FScrollLeft: TFresnelLength;
|
|
@@ -1320,6 +1318,7 @@ type
|
|
|
FStandardEvents : Array[0..evtLastEvent] of TEventHandlerItem;
|
|
|
FEventDispatcher : TFresnelEventDispatcher;
|
|
|
FUsedBorderBox: TFresnelRect;
|
|
|
+ FUsedClientBox: TFresnelRect;
|
|
|
FUsedContentBox: TFresnelRect;
|
|
|
function GetClientHeight: TFresnelLength;
|
|
|
function GetClientWidth: TFresnelLength;
|
|
@@ -1504,13 +1503,18 @@ type
|
|
|
function GetIntrinsicContentSize(aMode: TFresnelLayoutMode; aMaxWidth: TFresnelLength = NaN; aMaxHeight: TFresnelLength = NaN): TFresnelPoint; virtual; // ignoring min|max-height
|
|
|
function GetContainerContentWidth(UseNaNOnFail: boolean): TFresnelLength; virtual; // used value
|
|
|
function GetContainerContentHeight(UseNaNOnFail: boolean): TFresnelLength; virtual; // used value
|
|
|
- function GetContainerOffset: TFresnelPoint; virtual;
|
|
|
+ function GetContainerOffset: TFresnelPoint;
|
|
|
function IsBlockFormattingContext: boolean; virtual;
|
|
|
+ function GetUsedPaddingBox: TFresnelRect;
|
|
|
+ function GetBorderBoxOnViewport: TFresnelRect;
|
|
|
+ function ClientToBorderPos(const X, Y: TFresnelLength): TFresnelPoint;
|
|
|
+ function BorderToClientPos(const X, Y: TFresnelLength): TFresnelPoint;
|
|
|
property ClientWidth: TFresnelLength read GetClientWidth;
|
|
|
property ClientHeight: TFresnelLength read GetClientHeight;
|
|
|
property LayoutNode: TFresnelLayoutNode read FLayoutNode write FLayoutNode;
|
|
|
- property UsedBorderBox: TFresnelRect read FUsedBorderBox write FUsedBorderBox; // relative to layout parent's used contentbox
|
|
|
- property UsedContentBox: TFresnelRect read FUsedContentBox write FUsedContentBox; // relative to layout parent's used contentbox
|
|
|
+ property UsedBorderBox: TFresnelRect read FUsedBorderBox write FUsedBorderBox; // relative to layout parent's clientbox
|
|
|
+ property UsedContentBox: TFresnelRect read FUsedContentBox write FUsedContentBox; // the content including scroll gutters, relative to layout parent's clientbox
|
|
|
+ property UsedClientBox: TFresnelRect read FUsedClientBox write FUsedClientBox; // the content excluding scroll gutters, relative to layout parent's clientbox
|
|
|
// Scrolling
|
|
|
property ScrollLeft: TFresnelLength read FScrollLeft write SetScrollLeft;
|
|
|
property ScrollTop: TFresnelLength read FScrollTop write SetScrollTop;
|
|
@@ -1519,11 +1523,7 @@ type
|
|
|
property ScrollBarHorizontal: TPseudoElScrollBar read FScrollBarHorizontal;
|
|
|
property ScrollBarVertical: TPseudoElScrollBar read FScrollBarVertical;
|
|
|
// Renderer
|
|
|
- function GetBorderBoxOnViewport: TFresnelRect; virtual;
|
|
|
- function GetRenderedPaddingBox: TFresnelRect;
|
|
|
property Rendered: boolean read FRendered write FRendered;
|
|
|
- property RenderedBorderBox: TFresnelRect read FRenderedBorderBox write FRenderedBorderBox; // relative to layout parent's rendered contentbox
|
|
|
- property RenderedContentBox: TFresnelRect read FRenderedContentBox write FRenderedContentBox; // relative to layout parent's rendered contentbox
|
|
|
// Events
|
|
|
function AddEventListener(aID : TEventID; aHandler : TFresnelEventHandler) : Integer;
|
|
|
function AddEventListener(Const aName: TEventName; aHandler : TFresnelEventHandler) : Integer;
|
|
@@ -1609,7 +1609,6 @@ type
|
|
|
MouseDownPos: TFresnelLength;
|
|
|
constructor Create(TheElement: TFresnelElement; aHorizontal: boolean); overload;
|
|
|
function GetHit(const X, Y: TFresnelLength; out aPosition: TFresnelLength): THit; virtual; abstract;
|
|
|
- procedure MouseHandler(WSData: TFresnelMouseEventInit; MouseEventId: TEventID); virtual; abstract;
|
|
|
property Horizontal: boolean read FHorizontal;
|
|
|
end;
|
|
|
|
|
@@ -1632,9 +1631,9 @@ type
|
|
|
|
|
|
IFresnelVPApplication = interface ['{2075A1FE-F729-4083-8CE5-01932ADB4D69}']
|
|
|
function GetHoverElements: TFresnelElementArray;
|
|
|
- function GetMouseDownElement(out PageXY: TFresnelPoint): TFresnelElement;
|
|
|
+ function GetMouseDownElement(out ViewportXY: TFresnelPoint): TFresnelElement;
|
|
|
procedure SetHoverElements(const ElArr: TFresnelElementArray);
|
|
|
- procedure SetMouseDownElement(El: TFresnelElement; const PageXY: TFresnelPoint);
|
|
|
+ procedure SetMouseDownElement(El: TFresnelElement; const ViewportXY: TFresnelPoint);
|
|
|
end;
|
|
|
|
|
|
TFresnelVPPointerCapture = record
|
|
@@ -1776,15 +1775,19 @@ type
|
|
|
class function CSSTypeID: TCSSNumericalID; override;
|
|
|
class function CSSTypeName: TCSSString; override;
|
|
|
class function GetCSSTypeStyle: TCSSString; override;
|
|
|
- function GetElementAt(const x, y: TFresnelLength): TFresnelElement; virtual;
|
|
|
- function GetElementsAt(const x, y: TFresnelLength): TFresnelElementArray; virtual;
|
|
|
+ function GetElementAt(const x, y: TFresnelLength): TFresnelElement;
|
|
|
+ function GetElementsAt(const x, y: TFresnelLength): TFresnelElementArray;
|
|
|
// returns in stacking order top to bottom aka child to parents
|
|
|
procedure GetElementsAt(const x, y: TFresnelLength; OnlyLast: boolean;
|
|
|
- out Arr: TFresnelElementArray; out Hit: THit); virtual;
|
|
|
- function ContentToPagePos(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; virtual; overload; // content box of El to content of viewport
|
|
|
- function ContentToPagePos(El: TFresnelElement; const p: TFresnelPoint): TFresnelPoint; overload; // content box of El to content of viewport
|
|
|
- function PageToContentPos(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; virtual; overload; // content of viewport to content box of El
|
|
|
- function PageToContentPos(El: TFresnelElement; const p: TFresnelPoint): TFresnelPoint; virtual; overload; // content of viewport to content box of El
|
|
|
+ out Arr: TFresnelElementArray; out Hit: THit); virtual; // viewport coords
|
|
|
+ function ClientPosToViewport(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; overload; // child coord to viewport
|
|
|
+ function ViewportToClientPos(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; overload; // viewport to child coord
|
|
|
+ function ViewportToClientPos(El: TFresnelElement; const p: TFresnelPoint): TFresnelPoint; overload; // viewport to child coord
|
|
|
+ function PaddingBoxToViewport(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; overload; // padding-box coord of El to viewport
|
|
|
+ function PaddingBoxToViewport(El: TFresnelElement; const p: TFresnelPoint): TFresnelPoint; overload; // padding-box of El to viewport
|
|
|
+ function ViewportToPaddingBox(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; overload; // viewport to padding-box coord of El
|
|
|
+ function ViewportToPaddingBox(El: TFresnelElement; const p: TFresnelPoint): TFresnelPoint; overload; // viewport to padding-box coord of El
|
|
|
+ function GetPointerCaptureEl(const aPointerId: TFreHandle): TFresnelElement;
|
|
|
procedure SetPointerCapture(const aPointerId: TFreHandle); override; overload;
|
|
|
procedure SetPointerCapture(El: TFresnelElement; const aPointerId: TFreHandle); virtual; overload;
|
|
|
procedure ReleasePointerCapture(const aPointerId: TFreHandle); override; overload;
|
|
@@ -6604,7 +6607,7 @@ end;
|
|
|
|
|
|
constructor TPseudoElScrollBar.Create(TheElement: TFresnelElement; aHorizontal: boolean);
|
|
|
begin
|
|
|
- inherited Create(TheElement);
|
|
|
+ Create(TheElement);
|
|
|
FHorizontal:=aHorizontal;
|
|
|
Parent:=TheElement;
|
|
|
if Horizontal then
|
|
@@ -7075,46 +7078,43 @@ procedure TFresnelViewport.GetElementsAt(const x, y: TFresnelLength; OnlyLast: b
|
|
|
var
|
|
|
El: TFresnelElement;
|
|
|
i: Integer;
|
|
|
- BorderBox, r: TFresnelRect;
|
|
|
+ BorderBox, r, c: TFresnelRect;
|
|
|
aContentOffset: TFresnelPoint;
|
|
|
- HitX, HitY: TFresnelLength;
|
|
|
aBar: TPseudoElScrollBar;
|
|
|
ClipHorizontal, ClipVertical: Boolean;
|
|
|
+ CurX, CurY: TFresnelLength;
|
|
|
begin
|
|
|
Result:=false;
|
|
|
if Node=nil then exit;
|
|
|
El:=Node.Element;
|
|
|
if not El.Rendered then exit;
|
|
|
|
|
|
- HitX:=x-dx;
|
|
|
- HitY:=y-dy;
|
|
|
-
|
|
|
ClipHorizontal:=flfClipHorizontal in Node.Flags;
|
|
|
ClipVertical:=flfClipVertical in Node.Flags;
|
|
|
if ClipHorizontal or ClipVertical then
|
|
|
begin
|
|
|
- r:=El.GetRenderedPaddingBox;
|
|
|
+ r:=El.GetUsedPaddingBox;
|
|
|
//writeln('TFresnelElement.GetElementAts ',El.Name,' ClipH=',ClipHorizontal,' ClipV=',ClipVertical,' Hit=',FloatToCSSStr(HitX),',',FloatToCSSStr(HitY),' PadBox=',r.ToString);
|
|
|
if ClipHorizontal then
|
|
|
begin
|
|
|
- if HitX<r.Left then exit;
|
|
|
- if HitX>r.Right then exit;
|
|
|
+ if dx<r.Left then exit;
|
|
|
+ if dx>r.Right then exit;
|
|
|
end;
|
|
|
if ClipVertical then
|
|
|
begin
|
|
|
- if HitY<r.Top then exit;
|
|
|
- if HitY>r.Bottom then exit;
|
|
|
+ if dy<r.Top then exit;
|
|
|
+ if dy>r.Bottom then exit;
|
|
|
end;
|
|
|
aBar:=El.ScrollBarHorizontal;
|
|
|
//if aBar<>nil then writeln('Check ',aBar.Box.ToString);
|
|
|
- if (aBar<>nil) and aBar.Box.Contains(HitX,HitY) then
|
|
|
+ if (aBar<>nil) and aBar.Box.Contains(dx,dy) then
|
|
|
begin
|
|
|
Arr:=[El];
|
|
|
Hit:=THit.hScrollbarHorz;
|
|
|
exit(true);
|
|
|
end;
|
|
|
aBar:=El.ScrollBarVertical;
|
|
|
- if (aBar<>nil) and aBar.Box.Contains(HitX,HitY) then
|
|
|
+ if (aBar<>nil) and aBar.Box.Contains(dx,dy) then
|
|
|
begin
|
|
|
Arr:=[El];
|
|
|
Hit:=THit.hScrollbarVert;
|
|
@@ -7123,16 +7123,17 @@ procedure TFresnelViewport.GetElementsAt(const x, y: TFresnelLength; OnlyLast: b
|
|
|
end;
|
|
|
|
|
|
if Node.NodeCount>0 then begin
|
|
|
- aContentOffset:=El.RenderedContentBox.TopLeft;
|
|
|
+ c:=El.UsedClientBox;
|
|
|
+ CurX:=dx-c.Left+El.ScrollLeft;
|
|
|
+ CurY:=dy-c.Top+El.ScrollTop;
|
|
|
for i:=Node.NodeCount-1 downto 0 do
|
|
|
begin
|
|
|
- if Check(Node.Nodes[i],dx+aContentOffset.X,dy+aContentOffset.Y)
|
|
|
- and OnlyLast then
|
|
|
+ if Check(Node.Nodes[i],CurX,CurY) and OnlyLast then
|
|
|
exit;
|
|
|
end;
|
|
|
end;
|
|
|
- BorderBox:=El.RenderedBorderBox;
|
|
|
- if BorderBox.Contains(HitX,HitY) then
|
|
|
+ BorderBox:=El.UsedBorderBox;
|
|
|
+ if BorderBox.Contains(dx,dy) then
|
|
|
begin
|
|
|
if length(Arr)=0 then
|
|
|
begin
|
|
@@ -7148,52 +7149,102 @@ procedure TFresnelViewport.GetElementsAt(const x, y: TFresnelLength; OnlyLast: b
|
|
|
begin
|
|
|
Arr:=[];
|
|
|
Hit:=THit.hNone;
|
|
|
- Check(LayoutNode,0,0);
|
|
|
+ Check(LayoutNode,x,y);
|
|
|
//writeln('TFresnelViewport.GetElementsAt END ',Hit);
|
|
|
end;
|
|
|
|
|
|
-function TFresnelViewport.ContentToPagePos(El: TFresnelElement; const x,
|
|
|
- y: TFresnelLength): TFresnelPoint;
|
|
|
+function TFresnelViewport.ClientPosToViewport(El: TFresnelElement; const x, y: TFresnelLength
|
|
|
+ ): TFresnelPoint;
|
|
|
var
|
|
|
Node: TFresnelLayoutNode;
|
|
|
- aContentOffset: TFresnelPoint;
|
|
|
+ c: TFresnelRect;
|
|
|
begin
|
|
|
Result.X:=x;
|
|
|
Result.Y:=y;
|
|
|
- if not El.Rendered then exit;
|
|
|
Node:=El.LayoutNode;
|
|
|
-
|
|
|
+ if Node.SkipRendering then exit;
|
|
|
+ c:=El.UsedClientBox;
|
|
|
+ Result.X+=c.Left;
|
|
|
+ Result.Y+=c.Top;
|
|
|
repeat
|
|
|
- aContentOffset:=El.RenderedContentBox.TopLeft;
|
|
|
- Result.X+=aContentOffset.X;
|
|
|
- Result.Y+=aContentOffset.Y;
|
|
|
+ Node:=Node.Parent;
|
|
|
if Node=nil then exit;
|
|
|
+ El:=Node.Element;
|
|
|
+ c:=El.UsedClientBox;
|
|
|
+ Result.X+=c.Left-El.ScrollLeft;
|
|
|
+ Result.Y+=c.Top-El.ScrollTop;
|
|
|
+ until false;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelViewport.ViewportToClientPos(El: TFresnelElement; const x, y: TFresnelLength
|
|
|
+ ): TFresnelPoint;
|
|
|
+var
|
|
|
+ p: TFresnelPoint;
|
|
|
+begin
|
|
|
+ p:=ClientPosToViewport(El,0,0);
|
|
|
+ Result.X:=x-p.x;
|
|
|
+ Result.Y:=y-p.y;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelViewport.ViewportToClientPos(El: TFresnelElement; const p: TFresnelPoint
|
|
|
+ ): TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result:=ViewportToClientPos(El,p.X,p.Y);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelViewport.PaddingBoxToViewport(El: TFresnelElement; const x, y: TFresnelLength
|
|
|
+ ): TFresnelPoint;
|
|
|
+var
|
|
|
+ Node: TFresnelLayoutNode;
|
|
|
+ c: TFresnelRect;
|
|
|
+begin
|
|
|
+ Result.X:=x;
|
|
|
+ Result.Y:=y;
|
|
|
+ Node:=El.LayoutNode;
|
|
|
+ if Node.SkipRendering then exit;
|
|
|
+ Result.X+=Node.BorderLeft+El.UsedBorderBox.Left;
|
|
|
+ Result.Y+=Node.BorderTop+El.UsedBorderBox.Top;
|
|
|
+ repeat
|
|
|
Node:=Node.Parent;
|
|
|
if Node=nil then exit;
|
|
|
El:=Node.Element;
|
|
|
- until El=nil;
|
|
|
+ c:=El.UsedClientBox;
|
|
|
+ Result.X+=c.Left-El.ScrollLeft;
|
|
|
+ Result.Y+=c.Top-El.ScrollTop;
|
|
|
+ until false;
|
|
|
end;
|
|
|
|
|
|
-function TFresnelViewport.ContentToPagePos(El: TFresnelElement; const p: TFresnelPoint
|
|
|
+function TFresnelViewport.PaddingBoxToViewport(El: TFresnelElement; const p: TFresnelPoint
|
|
|
): TFresnelPoint;
|
|
|
begin
|
|
|
- Result:=ContentToPagePos(El,p.X,p.Y);
|
|
|
+ Result:=PaddingBoxToViewport(El,p.X,p.Y);
|
|
|
end;
|
|
|
|
|
|
-function TFresnelViewport.PageToContentPos(El: TFresnelElement; const x,
|
|
|
- y: TFresnelLength): TFresnelPoint;
|
|
|
+function TFresnelViewport.ViewportToPaddingBox(El: TFresnelElement; const x, y: TFresnelLength
|
|
|
+ ): TFresnelPoint;
|
|
|
var
|
|
|
p: TFresnelPoint;
|
|
|
begin
|
|
|
- p:=ContentToPagePos(El,0,0);
|
|
|
+ p:=PaddingBoxToViewport(El,0,0);
|
|
|
Result.X:=x-p.X;
|
|
|
Result.Y:=y-p.Y;
|
|
|
end;
|
|
|
|
|
|
-function TFresnelViewport.PageToContentPos(El: TFresnelElement; const p: TFresnelPoint
|
|
|
+function TFresnelViewport.ViewportToPaddingBox(El: TFresnelElement; const p: TFresnelPoint
|
|
|
): TFresnelPoint;
|
|
|
begin
|
|
|
- Result:=PageToContentPos(El,p.X,p.Y);
|
|
|
+ Result:=ViewportToPaddingBox(El,p.X,p.Y);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelViewport.GetPointerCaptureEl(const aPointerId: TFreHandle): TFresnelElement;
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+begin
|
|
|
+ if aPointerId=nil then exit(nil);
|
|
|
+ for i:=0 to length(FPointerCaptures)-1 do
|
|
|
+ if FPointerCaptures[i].Id=aPointerId then
|
|
|
+ exit(FPointerCaptures[i].Element);
|
|
|
+ Result:=nil;
|
|
|
end;
|
|
|
|
|
|
procedure TFresnelViewport.SetPointerCapture(const aPointerId: TFreHandle);
|
|
@@ -7294,11 +7345,11 @@ end;
|
|
|
|
|
|
procedure TFresnelViewport.WSMouseXY(WSData: TFresnelMouseEventInit; MouseEventId: TEventID);
|
|
|
var
|
|
|
- El, BubbleEl, OldMouseDownEl: TFresnelElement;
|
|
|
+ El, BubbleEl, OldMouseDownEl, CaptEl: TFresnelElement;
|
|
|
MouseEvt: TFresnelMouseEvent;
|
|
|
ClickEvt: TFresnelMouseClickEvent;
|
|
|
NewHoverElements, OldHoverElements: TFresnelElementArray;
|
|
|
- NewPageXY, OldPageXY: TFresnelPoint;
|
|
|
+ NewViewportXY, OldViewportXY, NewPageXY: TFresnelPoint;
|
|
|
i: Integer;
|
|
|
j: SizeInt;
|
|
|
Hit: THit;
|
|
@@ -7306,10 +7357,16 @@ begin
|
|
|
if not (MouseEventId in [evtMouseDown,evtMouseUp,evtMouseMove,evtMouseEnter,evtMouseLeave]) then
|
|
|
exit;
|
|
|
|
|
|
- NewPageXY:=WSData.PagePos;
|
|
|
- GetElementsAt(NewPageXY.X,NewPageXY.Y,false,NewHoverElements,Hit);
|
|
|
+ // compute PagePos
|
|
|
+ NewViewportXY:=WSData.ViewportPos;
|
|
|
+ NewPageXY.X:=NewViewportXY.X-UsedClientBox.Left+ScrollLeft;
|
|
|
+ NewPageXY.Y:=NewViewportXY.Y-UsedClientBox.Top+ScrollTop;
|
|
|
+ WSData.PagePos:=NewPageXY;
|
|
|
+
|
|
|
+ // hover: get all elements under the pointer
|
|
|
+ GetElementsAt(NewViewportXY.X,NewViewportXY.Y,false,NewHoverElements,Hit);
|
|
|
OldHoverElements:=VPApplication.GetHoverElements;
|
|
|
- OldMouseDownEl:=VPApplication.GetMouseDownElement(OldPageXY);
|
|
|
+ OldMouseDownEl:=VPApplication.GetMouseDownElement(OldViewportXY);
|
|
|
|
|
|
MouseEvt:=nil;
|
|
|
try
|
|
@@ -7376,84 +7433,93 @@ begin
|
|
|
FreeAndNil(MouseEvt);
|
|
|
end;
|
|
|
|
|
|
- if length(NewHoverElements)>0 then
|
|
|
+ if MouseEventId=evtMouseLeave then
|
|
|
begin
|
|
|
- El:=NewHoverElements[0];
|
|
|
- WSData.ControlPos:=PageToContentPos(El,NewPageXY);
|
|
|
- end else begin
|
|
|
- El:=Self;
|
|
|
- WSData.ControlPos:=WSData.PagePos;
|
|
|
- end;
|
|
|
-
|
|
|
- case MouseEventId of
|
|
|
- evtMouseDown:
|
|
|
- VPApplication.SetMouseDownElement(El,NewPageXY);
|
|
|
- evtMouseLeave:
|
|
|
+ // mouse left the form
|
|
|
VPApplication.SetMouseDownElement(nil,NewPageXY);
|
|
|
- end;
|
|
|
-
|
|
|
- if MouseEventId in [evtMouseDown,evtMouseUp,evtMouseMove] then
|
|
|
+ end else if MouseEventId in [evtMouseDown,evtMouseUp,evtMouseMove] then
|
|
|
begin
|
|
|
- case Hit of
|
|
|
- THit.hScrollbarHorz: El.ScrollBarHorizontal.MouseHandler(WSData,MouseEventId);
|
|
|
- THit.hScrollbarVert: El.ScrollBarVertical.MouseHandler(WSData,MouseEventId);
|
|
|
- else
|
|
|
- MouseEvt:=nil;
|
|
|
- ClickEvt:=nil;
|
|
|
- try
|
|
|
- // Dispatch mouse down/move/up events, in stacking order top to bottom aka child to parent,
|
|
|
- // until an element stops the dispatch.
|
|
|
- i:=0;
|
|
|
- MouseEvt:=El.EventDispatcher.CreateEvent(El,MouseEventId) as TFresnelMouseEvent;
|
|
|
- MouseEvt.InitEvent(WSData);
|
|
|
-
|
|
|
- BubbleEl:=El;
|
|
|
- repeat
|
|
|
- if MouseEvt is TBubbleMouseDownEvent then
|
|
|
- TBubbleMouseDownEvent(MouseEvt).FElement:=BubbleEl
|
|
|
- else if MouseEvt is TBubbleMouseUpEvent then
|
|
|
- TBubbleMouseUpEvent(MouseEvt).FElement:=BubbleEl
|
|
|
- else if MouseEvt is TBubbleMouseMoveEvent then
|
|
|
- TBubbleMouseMoveEvent(MouseEvt).FElement:=BubbleEl;
|
|
|
-
|
|
|
- {$IFDEF VerboseFresnelMouse}
|
|
|
- writeln('TFresnelViewport.WSMouseXY ',MouseEventId,' ',BubbleEl.GetPath,' ',FloatToCSSStr(MouseEvt.X),',',FloatToCSSStr(MouseEvt.Y));
|
|
|
- {$ENDIF}
|
|
|
- BubbleEl.DispatchEvent(MouseEvt);
|
|
|
- inc(i);
|
|
|
- if (MouseEvt.PropagationStopped) or (i>=length(NewHoverElements)) then
|
|
|
- break;
|
|
|
- BubbleEl:=NewHoverElements[i];
|
|
|
- if MouseEvt is TBubbleMouseDownEvent then
|
|
|
- TBubbleMouseDownEvent(MouseEvt).SetXY(PageToContentPos(BubbleEl,NewPageXY))
|
|
|
- else if MouseEvt is TBubbleMouseUpEvent then
|
|
|
- TBubbleMouseUpEvent(MouseEvt).SetXY(PageToContentPos(BubbleEl,NewPageXY))
|
|
|
- else if MouseEvt is TBubbleMouseMoveEvent then
|
|
|
- TBubbleMouseMoveEvent(MouseEvt).SetXY(PageToContentPos(BubbleEl,NewPageXY))
|
|
|
- else
|
|
|
- break;
|
|
|
- until false;
|
|
|
+ // these events have ClientPos and are affected by pointer capture
|
|
|
|
|
|
- FreeAndNil(MouseEvt);
|
|
|
+ CaptEl:=GetPointerCaptureEl(nil);
|
|
|
+ if CaptEl<>nil then
|
|
|
+ El:=CaptEl
|
|
|
+ else if length(NewHoverElements)>0 then
|
|
|
+ begin
|
|
|
+ El:=NewHoverElements[0];
|
|
|
+ case Hit of
|
|
|
+ THit.hScrollbarHorz: El:=El.ScrollBarHorizontal;
|
|
|
+ THit.hScrollbarVert: El:=El.ScrollBarVertical;
|
|
|
+ end;
|
|
|
+ end else
|
|
|
+ El:=Self;
|
|
|
+ if El is TPseudoElement then
|
|
|
+ WSData.ClientPos:=ViewportToClientPos(El.Parent,NewViewportXY)
|
|
|
+ else
|
|
|
+ WSData.ClientPos:=ViewportToClientPos(El,NewViewportXY);
|
|
|
+
|
|
|
+ //writeln('TFresnelViewport.WSMouseXY ',El.GetPath,' VP=',WSData.ViewportPos.ToString,' ClientPos=',WSData.ClientPos.ToString);
|
|
|
+ //BubbleEl:=El;
|
|
|
+ //while BubbleEl<>nil do begin
|
|
|
+ // writeln(' ',BubbleEl.Name,' Border=',BubbleEl.UsedBorderBox.ToString,' Content=',BubbleEl.UsedContentBox.ToString,' Client=',BubbleEl.UsedClientBox.ToString,' Scroll=',FloatToCSSStr(BubbleEl.ScrollLeft),',',FloatToCSSStr(BubbleEl.ScrollTop));
|
|
|
+ // BubbleEl:=BubbleEl.Parent;
|
|
|
+ //end;
|
|
|
+
|
|
|
+ if MouseEventId=evtMouseDown then
|
|
|
+ VPApplication.SetMouseDownElement(El,NewPageXY);
|
|
|
+
|
|
|
+ MouseEvt:=nil;
|
|
|
+ ClickEvt:=nil;
|
|
|
+ try
|
|
|
+ // Dispatch mouse down/move/up events up the element hierarchy
|
|
|
+ MouseEvt:=El.EventDispatcher.CreateEvent(El,MouseEventId) as TFresnelMouseEvent;
|
|
|
+ MouseEvt.InitEvent(WSData);
|
|
|
+
|
|
|
+ BubbleEl:=El;
|
|
|
+ repeat
|
|
|
+ if MouseEvt is TBubbleMouseDownEvent then
|
|
|
+ TBubbleMouseDownEvent(MouseEvt).FElement:=BubbleEl
|
|
|
+ else if MouseEvt is TBubbleMouseUpEvent then
|
|
|
+ TBubbleMouseUpEvent(MouseEvt).FElement:=BubbleEl
|
|
|
+ else if MouseEvt is TBubbleMouseMoveEvent then
|
|
|
+ TBubbleMouseMoveEvent(MouseEvt).FElement:=BubbleEl;
|
|
|
+
|
|
|
+ {$IFDEF VerboseFresnelMouse}
|
|
|
+ writeln('TFresnelViewport.WSMouseXY ',MouseEventId,' ',BubbleEl.GetPath,' ',FloatToCSSStr(MouseEvt.X),',',FloatToCSSStr(MouseEvt.Y));
|
|
|
+ {$ENDIF}
|
|
|
+ BubbleEl.DispatchEvent(MouseEvt);
|
|
|
+ if MouseEvt.PropagationStopped then break;
|
|
|
+ BubbleEl:=BubbleEl.Parent;
|
|
|
+ if BubbleEl=nil then break;
|
|
|
+ if MouseEvt is TBubbleMouseDownEvent then
|
|
|
+ TBubbleMouseDownEvent(MouseEvt).SetXY(ViewportToClientPos(BubbleEl,NewViewportXY))
|
|
|
+ else if MouseEvt is TBubbleMouseUpEvent then
|
|
|
+ TBubbleMouseUpEvent(MouseEvt).SetXY(ViewportToClientPos(BubbleEl,NewViewportXY))
|
|
|
+ else if MouseEvt is TBubbleMouseMoveEvent then
|
|
|
+ TBubbleMouseMoveEvent(MouseEvt).SetXY(ViewportToClientPos(BubbleEl,NewViewportXY))
|
|
|
+ else
|
|
|
+ break;
|
|
|
+ until false;
|
|
|
|
|
|
+ FreeAndNil(MouseEvt);
|
|
|
|
|
|
- if (MouseEventId=evtMouseUp) and (VPApplication.GetMouseDownElement(OldPageXY)=El) then
|
|
|
- begin
|
|
|
- // dispatch click event up the element hierarchy
|
|
|
- ClickEvt:=El.EventDispatcher.CreateEvent(El,evtClick) as TFresnelMouseClickEvent;
|
|
|
- Bubble(El,ClickEvt);
|
|
|
- VPApplication.SetMouseDownElement(nil,NewPageXY);
|
|
|
- end;
|
|
|
|
|
|
- // Focus gets set on mouse down. TrySetFocusControl will test whether the element actually can get focus.
|
|
|
- // Todo: Test what if a non-focus handling element is positioned over one which does handle focus ?
|
|
|
- // -> go over hover list ?
|
|
|
- if (MouseEventId=evtMouseDown) and Assigned(El) then
|
|
|
- TrySetFocusControl(El);
|
|
|
- finally
|
|
|
- MouseEvt.Free;
|
|
|
- ClickEvt.Free;
|
|
|
+ if (MouseEventId=evtMouseUp) and (VPApplication.GetMouseDownElement(OldViewportXY)=El) then
|
|
|
+ begin
|
|
|
+ // dispatch click event up the element hierarchy
|
|
|
+ ClickEvt:=El.EventDispatcher.CreateEvent(El,evtClick) as TFresnelMouseClickEvent;
|
|
|
+ Bubble(El,ClickEvt);
|
|
|
+ VPApplication.SetMouseDownElement(nil,NewPageXY);
|
|
|
end;
|
|
|
+
|
|
|
+ // Focus gets set on mouse down. TrySetFocusControl will test whether the element actually can get focus.
|
|
|
+ // Todo: Test what if a non-focus handling element is positioned over one which does handle focus ?
|
|
|
+ // -> go over hover list ?
|
|
|
+ if (MouseEventId=evtMouseDown) and Assigned(El) then
|
|
|
+ TrySetFocusControl(El);
|
|
|
+ finally
|
|
|
+ MouseEvt.Free;
|
|
|
+ ClickEvt.Free;
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
@@ -7580,35 +7646,35 @@ end;
|
|
|
|
|
|
procedure TFresnelViewport.TBubbleMouseClickEvent.SetXY(const XY: TFresnelPoint);
|
|
|
begin
|
|
|
- FMouseInit.ControlPos:=XY;
|
|
|
+ FMouseInit.ClientPos:=XY;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelViewport.TBubbleMouseDoubleClickEvent }
|
|
|
|
|
|
procedure TFresnelViewport.TBubbleMouseDoubleClickEvent.SetXY(const XY: TFresnelPoint);
|
|
|
begin
|
|
|
- FMouseInit.ControlPos:=XY;
|
|
|
+ FMouseInit.ClientPos:=XY;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelViewport.TBubbleMouseDownEvent }
|
|
|
|
|
|
procedure TFresnelViewport.TBubbleMouseDownEvent.SetXY(const XY: TFresnelPoint);
|
|
|
begin
|
|
|
- FMouseInit.ControlPos:=XY;
|
|
|
+ FMouseInit.ClientPos:=XY;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelViewport.TBubbleMouseMoveEvent }
|
|
|
|
|
|
procedure TFresnelViewport.TBubbleMouseMoveEvent.SetXY(const XY: TFresnelPoint);
|
|
|
begin
|
|
|
- FMouseInit.ControlPos:=XY;
|
|
|
+ FMouseInit.ClientPos:=XY;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelViewport.TBubbleMouseUpEvent }
|
|
|
|
|
|
procedure TFresnelViewport.TBubbleMouseUpEvent.SetXY(const XY: TFresnelPoint);
|
|
|
begin
|
|
|
- FMouseInit.ControlPos:=XY;
|
|
|
+ FMouseInit.ClientPos:=XY;
|
|
|
end;
|
|
|
|
|
|
{ TFresnelElement }
|
|
@@ -7661,21 +7727,13 @@ begin
|
|
|
end;
|
|
|
|
|
|
function TFresnelElement.GetClientWidth: TFresnelLength;
|
|
|
-var
|
|
|
- n: TFresnelLayoutNode;
|
|
|
begin
|
|
|
- n:=LayoutNode;
|
|
|
- Result:=n.Width-n.ScrollGutterLeft-n.ScrollGutterRight;
|
|
|
- if Result<0 then Result:=0;
|
|
|
+ Result:=FUsedClientBox.Width;
|
|
|
end;
|
|
|
|
|
|
function TFresnelElement.GetClientHeight: TFresnelLength;
|
|
|
-var
|
|
|
- n: TFresnelLayoutNode;
|
|
|
begin
|
|
|
- n:=LayoutNode;
|
|
|
- Result:=n.Height-n.ScrollGutterTop-n.ScrollGutterBottom;
|
|
|
- if Result<0 then Result:=0;
|
|
|
+ Result:=FUsedClientBox.Height;
|
|
|
end;
|
|
|
|
|
|
function TFresnelElement.GetViewportConnected: boolean;
|
|
@@ -8496,14 +8554,18 @@ end;
|
|
|
function TFresnelElement.GetContainerOffset: TFresnelPoint;
|
|
|
var
|
|
|
Container, El: TFresnelElement;
|
|
|
+ c: TFresnelRect;
|
|
|
begin
|
|
|
Result:=Default(TFresnelPoint);
|
|
|
Container:=LayoutNode.Container;
|
|
|
El:=Parent;
|
|
|
while El<>Container do
|
|
|
begin
|
|
|
- Result.X:=Result.X+El.UsedContentBox.Left;
|
|
|
- Result.Y:=Result.Y+El.UsedContentBox.Top;
|
|
|
+ // Note: scrolling creates a container, so it can be ignored and
|
|
|
+ // it must be ignored as this is used by the layouter
|
|
|
+ c:=El.UsedContentBox;
|
|
|
+ Result.X:=Result.X+c.Left;
|
|
|
+ Result.Y:=Result.Y+c.Top;
|
|
|
El:=El.Parent;
|
|
|
end;
|
|
|
end;
|
|
@@ -8548,34 +8610,62 @@ begin
|
|
|
Result:=false;
|
|
|
end;
|
|
|
|
|
|
+function TFresnelElement.GetUsedPaddingBox: TFresnelRect;
|
|
|
+var
|
|
|
+ Node: TFresnelLayoutNode;
|
|
|
+begin
|
|
|
+ Result:=UsedBorderBox;
|
|
|
+ Node:=LayoutNode;
|
|
|
+ Result.Left+=Node.BorderLeft;
|
|
|
+ Result.Top+=Node.BorderTop;
|
|
|
+ Result.Right-=Node.BorderRight;
|
|
|
+ Result.Bottom-=Node.BorderBottom;
|
|
|
+end;
|
|
|
+
|
|
|
function TFresnelElement.GetBorderBoxOnViewport: TFresnelRect;
|
|
|
var
|
|
|
Node: TFresnelLayoutNode;
|
|
|
+ El: TFresnelElement;
|
|
|
+ c: TFresnelRect;
|
|
|
+ x, y: TFresnelLength;
|
|
|
begin
|
|
|
- if (not Rendered) then
|
|
|
+ Node:=LayoutNode;
|
|
|
+ if (Node=nil) or Node.SkipRendering then
|
|
|
begin
|
|
|
Result.Clear;
|
|
|
exit;
|
|
|
end;
|
|
|
- Result:=RenderedBorderBox;
|
|
|
- Node:=LayoutNode.Parent;
|
|
|
+ x:=0;
|
|
|
+ y:=0;
|
|
|
+ Node:=Node.Parent;
|
|
|
while Node<>nil do begin
|
|
|
- Result.Offset(Node.Element.RenderedContentBox.TopLeft);
|
|
|
+ El:=Node.Element;
|
|
|
+ c:=El.UsedClientBox;
|
|
|
+ x+=c.Left-El.ScrollLeft;
|
|
|
+ y+=c.Top-El.ScrollTop;
|
|
|
Node:=Node.Parent;
|
|
|
end;
|
|
|
+ Result:=UsedBorderBox;
|
|
|
+ Result.Offset(x,y);
|
|
|
//debugln(['TFresnelElement.GetBoundingClientRect ',Name,' Result=',Result.Left,',',Result.Top,',',Result.Right,',',Result.Bottom]);
|
|
|
end;
|
|
|
|
|
|
-function TFresnelElement.GetRenderedPaddingBox: TFresnelRect;
|
|
|
+function TFresnelElement.ClientToBorderPos(const X, Y: TFresnelLength): TFresnelPoint;
|
|
|
var
|
|
|
N: TFresnelLayoutNode;
|
|
|
begin
|
|
|
- Result:=RenderedContentBox;
|
|
|
N:=LayoutNode;
|
|
|
- Result.Left:=Result.Left-N.PaddingLeft;
|
|
|
- Result.Top:=Result.Top-N.PaddingTop;
|
|
|
- Result.Right:=Result.Right+N.PaddingRight;
|
|
|
- Result.Bottom:=Result.Bottom+N.PaddingBottom;
|
|
|
+ Result.X:=X+N.ScrollGutterLeft+N.PaddingLeft+N.BorderLeft;
|
|
|
+ Result.Y:=Y+N.ScrollGutterTop+N.PaddingTop+N.BorderTop;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelElement.BorderToClientPos(const X, Y: TFresnelLength): TFresnelPoint;
|
|
|
+var
|
|
|
+ N: TFresnelLayoutNode;
|
|
|
+begin
|
|
|
+ N:=LayoutNode;
|
|
|
+ Result.X:=X-N.ScrollGutterLeft-N.PaddingLeft-N.BorderLeft;
|
|
|
+ Result.Y:=Y-N.ScrollGutterTop-N.PaddingTop-N.BorderTop;
|
|
|
end;
|
|
|
|
|
|
function TFresnelElement.GetComputedBorderRadius(Corner: TFresnelCSSCorner
|
|
@@ -9505,9 +9595,6 @@ end;
|
|
|
|
|
|
procedure TFresnelElement.BeforeRender;
|
|
|
begin
|
|
|
- FRenderedBorderBox:=FUsedBorderBox;
|
|
|
- FRenderedContentBox:=FUsedContentBox;
|
|
|
-
|
|
|
If Assigned(FBeforeRender) then
|
|
|
FBeforeRender(Self);
|
|
|
end;
|