]> O.S.I.I.S - jp/crow.git/commitdiff
mouse handling uniformisationn Handled property in eventHandler, xcb cursor, mouseCur...
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 8 Aug 2019 14:16:03 +0000 (16:16 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 8 Aug 2019 14:16:03 +0000 (16:16 +0200)
19 files changed:
1  2 
Crow/Crow.csproj
Crow/Default.style
Crow/Templates/MenuItem.template
Crow/Templates/Popper.template
Crow/src/GraphicObjects/CheckBox.cs
Crow/src/GraphicObjects/DockWindow.cs
Crow/src/GraphicObjects/Label.cs
Crow/src/GraphicObjects/MenuItem.cs
Crow/src/GraphicObjects/Popper.cs
Crow/src/GraphicObjects/Scroller.cs
Crow/src/GraphicObjects/Splitter.cs
Crow/src/GraphicObjects/TextRun.cs
Crow/src/GraphicObjects/Widget.cs
Crow/src/GraphicObjects/Window.cs
Crow/src/Input/KeyEventArgs.cs
Crow/src/Input/KeyPressEventArgs.cs
Crow/src/Input/MouseEventArgs.cs
Crow/src/Interface.cs
Samples/HelloWorld/HelloWorld.csproj

index 8bad25f67aa0fc28bcfd4fcb382eda9424c5f1e7,8bad25f67aa0fc28bcfd4fcb382eda9424c5f1e7..7a1330933d5f6768ab72c6d8dfd761472385637d
@@@ -33,7 -33,7 +33,7 @@@
    
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
      <DebugType>full</DebugType>
--    <DefineConstants>TRACE;DEBUG;DESIGN_MODE;_DEBUG_CLIP_RECTANGLE;NETFRAMEWORK;NET471</DefineConstants>
++    <DefineConstants>TRACE;DESIGN_MODE;_DEBUG_CLIP_RECTANGLE;_DEBUG_FOCUS;_DEBUG_DRAGNDROP;DEBUG;NETFRAMEWORK;NET471</DefineConstants>
      <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
    </PropertyGroup>
        
index 1e017ce6fbed01d445c4dc86c88fb2a86029562b,5343c09f583bc3b4eebcf97caf5022962f1ac2b9..4a03e706ff7c1adbce330a4d4ae3ac18f940eaaa
@@@ -27,7 -27,7 +27,6 @@@ Icon 
        Width = "12";
        Height = "12";
  }
--
  Wrapper {
        Orientation = "Vertical";
  }
@@@ -38,7 -38,7 +37,15 @@@ Button 
  Label {
        Height = "Fit";
        Width = "Fit";
--      Margin = "0";
++      Margin = "0";   
++}
++TextBox {
++      Background = "White";
++      Foreground = "Black";
++      Selectable = "True";
++      Text = "TextBox";
++      Margin = "1";
++      MouseCursor = "IBeam";
  }
  Menu {
        Margin = "1";
@@@ -96,13 -96,13 +103,6 @@@ TabItem 
        //MouseLeave = "{Foreground=LightGrey;Background=Jet;}";
        AllowDrag = "true";
  }
--TextBox {
--      Background = "White";
--      Foreground = "Black";
--      Selectable = "True";
--      Text = "TextBox";
--      Margin = "1";
--}
  Window {
        Caption = "Window";
        Focusable = "true";
index f6f9a9ac9ef781133bb9709b645f378fc9f498c1,ae31c8622c9f5e5631c56dc52c8c00c58e75b1ba..b619a8b1c726afd011f4fcd23a7179e6aa206f33
@@@ -1,6 -1,7 +1,6 @@@
  <?xml version="1.0"?>
 -<HorizontalStack>
  <Popper Font="{./Font}" Caption="{./Caption}"  Background="{./Background}" PopDirection="{./PopDirection}"
-       Foreground = "{./Foreground}" CanPop="{./HasChildren}" MouseClick="./onMI_Click"
+       Foreground = "{./Foreground}" CanPop="{./HasChildren}"
        IsPopped="{²./IsOpened}" PopWidth="{./PopWidth}" PopHeight="{./PopHeight}">
        <Template>
                <CheckBox IsChecked="{²./IsPopped}" Caption="{./Caption}" Background="{./Background}" Foreground="{./Foreground}">
index 47c6034c5acd7dfbb5a48ccf6c6074f7aa468240,6b9bef9f3331403ba80b0e4ffcf55b126d3bd214..01b466306df7386fb2faffdc5acfac66d9e49860
@@@ -1,7 -1,7 +1,7 @@@
  <?xml version="1.0"?>
  <CheckBox Caption="{./Caption}" IsChecked="{²./IsPopped}" Foreground="{./Foreground}" Background="{./Background}">
        <Template>
-               <Border Style="ControlBorder" Foreground="{./Foreground}" Background="{./Background}">
 -              <Border Style="ControlBorder" Foreground="{./Foreground}" Background="{./Background}" ForwardMouseEvents="true">
++              <Border Style="ControlBorder" Foreground="{./Foreground}" Background="{./Background}" >
                        <HorizontalStack Spacing="1">
                                <Image Style="Icon" Margin="1" Width="9" Height="9"     
                                        MouseEnter="{Background=White}" MouseLeave="{Background=Transparent}"
index 4860d604fa56df3b8d33f6dfd25b752d6dec82be,4860d604fa56df3b8d33f6dfd25b752d6dec82be..7dc2b073a8fd1cc4162aebf413ddf98426f76f7a
@@@ -65,10 -65,10 +65,10 @@@ namespace Cro
                        }
                }
  
