From 8faa417da2f804c61df957fd36e4db7c9b1fede6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Thu, 1 Feb 2018 07:26:35 +0100 Subject: [PATCH] :book: --- Tests/HelloWorld.cs | 14 +-- src/GraphicObjects/GraphicObject.cs | 134 ++++++++++++++++++++++++++-- src/Instantiator.cs | 31 ++++++- src/Interface.cs | 73 ++++++++++++--- 4 files changed, 216 insertions(+), 36 deletions(-) diff --git a/Tests/HelloWorld.cs b/Tests/HelloWorld.cs index ea37a142..b29bfac5 100644 --- a/Tests/HelloWorld.cs +++ b/Tests/HelloWorld.cs @@ -39,19 +39,7 @@ namespace Tests protected override void OnLoad (EventArgs e) { base.OnLoad (e); - - Container c = (Container) Instantiator.CreateFromImlFragment (@"").CreateInstance (CurrentInterface); - GraphicObject obj = new GraphicObject (this.CurrentInterface) - { - Background = Color.AirForceBlueRaf, - Margin = 10, - Width = 100, - Height = 100 - }; - c.SetChild (obj); - AddWidget (c); - - //Load(@"Interfaces/GraphicObject/2.crow"); + AddWidget (new Label (CurrentInterface) { Text = "Hello World" }); } [STAThread] diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 954c08e7..feea7520 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -38,6 +38,9 @@ using System.IO; namespace Crow { + /// + /// This is the base class for all the graphic trees elements + /// public class GraphicObject : ILayoutable, IValueChange, IDisposable { #region IDisposable implementation @@ -91,12 +94,29 @@ namespace Crow internal static ulong currentUid = 0; internal ulong uid = 0; + /// + /// interface this widget is bound to, this should not be changed once the instance is created + /// public Interface CurrentInterface = null; + /// + /// contains the dirty rectangles in the coordinate system of the cache. those dirty zones + /// are repeated at each cached levels of the tree with correspondig coordinate system. This is done + /// in a dedicated step of the update between layouting and drawing. + /// public Region Clipping; #region IValueChange implementation + /// + /// Raise to notify that the value of a property has changed, the binding system + /// rely mainly on this event. the member name may not be present in the class, this is + /// used in **propertyless** bindings, this allow to raise custom named events without needing + /// to create an new one in the class or a new property. + /// public event EventHandler ValueChanged; + /// + /// Helper function to raise the value changed event + /// public virtual void NotifyValueChanged(string MemberName, object _value) { //Debug.WriteLine ("Value changed: {0}->{1} = {2}", this, MemberName, _value); @@ -106,7 +126,9 @@ namespace Crow #region CTOR /// - /// default private parameter less constructor use in instantiators + /// default private parameter less constructor use in instantiators, it should not be used + /// when creating widget from code because widgets has to be bound to an interface before any other + /// action. /// protected GraphicObject () { Clipping = new Region (); @@ -115,6 +137,16 @@ namespace Crow currentUid++; #endif } + /// + /// This constructor **must** be used when creating widget from code. + /// + /// When creating new widgets derived from GraphicObject, both parameterless and this constructors are + /// facultatives, the compiler will create the parameterless one automaticaly if no other one exists. + /// But if you intend to be able to create instances of the new widget in code and override the constructor + /// with the Interface parameter, you **must** also provide the override of the parameterless constructor because + /// compiler will not create it automatically because of the presence of the other one. + /// + /// Iface. public GraphicObject (Interface iface) : this() { CurrentInterface = iface; @@ -126,8 +158,6 @@ namespace Crow /// Initialize this Graphic object instance by setting style and default values and loading template if required /// public virtual void Initialize(){ -// if (CurrentInterface == null) -// CurrentInterface = Interface.CurrentInterface; loadDefaultValues (); initialized = true; } @@ -248,24 +278,43 @@ namespace Crow #endregion #region EVENT HANDLERS + /// Occurs when mouse wheel is rolled in this object. It bubbles to the root public event EventHandler MouseWheelChanged; + /// Occurs when mouse button is released in this object. It bubbles to the root public event EventHandler MouseUp; + /// Occurs when mouse button is pressed in this object. It bubbles to the root public event EventHandler MouseDown; + /// Occurs when mouse button has been pressed then relesed in this object. It bubbles to the root public event EventHandler MouseClick; + /// Occurs when mouse button has been pressed then relesed 2 times in this object. It bubbles to the root public event EventHandler MouseDoubleClick; + /// Occurs when mouse mouve in this object. It bubbles to the root public event EventHandler MouseMove; + /// Occurs when mouse enter this object public event EventHandler MouseEnter; + /// Occurs when mouse leave this object public event EventHandler MouseLeave; + /// Occurs when key is pressed when this object is active public event EventHandler KeyDown; + /// Occurs when key is released when this object is active public event EventHandler KeyUp; + /// Occurs when translated key event occurs in the host when this object is active public event EventHandler KeyPress; + /// Occurs when this object received focus public event EventHandler Focused; + /// Occurs when this object loose focus public event EventHandler Unfocused; + /// Occurs when the enabled state this object is set to true public event EventHandler Enabled; + /// Occurs when the enabled state this object is set to false public event EventHandler Disabled; + /// Occurs when one part of the rendering slot changed public event EventHandler LayoutChanged; + /// Occurs when DataSource changed public event EventHandler DataSourceChanged; + /// Occurs when the parent has changed public event EventHandler ParentChanged; + /// Occurs when the logical parent has changed public event EventHandler LogicalParentChanged; #endregion @@ -282,7 +331,7 @@ namespace Crow } } /// - /// If enabled, resulting bitmap of graphic object is cached in an byte array + /// If enabled, resulting bitmap of graphic object is cached /// speeding up rendering of complex object. Default is enabled. /// [XmlAttributeAttribute][DefaultValue(true)] @@ -311,6 +360,8 @@ namespace Crow } /// /// Name is used in binding to reference other GraphicObjects inside the graphic tree + /// and by template controls to find special element in their template implementation such + /// as a container or a group to put children in. /// [XmlAttributeAttribute][DefaultValue(null)] public virtual string Name { @@ -328,6 +379,10 @@ namespace Crow NotifyValueChanged("Name", name); } } + /// + /// Vertical alignment inside parent, disabled if height is stretched + /// or top coordinate is not null + /// [XmlAttributeAttribute ()][DefaultValue(VerticalAlignment.Center)] public virtual VerticalAlignment VerticalAlignment { get { return verticalAlignment; } @@ -340,6 +395,10 @@ namespace Crow RegisterForLayouting (LayoutingType.Y); } } + /// + /// Horizontal alignment inside parent, disabled if width is stretched + /// or left coordinate is not null + /// [XmlAttributeAttribute()][DefaultValue(HorizontalAlignment.Center)] public virtual HorizontalAlignment HorizontalAlignment { get { return horizontalAlignment; } @@ -351,6 +410,9 @@ namespace Crow RegisterForLayouting (LayoutingType.X); } } + /// + /// x position inside parent + /// [XmlAttributeAttribute()][DefaultValue(0)] public virtual int Left { get { return left; } @@ -362,6 +424,9 @@ namespace Crow this.RegisterForLayouting (LayoutingType.X); } } + /// + /// y position inside parent + /// [XmlAttributeAttribute()][DefaultValue(0)] public virtual int Top { get { return top; } @@ -374,7 +439,7 @@ namespace Crow } } /// - /// When set to True, the 's width and height will be set to Fit. + /// Helper property used to set width and height to fit in one call /// [XmlAttributeAttribute()][DefaultValue(false)] public virtual bool Fit { @@ -386,6 +451,10 @@ namespace Crow Width = Height = Measure.Fit; } } + /// + /// Width of this control, by default inherited from parent. May have special values + /// such as Stretched or Fit. It may be proportionnal or absolute. + /// [XmlAttributeAttribute()][DefaultValue("Inherit")] public virtual Measure Width { get { @@ -422,6 +491,10 @@ namespace Crow this.RegisterForLayouting (LayoutingType.Width); } } + /// + /// Height of this control, by default inherited from parent. May have special values + /// such as Stretched or Fit. It may be proportionnal or absolute. + /// [XmlAttributeAttribute()][DefaultValue("Inherit")] public virtual Measure Height { get { @@ -456,16 +529,20 @@ namespace Crow } /// /// Used for binding on dimensions, this property will never hold fixed size, but instead only - /// Fit or Stretched + /// Fit or Stretched, **with inherited state implementation, it is not longer used in binding** /// [XmlIgnore]public virtual Measure WidthPolicy { get { return Width.IsFit ? Measure.Fit : Measure.Stretched; } } /// /// Used for binding on dimensions, this property will never hold fixed size, but instead only - /// Fit or Stretched + /// Fit or Stretched, **with inherited state implementation, it is not longer used in binding** /// [XmlIgnore]public virtual Measure HeightPolicy { get { return Height.IsFit ? Measure.Fit : Measure.Stretched; } } + /// + /// Indicate that this object may received focus or not, if not focusable all the descendants are + /// affected. + /// [XmlAttributeAttribute()][DefaultValue(false)] public virtual bool Focusable { get { return focusable; } @@ -476,6 +553,9 @@ namespace Crow NotifyValueChanged ("Focusable", focusable); } } + /// + /// True when this control has the focus, only one control per interface may have it. + /// [XmlIgnore]public virtual bool HasFocus { get { return hasFocus; } set { @@ -490,6 +570,10 @@ namespace Crow NotifyValueChanged ("HasFocus", hasFocus); } } + /// + /// true if this control is active, this means that mouse has been pressed in it and not yet released. It could + /// be used for other two states periferic action. + /// [XmlIgnore]public virtual bool IsActive { get { return isActive; } set { @@ -500,6 +584,9 @@ namespace Crow NotifyValueChanged ("IsActive", isActive); } } + /// + /// true if holding mouse button down should trigger multiple click events + /// [XmlAttributeAttribute()][DefaultValue(false)] public virtual bool MouseRepeat { get { return mouseRepeat; } @@ -511,6 +598,9 @@ namespace Crow } } bool clearBackground = false; + /// + /// background fill of the control, maybe solid color, gradient, image, or svg + /// [XmlAttributeAttribute()][DefaultValue("Transparent")] public virtual Fill Background { get { return background; } @@ -529,6 +619,9 @@ namespace Crow } } } + /// + /// Foreground fill of the control, usage may be different among derived controls + /// [XmlAttributeAttribute()][DefaultValue("White")] public virtual Fill Foreground { get { return foreground; } @@ -540,6 +633,9 @@ namespace Crow RegisterForRedraw (); } } + /// + /// Font being used in many controls, it is defined in the base GraphicObject class. + /// [XmlAttributeAttribute()][DefaultValue("sans,10")] public virtual Font Font { get { return font; } @@ -551,6 +647,9 @@ namespace Crow RegisterForGraphicUpdate (); } } + /// + /// to get rounded corners + /// [XmlAttributeAttribute()][DefaultValue(0.0)] public virtual double CornerRadius { get { return cornerRadius; } @@ -562,6 +661,10 @@ namespace Crow RegisterForRedraw (); } } + /// + /// This is a single integer for the 4 direction, a gap between the control and it's container, + /// by default it is filled with the background. + /// [XmlAttributeAttribute()][DefaultValue(0)] public virtual int Margin { get { return margin; } @@ -573,6 +676,9 @@ namespace Crow RegisterForGraphicUpdate (); } } + /// + /// set the visible state of the control, invisible controls does reserve space in the layouting system. + /// [XmlAttributeAttribute][DefaultValue(true)] public virtual bool Visible { get { return isVisible; } @@ -590,6 +696,10 @@ namespace Crow NotifyValueChanged ("Visible", isVisible); } } + /// + /// get or set the enabled state, disabling a control will affect focuability and + /// also it's rendering which will be grayed + /// [XmlAttributeAttribute][DefaultValue(true)] public virtual bool IsEnabled { get { return isEnabled; } @@ -608,6 +718,9 @@ namespace Crow RegisterForRedraw (); } } + /// + /// Minimal width and height for this control + /// [XmlAttributeAttribute()][DefaultValue("1,1")] public virtual Size MinimumSize { get { return minimumSize; } @@ -621,6 +734,9 @@ namespace Crow RegisterForLayouting (LayoutingType.Sizing); } } + /// + /// Maximum width and height for this control, unlimited if null. + /// [XmlAttributeAttribute()][DefaultValue("0,0")] public virtual Size MaximumSize { get { return maximumSize; } @@ -672,7 +788,9 @@ namespace Crow Debug.WriteLine("New DataSource for => {0} \n\t{1}=>{2}", this.ToString(),e.OldDataSource,e.NewDataSource); #endif } - + /// + /// Style key to use for this control + /// [XmlAttributeAttribute] public virtual string Style { get { return style; } diff --git a/src/Instantiator.cs b/src/Instantiator.cs index 42c5de96..ed3a4f07 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -43,10 +43,14 @@ namespace Crow /// /// Reflexion being very slow, the settings of the starting values for widgets are set by a dynamic method. /// This method is created on the first instacing and is recalled for further widget instancing. - /// It include + /// + /// It includes: /// - XML values setting /// - Default values (appearing as attribute in C#) loading - /// - Stiling + /// - Styling + /// + /// Instantiators are shared amongs interfaces. Their are stored with their path as key, and inlined template + /// and itemtemplate are stored with a generated uuid /// public class Instantiator { @@ -63,9 +67,15 @@ namespace Crow internal string sourcePath; #region CTOR + /// + /// Initializes a new instance of the Instantiator class. + /// public Instantiator (string path) : this (Interface.GetStreamFromPath(path)) { sourcePath = path; } + /// + /// Initializes a new instance of the Instantiator class. + /// public Instantiator (Stream stream) { #if DEBUG_LOAD @@ -81,11 +91,17 @@ namespace Crow loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath); #endif } + //TODO:check if still used public Instantiator (Type _root, InstanciatorInvoker _loader) { RootType = _root; loader = _loader; } + /// + /// Create a new instantiator from IML fragment provided directely as a string + /// + /// A new instantiator + /// IML string public static Instantiator CreateFromImlFragment (string fragment) { try { @@ -98,13 +114,22 @@ namespace Crow } #endregion + /// + /// Creates a new instance of the GraphicObject compiled in the instantiator + /// and bind it the an interface + /// + /// The new graphic object instance + /// The interface to bind to public GraphicObject CreateInstance(Interface iface){ return loader (iface) as GraphicObject; } List dsValueChangedDynMeths = new List(); List cachedDelegates = new List(); - List templateCachedDelegateIndices = new List();//store indices of template delegate to be handled by root parentChanged event + /// + /// store indices of template delegate to be handled by root parentChanged event + /// + List templateCachedDelegateIndices = new List(); Delegate templateBinding; #region IML parsing diff --git a/src/Interface.cs b/src/Interface.cs index 188c4a39..7d691152 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -39,15 +39,27 @@ using System.Globalization; namespace Crow { /// - /// The Interface Class is the top container of the application. - /// It provides the Dirty bitmap and zone of the interface to be drawn on screen + /// The Interface Class is the root of crow graphic trees. It is thread safe allowing + /// application to run multiple interfaces in different threads. + /// It provides the Dirty bitmap and zone of the interface to be drawn on screen. /// /// The Interface contains : /// - rendering and layouting queues and logic. - /// - helpers to load XML interfaces files - /// - global constants and variables of CROW + /// - helpers to load XML interfaces files directely bound to this interface + /// - global static constants and variables of CROW /// - Keyboard and Mouse logic /// - the resulting bitmap of the interface + /// + /// the master branch and the nuget package includes an OpenTK renderer which allows + /// the creation of multiple threaded interfaces. + /// + /// If you intend to create another renderer (GDK, vulkan, etc) the minimal step is to + /// put an interface instance as member of your root object and call (optionally in another thread) the update function + /// at regular interval. Then you have to call + /// mouse, keyboard and resize functions of the interface when those events occurs in the host app. + /// + /// The resulting surface (a byte array in the OpenTK renderer) is made available and protected with the + /// RenderMutex of the interface. /// public class Interface : ILayoutable { @@ -305,13 +317,15 @@ namespace Crow throw new Exception ("Error loading <" + path + ">:", ex); } } - /// Fetch it from cache or create it + /// Fetch instantiator it from cache or create it public static Instantiator GetInstantiator(string path){ if (!Instantiators.ContainsKey(path)) Instantiators [path] = new Instantiator(path); return Instantiators [path]; } - /// Item templates have additional properties for recursivity and + /// Item templates are derived from instantiator, this function + /// try to fetch the requested one in the cache or create it. + /// They have additional properties for recursivity and /// custom display per item type public static ItemTemplate GetItemTemplate(string path){ if (!Instantiators.ContainsKey(path)) @@ -395,12 +409,11 @@ namespace Crow } #endregion - #region UPDATE Loops /// Enqueue Graphic object for Repaint, DrawingQueue is locked because /// GraphObj's property Set methods could trigger an update from another thread - /// Once in that queue, the layouting of obj and childs is ok, the next step - /// when dequeued is clipping registration + /// Once in that queue, that means that the layouting of obj and childs have succeed, + /// the next step when dequeued will be clipping registration public void EnqueueForRepaint(GraphicObject g) { #if DEBUG_UPDATE @@ -413,7 +426,7 @@ namespace Crow g.IsQueueForRedraw = true; } } - /// Main Update loop, executed in this interface thread, lock the UpdateMutex + /// Main Update loop, executed in this interface thread, protected by the UpdateMutex /// Steps: /// - execute device Repeat events /// - Layouting @@ -686,6 +699,11 @@ namespace Crow } #endregion + /// + /// Resize the interface. This function should be called by the host + /// when window resize event occurs. + /// + /// bounding box of the interface public void ProcessResize(Rectangle bounds){ lock (UpdateMutex) { clientRectangle = bounds; @@ -715,8 +733,9 @@ namespace Crow MouseCursorChanged.Raise (this,new MouseCursorChangedEventArgs(cursor)); } } - /// Processes mouse move events from the root container - /// trueif mouse is in the interface + /// Processes mouse move events from the root container, this function + /// should be called by the host on mouse move event to forward events to crow interfaces + /// true if mouse is in the interface public bool ProcessMouseMove(int x, int y) { int deltaX = x - Mouse.X; @@ -792,6 +811,11 @@ namespace Crow HoverWidget = null; return false; } + /// + /// Forward the mouse up event from the host to the crow interface + /// + /// return true, if interface handled the event, false otherwise. + /// Button index public bool ProcessMouseButtonUp(int button) { Mouse.DisableBit (button); @@ -810,6 +834,11 @@ namespace Crow ActiveWidget = null; return true; } + /// + /// Forward the mouse down event from the host to the crow interface + /// + /// return true, if interface handled the event, false otherwise. + /// Button index public bool ProcessMouseButtonDown(int button) { Mouse.EnableBit (button); @@ -829,6 +858,11 @@ namespace Crow mouseRepeatThread.Start (); return true; } + /// + /// Forward the mouse wheel event from the host to the crow interface + /// + /// return true, if interface handled the event, false otherwise. + /// Button index public bool ProcessMouseWheelChanged(float delta) { Mouse.SetScrollRelative (0, delta); @@ -839,6 +873,11 @@ namespace Crow HoverWidget.onMouseWheel (this, e); return true; } + /// + /// Forward key down event from the host to the crow interface + /// + /// return true, if interface handled the event, false otherwise. + /// Button index public bool ProcessKeyDown(int Key){ Keyboard.SetKeyState((Crow.Key)Key,true); if (_focusedWidget == null) @@ -853,6 +892,11 @@ namespace Crow return true; } + /// + /// Forward key up event from the host to the crow interface + /// + /// return true, if interface handled the event, false otherwise. + /// Button index public bool ProcessKeyUp(int Key){ Keyboard.SetKeyState((Crow.Key)Key,false); if (_focusedWidget == null) @@ -868,6 +912,11 @@ namespace Crow } return true; } + /// + /// Forward a translated key press event from the host to the crow interface + /// + /// return true, if interface handled the event, false otherwise. + /// Button index public bool ProcessKeyPress(char Key){ if (_focusedWidget == null) return false; -- 2.47.3