Browse Source

added lcl MouseUp/Move/Down/Click events

mattias 1 year ago
parent
commit
38c687f3e4

+ 2 - 0
.gitignore

@@ -17,3 +17,5 @@
 /*.dll
 /*.dll
 link*.res
 link*.res
 .DS_Store
 .DS_Store
+**/lib
+**/*.app

+ 2 - 0
demo/Button/.gitignore

@@ -1 +1,3 @@
+lib
 ButtonSkia
 ButtonSkia
+

+ 1 - 0
demo/LCLButton/.gitignore

@@ -1 +1,2 @@
 LCLButton
 LCLButton
+lib

+ 3 - 3
demo/LCLButton/FreBtnForm.lfm

@@ -1,7 +1,6 @@
 object FresnelButtonForm: TFresnelButtonForm
 object FresnelButtonForm: TFresnelButtonForm
-  Caption = 'FresnelButtonForm'
-  FormLeft = 450
-  FormTop = 300
+  FormLeft = 435
+  FormTop = 318
   FormWidth = 350
   FormWidth = 350
   FormHeight = 255
   FormHeight = 255
   Stylesheet.Strings = (
   Stylesheet.Strings = (
@@ -17,6 +16,7 @@ object FresnelButtonForm: TFresnelButtonForm
       Style = 'background-color: blue;'#10'border-color: black;'#10'height:50px;'
       Style = 'background-color: blue;'#10'border-color: black;'#10'height:50px;'
       object Label1: TLabel
       object Label1: TLabel
         Style = 'color: green;'
         Style = 'color: green;'
+        OnClick = Label1Click
         Caption = 'Label1'
         Caption = 'Label1'
       end
       end
     end
     end

+ 13 - 1
demo/LCLButton/FreBtnForm.pas

@@ -10,13 +10,18 @@ unit FreBtnForm;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, Fresnel.Forms, Fresnel.Controls;
+  Classes, SysUtils, Fresnel.Forms, Fresnel.Controls, Fresnel.Events,
+  FCL.Events, LazLoggerBase;
 
 
 type
 type
+
+  { TFresnelButtonForm }
+
   TFresnelButtonForm = class(TFresnelForm)
   TFresnelButtonForm = class(TFresnelForm)
     Body1: TBody;
     Body1: TBody;
     Div1: TDiv;
     Div1: TDiv;
     Label1: TLabel;
     Label1: TLabel;
+    procedure Label1Click(Event: TAbstractEvent);
   public
   public
   end;
   end;
 
 
@@ -27,5 +32,12 @@ implementation
 
 
 {$R *.lfm}
 {$R *.lfm}
 
 
+{ TFresnelButtonForm }
+
+procedure TFresnelButtonForm.Label1Click(Event: TAbstractEvent);
+begin
+  DebugLn(['TFresnelButtonForm.Label1Click ',Event.EventID]);
+end;
+
 end.
 end.
 
 

+ 4 - 2
design/fresnel.register.pas

@@ -32,8 +32,7 @@ type
     FDsgnForm: TFresnelForm;
     FDsgnForm: TFresnelForm;
     FRenderer: TFresnelLCLRenderer;
     FRenderer: TFresnelLCLRenderer;
   protected
   protected
-    procedure Notification(AComponent: TComponent; Operation: TOperation);
-      override;
+    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure SetLCLForm(const AValue: TForm); override;
     procedure SetLCLForm(const AValue: TForm); override;
   public
   public
     // needed by the Lazarus form editor
     // needed by the Lazarus form editor
@@ -254,7 +253,9 @@ end;
 
 
 procedure TFresnelFormMediator.Paint;
 procedure TFresnelFormMediator.Paint;
 begin
 begin
+  //debugln(['TFresnelFormMediator.Paint FDsgnForm=',DbgSName(FDsgnForm)]);
   if FDsgnForm=nil then exit;
   if FDsgnForm=nil then exit;
+  //debugln(['TFresnelFormMediator.Paint FDsgnForm=',DbgSName(FDsgnForm),' Rednerer=',DbgSName(FDsgnForm.Renderer)]);
   FDsgnForm.Renderer.Draw(FDsgnForm);
   FDsgnForm.Renderer.Draw(FDsgnForm);
 end;
 end;
 
 
@@ -320,6 +321,7 @@ end;
 procedure TFresnelFormMediator.InvalidateRect(Sender: TObject; ARect: TRect;
 procedure TFresnelFormMediator.InvalidateRect(Sender: TObject; ARect: TRect;
   Erase: boolean);
   Erase: boolean);
 begin
 begin
+  //debugln(['TFresnelFormMediator.InvalidateRect ',DbgSName(FDsgnForm),' ',dbgs(ARect)]);
   if (LCLForm=nil) or (not LCLForm.HandleAllocated) then exit;
   if (LCLForm=nil) or (not LCLForm.HandleAllocated) then exit;
   LCLIntf.InvalidateRect(LCLForm.Handle,@ARect,Erase);
   LCLIntf.InvalidateRect(LCLForm.Handle,@ARect,Erase);
 end;
 end;

+ 1 - 1
src/base/fresnel.app.pas

@@ -5,7 +5,7 @@ unit Fresnel.App;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, CustApp, Fresnel.Classes, Fresnel.Forms, Fresnel.WidgetSet,
+  Classes, SysUtils, CustApp, Fresnel.Forms, Fresnel.WidgetSet,
   LazMethodList, LazLoggerBase;
   LazMethodList, LazLoggerBase;
 
 
 type
 type

+ 62 - 7
src/base/fresnel.dom.pas

@@ -302,7 +302,9 @@ type
     FStandardEvents : Array[0..evtLastEvent] of TEventHandlerItem;
     FStandardEvents : Array[0..evtLastEvent] of TEventHandlerItem;
     FEventDispatcher : TFresnelEventDispatcher;
     FEventDispatcher : TFresnelEventDispatcher;
     function GetEventHandler(AIndex: Integer): TFresnelEventHandler;
     function GetEventHandler(AIndex: Integer): TFresnelEventHandler;
-    procedure SetEventHandler(AIndex: Integer; AValue: TFresnelEventHandler);
+    function GetMouseEventHandler(AIndex: Integer): TFresnelMouseEventHandler;
+    procedure SetEventHandler(AIndex: Integer; const AValue: TFresnelEventHandler);
+    procedure SetMouseEventHandler(AIndex: Integer; const AValue: TFresnelMouseEventHandler);
  class var
  class var
     // Stuff for registering CSS numerical IDs
     // Stuff for registering CSS numerical IDs
     FCSSNumericalIDs: array[TCSSNumericalIDKind] of TCSSNumericalIDs;
     FCSSNumericalIDs: array[TCSSNumericalIDKind] of TCSSNumericalIDs;
@@ -440,7 +442,7 @@ type
     class property FresnelElementBaseAttrID: TCSSNumericalID read FFresnelElementBaseAttrID;
     class property FresnelElementBaseAttrID: TCSSNumericalID read FFresnelElementBaseAttrID;
     class property FresnelElementBasePseudoID: TCSSNumericalID read FFresnelElementBasePseudoID;
     class property FresnelElementBasePseudoID: TCSSNumericalID read FFresnelElementBasePseudoID;
     // layouter
     // layouter
-    function GetMaxWidthIntrinsicContentBox: TFresnelLength; virtual; // this element, excluding children, ignoring min-width
+    function GetMaxWidthIntrinsicContentBox: TFresnelLength; virtual; // this element, excluding children, ignoring max-width
     function GetMaxWidthContentBox: TFresnelLength; virtual; // this element, excluding children
     function GetMaxWidthContentBox: TFresnelLength; virtual; // this element, excluding children
     function GetMaxWidthBorderBox: TFresnelLength; virtual; // this element, excluding children
     function GetMaxWidthBorderBox: TFresnelLength; virtual; // this element, excluding children
     function GetMinWidthIntrinsicContentBox: TFresnelLength; virtual; // this element, excluding children, ignoring min-width
     function GetMinWidthIntrinsicContentBox: TFresnelLength; virtual; // this element, excluding children, ignoring min-width
@@ -460,16 +462,19 @@ type
     property RenderedContentBox: TFresnelRect read FRenderedContentBox write FRenderedContentBox; // relative to layout parent
     property RenderedContentBox: TFresnelRect read FRenderedContentBox write FRenderedContentBox; // relative to layout parent
     property CSSRenderedAttribute[Attr: TFresnelCSSAttribute]: string read GetCSSRenderedAttribute write SetCSSRenderedAttribute;
     property CSSRenderedAttribute[Attr: TFresnelCSSAttribute]: string read GetCSSRenderedAttribute write SetCSSRenderedAttribute;
     // Events
     // Events
-    Procedure AddEventListener(aID : TEventID; aHandler : TFresnelEventHandler);
-    Procedure AddEventListener(Const aName: TEventName; aHandler : TFresnelEventHandler);
-    Property EventDispatcher : TFresnelEventDispatcher Read FEventDispatcher;
+    procedure AddEventListener(aID : TEventID; aHandler : TFresnelEventHandler);
+    procedure AddEventListener(Const aName: TEventName; aHandler : TFresnelEventHandler);
+    property EventDispatcher : TFresnelEventDispatcher Read FEventDispatcher;
     // font
     // font
     property Font: IFresnelFont read GetFont write FFont;
     property Font: IFresnelFont read GetFont write FFont;
   published
   published
     // ToDo
     // ToDo
     property CSSClasses: TStrings read FCSSClasses write SetCSSClasses;
     property CSSClasses: TStrings read FCSSClasses write SetCSSClasses;
     property Style: string read FStyle write SetStyle;
     property Style: string read FStyle write SetStyle;
-    Property OnClick : TFresnelEventHandler Index evtClick Read GetEventHandler Write SetEventHandler;
+    property OnClick: TFresnelEventHandler Index evtClick Read GetEventHandler Write SetEventHandler;
+    property OnMouseDown: TFresnelMouseEventHandler Index evtMouseDown Read GetMouseEventHandler Write SetMouseEventHandler;
+    property OnMouseMove: TFresnelMouseEventHandler Index evtMouseMove Read GetMouseEventHandler Write SetMouseEventHandler;
+    property OnMouseUp: TFresnelMouseEventHandler Index evtMouseUp Read GetMouseEventHandler Write SetMouseEventHandler;
   end;
   end;
   TFresnelElementClass = class of TFresnelElement;
   TFresnelElementClass = class of TFresnelElement;
   TFresnelElementArray = array of TFresnelElement;
   TFresnelElementArray = array of TFresnelElement;
@@ -544,6 +549,8 @@ type
     procedure DomChanged; override;
     procedure DomChanged; override;
     function AllocateFont(const Desc: TFresnelFontDesc): IFresnelFont; virtual;
     function AllocateFont(const Desc: TFresnelFontDesc): IFresnelFont; virtual;
     function GetElementAt(const x, y: TFresnelLength): TFresnelElement; virtual;
     function GetElementAt(const x, y: TFresnelLength): TFresnelElement; virtual;
+    function ContentToPagePos(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; virtual;
+    function PageToContentPos(El: TFresnelElement; const x, y: TFresnelLength): TFresnelPoint; virtual;
     property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
     property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
     property FontMinSize: TFresnelLength read FFontMinSize write SetFontMinSize;
     property FontMinSize: TFresnelLength read FFontMinSize write SetFontMinSize;
     property ScrollbarWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarWidth write SetScrollbarWidth;
     property ScrollbarWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarWidth write SetScrollbarWidth;
@@ -1202,6 +1209,38 @@ begin
   Result:=Check(LayoutNode,0,0);
   Result:=Check(LayoutNode,0,0);
 end;
 end;
 
 
+function TFresnelViewport.ContentToPagePos(El: TFresnelElement; const x,
+  y: TFresnelLength): TFresnelPoint;
+var
+  Node: TFresnelLayoutNode;
+  aContentOffset: TFresnelPoint;
+begin
+  Result.X:=x;
+  Result.Y:=y;
+  if not El.Rendered then exit;
+  Node:=El.LayoutNode;
+
+  repeat
+    aContentOffset:=El.RenderedContentBox.TopLeft;
+    Result.X+=aContentOffset.X;
+    Result.Y+=aContentOffset.Y;
+    if Node=nil then exit;
+    Node:=Node.Parent;
+    if Node=nil then exit;
+    El:=Node.Element;
+  until El=nil;
+end;
+
+function TFresnelViewport.PageToContentPos(El: TFresnelElement; const x,
+  y: TFresnelLength): TFresnelPoint;
+var
+  p: TFresnelPoint;
+begin
+  p:=ContentToPagePos(El,0,0);
+  Result.X:=x-p.X;
+  Result.Y:=y-p.Y;
+end;
+
 constructor TFresnelViewport.Create(AOwner: TComponent);
 constructor TFresnelViewport.Create(AOwner: TComponent);
 begin
 begin
   inherited Create(AOwner);
   inherited Create(AOwner);
@@ -1265,7 +1304,16 @@ begin
     Result:=TObjectEventHandlerItem(FStandardEvents[aIndex]).EventHandler;
     Result:=TObjectEventHandlerItem(FStandardEvents[aIndex]).EventHandler;
 end;
 end;
 
 
-procedure TFresnelElement.SetEventHandler(AIndex: Integer; AValue: TFresnelEventHandler);
+function TFresnelElement.GetMouseEventHandler(AIndex: Integer
+  ): TFresnelMouseEventHandler;
+begin
+  Result:=nil;
+  if AIndex in evtAllMouse then
+    Result:=TFresnelMouseEventHandler(GetEventHandler(AIndex));
+end;
+
+procedure TFresnelElement.SetEventHandler(AIndex: Integer;
+  const AValue: TFresnelEventHandler);
 begin
 begin
   If Assigned(FStandardEvents[aIndex]) then
   If Assigned(FStandardEvents[aIndex]) then
     TObjectEventHandlerItem(FStandardEvents[aIndex]).EventHandler:=aValue
     TObjectEventHandlerItem(FStandardEvents[aIndex]).EventHandler:=aValue
@@ -1273,6 +1321,13 @@ begin
     FStandardEvents[aIndex]:=FEventDispatcher.RegisterHandler(aValue,aIndex);
     FStandardEvents[aIndex]:=FEventDispatcher.RegisterHandler(aValue,aIndex);
 end;
 end;
 
 
+procedure TFresnelElement.SetMouseEventHandler(AIndex: Integer;
+  const AValue: TFresnelMouseEventHandler);
+begin
+  if AIndex in evtAllMouse then
+    SetEventHandler(AIndex,TFresnelEventHandler(AValue));
+end;
+
 procedure TFresnelElement.SetCSSClasses(const AValue: TStrings);
 procedure TFresnelElement.SetCSSClasses(const AValue: TStrings);
 begin
 begin
   if FCSSClasses=AValue then Exit;
   if FCSSClasses=AValue then Exit;

+ 44 - 4
src/base/fresnel.events.pas

@@ -40,6 +40,7 @@ Const
 
 
   evtLastEvent = evtBlur;
   evtLastEvent = evtBlur;
 
 
+  evtAllMouse = [evtMouseMove,evtMouseDown,evtMouseUp];
 
 
 Type
 Type
 
 
@@ -61,7 +62,6 @@ Type
   TFresnelEventCallBack = TEventCallBack;
   TFresnelEventCallBack = TEventCallBack;
   TFresnelEventHandlerRef = TEventHandlerRef;
   TFresnelEventHandlerRef = TEventHandlerRef;
 
 
-
   TFresnelUIEvent = class(TFresnelEvent)
   TFresnelUIEvent = class(TFresnelEvent)
 
 
   end;
   end;
@@ -106,6 +106,7 @@ Type
     Property CtrlKey : Boolean Index Ord(ssCtrl) read GetShiftKey;
     Property CtrlKey : Boolean Index Ord(ssCtrl) read GetShiftKey;
     Property ShiftKey : Boolean Index Ord(ssShift) read GetShiftKey;
     Property ShiftKey : Boolean Index Ord(ssShift) read GetShiftKey;
   end;
   end;
+  TFresnelMouseEventHandler = Procedure(Event: TFresnelMouseEvent) of object;
 
 
   { TFresnelMouseClickEvent }
   { TFresnelMouseClickEvent }
 
 
@@ -113,6 +114,24 @@ Type
     class function FresnelEventID : TEventID; override;
     class function FresnelEventID : TEventID; override;
   end;
   end;
 
 
+  { TFresnelMouseDownEvent }
+
+  TFresnelMouseDownEvent = class(TFresnelMouseEvent)
+    class function FresnelEventID : TEventID; override;
+  end;
+
+  { TFresnelMouseMoveEvent }
+
+  TFresnelMouseMoveEvent = class(TFresnelMouseEvent)
+    class function FresnelEventID : TEventID; override;
+  end;
+
+  { TFresnelMouseUpEvent }
+
+  TFresnelMouseUpEvent = class(TFresnelMouseEvent)
+    class function FresnelEventID : TEventID; override;
+  end;
+
   TFresnelKeyEventInit = Record
   TFresnelKeyEventInit = Record
     ShiftState : TShiftState;
     ShiftState : TShiftState;
     IsComposing : Boolean;
     IsComposing : Boolean;
@@ -359,13 +378,11 @@ end;
 
 
 { TFresnelKeyEvent }
 { TFresnelKeyEvent }
 
 
-
 function TFresnelKeyEvent.GetShiftKey(AIndex: Integer): Boolean;
 function TFresnelKeyEvent.GetShiftKey(AIndex: Integer): Boolean;
 begin
 begin
   Result:=TShiftStateEnum(aIndex) in Finit.ShiftState;
   Result:=TShiftStateEnum(aIndex) in Finit.ShiftState;
 end;
 end;
 
 
-
 constructor TFresnelKeyEvent.Create(const aInit: TFresnelKeyEventInit);
 constructor TFresnelKeyEvent.Create(const aInit: TFresnelKeyEventInit);
 begin
 begin
   FInit:=aInit;
   FInit:=aInit;
@@ -388,7 +405,6 @@ begin
   FInit:=aInit;
   FInit:=aInit;
 end;
 end;
 
 
-
 { TFresnelChangeEvent }
 { TFresnelChangeEvent }
 
 
 class function TFresnelChangeEvent.FresnelEventID: TEventID;
 class function TFresnelChangeEvent.FresnelEventID: TEventID;
@@ -403,6 +419,27 @@ begin
   Result:=evtClick;
   Result:=evtClick;
 end;
 end;
 
 
+{ TFresnelMouseDownEvent }
+
+class function TFresnelMouseDownEvent.FresnelEventID: TEventID;
+begin
+  Result:=evtMouseDown;
+end;
+
+{ TFresnelMouseMoveEvent }
+
+class function TFresnelMouseMoveEvent.FresnelEventID: TEventID;
+begin
+  Result:=evtMouseMove;
+end;
+
+{ TFresnelMouseUpEvent }
+
+class function TFresnelMouseUpEvent.FresnelEventID: TEventID;
+begin
+  Result:=evtMouseUp;
+end;
+
 { TFresnelEvent }
 { TFresnelEvent }
 
 
 class function TFresnelEvent.StandardEventName(aEventID : TEventID): TEventName;
 class function TFresnelEvent.StandardEventName(aEventID : TEventID): TEventName;
@@ -468,6 +505,9 @@ class procedure TFresnelEventDispatcher.RegisterFresnelEvents;
 begin
 begin
   R(TFresnelChangeEvent);
   R(TFresnelChangeEvent);
   R(TFresnelMouseClickEvent);
   R(TFresnelMouseClickEvent);
+  R(TFresnelMouseDownEvent);
+  R(TFresnelMouseMoveEvent);
+  R(TFresnelMouseUpEvent);
 end;
 end;
 
 
 class destructor TFresnelEventDispatcher.Done;
 class destructor TFresnelEventDispatcher.Done;

+ 54 - 21
src/base/fresnel.forms.pas

@@ -6,7 +6,7 @@ interface
 
 
 uses
 uses
   Classes, SysUtils, Math, CustApp, fpCSSResolver, fpCSSTree, LazLogger,
   Classes, SysUtils, Math, CustApp, fpCSSResolver, fpCSSTree, LazLogger,
-  LazMethodList, Fresnel.StrConsts, Fresnel.Classes, Fresnel.Resources,
+  Fresnel.StrConsts, Fresnel.Classes, Fresnel.Resources,
   Fresnel.DOM, Fresnel.Renderer, Fresnel.Layouter, Fresnel.WidgetSet,
   Fresnel.DOM, Fresnel.Renderer, Fresnel.Layouter, Fresnel.WidgetSet,
   Fresnel.Events, fcl.events;
   Fresnel.Events, fcl.events;
 
 
@@ -41,10 +41,10 @@ type
     FCaption: TFresnelCaption;
     FCaption: TFresnelCaption;
     FFormStates: TFormStates;
     FFormStates: TFormStates;
     FFormStyle: TFormStyle;
     FFormStyle: TFormStyle;
+    fMouseDownElement: TFresnelElement;
     FVisible: boolean;
     FVisible: boolean;
     FWSForm: TFresnelWSForm;
     FWSForm: TFresnelWSForm;
     function GetCaption: TFresnelCaption;
     function GetCaption: TFresnelCaption;
-    function GetFormBounds: TFresnelRect;
     function GetFormHeight: TFresnelLength;
     function GetFormHeight: TFresnelLength;
     function GetFormLeft: TFresnelLength;
     function GetFormLeft: TFresnelLength;
     function GetFormTop: TFresnelLength;
     function GetFormTop: TFresnelLength;
@@ -94,7 +94,7 @@ type
     property LayoutQueued: boolean read GetLayoutQueued write SetLayoutQueued;
     property LayoutQueued: boolean read GetLayoutQueued write SetLayoutQueued;
     property Renderer: TFresnelRenderer read GetRenderer;
     property Renderer: TFresnelRenderer read GetRenderer;
     property FormStyle: TFormStyle read FFormStyle write SetFormStyle default fsNormal;
     property FormStyle: TFormStyle read FFormStyle write SetFormStyle default fsNormal;
-    property FormBounds: TFresnelRect read GetFormBounds write SetFormBounds;
+    property FormBounds: TFresnelRect read FFormBounds write SetFormBounds;
     property FormLeft: TFresnelLength read GetFormLeft write SetFormLeft;
     property FormLeft: TFresnelLength read GetFormLeft write SetFormLeft;
     property FormTop: TFresnelLength read GetFormTop write SetFormTop;
     property FormTop: TFresnelLength read GetFormTop write SetFormTop;
     property FormWidth: TFresnelLength read GetFormWidth write SetFormWidth;
     property FormWidth: TFresnelLength read GetFormWidth write SetFormWidth;
@@ -157,11 +157,6 @@ begin
     Result:=nil;
     Result:=nil;
 end;
 end;
 
 
-function TCustomFresnelForm.GetFormBounds: TFresnelRect;
-begin
-  Result:=FFormBounds;
-end;
-
 function TCustomFresnelForm.GetCaption: TFresnelCaption;
 function TCustomFresnelForm.GetCaption: TFresnelCaption;
 begin
 begin
   if WSFormAllocated then
   if WSFormAllocated then
@@ -219,7 +214,7 @@ begin
   if AValue.Bottom<AValue.Top then
   if AValue.Bottom<AValue.Top then
     AValue.Bottom:=AValue.Top;
     AValue.Bottom:=AValue.Top;
   if FFormBounds=AValue then exit;
   if FFormBounds=AValue then exit;
-  debugln(['TCustomFresnelForm.SetFormBoundsRect ',DbgSName(Self),' ',dbgs(AValue)]);
+  debugln(['TCustomFresnelForm.SetFormBounds ',DbgSName(Self),' ',dbgs(AValue)]);
   FFormBounds:=AValue;
   FFormBounds:=AValue;
   if Designer<>nil then
   if Designer<>nil then
     Designer.SetDesignerFormBounds(Self,FFormBounds.GetRect)
     Designer.SetDesignerFormBounds(Self,FFormBounds.GetRect)
@@ -291,16 +286,20 @@ begin
   begin
   begin
     if FWSForm=AComponent then
     if FWSForm=AComponent then
       FWSForm:=nil;
       FWSForm:=nil;
+    if fMouseDownElement=AComponent then
+      fMouseDownElement:=nil;
   end;
   end;
 end;
 end;
 
 
 procedure TCustomFresnelForm.OnQueuedLayout(Data: Pointer);
 procedure TCustomFresnelForm.OnQueuedLayout(Data: Pointer);
 begin
 begin
+  //debugln(['TCustomFresnelForm.OnQueuedLayout ',DbgSName(Self),' ',LayoutQueued]);
   if not LayoutQueued then exit;
   if not LayoutQueued then exit;
   try
   try
     ApplyCSS;
     ApplyCSS;
     //Layouter.WriteLayoutTree;
     //Layouter.WriteLayoutTree;
     Layouter.Apply(Self);
     Layouter.Apply(Self);
+    //debugln(['TCustomFresnelForm.OnQueuedLayout ',DbgSName(Self),' After Layouter.Apply, Invalidate...']);
     Invalidate;
     Invalidate;
   finally
   finally
     Exclude(FFormStates,fsLayoutQueued);
     Exclude(FFormStates,fsLayoutQueued);
@@ -366,8 +365,10 @@ end;
 
 
 procedure TCustomFresnelForm.Hide;
 procedure TCustomFresnelForm.Hide;
 begin
 begin
-  writeln('TCustomFresnelForm.Hide ',DbgSName(Self));
-  if Designer<>nil then
+  debugln('TCustomFresnelForm.Hide ',DbgSName(Self));
+  if (Designer<>nil)
+      or ([csLoading,csDesigning]*ComponentState<>[])
+      or not WSFormAllocated then
     FVisible:=false
     FVisible:=false
   else
   else
     WSForm.Visible:=false;
     WSForm.Visible:=false;
@@ -375,8 +376,8 @@ end;
 
 
 procedure TCustomFresnelForm.Show;
 procedure TCustomFresnelForm.Show;
 begin
 begin
-  writeln('TCustomFresnelForm.Show ',DbgSName(Self));
-  if Designer<>nil then
+  debugln('TCustomFresnelForm.Show ',DbgSName(Self));
+  if (Designer<>nil) or ([csLoading,csDesigning,csDestroying]*ComponentState<>[]) then
     FVisible:=true
     FVisible:=true
   else
   else
     WSForm.Visible:=true;
     WSForm.Visible:=true;
@@ -384,6 +385,8 @@ end;
 
 
 procedure TCustomFresnelForm.Invalidate;
 procedure TCustomFresnelForm.Invalidate;
 begin
 begin
+  if ([csLoading,csDestroying]*ComponentState<>[]) then
+    exit;
   if Designer<>nil then
   if Designer<>nil then
     Designer.InvalidateRect(Self,Rect(0,0,Ceil(Width),Ceil(Height)),false)
     Designer.InvalidateRect(Self,Rect(0,0,Ceil(Width),Ceil(Height)),false)
   else if WSFormAllocated then
   else if WSFormAllocated then
@@ -392,6 +395,8 @@ end;
 
 
 procedure TCustomFresnelForm.InvalidateRect(const aRect: TFresnelRect);
 procedure TCustomFresnelForm.InvalidateRect(const aRect: TFresnelRect);
 begin
 begin
+  if ([csLoading,csDestroying]*ComponentState<>[]) then
+    exit;
   if Designer<>nil then
   if Designer<>nil then
     Designer.InvalidateRect(Self,aRect.GetRect,false)
     Designer.InvalidateRect(Self,aRect.GetRect,false)
   else if WSFormAllocated then
   else if WSFormAllocated then
@@ -460,22 +465,50 @@ procedure TCustomFresnelForm.WSMouseXY(WSData: TFresnelMouseEventInit;
   MouseEventId: TEventID);
   MouseEventId: TEventID);
 var
 var
   El: TFresnelElement;
   El: TFresnelElement;
-  Evt: TFresnelMouseEvent;
+  MouseEvt: TFresnelMouseEvent;
+  X, Y: TFresnelLength;
+  ClickEvt: TFresnelMouseClickEvent;
 begin
 begin
-  El:=GetElementAt(WSData.PagePos.X,WSData.PagePos.Y);
-  WSData.ControlPos:=WSData.PagePos;
+  X:=WSData.PagePos.X;
+  Y:=WSData.PagePos.Y;
+  El:=GetElementAt(X,Y);
   if El=Nil then
   if El=Nil then
   begin
   begin
     El:=Self;
     El:=Self;
+    WSData.ControlPos:=WSData.PagePos;
   end else begin
   end else begin
-    // todo: translate ControlPos
+    WSData.ControlPos:=PageToContentPos(El,X,Y);
+  end;
+  case MouseEventId of
+  evtMouseDown:
+    fMouseDownElement:=El;
   end;
   end;
-  Evt:=El.EventDispatcher.CreateEvent(El,MouseEventId) as TFresnelMouseEvent;
+
+  MouseEvt:=nil;
+  ClickEvt:=nil;
   try
   try
-    Evt.InitEvent(WSData);
-    El.EventDispatcher.DispatchEvent(Evt);
+    // dispatch mouse down/move/up event
+    MouseEvt:=El.EventDispatcher.CreateEvent(El,MouseEventId) as TFresnelMouseEvent;
+    MouseEvt.InitEvent(WSData);
+    El.EventDispatcher.DispatchEvent(MouseEvt);
+    FreeAndNil(MouseEvt);
+
+    case MouseEventId of
+    evtMouseUp:
+      begin
+        if fMouseDownElement=El then
+        begin
+          // dispatch click event
+          ClickEvt:=El.EventDispatcher.CreateEvent(El,evtClick) as TFresnelMouseClickEvent;
+          ClickEvt.InitEvent(WSData);
+          El.EventDispatcher.DispatchEvent(ClickEvt);
+        end;
+        fMouseDownElement:=nil;
+      end;
+    end;
   finally
   finally
-    Evt.Free;
+    MouseEvt.Free;
+    ClickEvt.Free;
   end;
   end;
 end;
 end;
 
 

+ 5 - 0
src/lcl/fresnel.lcl.pas

@@ -439,6 +439,11 @@ var
 begin
 begin
   if not (aFresnelForm is TCustomFresnelForm) then
   if not (aFresnelForm is TCustomFresnelForm) then
     raise Exception.Create('TFresnelLCLWidgetSet.CreateWSForm '+DbgSName(aFresnelForm));
     raise Exception.Create('TFresnelLCLWidgetSet.CreateWSForm '+DbgSName(aFresnelForm));
+  if csDesigning in aFresnelForm.ComponentState then
+    raise Exception.Create('TFresnelLCLWidgetSet.CreateWSForm '+DbgSName(aFresnelForm)+' csDesigning');
+  if csDestroying in aFresnelForm.ComponentState then
+    raise Exception.Create('TFresnelLCLWidgetSet.CreateWSForm '+DbgSName(aFresnelForm)+' csDestroying');
+
   aForm:=TCustomFresnelForm(aFresnelForm);
   aForm:=TCustomFresnelForm(aFresnelForm);
 
 
   aWSForm:=TLCLWSForm.Create(aForm);
   aWSForm:=TLCLWSForm.Create(aForm);