From a25ff30120987cf9d24e27ff5d062b451d508b6e Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Tue, 23 Feb 2016 18:15:30 +0100 Subject: [PATCH] CrowInterface object holding common functions, IGOLibHost removed --- Crow.csproj | 1 + GtkCrow/CrowContainer.cs | 388 ++----------------- OTKCrow/OpenTKGameWindow.cs | 51 +-- Tests/GOLIBTests.cs | 40 +- src/CompilerServices/CompilerServices.cs | 2 +- src/GraphicObjects/GraphicObject.cs | 26 +- src/GraphicObjects/Group.cs | 4 +- src/GraphicObjects/ILayoutable.cs | 2 - src/GraphicObjects/Popper.cs | 10 +- src/GraphicObjects/Splitter.cs | 6 +- src/GraphicObjects/TabView.cs | 4 +- src/GraphicObjects/Window.cs | 6 +- src/Interface.cs | 471 ++++++++++++++++++++++- src/MouseCursorChangedEventArgs.cs | 33 ++ 14 files changed, 572 insertions(+), 472 deletions(-) create mode 100644 src/MouseCursorChangedEventArgs.cs diff --git a/Crow.csproj b/Crow.csproj index a87b1548..735426e5 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -148,6 +148,7 @@ + diff --git a/GtkCrow/CrowContainer.cs b/GtkCrow/CrowContainer.cs index 0bf17b2f..7ea77d03 100644 --- a/GtkCrow/CrowContainer.cs +++ b/GtkCrow/CrowContainer.cs @@ -30,13 +30,18 @@ using Cairo; namespace Crow { - public class OpenTKGameWindow : Gtk.Window, ILayoutable, IGOLibHost + public class OpenTKGameWindow : Gtk.Window { + public Interface CrowInterface; + + #region ctor public OpenTKGameWindow(int _width, int _height, string _title="Crow") : base(Gtk.WindowType.Toplevel) { - currentWindow = this; + CrowInterface = new Interface (); + CrowInterface.Quit += Quit; + Decorated = false; this.AddEvents ((int)Gdk.EventMask.PointerMotionMask); @@ -44,40 +49,41 @@ namespace Crow this.Drawn += Win_Drawn; this.OverrideBackgroundColor (Gtk.StateFlags.Normal, Gdk.RGBA.Zero); this.Visual = Gdk.Global.DefaultRootWindow.Screen.RgbaVisual; - // this.AcceptFocus = false; - // this.CanFocus = false; this.ButtonPressEvent += OpenTKGameWindow_ButtonPressEvent; this.ButtonReleaseEvent += OpenTKGameWindow_ButtonReleaseEvent; this.MotionNotifyEvent += OpenTKGameWindow_MotionNotifyEvent; this.KeyPressEvent += OpenTKGameWindow_KeyPressEvent; - this.SizeAllocated += OpenTKGameWindow_SizeAllocated; this.Show (); this.Maximize (); - OnLoad (null); GLib.Idle.Add (new GLib.IdleHandler (idleHandler)); GLib.Timeout.Add (10, new GLib.TimeoutHandler (updateHandler)); interval.Start (); } + #endregion + + + #region Timers Stopwatch interval = new Stopwatch(); bool updateHandler(){ - update(); + CrowInterface.Update(); return true; } bool idleHandler(){ - if (isDirty && interval.ElapsedMilliseconds > 1) { + if (CrowInterface.IsDirty && interval.ElapsedMilliseconds > 1) { Debug.WriteLine (interval.ElapsedTicks.ToString ()); - QueueDrawArea (DirtyRect.X, DirtyRect.Y, DirtyRect.Width, DirtyRect.Height); + QueueDrawArea (CrowInterface.DirtyRect.X, CrowInterface.DirtyRect.Y, CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height); interval.Restart (); } return true; } #endregion +<<<<<<< 70bcdc77ff42c74fcd8e6e7dffd4eb6b16f24f39 public List GraphicObjects = new List(); public Color Background = Color.Transparent; @@ -216,310 +222,56 @@ namespace Crow Surface surf; byte[] bmp; +======= + protected void Quit (object sender, EventArgs e) + { + Gtk.Application.Quit (); + } +>>>>>>> CrowInterface object holding common functions, IGOLibHost removed void Win_Drawn (object o, Gtk.DrawnArgs args) { - if (isDirty) { - byte[] tmp = new byte[4 * DirtyRect.Width * DirtyRect.Height]; - for (int y = 0; y < DirtyRect.Height; y++) { - Array.Copy(bmp, - ((DirtyRect.Top + y) * ClientRectangle.Width * 4) + DirtyRect.Left * 4, - tmp, y * DirtyRect.Width * 4, DirtyRect.Width *4); + if (CrowInterface.IsDirty) { + byte[] tmp = new byte[4 * CrowInterface.DirtyRect.Width * CrowInterface.DirtyRect.Height]; + for (int y = 0; y < CrowInterface.DirtyRect.Height; y++) { + Array.Copy(CrowInterface.bmp, + ((CrowInterface.DirtyRect.Top + y) * CrowInterface.ClientRectangle.Width * 4) + CrowInterface.DirtyRect.Left * 4, + tmp, y * CrowInterface.DirtyRect.Width * 4, CrowInterface.DirtyRect.Width *4); } - using (ImageSurface img = new ImageSurface (tmp, Format.Argb32, DirtyRect.Width, DirtyRect.Height, 4 * DirtyRect.Width)) { - args.Cr.SetSourceSurface (img, DirtyRect.X, DirtyRect.Y); + using (ImageSurface img = new ImageSurface (tmp, Format.Argb32, CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height, 4 * CrowInterface.DirtyRect.Width)) { + args.Cr.SetSourceSurface (img, CrowInterface.DirtyRect.X, CrowInterface.DirtyRect.Y); args.Cr.Paint(); } - isDirty = false; + CrowInterface.IsDirty = false; return; } - if (bmp == null) + if (CrowInterface.bmp == null) return; - using (ImageSurface img = new ImageSurface (bmp, Format.Argb32, ClientRectangle.Width, ClientRectangle.Height, 4 * ClientRectangle.Width)) { - args.Cr.SetSourceSurface (img, ClientRectangle.X, ClientRectangle.Y); + using (ImageSurface img = new ImageSurface (CrowInterface.bmp, Format.Argb32, CrowInterface.ClientRectangle.Width, CrowInterface.ClientRectangle.Height, 4 * CrowInterface.ClientRectangle.Width)) { + args.Cr.SetSourceSurface (img, CrowInterface.ClientRectangle.X, CrowInterface.ClientRectangle.Y); args.Cr.Paint(); } } - void Win_DeleteEvent (object o, Gtk.DeleteEventArgs args) { Gtk.Application.Quit (); } - - void OpenTKGameWindow_SizeAllocated (object o, Gtk.SizeAllocatedArgs args) { - int stride = 4 * ClientRectangle.Width; - int bmpSize = Math.Abs (stride) * ClientRectangle.Height; - bmp = new byte[bmpSize]; - - foreach (GraphicObject g in GraphicObjects) - g.RegisterForLayouting (LayoutingType.All); - - //_redrawClip.AddRectangle (ClientRectangle); - } - #endregion - - protected virtual void OnLoad (EventArgs e){ - Interface.LoadCursors (); - } - - #if MEASURE_TIME - public Stopwatch updateTime = new Stopwatch (); - public Stopwatch layoutTime = new Stopwatch (); - public Stopwatch guTime = new Stopwatch (); - public Stopwatch drawingTime = new Stopwatch (); - #endif - - bool isDirty = false; - Rectangle DirtyRect; - - #region update - void update () - { - if (mouseRepeatCount > 0) { - int mc = mouseRepeatCount; - mouseRepeatCount -= mc; - for (int i = 0; i < mc; i++) { - //FocusedWidget.onMouseClick (this, new MouseButtonEventArgs (Mouse.X, Mouse.Y, MouseButton.Left, true)); - } - } - #if MEASURE_TIME - layoutTime.Reset (); - guTime.Reset (); - drawingTime.Reset (); - updateTime.Restart (); - #endif - - #if MEASURE_TIME - layoutTime.Start (); - #endif - //Debug.WriteLine ("======= Layouting queue start ======="); - - while (Interface.LayoutingQueue.Count > 0) { - LayoutingQueueItem lqi = Interface.LayoutingQueue.Dequeue (); - lqi.ProcessLayouting (); - } - - #if MEASURE_TIME - layoutTime.Stop (); - #endif - - //Debug.WriteLine ("otd:" + gobjsToRedraw.Count.ToString () + "-"); - //final redraw clips should be added only when layout is completed among parents, - //that's why it take place in a second pass - GraphicObject[] gotr = new GraphicObject[gobjsToRedraw.Count]; - gobjsToRedraw.CopyTo (gotr); - gobjsToRedraw.Clear (); - foreach (GraphicObject p in gotr) { - p.IsQueuedForRedraw = false; - p.Parent.RegisterClip (p.LastPaintedSlot); - p.Parent.RegisterClip (p.getSlot()); - } - - #if MEASURE_TIME - updateTime.Stop (); - drawingTime.Start (); - #endif - - using (surf = new ImageSurface (bmp, Format.Argb32, ClientRectangle.Width, ClientRectangle.Height, ClientRectangle.Width * 4)) { - using (ctx = new Context (surf)){ - - - if (clipping.count > 0) { - //Link.draw (ctx); - clipping.clearAndClip(ctx); - - GraphicObject[] invGOList = new GraphicObject[GraphicObjects.Count]; - GraphicObjects.CopyTo (invGOList, 0); - invGOList = invGOList.Reverse ().ToArray (); - - foreach (GraphicObject p in invGOList) { - if (!p.Visible) - continue; - if (!clipping.intersect (p.Slot)) - continue; - ctx.Save (); - - p.Paint (ref ctx); - - ctx.Restore (); - } - - #if DEBUG_CLIP_RECTANGLE - clipping.stroke (ctx, Color.Red.AdjustAlpha(0.5)); - #endif - - if (isDirty) - DirtyRect += clipping.Bounds; - else - DirtyRect = clipping.Bounds; - isDirty = true; - - DirtyRect.Left = Math.Max (0, DirtyRect.Left); - DirtyRect.Top = Math.Max (0, DirtyRect.Top); - DirtyRect.Width = Math.Min (ClientRectangle.Width - DirtyRect.Left, DirtyRect.Width); - DirtyRect.Height = Math.Min (ClientRectangle.Height - DirtyRect.Top, DirtyRect.Height); - - clipping.Reset (); - } - - #if MEASURE_TIME - drawingTime.Stop (); - #endif - //surf.WriteToPng (@"/mnt/data/test.png"); - } - } -// if (ToolTip.isVisible) { -// ToolTip.panel.processkLayouting(); -// if (ToolTip.panel.layoutIsValid) -// ToolTip.panel.Paint(ref ctx); -// } -// Debug.WriteLine("INTERFACE: layouting: {0} ticks \t graphical update {1} ticks \t drawing {2} ticks", -// layoutTime.ElapsedTicks, -// guTime.ElapsedTicks, -// drawingTime.ElapsedTicks); -// Debug.WriteLine("INTERFACE: layouting: {0} ms \t graphical update {1} ms \t drawing {2} ms", -// layoutTime.ElapsedMilliseconds, -// guTime.ElapsedMilliseconds, -// drawingTime.ElapsedMilliseconds); - -// Debug.WriteLine("UPDATE: {0} ticks \t, {1} ms", -// updateTime.ElapsedTicks, -// updateTime.ElapsedMilliseconds); - } - #endregion - - #region loading - public GraphicObject LoadInterface (string path) - { - GraphicObject tmp = Interface.Load (path, this); - AddWidget (tmp); - return tmp; - } - #endregion - - - MouseState mouse; - KeyboardState Keyboard; - + CrowInterface.ProcessResize (new Rectangle (args.Allocation.X, args.Allocation.Y, args.Allocation.Width, args.Allocation.Height)); + } void OpenTKGameWindow_MotionNotifyEvent (object o, Gtk.MotionNotifyEventArgs args) { - int deltaX = (int)args.Event.X - mouse.X; - int deltaY = (int)args.Event.Y - mouse.Y; - MouseMoveEventArgs e = new MouseMoveEventArgs ((int)args.Event.X, (int)args.Event.Y, deltaX, deltaY); - mouse.X = (int)args.Event.X; - mouse.Y = (int)args.Event.Y; - e.Mouse = mouse; - - if (_activeWidget != null) { - //first, ensure object is still in the graphic tree - if (_activeWidget.HostContainer == null) { - activeWidget = null; - } else { - - //send move evt even if mouse move outside bounds - _activeWidget.onMouseMove (this, e); - return; - } - } - - if (hoverWidget != null) { - //first, ensure object is still in the graphic tree - if (hoverWidget.HostContainer == null) { - hoverWidget = null; - } else { - //check topmost graphicobject first - GraphicObject tmp = hoverWidget; - GraphicObject topc = null; - while (tmp is GraphicObject) { - topc = tmp; - tmp = tmp.Parent as GraphicObject; - } - int idxhw = GraphicObjects.IndexOf (topc); - if (idxhw != 0) { - int i = 0; - while (i < idxhw) { - if (GraphicObjects [i].MouseIsIn (e.Position)) { - hoverWidget.onMouseLeave (this, e); - GraphicObjects [i].checkHoverWidget (e); - return; - } - i++; - } - } - - - if (hoverWidget.MouseIsIn (e.Position)) { - hoverWidget.checkHoverWidget (e); - return; - } else { - hoverWidget.onMouseLeave (this, e); - //seek upward from last focused graph obj's - while (hoverWidget.Parent as GraphicObject != null) { - hoverWidget = hoverWidget.Parent as GraphicObject; - if (hoverWidget.MouseIsIn (e.Position)) { - hoverWidget.checkHoverWidget (e); - return; - } else - hoverWidget.onMouseLeave (this, e); - } - } - } - } - - //top level graphic obj's parsing - for (int i = 0; i < GraphicObjects.Count; i++) { - GraphicObject g = GraphicObjects[i]; - if (g.MouseIsIn (e.Position)) { - g.checkHoverWidget (e); - PutOnTop (g); - return; - } - } - hoverWidget = null; - //MouseMove.Raise (this, otk_e); - } + CrowInterface.ProcessMouseMove ((int)args.Event.X, (int)args.Event.Y); + } void OpenTKGameWindow_ButtonReleaseEvent (object o, Gtk.ButtonReleaseEventArgs args) { - MouseButtonEventArgs e = new MouseButtonEventArgs ((int)args.Event.X, (int)args.Event.Y, (Crow.MouseButton)args.Event.Button-1, false); - mouse.DisableBit ((int)args.Event.Button-1); - e.Mouse = mouse; - - if (_activeWidget == null) { - //MouseButtonUp.Raise (this, otk_e); - return; - } - - if (mouseRepeatThread != null) { - mouseRepeatOn = false; - mouseRepeatThread.Abort(); - mouseRepeatThread.Join (); - } - - _activeWidget.onMouseUp (this, e); - activeWidget = null; + CrowInterface.ProcessMouseButtonUp ((int)args.Event.Button - 1); } void OpenTKGameWindow_ButtonPressEvent (object o, Gtk.ButtonPressEventArgs args) { - MouseButtonEventArgs e = new MouseButtonEventArgs ((int)args.Event.X, (int)args.Event.Y, (Crow.MouseButton)args.Event.Button - 1, true); - mouse.EnableBit ((int)args.Event.Button - 1); - e.Mouse = mouse; - - if (hoverWidget == null) { - //MouseButtonDown.Raise (this, otk_e); - return; - } - - hoverWidget.onMouseDown(hoverWidget,new BubblingMouseButtonEventArg(e)); - - if (FocusedWidget == null) - return; - if (!FocusedWidget.MouseRepeat) - return; - mouseRepeatThread = new Thread (mouseRepeatThreadFunc); - mouseRepeatThread.Start (); + CrowInterface.ProcessMouseButtonDown ((int)args.Event.Button - 1); } // void Mouse_WheelChanged(object sender, OpenTK.Input.MouseWheelEventArgs otk_e) @@ -536,19 +288,6 @@ namespace Crow // hoverWidget.onMouseWheel (this, e); // } - volatile bool mouseRepeatOn; - volatile int mouseRepeatCount; - Thread mouseRepeatThread; - void mouseRepeatThreadFunc() - { - mouseRepeatOn = true; - Thread.Sleep (Interface.DeviceRepeatDelay); - while (mouseRepeatOn) { - mouseRepeatCount++; - Thread.Sleep (Interface.DeviceRepeatInterval); - } - mouseRepeatCount = 0; - } #region keyboard Handling @@ -565,56 +304,9 @@ namespace Crow // } void OpenTKGameWindow_KeyPressEvent (object o, Gtk.KeyPressEventArgs args) { - if (_focusedWidget == null) { -// KeyboardKeyDown.Raise (this, otk_e); - return; - } - Keyboard.SetKeyState ((Crow.Key)args.Event.KeyValue, true); - KeyboardKeyEventArgs e = new KeyboardKeyEventArgs((Crow.Key)args.Event.KeyValue, false, Keyboard); - _focusedWidget.onKeyDown (o, e); - } - #endregion - - #region ILayoutable implementation - public void RegisterClip(Rectangle r){ - clipping.AddRectangle (r); - } - public bool ArrangeChildren { get { return false; }} - public int LayoutingTries { - get { throw new NotImplementedException (); } - set { throw new NotImplementedException (); } - } - public LayoutingType RegisteredLayoutings { - get { return LayoutingType.None; } - set { throw new NotImplementedException (); } - } - public void RegisterForLayouting (LayoutingType layoutType) { throw new NotImplementedException (); } - public bool UpdateLayout (LayoutingType layoutType) { throw new NotImplementedException (); } - public Rectangle ContextCoordinates (Rectangle r) => r; - public Rectangle ScreenCoordinates (Rectangle r) => r; - - public ILayoutable Parent { - get { return null; } - set { throw new NotImplementedException (); } - } - public ILayoutable LogicalParent { - get { return null; } - set { throw new NotImplementedException (); } } - public Rectangle ClientRectangle { - get { - int width, height; - this.GetSize (out width, out height); - return new Size(width, height); - } - } - public IGOLibHost HostContainer { - get { return this; } - } - public Rectangle getSlot () => ClientRectangle; - public Rectangle getBounds () => ClientRectangle; - #endregion + #endregion } } diff --git a/OTKCrow/OpenTKGameWindow.cs b/OTKCrow/OpenTKGameWindow.cs index 111163b4..ae013bd8 100644 --- a/OTKCrow/OpenTKGameWindow.cs +++ b/OTKCrow/OpenTKGameWindow.cs @@ -270,12 +270,6 @@ namespace Crow } #endregion - #if MEASURE_TIME - public Stopwatch updateTime = new Stopwatch (); - public Stopwatch layoutTime = new Stopwatch (); - public Stopwatch guTime = new Stopwatch (); - public Stopwatch drawingTime = new Stopwatch (); - #endif bool isDirty = false; Rectangle DirtyRect; @@ -290,20 +284,11 @@ namespace Crow FocusedWidget.onMouseClick (this, new MouseButtonEventArgs (Mouse.X, Mouse.Y, MouseButton.Left, true)); } } - #if MEASURE_TIME - layoutTime.Reset (); - guTime.Reset (); - drawingTime.Reset (); - updateTime.Restart (); - #endif GraphicObject[] invGOList = new GraphicObject[GraphicObjects.Count]; GraphicObjects.CopyTo (invGOList, 0); invGOList = invGOList.Reverse ().ToArray (); - #if MEASURE_TIME - layoutTime.Start (); - #endif //Debug.WriteLine ("======= Layouting queue start ======="); while (Interface.LayoutingQueue.Count > 0) { @@ -311,9 +296,6 @@ namespace Crow lqi.ProcessLayouting (); } - #if MEASURE_TIME - layoutTime.Stop (); - #endif //Debug.WriteLine ("otd:" + gobjsToRedraw.Count.ToString () + "-"); //final redraw clips should be added only when layout is completed among parents, @@ -327,11 +309,6 @@ namespace Crow p.Parent.RegisterClip (p.getSlot()); } - #if MEASURE_TIME - updateTime.Stop (); - drawingTime.Start (); - #endif - using (surf = new ImageSurface (bmp, Format.Argb32, ClientRectangle.Width, ClientRectangle.Height, ClientRectangle.Width * 4)) { using (ctx = new Context (surf)){ @@ -364,36 +341,14 @@ namespace Crow DirtyRect.Left = Math.Max (0, DirtyRect.Left); DirtyRect.Top = Math.Max (0, DirtyRect.Top); - DirtyRect.Width = Math.Min (ClientRectangle.Width - DirtyRect.Left, DirtyRect.Width); - DirtyRect.Height = Math.Min (ClientRectangle.Height - DirtyRect.Top, DirtyRect.Height); + DirtyRect.Width = Math.Min (ClientRectangle.Right, DirtyRect.Width); + DirtyRect.Height = Math.Min (ClientRectangle.Bottom, DirtyRect.Height); clipping.Reset (); } - - #if MEASURE_TIME - drawingTime.Stop (); - #endif - //surf.WriteToPng (@"/mnt/data/test.png"); } } -// if (ToolTip.isVisible) { -// ToolTip.panel.processkLayouting(); -// if (ToolTip.panel.layoutIsValid) -// ToolTip.panel.Paint(ref ctx); -// } -// Debug.WriteLine("INTERFACE: layouting: {0} ticks \t graphical update {1} ticks \t drawing {2} ticks", -// layoutTime.ElapsedTicks, -// guTime.ElapsedTicks, -// drawingTime.ElapsedTicks); -// Debug.WriteLine("INTERFACE: layouting: {0} ms \t graphical update {1} ms \t drawing {2} ms", -// layoutTime.ElapsedMilliseconds, -// guTime.ElapsedMilliseconds, -// drawingTime.ElapsedMilliseconds); - -// Debug.WriteLine("UPDATE: {0} ticks \t, {1} ms", -// updateTime.ElapsedTicks, -// updateTime.ElapsedMilliseconds); - } + } #endregion #region loading diff --git a/Tests/GOLIBTests.cs b/Tests/GOLIBTests.cs index c3622ef4..8c504a7b 100644 --- a/Tests/GOLIBTests.cs +++ b/Tests/GOLIBTests.cs @@ -31,6 +31,10 @@ namespace test : base(800, 600,"test: press spacebar to toogle test files") { //VSync = VSyncMode.Off; + Interface.CurrentInterface = CrowInterface; + GraphicObject obj = CrowInterface.LoadInterface("Interfaces/" + testFiles[idx]); + obj.DataSource = this; + } int frameCpt = 0; @@ -51,14 +55,9 @@ namespace test "0.crow", "testImage.crow", "testOutOfClipUpdate.crow", -<<<<<<< 328c6d4eab1127cd9799540f253deda66060b68a - "testTreeView.crow", - "testWindow.goml", -======= // "test_Listbox.goml", // "testTreeView.crow", "1.crow", ->>>>>>> GtkCrowContainer test, functionnal, keyboard issue "clip4.crow", "clip3.crow", "clip2.crow", @@ -113,11 +112,11 @@ namespace test ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); #if MEASURE_TIME ValueChanged.Raise (this, new ValueChangeEventArgs ("update", - this.updateTime.ElapsedTicks.ToString () + " ticks")); + this.CrowInterface.updateTime.ElapsedTicks.ToString () + " ticks")); ValueChanged.Raise (this, new ValueChangeEventArgs ("layouting", - this.layoutTime.ElapsedTicks.ToString () + " ticks")); + this.CrowInterface.layoutTime.ElapsedTicks.ToString () + " ticks")); ValueChanged.Raise (this, new ValueChangeEventArgs ("drawing", - this.drawingTime.ElapsedTicks.ToString () + " ticks")); + this.CrowInterface.drawingTime.ElapsedTicks.ToString () + " ticks")); #endif } } @@ -191,35 +190,26 @@ namespace test TestList = Color.ColorDic.ToList(); } - protected override void OnLoad (EventArgs e) - { - base.OnLoad (e); - //this.AddWidget(new test4()); - //KeyboardKeyDown += GOLIBTests_KeyboardKeyDown1;; - - GraphicObject obj = LoadInterface("Interfaces/" + testFiles[idx]); - obj.DataSource = this; - } void GOLIBTests_KeyboardKeyDown1 (object sender, OpenTK.Input.KeyboardKeyEventArgs e) { if (e.Key == OpenTK.Input.Key.Escape) { - this.Quit (); + Quit (null, null); return; } else if (e.Key == OpenTK.Input.Key.L) { TestList.Add ("new string"); NotifyValueChanged ("TestList", TestList); return; } else if (e.Key == OpenTK.Input.Key.W) { - GraphicObject w = LoadInterface("Interfaces/testWindow.goml"); + GraphicObject w = CrowInterface.LoadInterface("Interfaces/testWindow.goml"); w.DataSource = this; return; } - ClearInterface (); + CrowInterface.ClearInterface (); idx++; if (idx == testFiles.Length) idx = 0; this.Title = testFiles [idx]; - GraphicObject obj = LoadInterface("Interfaces/" + testFiles[idx]); + GraphicObject obj = CrowInterface.LoadInterface("Interfaces/" + testFiles[idx]); obj.DataSource = this; } @@ -246,7 +236,7 @@ namespace test } void onAddTabButClick(object sender, MouseButtonEventArgs e){ - TabView tv = this.FindByName("tabview1") as TabView; + TabView tv = CrowInterface.FindByName("tabview1") as TabView; if (tv == null) return; tv.AddChild (new TabItem () { Caption = "NewTab" }); @@ -270,13 +260,13 @@ namespace test } void Win_KeyPressEvent (object o, Gtk.KeyPressEventArgs args) { - ClearInterface (); + CrowInterface.ClearInterface (); idx++; if (idx == testFiles.Length) idx = 0; this.Title = testFiles [idx]; - GraphicObject obj = LoadInterface("Interfaces/" + testFiles[idx]); - obj.DataSource = this; + GraphicObject obj = CrowInterface.LoadInterface("Interfaces/" + testFiles[idx]); + obj.DataSource = this; } } } diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 76a38c49..bdfe362e 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -115,7 +115,7 @@ namespace Crow ILayoutable tmp = Target.Instance as ILayoutable; if (string.IsNullOrEmpty (bindingExp [0])) { //if exp start with '/' => Graphic tree parsing start at top container - tmp = tmp.HostContainer as ILayoutable; + tmp = Interface.CurrentInterface as ILayoutable; ptr++; } while (ptr < bindingExp.Length - 1) { diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 9f1bf811..56b50684 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -128,9 +128,7 @@ namespace Crow return cb; } } - [XmlIgnore]public virtual IGOLibHost HostContainer { - get { return Parent == null ? null : Parent.HostContainer; } - } + public virtual Rectangle ContextCoordinates(Rectangle r){ GraphicObject go = Parent as GraphicObject; if (go == null) @@ -374,12 +372,12 @@ namespace Crow _isVisible = value; - if (HostContainer == null) + if (Interface.CurrentInterface == null) return; //ensure main win doesn't keep hidden childrens ref - if (!_isVisible && this.Contains (HostContainer.hoverWidget)) - HostContainer.hoverWidget = null; + if (!_isVisible && this.Contains (Interface.CurrentInterface.hoverWidget)) + Interface.CurrentInterface.hoverWidget = null; if (Parent is GraphicObject) Parent.RegisterForLayouting (LayoutingType.Sizing); @@ -645,9 +643,9 @@ namespace Crow { if (IsQueuedForRedraw) return; - if (HostContainer == null) + if (Interface.CurrentInterface == null) return; - HostContainer.gobjsToRedraw.Add (this); + Interface.CurrentInterface.gobjsToRedraw.Add (this); IsQueuedForRedraw = true; } @@ -957,9 +955,8 @@ namespace Crow } public virtual void checkHoverWidget(MouseMoveEventArgs e) { - IGOLibHost glh = HostContainer; - if (glh.hoverWidget != this) { - glh.hoverWidget = this; + if (Interface.CurrentInterface.hoverWidget != this) { + Interface.CurrentInterface.hoverWidget = this; onMouseEnter (this, e); } @@ -975,14 +972,13 @@ namespace Crow MouseMove.Raise (sender, e); } public virtual void onMouseDown(object sender, MouseButtonEventArgs e){ - IGOLibHost hc = HostContainer; - if (hc.activeWidget == null) - hc.activeWidget = this; + if (Interface.CurrentInterface.activeWidget == null) + Interface.CurrentInterface.activeWidget = this; if (this.Focusable && !Interface.FocusOnHover) { BubblingMouseButtonEventArg be = e as BubblingMouseButtonEventArg; if (be.Focused == null) { be.Focused = this; - hc.FocusedWidget = this; + Interface.CurrentInterface.FocusedWidget = this; } } //bubble event to the top diff --git a/src/GraphicObjects/Group.cs b/src/GraphicObjects/Group.cs index 887d9e22..869ec113 100644 --- a/src/GraphicObjects/Group.cs +++ b/src/GraphicObjects/Group.cs @@ -305,8 +305,8 @@ namespace Crow #region Mouse handling public override void checkHoverWidget (MouseMoveEventArgs e) { - if (HostContainer.hoverWidget != this) { - HostContainer.hoverWidget = this; + if (Interface.CurrentInterface.hoverWidget != this) { + Interface.CurrentInterface.hoverWidget = this; onMouseEnter (this, e); } for (int i = Children.Count - 1; i >= 0; i--) { diff --git a/src/GraphicObjects/ILayoutable.cs b/src/GraphicObjects/ILayoutable.cs index 51abc25d..a8df3ae0 100644 --- a/src/GraphicObjects/ILayoutable.cs +++ b/src/GraphicObjects/ILayoutable.cs @@ -17,8 +17,6 @@ namespace Crow Rectangle getSlot(); Rectangle getBounds(); - IGOLibHost HostContainer { get; } - bool ArrangeChildren { get; } LayoutingType RegisteredLayoutings { get; set; } void RegisterForLayouting(LayoutingType layoutType); diff --git a/src/GraphicObjects/Popper.cs b/src/GraphicObjects/Popper.cs index 4c5ca11c..fdbed62c 100644 --- a/src/GraphicObjects/Popper.cs +++ b/src/GraphicObjects/Popper.cs @@ -174,22 +174,20 @@ namespace Crow public virtual void onPop(object sender, EventArgs e) { - IGOLibHost tc = HostContainer; - if (tc == null) + if (Interface.CurrentInterface == null) return; if (Content != null) { Content.Visible = true; if (Content.Parent == null) - tc.AddWidget (Content); - tc.PutOnTop (Content); + Interface.CurrentInterface.AddWidget (Content); + Interface.CurrentInterface.PutOnTop (Content); _content_LayoutChanged (this, new LayoutingEventArgs (LayoutingType.Sizing)); } Pop.Raise (this, e); } public virtual void onUnpop(object sender, EventArgs e) { - IGOLibHost tc = HostContainer; - if (tc == null) + if (Interface.CurrentInterface == null) return; Content.Visible = false; Unpop.Raise (this, e); diff --git a/src/GraphicObjects/Splitter.cs b/src/GraphicObjects/Splitter.cs index dbda87af..9372f1bc 100644 --- a/src/GraphicObjects/Splitter.cs +++ b/src/GraphicObjects/Splitter.cs @@ -62,14 +62,14 @@ namespace Crow { base.onMouseEnter (sender, e); if ((Parent as GenericStack).Orientation == Orientation.Horizontal) - this.HostContainer.MouseCursor = XCursor.H; + Interface.CurrentInterface.MouseCursor = XCursor.H; else - this.HostContainer.MouseCursor = XCursor.V; + Interface.CurrentInterface.MouseCursor = XCursor.V; } public override void onMouseLeave (object sender, MouseMoveEventArgs e) { base.onMouseLeave (sender, e); - this.HostContainer.MouseCursor = XCursor.Default; + Interface.CurrentInterface.MouseCursor = XCursor.Default; } public override void onMouseMove (object sender, MouseMoveEventArgs e) { diff --git a/src/GraphicObjects/TabView.cs b/src/GraphicObjects/TabView.cs index 7bf827d6..97ac4c64 100644 --- a/src/GraphicObjects/TabView.cs +++ b/src/GraphicObjects/TabView.cs @@ -183,8 +183,8 @@ namespace Crow #region Mouse handling public override void checkHoverWidget (MouseMoveEventArgs e) { - if (HostContainer.hoverWidget != this) { - HostContainer.hoverWidget = this; + if (Interface.CurrentInterface.hoverWidget != this) { + Interface.CurrentInterface.hoverWidget = this; onMouseEnter (this, e); } diff --git a/src/GraphicObjects/Window.cs b/src/GraphicObjects/Window.cs index 617670fc..429d4269 100644 --- a/src/GraphicObjects/Window.cs +++ b/src/GraphicObjects/Window.cs @@ -83,7 +83,7 @@ namespace Crow { base.onMouseMove (sender, e); - IGOLibHost otkgw = HostContainer; + Interface otkgw = Interface.CurrentInterface; if (e.Mouse.IsButtonDown (MouseButton.Left)) { if (!HasFocus) @@ -210,7 +210,7 @@ namespace Crow { base.onMouseLeave (sender, e); currentDirection = Direction.None; - HostContainer.MouseCursor = XCursor.Default; + Interface.CurrentInterface.MouseCursor = XCursor.Default; } protected override void loadTemplate(GraphicObject template = null) @@ -224,7 +224,7 @@ namespace Crow ILayoutable parent = (sender as GraphicObject).Parent; while(!(parent is Window)) parent = parent.Parent; - HostContainer.DeleteWidget (parent as GraphicObject); + Interface.CurrentInterface.DeleteWidget (parent as GraphicObject); } public override void ResolveBindings () diff --git a/src/Interface.cs b/src/Interface.cs index 3dd20a25..352f2a1a 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -30,11 +30,20 @@ using System.Reflection.Emit; using System.CodeDom; using Microsoft.CSharp; using System.CodeDom.Compiler; +using System.Threading; +using Cairo; namespace Crow { - public static class Interface + public class Interface : ILayoutable { + #region CTOR + static Interface(){ + Interface.LoadCursors (); + } + #endregion + + #region Static and constants /// Used to prevent spurious loading of templates internal static bool XmlSerializerInit = false; /// keep ressource path for debug msg @@ -55,10 +64,13 @@ namespace Crow public static int BorderThreshold = 5; public const int MaxCacheSize = 2048; public const int MaxLayoutingTries = 50; + #endregion public static Queue LayoutingQueue = new Queue(); + #region default values loading helpers public delegate void loadDefaultInvoker(object instance); public static Dictionary DefaultValuesLoader = new Dictionary(); + #endregion public static void LoadCursors(){ //Load cursors @@ -73,19 +85,6 @@ namespace Crow } #region Load/Save - - public static void Save (string file, T graphicObject) - { - XmlSerializerNamespaces xn = new XmlSerializerNamespaces (); - xn.Add ("", ""); - XmlSerializer xs = new XmlSerializer (typeof(T)); - - xs = new XmlSerializer (typeof(T)); - using (Stream s = new FileStream (file, FileMode.Create)) { - xs.Serialize (s, graphicObject, xn); - } - } - public static Stream GetStreamFromPath (string path) { Stream stream = null; @@ -132,7 +131,17 @@ namespace Crow return t; } + public static void Save (string file, T graphicObject) + { + XmlSerializerNamespaces xn = new XmlSerializerNamespaces (); + xn.Add ("", ""); + XmlSerializer xs = new XmlSerializer (typeof(T)); + xs = new XmlSerializer (typeof(T)); + using (Stream s = new FileStream (file, FileMode.Create)) { + xs.Serialize (s, graphicObject, xn); + } + } public static GraphicObject Load (string path, object hostClass = null) { Interface.XmlLoaderCount ++; @@ -144,9 +153,6 @@ namespace Crow Interface.XmlLoaderCount --; return tmp; } - - - public static GraphicObject Load (Stream stream, Type type, object hostClass = null) { #if DEBUG_LOAD @@ -181,7 +187,438 @@ namespace Crow return result; } + public GraphicObject LoadInterface (string path) + { + GraphicObject tmp = Interface.Load (path, this); + AddWidget (tmp); + return tmp; + } + + #endregion + + #if MEASURE_TIME + public Stopwatch updateTime = new Stopwatch (); + public Stopwatch layoutTime = new Stopwatch (); + public Stopwatch guTime = new Stopwatch (); + public Stopwatch drawingTime = new Stopwatch (); + #endif + + public List GraphicObjects = new List(); + public Color Background = Color.Transparent; + + internal static Interface currentWindow; + public static Interface CurrentInterface; + + Rectangles _redrawClip = new Rectangles();//should find another way to access it from child + List _gobjsToRedraw = new List(); + + Context ctx; + Surface surf; + public byte[] bmp; + public bool IsDirty = false; + public Rectangle DirtyRect; + + #region focus + GraphicObject _activeWidget; //button is pressed on widget + GraphicObject _hoverWidget; //mouse is over + GraphicObject _focusedWidget; //has keyboard (or other perif) focus + + public GraphicObject activeWidget + { + get { return _activeWidget; } + set + { + if (_activeWidget == value) + return; + + if (_activeWidget != null) + _activeWidget.IsActive = false; + + _activeWidget = value; + + if (_activeWidget != null) + _activeWidget.IsActive = true; + } + } + public GraphicObject hoverWidget + { + get { return _hoverWidget; } + set { + if (_hoverWidget == value) + return; + _hoverWidget = value; + } + } + public GraphicObject FocusedWidget { + get { return _focusedWidget; } + set { + if (_focusedWidget == value) + return; + if (_focusedWidget != null) + _focusedWidget.onUnfocused (this, null); + _focusedWidget = value; + if (_focusedWidget != null) + _focusedWidget.onFocused (this, null); + } + } + #endregion + + + public void Update(){ + if (mouseRepeatCount > 0) { + int mc = mouseRepeatCount; + mouseRepeatCount -= mc; + for (int i = 0; i < mc; i++) { + FocusedWidget.onMouseClick (this, new MouseButtonEventArgs (Mouse.X, Mouse.Y, MouseButton.Left, true)); + } + } + #if MEASURE_TIME + layoutTime.Reset (); + guTime.Reset (); + drawingTime.Reset (); + updateTime.Restart (); + #endif + + GraphicObject[] invGOList = new GraphicObject[GraphicObjects.Count]; + GraphicObjects.CopyTo (invGOList, 0); + invGOList = invGOList.Reverse ().ToArray (); + + #if MEASURE_TIME + layoutTime.Start (); + #endif + //Debug.WriteLine ("======= Layouting queue start ======="); + + while (Interface.LayoutingQueue.Count > 0) { + LayoutingQueueItem lqi = Interface.LayoutingQueue.Dequeue (); + lqi.ProcessLayouting (); + } + + #if MEASURE_TIME + layoutTime.Stop (); + #endif + + //Debug.WriteLine ("otd:" + gobjsToRedraw.Count.ToString () + "-"); + //final redraw clips should be added only when layout is completed among parents, + //that's why it take place in a second pass + GraphicObject[] gotr = new GraphicObject[gobjsToRedraw.Count]; + gobjsToRedraw.CopyTo (gotr); + gobjsToRedraw.Clear (); + foreach (GraphicObject p in gotr) { + p.IsQueuedForRedraw = false; + p.Parent.RegisterClip (p.LastPaintedSlot); + p.Parent.RegisterClip (p.getSlot()); + } + + #if MEASURE_TIME + updateTime.Stop (); + drawingTime.Start (); + #endif + + using (surf = new ImageSurface (bmp, Format.Argb32, ClientRectangle.Width, ClientRectangle.Height, ClientRectangle.Width * 4)) { + using (ctx = new Context (surf)){ + + + if (clipping.count > 0) { + //Link.draw (ctx); + clipping.clearAndClip(ctx); + + foreach (GraphicObject p in invGOList) { + if (!p.Visible) + continue; + if (!clipping.intersect (p.Slot)) + continue; + ctx.Save (); + + p.Paint (ref ctx); + + ctx.Restore (); + } + + #if DEBUG_CLIP_RECTANGLE + clipping.stroke (ctx, Color.Red.AdjustAlpha(0.5)); + #endif + + if (IsDirty) + DirtyRect += clipping.Bounds; + else + DirtyRect = clipping.Bounds; + IsDirty = true; + + DirtyRect.Left = Math.Max (0, DirtyRect.Left); + DirtyRect.Top = Math.Max (0, DirtyRect.Top); + DirtyRect.Width = Math.Min (ClientRectangle.Width - DirtyRect.Left, DirtyRect.Width); + DirtyRect.Height = Math.Min (ClientRectangle.Height - DirtyRect.Top, DirtyRect.Height); + + clipping.Reset (); + } + + #if MEASURE_TIME + drawingTime.Stop (); + #endif + //surf.WriteToPng (@"/mnt/data/test.png"); + } + } + // if (ToolTip.isVisible) { + // ToolTip.panel.processkLayouting(); + // if (ToolTip.panel.layoutIsValid) + // ToolTip.panel.Paint(ref ctx); + // } + // Debug.WriteLine("INTERFACE: layouting: {0} ticks \t graphical update {1} ticks \t drawing {2} ticks", + // layoutTime.ElapsedTicks, + // guTime.ElapsedTicks, + // drawingTime.ElapsedTicks); + // Debug.WriteLine("INTERFACE: layouting: {0} ms \t graphical update {1} ms \t drawing {2} ms", + // layoutTime.ElapsedMilliseconds, + // guTime.ElapsedMilliseconds, + // drawingTime.ElapsedMilliseconds); + + // Debug.WriteLine("UPDATE: {0} ticks \t, {1} ms", + // updateTime.ElapsedTicks, + // updateTime.ElapsedMilliseconds); + } + public Rectangles clipping { + get { return _redrawClip; } + set { _redrawClip = value; } + } + public List gobjsToRedraw { + get { return _gobjsToRedraw; } + set { _gobjsToRedraw = value; } + } + public void AddWidget(GraphicObject g) + { + g.Parent = this; + GraphicObjects.Insert (0, g); + + g.RegisterForLayouting (LayoutingType.Sizing); + } + public void DeleteWidget(GraphicObject g) + { + g.Visible = false;//trick to ensure clip is added to refresh zone + g.ClearBinding(); + GraphicObjects.Remove (g); + } + public void PutOnTop(GraphicObject g) + { + if (GraphicObjects.IndexOf(g) > 0) + { + GraphicObjects.Remove(g); + GraphicObjects.Insert(0, g); + //g.registerClipRect (); + } + } + /// Remove all Graphic objects from top container + public void ClearInterface() + { + int i = 0; + while (GraphicObjects.Count>0) { + //TODO:parent is not reset to null because object will be added + //to ObjectToRedraw list, and without parent, it fails + GraphicObject g = GraphicObjects [i]; + g.Visible = false; + g.ClearBinding (); + GraphicObjects.RemoveAt (0); + } + } + public GraphicObject FindByName (string nameToFind) + { + foreach (GraphicObject w in GraphicObjects) { + GraphicObject r = w.FindByName (nameToFind); + if (r != null) + return r; + } + return null; + } + public void ProcessResize(Rectangle bounds){ + clientRectangle = bounds; + + int stride = 4 * ClientRectangle.Width; + int bmpSize = Math.Abs (stride) * ClientRectangle.Height; + bmp = new byte[bmpSize]; + + foreach (GraphicObject g in GraphicObjects) + g.RegisterForLayouting (LayoutingType.All); + } + + XCursor cursor = XCursor.Default; + public MouseState Mouse; + public KeyboardState Keyboard; + Rectangle clientRectangle; + + public event EventHandler MouseCursorChanged; + public event EventHandler Quit; + + #region Mouse Handling + + public XCursor MouseCursor { + set { + if (value == cursor) + return; + cursor = value; + MouseCursorChanged.Raise (this,new MouseCursorChangedEventArgs(value)); + } + } + public bool ProcessMouseMove(int x, int y) + { + int deltaX = x - Mouse.X; + int deltaY = y - Mouse.Y; + Mouse.X = x; + Mouse.Y = y; + MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY); + e.Mouse = Mouse; + + if (_activeWidget != null) { + //TODO, ensure object is still in the graphic tree + //send move evt even if mouse move outside bounds + _activeWidget.onMouseMove (this, e); + return true; + } + + if (hoverWidget != null) { + //TODO, ensure object is still in the graphic tree + //check topmost graphicobject first + GraphicObject tmp = hoverWidget; + GraphicObject topc = null; + while (tmp is GraphicObject) { + topc = tmp; + tmp = tmp.Parent as GraphicObject; + } + int idxhw = GraphicObjects.IndexOf (topc); + if (idxhw != 0) { + int i = 0; + while (i < idxhw) { + if (GraphicObjects [i].MouseIsIn (e.Position)) { + hoverWidget.onMouseLeave (this, e); + GraphicObjects [i].checkHoverWidget (e); + return true; + } + i++; + } + } + + + if (hoverWidget.MouseIsIn (e.Position)) { + hoverWidget.checkHoverWidget (e); + return true; + } else { + hoverWidget.onMouseLeave (this, e); + //seek upward from last focused graph obj's + while (hoverWidget.Parent as GraphicObject != null) { + hoverWidget = hoverWidget.Parent as GraphicObject; + if (hoverWidget.MouseIsIn (e.Position)) { + hoverWidget.checkHoverWidget (e); + return true; + } else + hoverWidget.onMouseLeave (this, e); + } + } + } + + //top level graphic obj's parsing + for (int i = 0; i < GraphicObjects.Count; i++) { + GraphicObject g = GraphicObjects[i]; + if (g.MouseIsIn (e.Position)) { + g.checkHoverWidget (e); + PutOnTop (g); + return true; + } + } + hoverWidget = null; + return false; + } + public bool ProcessMouseButtonUp(int button) + { + Mouse.DisableBit (button); + MouseButtonEventArgs e = new MouseButtonEventArgs () { Mouse = Mouse }; + + if (_activeWidget == null) + return false; + + if (mouseRepeatThread != null) { + mouseRepeatOn = false; + mouseRepeatThread.Abort(); + mouseRepeatThread.Join (); + } + + _activeWidget.onMouseUp (this, e); + activeWidget = null; + return true; + } + public bool ProcessMouseButtonDown(int button) + { + Mouse.EnableBit (button); + MouseButtonEventArgs e = new MouseButtonEventArgs () { Mouse = Mouse }; + + if (hoverWidget == null) + return false; + + hoverWidget.onMouseDown(hoverWidget,new BubblingMouseButtonEventArg(e)); + + if (FocusedWidget == null) + return true; + if (!FocusedWidget.MouseRepeat) + return true; + mouseRepeatThread = new Thread (mouseRepeatThreadFunc); + mouseRepeatThread.Start (); + return true; + } +// public bool ProcessMouseWheelChanged(int delta) +// { +// if (hoverWidget == null) +// return false; +// hoverWidget.onMouseWheel (this, e); +// return true; +// } + + volatile bool mouseRepeatOn; + volatile int mouseRepeatCount; + Thread mouseRepeatThread; + void mouseRepeatThreadFunc() + { + mouseRepeatOn = true; + Thread.Sleep (Interface.DeviceRepeatDelay); + while (mouseRepeatOn) { + mouseRepeatCount++; + Thread.Sleep (Interface.DeviceRepeatInterval); + } + mouseRepeatCount = 0; + } + #endregion + #region ILayoutable implementation + public void RegisterClip(Rectangle r){ + clipping.AddRectangle (r); + } + public bool ArrangeChildren { get { return false; }} + public int LayoutingTries { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + public LayoutingType RegisteredLayoutings { + get { return LayoutingType.None; } + set { throw new NotImplementedException (); } + } + public void RegisterForLayouting (LayoutingType layoutType) { throw new NotImplementedException (); } + public bool UpdateLayout (LayoutingType layoutType) { throw new NotImplementedException (); } + public Rectangle ContextCoordinates (Rectangle r) => r; + public Rectangle ScreenCoordinates (Rectangle r) => r; + + public ILayoutable Parent { + get { return null; } + set { throw new NotImplementedException (); } + } + public ILayoutable LogicalParent { + get { return null; } + set { throw new NotImplementedException (); } + } + + public Rectangle ClientRectangle { + get { return clientRectangle; } + } + public Interface HostContainer { + get { return this; } + } + public Rectangle getSlot () => ClientRectangle; + public Rectangle getBounds () => ClientRectangle; #endregion } } diff --git a/src/MouseCursorChangedEventArgs.cs b/src/MouseCursorChangedEventArgs.cs new file mode 100644 index 00000000..b39d4a57 --- /dev/null +++ b/src/MouseCursorChangedEventArgs.cs @@ -0,0 +1,33 @@ +// +// MouseCursorChangedEventArg.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2016 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; + +namespace Crow +{ + public class MouseCursorChangedEventArgs : EventArgs + { + public XCursor NewCursor; + public MouseCursorChangedEventArgs (XCursor NewCursor) : base() + { + NewCursor = NewCursor; + } + } +} -- 2.47.3