Font font = "sans, 10";
protected Measure width, height;
int left, top;
- double cornerRadius = 0;
- int margin = 0;
- bool focusable = false;
- bool hasFocus = false;
- bool isActive = false;
- //bool isHover = false;
+ double cornerRadius;
+ int margin;
+ bool focusable ;
+ bool hasFocus;
+ bool isActive;
+ bool isHover;
bool mouseRepeat;
+ bool forwardMouseEvents;
protected bool isVisible = true;
bool isEnabled = true;
VerticalAlignment verticalAlignment = VerticalAlignment.Center;
HorizontalAlignment horizontalAlignment = HorizontalAlignment.Center;
Size maximumSize = "0,0";
Size minimumSize = "0,0";
- bool cacheEnabled = false;
+ bool cacheEnabled;
bool clipToClientRect = true;
Type dataSourceType;
protected object dataSource;
/// <summary>Occurs when this object loose focus</summary>
public event EventHandler Unfocused;
/// <summary>Occurs when mouse is over</summary>
- //public event EventHandler Hover;
+ public event EventHandler Hover;
/// <summary>Occurs when this control is no longer the Hover one</summary>
//public event EventHandler UnHover;
/// <summary>Occurs when this object loose focus</summary>
public event EventHandler<DataSourceChangeEventArgs> LogicalParentChanged;
#endregion
+ internal bool hasDoubleClick => MouseDoubleClick != null;
+ internal bool hasClick => MouseClick != null;
+
#region public properties
/// <summary>Random value placeholder</summary>
[DesignCategory ("Divers")]
/// <summary>
/// true if this control has the pointer hover
/// </summary>
- /*[XmlIgnore]public virtual bool IsHover {
+ [XmlIgnore]public virtual bool IsHover {
get { return isHover; }
set {
if (value == isHover)
isHover = value;
if (isHover)
- onHover (this, null);
- else
- onUnHover (this, null);
+ Hover.Raise (this, null);
NotifyValueChanged ("IsHover", isHover);
}
- }*/
+ }
/// <summary>
/// true if holding mouse button down should trigger multiple click events
/// </summary>
NotifyValueChanged ("MouseRepeat", mouseRepeat);
}
}
+ /// <summary>
+ /// forward mouse events even if an handle is bound
+ /// </summary>
+ [DesignCategory ("Behaviour")][DefaultValue (false)]
+ public bool ForwardMouseEvents {
+ get { return forwardMouseEvents; }
+ set {
+ if (forwardMouseEvents == value)
+ return;
+ forwardMouseEvents = value;
+ NotifyValueChanged ("ForwardMouseEvents", forwardMouseEvents);
+ }
+ }
bool clearBackground = false;
/// <summary>
/// background fill of the control, maybe solid color, gradient, image, or svg
else if (LastPaintedSlot.Width != Slot.Width || LastPaintedSlot.Height != Slot.Height)
bmp.SetSize (Slot.Width, Slot.Height);*/
bmp?.Dispose ();
+ //bmp = IFace.surf.CreateSimilar (Content.ColorAlpha, Slot.Width, Slot.Height);
bmp = new ImageSurface(Format.Argb32, Slot.Width, Slot.Height);
-
+
using (Context gr = new Context (bmp)) {
gr.Antialias = Interface.Antialias;
onDraw (gr);
//to let other control behind have mouse entering
if (isDragged)
return;
-
- //bubble event to the top
- Widget p = focusParent;
- if (p != null)
- p.onMouseMove(sender,e);
- MouseMove.Raise (this, e);
+ if (MouseMove == null)
+ focusParent?.onMouseMove (sender, e);
+ else
+ MouseMove.Invoke (this, e);
+
}
public virtual void onMouseDown(object sender, MouseButtonEventArgs e){
- #if DEBUG_FOCUS
+#if DEBUG_FOCUS
Debug.WriteLine("MOUSE DOWN => " + this.ToString());
- #endif
+#endif
- if (focusable && !Interface.FocusOnHover) {
+ /*if (focusable && !Interface.FocusOnHover) {
BubblingMouseButtonEventArg be = e as BubblingMouseButtonEventArg;
if (be.Focused == null) {
be.Focused = this;
if (e.Button == MouseButton.Right && contextCommands != null)
IFace.ShowContextMenu (this);
}
- }
- //bubble event to the top
- Widget p = focusParent;
- if (p != null)
- p.onMouseDown(sender,e);
-
- MouseDown.Raise (this, e);
+ }*/
+ if (MouseDown != null)
+ MouseDown.Invoke (this, e);
+ if (MouseDown == null || forwardMouseEvents)
+ focusParent?.onMouseDown (sender, e);
}
public virtual void onMouseUp(object sender, MouseButtonEventArgs e){
- #if DEBUG_FOCUS
+#if DEBUG_FOCUS
Debug.WriteLine("MOUSE UP => " + this.ToString());
- #endif
+#endif
- if (IFace.DragAndDropOperation != null){
+ /*if (IFace.DragAndDropOperation != null){
if (IFace.DragAndDropOperation.DragSource == this) {
if (IFace.DragAndDropOperation.DropTarget != null)
onDrop (this, IFace.DragAndDropOperation);
onEndDrag (this, IFace.DragAndDropOperation);
IFace.DragAndDropOperation = null;
}
- }
+ }*/
- //bubble event to the top
- Widget p = focusParent;
- if (p != null)
- p.onMouseUp(sender,e);
+ if (MouseUp != null)
+ MouseUp.Invoke (this, e);
+ if (MouseUp == null || forwardMouseEvents)
+ focusParent?.onMouseUp (sender, e);
- MouseUp.Raise (this, e);
}
public virtual void onMouseClick(object sender, MouseButtonEventArgs e){
#if DEBUG_FOCUS
Debug.WriteLine("CLICK => " + this.ToString());
#endif
- if (MouseClick != null)
- {
- MouseClick.Raise(this, e);
- return;
- }
- Widget p = focusParent;
- if (p != null)
- p.onMouseClick(sender,e);
+ if (MouseClick != null)
+ MouseClick.Invoke (this, e);
+ if (MouseClick == null || forwardMouseEvents)
+ focusParent?.onMouseClick (sender, e);
}
public virtual void onMouseDoubleClick(object sender, MouseButtonEventArgs e){
#if DEBUG_FOCUS
Debug.WriteLine("DOUBLE CLICK => " + this.ToString());
#endif
- if (MouseDoubleClick != null)
- {
- MouseDoubleClick.Raise(this, e);
- return;
- }
- Widget p = focusParent;
- if (p != null)
- p.onMouseDoubleClick(sender,e);
+ if (MouseDoubleClick != null)
+ MouseDoubleClick.Invoke (this, e);
+ if (MouseDoubleClick == null || forwardMouseEvents)
+ focusParent?.onMouseDoubleClick (sender, e);
}
public virtual void onMouseWheel(object sender, MouseWheelEventArgs e){
- if (MouseWheelChanged != null)
- {
- MouseWheelChanged.Raise(this, e);
- return;
- }
- Widget p = focusParent;
- if (p != null)
- p.onMouseWheel(sender,e);
+ if (MouseWheelChanged != null)
+ MouseWheelChanged.Invoke (this, e);
+ if (MouseWheelChanged == null || forwardMouseEvents)
+ focusParent?.onMouseWheel (sender, e);
+
}
public virtual void onMouseEnter(object sender, MouseMoveEventArgs e)
{
#endregion
protected virtual void onFocused(object sender, EventArgs e){
- if (IFace.FocusedWidget != this)
- IFace.FocusedWidget = this;
#if DEBUG_FOCUS
Debug.WriteLine("Focused => " + this.ToString());
#endif
#endif
Unfocused.Raise (this, e);
}
+
public virtual void onEnable(object sender, EventArgs e){
Enabled.Raise (this, e);
}
Disabled.Raise (this, e);
}
protected virtual void onParentChanged(object sender, DataSourceChangeEventArgs e) {
-// if (e.NewDataSource != null) {
-// if (width == Measure.Inherit)
-// RegisterForLayouting (LayoutingType.Width);
-// if (height == Measure.Inherit)
-// RegisterForLayouting (LayoutingType.Height);
-// }
-
ParentChanged.Raise (this, e);
if (logicalParent == null)
LogicalParentChanged.Raise (this, e);
t.Start ();
}
public void Run () {
+ //load default main.crow if present
+ try {
+ Load ("#main.crow").DataSource = this;
+ } catch { }
+
while (running) {
ProcessEvents ();
Thread.Sleep(1);
}
#endregion
- public void ProcessEvents() {
+ public void ProcessEvents ()
+ {
+
+ if (armedClick != null) {
+ if (lastClickTime.ElapsedMilliseconds > DoubleClick) {
+ //cancel double click and
+ armedClick.onMouseClick (armedClick, armedClickEventArgs);
+ armedClick = null;
+ }
+ }
+
+ Widget w = _hoverWidget; //previous hover widget
+
backend.ProcessEvents ();
+
+ if (!FocusOnHover || (w == _hoverWidget))
+ return;
+
+ w = _hoverWidget;
+ while (w != null) {
+ if (w.Focusable) {
+ FocusedWidget = _hoverWidget;
+ break;
+ }
+ w = w.focusParent;
+ }
+
}
public void Init () {
CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
/// </summary>
public static string CrowConfigRoot;
/// <summary>If true, mouse focus is given when mouse is over control</summary>
- public static bool FocusOnHover = false;
+ public static bool FocusOnHover = true;
/// <summary> Threshold to catch borders for sizing </summary>
public static int BorderThreshold = 5;
/// <summary> delay before tooltip appear </summary>
public static int ToolTipDelay = 500;
/// <summary>Double click threshold in milisecond</summary>
- public static int DoubleClick = 250;//max duration between two mouse_down evt for a dbl clk in milisec.
+ public static int DoubleClick = 240;//max duration between two mouse_down evt for a dbl clk in milisec.
/// <summary> Time to wait in millisecond before starting repeat loop</summary>
public static int DeviceRepeatDelay = 700;
/// <summary> Time interval in millisecond between device event repeat</summary>
/// the ref of this one will be stored in GraphicObject.currentInterface
/// </summary>
protected static Interface CurrentInterface;
- internal Stopwatch clickTimer = new Stopwatch();
- Widget armedClickSender = null;
- MouseButtonEventArgs armedClickEvtArgs = null;
-// internal GraphicObject EligibleForDoubleClick {
-// get { return eligibleForDoubleClick; }
-// set {
-// eligibleForDoubleClick = value;
-// clickTimer.Restart ();
-// }
-// }
- internal void armeClick (Widget sender, MouseButtonEventArgs e){
- armedClickSender = sender;
- armedClickEvtArgs = e;
- clickTimer.Restart ();
- }
+
+ Stopwatch lastClickTime = new Stopwatch ();
+ Widget armedClick;//store widget with double click on first click
+ MouseButtonEventArgs armedClickEventArgs;
#endregion
#region Events
/// <summary>resulting bitmap limited to last redrawn part</summary>
public byte[] dirtyBmp;
/// <summary>True when host has to repaint Interface</summary>
- public bool IsDirty = false;
+ public bool IsDirty;
/// <summary>Coordinate of the dirty bmp on the original bmp</summary>
public Rectangle DirtyRect;
/// <summary>Locked for each layouting operation</summary>
if (_hoverWidget == value)
return;
- //if (_hoverWidget != null)
- // _hoverWidget.IsHover = false;
+ if (_hoverWidget != null)
+ _hoverWidget.IsHover = false;
_hoverWidget = value;
/// Result: the Interface bitmap is drawn in memory (byte[] bmp) and a dirtyRect and bitmap are available
/// </summary>
public void Update(){
- if (armedClickSender != null && clickTimer.ElapsedMilliseconds >= Interface.DoubleClick) {
- armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs);
- armedClickSender = null;
- }
-
- if (mouseRepeatCount > 0) {
- int mc = mouseRepeatCount;
- mouseRepeatCount -= mc;
- if (_focusedWidget != null) {
- mouseRepeatTriggeredAtLeastOnce = true;
- for (int i = 0; i < mc; i++) {
- _focusedWidget.onMouseDown (this, new BubblingMouseButtonEventArg(Mouse.X, Mouse.Y, MouseButton.Left, true));
- }
- }
- }
-
CrowThread[] tmpThreads;
lock (CrowThreads) {
tmpThreads = new CrowThread[CrowThreads.Count];
for (int i = 0; i < tmpThreads.Length; i++)
tmpThreads [i].CheckState ();
+ if (mouseRepeatTimer.ElapsedMilliseconds > 0) {
+ if (_hoverWidget != null && _hoverWidget.MouseRepeat) {
+ int repeatCount = (int)mouseRepeatTimer.ElapsedMilliseconds / DeviceRepeatInterval - mouseRepeatCount;
+ for (int i = 0; i < repeatCount; i++)
+ _hoverWidget.onMouseDown (_hoverWidget, lastMouseDownEvent);
+ mouseRepeatCount += repeatCount;
+ }
+ } else if (lastMouseDown.ElapsedMilliseconds > DeviceRepeatDelay)
+ mouseRepeatTimer.Start ();
+
if (!Monitor.TryEnter (UpdateMutex))
return;
XCursor cursor = XCursor.Default;
public MouseState Mouse;
+ Stopwatch lastMouseDown = new Stopwatch (), mouseRepeatTimer = new Stopwatch ();
+ int mouseRepeatCount;
+ MouseButtonEventArgs lastMouseDownEvent;
public XCursor MouseCursor {
set {
/// <returns>true if mouse is in the interface</returns>
public virtual bool ProcessMouseMove(int x, int y)
{
- /*if (armedClickSender != null) {
- //armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs);
- armedClickSender = null;
- }*/
int deltaX = x - Mouse.X;
int deltaY = y - Mouse.Y;
Mouse.X = x;
MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY);
e.Mouse = Mouse;
+ if (armedClick != null) {
+ armedClick.onMouseClick (armedClick, armedClickEventArgs);
+ armedClick = null;
+ }
+
if (ActiveWidget != null && DragAndDropOperation == null) {
//TODO, ensure object is still in the graphic tree
//send move evt even if mouse move outside bounds
- ActiveWidget.onMouseMove (this, e);
+ _activeWidget.onMouseMove (this, e);
return true;
}
if (DragAndDropOperation != null)//drag source cant have hover event, so move has to be handle here
DragAndDropOperation.DragSource.onMouseMove (this, e);
- if (HoverWidget != null) {
+ if (_hoverWidget != null) {
resetTooltip ();
//check topmost graphicobject first
- Widget tmp = HoverWidget;
+ Widget tmp = _hoverWidget;
Widget topc = null;
while (tmp is Widget) {
topc = tmp;
while (i < idxhw) {
if (!GraphicTree [i].isPopup) {
if (GraphicTree [i].MouseIsIn (e.Position)) {
- while (HoverWidget != null) {
- HoverWidget.onMouseLeave (HoverWidget, e);
- HoverWidget = HoverWidget.focusParent;
+ while (_hoverWidget != null) {
+ _hoverWidget.onMouseLeave (_hoverWidget, e);
+ HoverWidget = _hoverWidget.focusParent;
}
GraphicTree [i].checkHoverWidget (e);
- HoverWidget.onMouseMove (this, e);
+ _hoverWidget.onMouseMove (this, e);
return true;
}
}
}
}
- if (HoverWidget.MouseIsIn (e.Position)) {
- HoverWidget.checkHoverWidget (e);
- HoverWidget.onMouseMove (this, e);
+ if (_hoverWidget.MouseIsIn (e.Position)) {
+ _hoverWidget.checkHoverWidget (e);
+ _hoverWidget.onMouseMove (this, e);
return true;
- } else {
- HoverWidget.onMouseLeave (HoverWidget, e);
- //seek upward from last focused graph obj's
- while (HoverWidget.focusParent != null) {
- HoverWidget = HoverWidget.focusParent;
- if (HoverWidget.MouseIsIn (e.Position)) {
- HoverWidget.checkHoverWidget (e);
- HoverWidget.onMouseMove (this, e);
- return true;
- } else
- HoverWidget.onMouseLeave (HoverWidget, e);
+ }
+ _hoverWidget.onMouseLeave (_hoverWidget, e);
+ //seek upward from last focused graph obj's
+ while (_hoverWidget.focusParent != null) {
+ HoverWidget = _hoverWidget.focusParent;
+ if (_hoverWidget.MouseIsIn (e.Position)) {
+ _hoverWidget.checkHoverWidget (e);
+ _hoverWidget.onMouseMove (_hoverWidget, e);
+ return true;
}
- }
+ _hoverWidget.onMouseLeave (_hoverWidget, e);
+ }
}
//top level graphic obj's parsing
g.checkHoverWidget (e);
if (g is Window)
PutOnTop (g);
- HoverWidget.onMouseMove (this, e);
+ _hoverWidget.onMouseMove (_hoverWidget, e);
return true;
}
}
public bool ProcessMouseButtonUp(Crow.MouseButton button)
{
Mouse.DisableBit ((int)button);
+
+ lastMouseDown.Reset ();
+ mouseRepeatTimer.Reset ();
+
MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
if (_activeWidget == null)
return false;
- if (mouseRepeatThread != null) {
- mouseRepeatOn = false;
- mouseRepeatThread.Cancel();
+ _activeWidget.onMouseUp (_activeWidget, e);
+
+ if (armedClick != null) {
+ if (lastClickTime.ElapsedMilliseconds <= DoubleClick) {
+ armedClick.onMouseDoubleClick (armedClick, armedClickEventArgs);
+ ActiveWidget = null;
+ } else
+ armedClick.onMouseClick (armedClick, armedClickEventArgs);
+ armedClick = null;
}
- if (!mouseRepeatTriggeredAtLeastOnce) {
- if (_activeWidget.MouseIsIn (e.Position))
- armeClick (_activeWidget, e);
+
+ Widget target = _activeWidget;
+ while (target != null) {
+ if (target.hasDoubleClick) {
+ armedClick = _activeWidget;
+ armedClickEventArgs = e;
+ lastClickTime.Restart ();
+ break;
+ }
+ if (target.hasClick) {
+ _activeWidget.onMouseClick (_activeWidget, e);
+ break;
+ }
+ target = target.focusParent;
}
- mouseRepeatTriggeredAtLeastOnce = false;
- _activeWidget.onMouseUp (_activeWidget, e);
-// GraphicObject lastActive = _activeWidget;
+ // GraphicObject lastActive = _activeWidget;
ActiveWidget = null;
-// if (!lastActive.MouseIsIn (Mouse.Position)) {
-// ProcessMouseMove (Mouse.X, Mouse.Y);
-// }
+ // if (!lastActive.MouseIsIn (Mouse.Position)) {
+ // ProcessMouseMove (Mouse.X, Mouse.Y);
+ // }
return true;
}
/// <summary>
public bool ProcessMouseButtonDown(Crow.MouseButton button)
{
Mouse.EnableBit ((int)button);
- MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
+ lastMouseDown.Start ();
+ mouseRepeatCount = 0;
+
+ lastMouseDownEvent = new MouseButtonEventArgs (button) { Mouse = Mouse };
if (HoverWidget == null)
return false;
break;
}
}
- if (hoverFocused == armedClickSender) {
- if (clickTimer.ElapsedMilliseconds < Interface.DoubleClick) {
- armedClickSender.onMouseDoubleClick (armedClickSender, e);
- armedClickSender = null;
- return true;
- }
-
- }
- if (armedClickSender!=null)
- armedClickSender.onMouseClick (armedClickSender, armedClickEvtArgs);
- armedClickSender = null;
-
- HoverWidget.onMouseDown(HoverWidget,new BubblingMouseButtonEventArg(e));
- if (FocusedWidget == null)
- return true;
+ _hoverWidget.onMouseDown (_hoverWidget, lastMouseDownEvent);
- ActiveWidget = FocusedWidget;
+ /*if (_focusedWidget == null)
+ return true;*/
- if (!FocusedWidget.MouseRepeat)
- return true;
- mouseRepeatThread = new CrowThread (FocusedWidget, mouseRepeatThreadFunc);
- mouseRepeatThread.Start ();
+ ActiveWidget = _hoverWidget;
return true;
}
/// <summary>
#endregion
#region Device Repeat Events
- volatile bool mouseRepeatOn, keyboardRepeatOn, mouseRepeatTriggeredAtLeastOnce = false;
- volatile int mouseRepeatCount, keyboardRepeatCount;
- CrowThread mouseRepeatThread, keyboardRepeatThread;
+ volatile bool keyboardRepeatOn;
+ volatile int keyboardRepeatCount;
KeyEventArgs lastKeyDownEvt;
- void mouseRepeatThreadFunc()
- {
- mouseRepeatOn = true;
- mouseRepeatTriggeredAtLeastOnce = false;
- Thread.Sleep (Interface.DeviceRepeatDelay);
- while (mouseRepeatOn&!mouseRepeatThread.cancelRequested) {
- mouseRepeatCount++;
- Thread.Sleep (Interface.DeviceRepeatInterval);
- }
- mouseRepeatCount = 0;
- }
+
void keyboardRepeatThreadFunc()
{
keyboardRepeatOn = true;