--              public override void onMouseDown (object sender, MouseButtonEventArgs e)
++              public override void onMouseClick (object sender, MouseButtonEventArgs e)
                {
                        IsChecked = !IsChecked;
--                      base.onMouseDown (sender, e);
++                      base.onMouseClick (sender, e);
                }
        }
  }
index e368db516795081abfe0f6b49d0e92d14058329f,e368db516795081abfe0f6b49d0e92d14058329f..4be23adb26ef918741c9138157bb4522ce08a57d
@@@ -101,6 -101,6 +101,7 @@@ namespace Cro
                }
                public override void onMouseDown (object sender, MouseButtonEventArgs e)
                {
++                      e.Handled = true;
                        base.onMouseDown (sender, e);
  
                        if (this.HasFocus && IsDocked && e.Button == MouseButton.Left)
                public bool CheckUndock (Point mousePos) {
                        //if (DockingPosition == Alignment.Center)
                        //      return false;
++                      Console.WriteLine ($"{mousePos.X},{mousePos.Y}");
                        if (Math.Abs (mousePos.X - undockingMousePosOrig.X) < undockThreshold ||
                            Math.Abs (mousePos.X - undockingMousePosOrig.X) < undockThreshold)
                                return false;
index 265afcb3e04d778ef89dcc4e4d6c2af5eba3cc70,c7bd5124fb586168aa5325604d7b944248468d6d..3736f968c61629f1881c3cd790d8be8870067fcc
@@@ -462,7 -462,7 +462,7 @@@ namespace Cro
  
                                        try {
                                                for (int i = 0; i < lines.Count; i++) {
--                                                      string l = lines[i].Replace ("\t", new String (' ', Interface.TabSize));
++                                                      string l = lines[i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
  
                                                        TextExtents tmp = gr.TextExtents (l);
  
                        //*******************
  
                        for (int i = 0; i < lines.Count; i++) {
--                              string l = lines [i].Replace ("\t", new String (' ', Interface.TabSize));
++                              string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
                                int lineLength = (int)gr.TextExtents (l).XAdvance;
                                Rectangle lineRect = new Rectangle (
                                        rText.X,
                        if (mouseLocalPos.Y < 0)
                                mouseLocalPos.Y = 0;
                }
--              public override void onMouseEnter (object sender, MouseMoveEventArgs e)
--              {
--                      base.onMouseEnter (sender, e);
--                      if (Selectable)
-                               IFace.MouseCursor = MouseCursor.IBeam;
 -                              IFace.MouseCursor = XCursor.Text;
--              }
--              public override void onMouseLeave (object sender, MouseMoveEventArgs e)
--              {
--                      base.onMouseLeave (sender, e);
-                       IFace.MouseCursor = MouseCursor.Arrow;
 -                      IFace.MouseCursor = XCursor.Default;
--              }
                protected override void onFocused (object sender, EventArgs e)
                {
                        base.onFocused (sender, e);
                        {
                                string c = lines [CurrentLine].Substring (i, 1);
                                if (c == "\t")
--                                      c = new string (' ', Interface.TabSize);
++                                      c = new string (' ', Interface.TAB_SIZE);
  
                                te = gr.TextExtents(c);
  
                {
                        try {
                                string l = lines [pos.Y].Substring (0, pos.X).
--                                      Replace ("\t", new String (' ', Interface.TabSize));
++                                      Replace ("\t", new String (' ', Interface.TAB_SIZE));
                                return gr.TextExtents (l).XAdvance;
                        } catch{
                                return -1;
index 7ad9f758986aed3459bf7927e907887ba3c5587a,5cfce44f89bf22ae567ec8887616a05f2a9dcad3..abc9d114e4454980dada13465d7de5fe24bf32ba
@@@ -176,7 -167,18 +167,21 @@@ namespace Cro
                                IsOpened = false;
                        base.onMouseLeave (this, e);
                }
+               public override void onMouseClick (object sender, MouseButtonEventArgs e)
+               {
++#if DEBUG_FOCUS
++                      System.Diagnostics.Debug.WriteLine ("MENU CLICK => " + this.ToString ());
++#endif
+                       if (command != null) {
+                               command.Execute ();
+                               closeMenu ();
+                       }
+                       if (hasClick)
+                               base.onMouseClick (sender, e);
  
+                       if (!IsOpened)
+                               (LogicalParent as Menu).AutomaticOpening = false;
+               }
                void closeMenu () {
                        MenuItem tmp = LogicalParent as MenuItem;
                        while (tmp != null) {
index 285c6e3538be32aa697f904ee9d3214e4bd3e273,285c6e3538be32aa697f904ee9d3214e4bd3e273..b6acabd2a42b8f615a880cb845c9728fbae4ee20
@@@ -119,7 -119,7 +119,7 @@@ namespace Cro
                        set {
                                if (_content != null) {
                                        _content.LogicalParent = null;
--                                      _content.isPopup = false;
++                                      //_content.isPopup = false;
                                        _content.LayoutChanged -= _content_LayoutChanged;
                                }
  
                                        return;
  
                                _content.LogicalParent = this;
--                              _content.isPopup = true;
++                              //_content.isPopup = true;
                                _content.HorizontalAlignment = HorizontalAlignment.Left;
                                _content.VerticalAlignment = VerticalAlignment.Top;
                                _content.LayoutChanged += _content_LayoutChanged;
                                Content.Visible = true;
                                if (Content.Parent == null)
                                        IFace.AddWidget (Content);
--                              if (Content.LogicalParent != this)
--                                      Content.LogicalParent = this;
++                              //if (Content.LogicalParent != this)
++                              Content.LogicalParent = this;
                                IFace.PutOnTop (Content, true);
                                _content_LayoutChanged (this, new LayoutingEventArgs (LayoutingType.Sizing));
                        }
index 99500d89b5360eb7e5b5fc1c35d57d46a8fb3d77,99500d89b5360eb7e5b5fc1c35d57d46a8fb3d77..e9d14711d08a177ee880c2af5d55bfb33303ba6d
@@@ -221,11 -221,11 +221,12 @@@ namespace Cro
                /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
                public override void onMouseWheel (object sender, MouseWheelEventArgs e)
                {
--                      base.onMouseWheel (sender, e);
                        if (IFace.IsKeyDown (Key.Shift_L))
                                ScrollX += e.Delta * ScrollSpeed;
                        else
                                ScrollY -= e.Delta * ScrollSpeed;
++                      e.Handled = true;
++                      base.onMouseWheel (sender, e);
                }
                /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
                public override void onKeyDown (object sender, KeyEventArgs e)
index 5b400e8063891ed233f17e8cc08a3f5794872d2a,e1f8e637739ac3f509f778278dffa86ba950fbd2..e3f2161b70bc32fc7f209f3d157c15cb1d329dae
@@@ -91,15 -91,15 +91,10 @@@ namespace Cro
                {
                        base.onMouseEnter (sender, e);
                        if ((Parent as GenericStack).Orientation == Orientation.Horizontal)
 -                              IFace.MouseCursor = XCursor.H;
 +                              IFace.MouseCursor = MouseCursor.H;
                        else
 -                              IFace.MouseCursor = XCursor.V;
 -              }
 -              public override void onMouseLeave (object sender, MouseMoveEventArgs e)
 -              {
 -                      base.onMouseLeave (sender, e);
 -                      IFace.MouseCursor = XCursor.Default;
 +                              IFace.MouseCursor = MouseCursor.V;
                }
-               public override void onMouseLeave (object sender, MouseMoveEventArgs e)
-               {
-                       base.onMouseLeave (sender, e);
-                       IFace.MouseCursor = MouseCursor.Arrow;
-               }
                public override void onMouseDown (object sender, MouseButtonEventArgs e)
                {
                        base.onMouseDown (sender, e);
index 48687176724f430027d5d1c73e9787a219bf3592,48687176724f430027d5d1c73e9787a219bf3592..6550411e6ed94bf2b5e5012aeff52eb9b28b28f7
@@@ -170,7 -170,7 +170,7 @@@ namespace Cro
                                }
  
                                foreach (string s in lines) {
--                                      string l = s.Replace("\t", new String (' ', Interface.TabSize));
++                                      string l = s.Replace("\t", new String (' ', Interface.TAB_SIZE));
                                        TextExtents tmp = gr.TextExtents (l);
                                        if (tmp.XAdvance > te.XAdvance)
                                                te = tmp;
  
                        int curLineCount = 0;
                        for (int i = 0; i < lines.Count; i++) {
--                              string l = lines [i].Replace ("\t", new String (' ', Interface.TabSize));
++                              string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
                                List<string> wl = new List<string> ();
                                int lineLength = (int)gr.TextExtents (l).XAdvance;
  
index ea076f827f2fcdcbcd9e1c14a1593d4bedab8422,43310d2d13996904f311397f0952d30ecf3728f4..d2314138a08285b9173bcc5dcc06ab8079dc6a9f
@@@ -201,10 -201,10 +201,10 @@@ namespace Cro
                internal static List<GraphicObject> GraphicObjects = new List<GraphicObject>();
                #endif
  
--              internal bool isPopup = false;
--              public Widget focusParent {
--                      get { return (isPopup ? LogicalParent : parent) as Widget; }
--              }
++              //internal bool isPopup = false;
++              //public Widget focusParent {
++              //      get { return (isPopup ? LogicalParent : parent) as Widget; }
++              //}
  
                /// <summary>
                /// interface this widget is bound to, this should not be changed once the instance is created
                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;
++              MouseCursor mouseCursor = MouseCursor.Arrow;
                protected bool isVisible = true;
                bool isEnabled = true;
                VerticalAlignment verticalAlignment = VerticalAlignment.Center;
                                onParentChanged (this, e);
                        }
                }
++              /// <summary>
++              /// Mouse routing need to go back to logical parent for popups
++              /// </summary>
++              public Widget FocusParent => (parent is Interface ? LogicalParent : parent) as Widget; 
++
                [XmlIgnore]public ILayoutable LogicalParent {
                        get { return logicalParent == null ? Parent : logicalParent; }
                        set {
                                if (logicalParent == value)
                                        return;
--                              if (logicalParent != null)
++                              if (logicalParent is Widget)
                                        (logicalParent as Widget).DataSourceChanged -= onLogicalParentDataSourceChanged;
                                DataSourceChangeEventArgs dsce = new DataSourceChangeEventArgs (LogicalParent, null);
                                logicalParent = value;
                                dsce.NewDataSource = LogicalParent;
--                              if (logicalParent != null)
++                              if (logicalParent is Widget)
                                        (logicalParent as Widget).DataSourceChanged += onLogicalParentDataSourceChanged;
                                onLogicalParentChanged (this, dsce);
                        }
                                NotifyValueChanged ("MouseRepeat", mouseRepeat);
                        }
                }
 -              /// forward mouse events even if an handle is bound
+               /// <summary>
 -              [DesignCategory ("Behaviour")][DefaultValue (false)]
 -              public bool ForwardMouseEvents {
 -                      get { return forwardMouseEvents; }
++              /// Determine Cursor when mouse is Hover.
+               /// </summary>
 -                              if (forwardMouseEvents == value)
++              [DesignCategory ("Behaviour")]
++              [DefaultValue (MouseCursor.Arrow)]
++              public virtual MouseCursor MouseCursor {
++                      get { return mouseCursor; }
+                       set {
 -                              forwardMouseEvents = value;
 -                              NotifyValueChanged ("ForwardMouseEvents", forwardMouseEvents);
++                              if (mouseCursor == value)
+                                       return;
++                              mouseCursor = value;
++                              NotifyValueChanged ("MouseCursor", mouseCursor);
++                              this.RegisterForRedraw ();
++
++                              if (isHover)
++                                      IFace.MouseCursor = mouseCursor;
+                       }
+               }
++
++              /// <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
  
          #region Keyboard handling
                public virtual void onKeyDown(object sender, KeyEventArgs e){
--                      KeyDown.Raise (this, e);
++                      if (KeyDown != null)
++                              KeyDown.Invoke (this, e);
++                      else if (!e.Handled)
++                              FocusParent?.onKeyDown (sender, e);
                }
                public virtual void onKeyUp(object sender, KeyEventArgs e){
--                      KeyUp.Raise (this, e);
++                      if (KeyUp != null)
++                              KeyUp.Invoke (this, e);
++                      else if (!e.Handled)
++                              FocusParent?.onKeyUp (sender, e);
                }
                public virtual void onKeyPress(object sender, KeyPressEventArgs e){
--                      KeyPress.Raise (this, e);
++                      if (KeyPress != null)
++                              KeyPress.Invoke (this, e);
++                      else if (!e.Handled)
++                              FocusParent?.onKeyPress (sender, e);
                }
          #endregion
  
  
                        //this.onMouseMove (this, e);//without this, window border doesn't work, should be removed
                }
--              public virtual void onMouseMove(object sender, MouseMoveEventArgs e)
++              public virtual void onMouseMove (object sender, MouseMoveEventArgs e)
                {
                        if (allowDrag & hasFocus & e.Mouse.LeftButton == ButtonState.Pressed) {
                                if (IFace.DragAndDropOperation == null) {
                        //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);
++                      if (MouseMove != null)
++                              MouseMove.Invoke (this, e);                     
++                      else if (!e.Handled)
++                              FocusParent?.onMouseMove (sender, 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;
--                                      IFace.FocusedWidget = this;
--                                      if (e.Button == MouseButton.Right && contextCommands != null)
--                                              IFace.ShowContextMenu (this);                                   
--                              }
 -                      }*/
++                      if (e.Button == MouseButton.Right && contextCommands != null) {
++                              IFace.ShowContextMenu (this);
++                              e.Handled = true;
 +                      }
-                       //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);
++                              MouseDown?.Invoke (this, e);
++                      else if (!e.Handled)
++                              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);
-                       MouseUp.Raise (this, e);
+                       if (MouseUp != null)
+                               MouseUp.Invoke (this, e);
 -                      if (MouseUp == null || forwardMouseEvents)
 -                              focusParent?.onMouseUp (sender, e);
 -
++                      else if (!e.Handled)
++                              FocusParent?.onMouseUp (sender, 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);
++                      else if (!e.Handled)
++                              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)
++                      if (MouseDoubleClick != null)                   
+                               MouseDoubleClick.Invoke (this, e);
 -                      if (MouseDoubleClick == null || forwardMouseEvents)
 -                              focusParent?.onMouseDoubleClick (sender, e);
++                      else if (!e.Handled)
++                              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);
 -
++                      else if (!e.Handled)
++                              FocusParent?.onMouseWheel (sender, e);
                }
                public virtual void onMouseEnter(object sender, MouseMoveEventArgs e)
                {
                        #if DEBUG_FOCUS
                        Debug.WriteLine("MouseEnter => " + this.ToString());
--                      #endif
++#endif
++
++                      IFace.MouseCursor = mouseCursor;
  
                        if (IFace.DragAndDropOperation != null) {
                                Widget g = this;
                                                }
                                                break;
                                        }
--                                      g = g.focusParent;
++                                      g = g.FocusParent;
                                }
                        }
  
index a9effb8886e2696c8d6c9597d56bb1218b46ef3c,6c8f005e0d770c59e9c4e0df4d01e7bfca951f68..22ad640ecffd529a48ad9feb345d3d2a3a38b5aa
@@@ -294,11 -294,11 +294,11 @@@ namespace Cro
  
                        Interface otkgw = IFace;
  
--                      if (!hoverBorder) {
++                      /*if (!hoverBorder) {
                                currentDirection = Direction.None;
 -                              IFace.MouseCursor = XCursor.Default;
 +                              IFace.MouseCursor = MouseCursor.Arrow;
                                return;
--                      }
++                      }*/
  
                        if (this.HasFocus && movable) {
                                if (e.Mouse.IsButtonDown (MouseButton.Left)) {
index 510e68a076fa24300e328a537b8c4bb53133bdc9,510e68a076fa24300e328a537b8c4bb53133bdc9..29864f07fa53c11903da1d39928bc7d3ee021be5
@@@ -31,7 -31,7 +31,7 @@@ using System.Text
  
  namespace Crow
  {
--    public class KeyEventArgs : EventArgs
++    public class KeyEventArgs : CrowEventArgs
      {
                int keyCode;
                Key key;
index 739906139be80aef4e86eca38416f46970762eed,739906139be80aef4e86eca38416f46970762eed..7ff9565b461be610203f328a6a3f7ce023a504a3
@@@ -33,7 -33,7 +33,7 @@@ namespace Cro
      /// Defines the event arguments for KeyPress events. Instances of this class are cached:
      /// KeyPressEventArgs should only be used inside the relevant event, unless manually cloned.
      /// </summary>
--    public class KeyPressEventArgs : EventArgs
++    public class KeyPressEventArgs : CrowEventArgs
      {
          char key_char;
          
index 6874109424dd3367452aaf638a035b492b58c8c5,6874109424dd3367452aaf638a035b492b58c8c5..84a45818fc7ca8ec601f4fc4b950d8204b4b1cdb
@@@ -31,17 -31,17 +31,11 @@@ using System
  
  namespace Crow
  {
--    /// <summary>
--    /// Defines the event data for <see cref="MouseDevice"/> events.
--    /// </summary>
--    /// <remarks>
--    /// <para>
--    /// Do not cache instances of this type outside their event handler.
--    /// If necessary, you can clone an instance using the
--    /// <see cref="MouseEventArgs(MouseEventArgs)"/> constructor.
--    /// </para>
--    /// </remarks>
--    public class MouseEventArgs : EventArgs
++      public class CrowEventArgs : EventArgs
++      {
++              public bool Handled;
++      }
++      public class MouseEventArgs : CrowEventArgs             
      {
        #region Fields
  
index b18d1f734ba4fc3b0f564ebb981030b2c5135fb6,93d9564508f5901eaafd9cb164cbe903ac076a86..495ca23b5e07351e7d076c5f5a12170bba265546
@@@ -81,13 -81,13 +81,13 @@@ namespace Cro
                                throw new Exception (@"C.R.O.W. run only on Mono, download latest version at: http://www.mono-project.com/download/stable/");
                        }*/
  
--                      CrowConfigRoot =
++                      CROW_CONFIG_ROOT =
                                System.IO.Path.Combine(
                                        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                                        ".config");
--                      CrowConfigRoot = System.IO.Path.Combine (CrowConfigRoot, "crow");
--                      if (!Directory.Exists (CrowConfigRoot))
--                              Directory.CreateDirectory (CrowConfigRoot);
++                      CROW_CONFIG_ROOT = System.IO.Path.Combine (CROW_CONFIG_ROOT, "crow");
++                      if (!Directory.Exists (CROW_CONFIG_ROOT))
++                              Directory.CreateDirectory (CROW_CONFIG_ROOT);
  
                        //ensure all assemblies are loaded, because IML could contains classes not instanciated in source
                        foreach (string af in Directory.GetFiles (AppDomain.CurrentDomain.BaseDirectory, "*.dll")){
                        t.Start ();
                }
                public void Run () {
 -                      //load default main.crow if present
 -                      try {
 -                              Load ("#main.crow").DataSource = this;
 -                      } catch { }
 -
++                      Startup ();
                        while (running) {
                                ProcessEvents ();
                                Thread.Sleep(1);
                        }
                }
++              protected virtual void Startup ()
++              {
++                      //load default main.crow if present
++                      try {
++                              Load ("#main.crow").DataSource = this;
++                      } catch { }
++              }
                public void ProcessKeyPress (char c)
                {
--                      if (_focusedWidget != null)
--                              _focusedWidget.onKeyPress (this, new KeyPressEventArgs(c));
++                      _focusedWidget?.onKeyPress (_focusedWidget, new KeyPressEventArgs(c));
                }
  
                public void ProcessKeyUp (Key key)
                {
--                      if (_focusedWidget != null)
--                              _focusedWidget.onKeyUp (this, new KeyEventArgs(key, false));
++                      _focusedWidget?.onKeyUp (_focusedWidget, new KeyEventArgs(key, false));
  //                    if (keyboardRepeatThread != null) {
  //                            keyboardRepeatOn = false;
  //                            keyboardRepeatThread.Abort();
                        //Keyboard.SetKeyState((Crow.Key)Key,true);
                        lastKeyDownEvt = new KeyEventArgs (key, true);
  
--                      if (_focusedWidget != null)
--                              _focusedWidget.onKeyDown (this, new KeyEventArgs (key, false));
++                      _focusedWidget?.onKeyDown (_focusedWidget, new KeyEventArgs (key, false));
  
                        //                      keyboardRepeatThread = new Thread (keyboardRepeatThreadFunc);
                        //                      keyboardRepeatThread.IsBackground = true;
                }
                #endregion
  
-               public void ProcessEvents() {
+               public void ProcessEvents ()
+               {
 -                      if (armedClick != null) {
 -                              if (lastClickTime.ElapsedMilliseconds > DoubleClick) {
 -                                      //cancel double click and 
 -                                      armedClick.onMouseClick (armedClick, armedClickEventArgs);
 -                                      armedClick = null;
 -                              }
 -                      }
++                      //if (armedClick != null) {
++                      //      if (lastClickTime.ElapsedMilliseconds > DOUBLECLICK_TRESHOLD) {
++                      //              //cancel double click and 
++                      //              armedClick.onMouseClick (armedClick, armedClickEventArgs);
++                      //              armedClick = null;
++                      //      }
++                      //}
+                       Widget w = _hoverWidget;  //previous hover widget 
                        backend.ProcessEvents ();
 -                      if (!FocusOnHover || (w == _hoverWidget))
 -                                      FocusedWidget = _hoverWidget;
++                      if (DragAndDropOperation != null)
++                              return;
++
++                      if (!FOCUS_ON_HOVER || (w == _hoverWidget))
+                               return;
+                       w = _hoverWidget;
+                       while (w != null) {
+                               if (w.Focusable) {
 -                              w = w.focusParent;
++                                      FocusedWidget = w;
+                                       break;
+                               }
++                              w = w.LogicalParent as Widget;
+                       }
                }
                public void Init () {
                        CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
                /// <summary>
                /// Crow configuration root path
                /// </summary>
--              public static string CrowConfigRoot;
++              public static string CROW_CONFIG_ROOT;
                /// <summary>If true, mouse focus is given when mouse is over control</summary>
-               public static bool FocusOnHover = false;
 -              public static bool FocusOnHover = true;
++              public static bool FOCUS_ON_HOVER = 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;
++              public static int TOOLTIP_DELAY = 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.
++              public static int DOUBLECLICK_TRESHOLD = 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;
++              public static int DEVICE_REPEAT_DELAY = 700;
                /// <summary> Time interval in millisecond between device event repeat</summary>
--              public static int DeviceRepeatInterval = 40;
++              public static int DEVICE_REPEAT_INTERVAL = 40;
                public static float WheelIncrement = 1;
                /// <summary>Tabulation size in Text controls</summary>
--              public static int TabSize = 4;
++              public static int TAB_SIZE = 4;
                public static string LineBreak = "\n";
                /// <summary> Allow rendering of interface in development environment </summary>
                public static bool DesignerMode = false;
                /// 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
                                #if DEBUG_FOCUS
                                NotifyValueChanged("HoverWidget", _hoverWidget);
                                #endif
--                              /*
++
                                if (_hoverWidget != null)
                                {
                                        _hoverWidget.IsHover = true;
--                                      #if DEBUG_FOCUS
++#if DEBUG_FOCUS
                                        Debug.WriteLine("Hover => " + _hoverWidget.ToString());
--                                      }else
++                              }else
                                        Debug.WriteLine("Hover => null");
--                                      #else
++#else
                                }
--                                      #endif
--                                      */
++#endif                                        
                        }
                }
                /// <summary>Widget has the keyboard or mouse focus</summary>
                        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 (mouseRepeatTimer.ElapsedMilliseconds > 0) {
++                      //      if ((bool)_hoverWidget?.MouseRepeat) {
++                      //              int repeatCount = (int)mouseRepeatTimer.ElapsedMilliseconds / DEVICE_REPEAT_INTERVAL - mouseRepeatCount;
++                      //              for (int i = 0; i < repeatCount; i++)
++                      //                      _hoverWidget.onMouseDown (_hoverWidget, lastMouseDownEvent);
++                      //              mouseRepeatCount += repeatCount;
++                      //      }
++                      //} else if (lastMouseDown.ElapsedMilliseconds > DEVICE_REPEAT_DELAY)
++                              //mouseRepeatTimer.Start ();
                        if (!Monitor.TryEnter (UpdateMutex))
                                return;
  
                }
  
                #region Mouse and Keyboard Handling
 -              XCursor cursor = XCursor.Default;
 +              MouseCursor cursor = MouseCursor.Arrow;
  
                public MouseState Mouse;
+               Stopwatch lastMouseDown = new Stopwatch (), mouseRepeatTimer = new Stopwatch ();
++              bool doubleClickTriggered;      //next mouse up will trigger a double click
+               int mouseRepeatCount;
+               MouseButtonEventArgs lastMouseDownEvent;
  
 -              public XCursor MouseCursor {
 +              public MouseCursor MouseCursor {
                        set {
 +
                                if (value == cursor)
                                        return;
                                cursor = value;
                                Widget topc = null;
                                while (tmp is Widget) {
                                        topc = tmp;
--                                      tmp = tmp.focusParent;
++                                      tmp = tmp.LogicalParent as Widget;
                                }
                                int idxhw = GraphicTree.IndexOf (topc);
                                if (idxhw != 0) {
                                        int i = 0;
                                        while (i < idxhw) {
--                                              if (!GraphicTree [i].isPopup) {
++                                              //if logical parent of top container is a widget, that's a popup
++                                              if (GraphicTree [i].LogicalParent is Interface) {                                               
                                                        if (GraphicTree [i].MouseIsIn (e.Position)) {
                                                                while (_hoverWidget != null) {
                                                                        _hoverWidget.onMouseLeave (_hoverWidget, e);
--                                                                      HoverWidget = _hoverWidget.focusParent;
++                                                                      HoverWidget = _hoverWidget.FocusParent;
                                                                }
  
                                                                GraphicTree [i].checkHoverWidget (e);
                                } 
                                _hoverWidget.onMouseLeave (_hoverWidget, e);
                                //seek upward from last focused graph obj's
--                              while (_hoverWidget.focusParent != null) {
--                                      HoverWidget = _hoverWidget.focusParent;
++                              tmp = _hoverWidget.FocusParent;
++                              while (tmp != null) {
++                                      HoverWidget = tmp;
                                        if (_hoverWidget.MouseIsIn (e.Position)) {
                                                _hoverWidget.checkHoverWidget (e);
-                                               _hoverWidget.onMouseMove (this, e);
+                                               _hoverWidget.onMouseMove (_hoverWidget, e);
                                                return true;
                                        }
                                        _hoverWidget.onMouseLeave (_hoverWidget, e);
-                               }                       
++                                      tmp = _hoverWidget.FocusParent;
+                               }                               
                        }
  
                        //top level graphic obj's parsing
                        return false;
                }
                /// <summary>
--              /// Forward the mouse up event from the host to the crow interface
++              /// Forward the mouse down event from the host to the hover widget in the crow interface
                /// </summary>
                /// <returns>return true, if interface handled the event, false otherwise.</returns>
                /// <param name="button">Button index</param>
--              public bool ProcessMouseButtonUp(Crow.MouseButton button)
++              public bool ProcessMouseButtonDown (MouseButton button)
                {
--                      Mouse.DisableBit ((int)button);
-                       MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
-                       if (_activeWidget == null)
 -
 -                      lastMouseDown.Reset ();
 -                      mouseRepeatTimer.Reset ();
++                      Mouse.EnableBit ((int)button);
 -                      MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
 -                      if (_activeWidget == null)
 -                              return false;
++                      doubleClickTriggered = (lastMouseDown.ElapsedMilliseconds < DOUBLECLICK_TRESHOLD);
++                      lastMouseDown.Restart ();
++                      mouseRepeatCount = -1;//stays negative until repeat delay is hit
 -                      _activeWidget.onMouseUp (_activeWidget, e);
++                      lastMouseDownEvent = new MouseButtonEventArgs (button) { Mouse = Mouse };
 -                      if (armedClick != null) {
 -                              if (lastClickTime.ElapsedMilliseconds <= DoubleClick) {
 -                                      armedClick.onMouseDoubleClick (armedClick, armedClickEventArgs);
 -                                      ActiveWidget = null;
 -                              } else
 -                                      armedClick.onMouseClick (armedClick, armedClickEventArgs);
 -                              armedClick = null;
 -                      }
++                      if (_hoverWidget == null)
 +                              return false;
  
-                       if (mouseRepeatThread != null) {
-                               mouseRepeatOn = false;
-                               mouseRepeatThread.Cancel();
-                       }
-                       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);
++                      _hoverWidget.onMouseDown (_hoverWidget, lastMouseDownEvent);
  
- //                    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);
 -                      //                      }
++                      ActiveWidget = _hoverWidget;
                        return true;
                }
                /// <summary>
--              /// Forward the mouse down event from the host to the crow interface
++              /// Forward the mouse up event from the host to the crow interface
                /// </summary>
                /// <returns>return true, if interface handled the event, false otherwise.</returns>
                /// <param name="button">Button index</param>
--              public bool ProcessMouseButtonDown(Crow.MouseButton button)
++              public bool ProcessMouseButtonUp(MouseButton button)
                {
--                      Mouse.EnableBit ((int)button);
-                       MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
-                       if (_hoverWidget == null)
-                               return false;
 -                      lastMouseDown.Start ();
 -                      mouseRepeatCount = 0;
++                      Mouse.DisableBit ((int)button);
  
-                       Widget hoverFocused = _hoverWidget;
-                       while (!hoverFocused.Focusable) {
-                               hoverFocused = hoverFocused.focusParent;
-                               if (hoverFocused == null) {
-                                       hoverFocused = _hoverWidget;
-                                       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;
 -                      lastMouseDownEvent = new MouseButtonEventArgs (button) { Mouse = Mouse };
++                      mouseRepeatTimer.Reset ();
  
-                       _hoverWidget.onMouseDown(_hoverWidget,new BubblingMouseButtonEventArg(e));
 -                      if (HoverWidget == null)
++                      MouseButtonEventArgs e = new MouseButtonEventArgs (button) { Mouse = Mouse };
++                      if (_activeWidget == null)
+                               return false;
  
-                       if (_focusedWidget == null)
-                               return true;
 -                      Widget hoverFocused = HoverWidget;
 -                      while (!hoverFocused.Focusable) {
 -                              hoverFocused = hoverFocused.focusParent;
 -                              if (hoverFocused == null) {
 -                                      hoverFocused = HoverWidget;
 -                                      break;
 -                              }
 -                      }
 -
 -                      _hoverWidget.onMouseDown (_hoverWidget, lastMouseDownEvent);
++                      _activeWidget.onMouseUp (_activeWidget, e);
  
-                       ActiveWidget = FocusedWidget;
 -                      /*if (_focusedWidget == null)
 -                              return true;*/
++                      if (doubleClickTriggered)
++                              _activeWidget.onMouseDoubleClick (_activeWidget, e);
++                      else
++                              _activeWidget.onMouseClick (_activeWidget, e);
  
-                       if (!FocusedWidget.MouseRepeat)
-                               return true;
-                       mouseRepeatThread = new CrowThread (FocusedWidget, mouseRepeatThreadFunc);                      
-                       mouseRepeatThread.Start ();
 -                      ActiveWidget = _hoverWidget;
++                      ActiveWidget = null;
++//                    if (!lastActive.MouseIsIn (Mouse.Position)) {
++//                            ProcessMouseMove (Mouse.X, Mouse.Y);
++//                    }
                        return true;
                }
                /// <summary>
                /// Forward the mouse wheel event from the host to the crow interface
                /// </summary>
                /// <returns>return true, if interface handled the event, false otherwise.</returns>
--              /// <param name="button">Button index</param>
++              /// <param name="delta">wheel delta</param>
                public bool ProcessMouseWheelChanged(float delta)
                {
                        Mouse.SetScrollRelative (0, delta);
                        MouseWheelEventArgs e = new MouseWheelEventArgs () { Mouse = Mouse, DeltaPrecise = delta };
  
 -                      if (HoverWidget == null)
 +                      if (_hoverWidget == null)
                                return false;
-                       _hoverWidget.onMouseWheel (this, e);
 -                      HoverWidget.onMouseWheel (this, e);
++                      _hoverWidget.onMouseWheel (_hoverWidget, e);
                        return true;
                }
  
                void toolTipThreadFunc ()
                {
                        while(true) {
--                              if (tooltipTimer.ElapsedMilliseconds > ToolTipDelay) {
++                              if (tooltipTimer.ElapsedMilliseconds > TOOLTIP_DELAY) {
                                        if (!tooltipVisible) {
                                                Widget g = _hoverWidget;
                                                while (g != null) {
                                else
                                        ctxMenuContainer.IsOpened = true;
  
--                              ctxMenuContainer.isPopup = true;
++                              //ctxMenuContainer.isPopup = true;
                                ctxMenuContainer.LogicalParent = go;
                                ctxMenuContainer.DataSource = go;
  
                void keyboardRepeatThreadFunc()
                {
                        keyboardRepeatOn = true;
--                      Thread.Sleep (Interface.DeviceRepeatDelay);
++                      Thread.Sleep (Interface.DEVICE_REPEAT_DELAY);
                        while (keyboardRepeatOn) {
                                keyboardRepeatCount++;
--                              Thread.Sleep (Interface.DeviceRepeatInterval);
++                              Thread.Sleep (Interface.DEVICE_REPEAT_INTERVAL);
                        }
                        keyboardRepeatCount = 0;
                }
index c8787225ce0cb3e9d333c2cc58eebde157b93b28,c8787225ce0cb3e9d333c2cc58eebde157b93b28..14bb3d73ad02b2af705061f9c2b013040ff03b21
@@@ -11,6 -11,6 +11,9 @@@
      <ReleaseVersion>0.8.0</ReleaseVersion>
    </PropertyGroup>
              
++  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++    <DefineConstants>TRACE;DEBUG;NETFRAMEWORK;NET471</DefineConstants>
++  </PropertyGroup>
    <ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
      <Reference Include="System" />
    </ItemGroup>