From: Jean-Philippe Bruyère Date: Mon, 5 Feb 2018 19:51:26 +0000 (+0100) Subject: :book:, ItemTemplate files handling with multime root, Content made mandatory in... X-Git-Tag: v0.9.5-beta~185 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=6a52a7126e74e1f1b26beb46b89ce6b03dafad2a;p=jp%2Fcrow.git :book:, ItemTemplate files handling with multime root, Content made mandatory in TemplatedContainer --- diff --git a/Crow.Test/Crow.Test.csproj b/Crow.Test/Crow.Test.csproj index 94ec07b8..fe1bbca7 100644 --- a/Crow.Test/Crow.Test.csproj +++ b/Crow.Test/Crow.Test.csproj @@ -10,6 +10,7 @@ Crow.Test Crow.Test v4.6.1 + 0.5 true diff --git a/Crow.csproj b/Crow.csproj index b58634db..e6cf6864 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -370,6 +370,7 @@ Crow.DockingView.template + diff --git a/README.md b/README.md index 17ecb240..cfd9cde4 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@

+## Presentation **C.R.O.W.** is a [widget toolkit](https://en.wikipedia.org/wiki/Widget_toolkit) and rendering engine entirely developed in **C#**, offering a nice trade-off between complexity of language and performances. Crow provides a declarative interface language @@ -36,16 +37,25 @@ for easy c# code linking.

-For **documentation** and **tutorials** visit the [Wiki](https://github.com/jpbruyere/Crow/wiki) -or the [Project Site](https://jpbruyere.github.io/Crow/). +#### Features +- [Declarative interface definition](interface-markup-language). +- [Templates](Templates) +- [Styling](Styling) +- [Dynamic binding system](The-binding-system) +- SVG rendering (with [rsvg library](https://developer.gnome.org/rsvg/)) + +#### Documentation +* [Introduction](Global-architecture) +* [Classes documentation autogenerated from doxygen](index) +* [Tutorials](Tutorials) Please report bugs and issues on [GitHub](https://github.com/jpbruyere/Crow/issues) ## Getting Start ### Requirements -- [mono > 5.0](http://www.mono-project.com/download/) -- [Cairo Graphic Library](https://cairographics.org/) >= 1.10 +- [mono >= 5.0](http://www.mono-project.com/download/) +- [Cairo Graphic Library](https://cairographics.org/) >= 1.20 - [rsvg library](https://developer.gnome.org/rsvg/) for svg rendering - [nuget](https://www.nuget.org/). diff --git a/Templates/FileDialog.template b/Templates/FileDialog.template index 8305dfc9..7eba6828 100644 --- a/Templates/FileDialog.template +++ b/Templates/FileDialog.template @@ -28,7 +28,8 @@ diff --git a/Templates/FileItems.template b/Templates/FileItems.template new file mode 100644 index 00000000..99d7b6a9 --- /dev/null +++ b/Templates/FileItems.template @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/src/GraphicObjects/Button.cs b/src/GraphicObjects/Button.cs index 5967d94e..d4b95457 100644 --- a/src/GraphicObjects/Button.cs +++ b/src/GraphicObjects/Button.cs @@ -54,24 +54,6 @@ namespace Crow public event EventHandler Pressed; public event EventHandler Released; - #region TemplatedContainer overrides - public override GraphicObject Content { - get { - return _contentContainer == null ? null : _contentContainer.Child; - } - set { - if (_contentContainer != null) - _contentContainer.SetChild(value); - } - } - protected override void loadTemplate(GraphicObject template = null) - { - base.loadTemplate (template); - - _contentContainer = this.child.FindByName ("Content") as Container; - } - #endregion - #region GraphicObject Overrides public override void onMouseDown (object sender, MouseButtonEventArgs e) { diff --git a/src/GraphicObjects/Expandable.cs b/src/GraphicObjects/Expandable.cs index 2328fd5f..43f44a93 100644 --- a/src/GraphicObjects/Expandable.cs +++ b/src/GraphicObjects/Expandable.cs @@ -65,25 +65,6 @@ namespace Crow { IsExpanded = !IsExpanded; } - /// - /// Implement the abstract Content property of TemplatedControl - /// - public override GraphicObject Content { - get { - return _contentContainer == null ? null : _contentContainer.Child; - } - set { - _contentContainer.SetChild(value); - NotifyValueChanged ("HasContent", HasContent); - } - } - //TODO: move loadTemplate and ResolveBinding in TemplatedContainer - protected override void loadTemplate(GraphicObject template = null) - { - base.loadTemplate (template); - - _contentContainer = this.child.FindByName ("Content") as Container; - } #region Public properties [XmlAttributeAttribute][DefaultValue("#Crow.Images.Icons.expandable.svg")] @@ -120,9 +101,6 @@ namespace Crow onCollapse (this, null); } } - [XmlIgnore]public bool HasContent { - get { return _contentContainer == null ? false : _contentContainer.Child != null; } - } [XmlIgnore]public bool IsExpandable { get { try { diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index b7ca11f6..3da8330d 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -205,10 +205,10 @@ namespace Crow public Rectangle LastSlots; /// /// keep last slot painted on screen to clear traces if moved or resized - /// TODO: we should ensure the whole parsed widget tree is the last painted /// version to clear effective oldslot if parents have been moved or resized. /// IDEA is to add a ScreenCoordinates function that use only lastPaintedSlots /// + //TODO: we should ensure the whole parsed widget tree is the last painted public Rectangle LastPaintedSlot; /// Prevent requeuing multiple times the same widget public bool IsQueueForRedraw = false; diff --git a/src/GraphicObjects/GroupBox.cs b/src/GraphicObjects/GroupBox.cs index e5a170ae..61e7f2af 100644 --- a/src/GraphicObjects/GroupBox.cs +++ b/src/GraphicObjects/GroupBox.cs @@ -39,22 +39,5 @@ namespace Crow public GroupBox () : base(){} public GroupBox(Interface iface) : base(iface){} #endregion - - #region TemplatedContainer implementation - public override GraphicObject Content { - get { - return _contentContainer == null ? null : _contentContainer.Child; - } - set { - _contentContainer.SetChild(value); - } - } - protected override void loadTemplate(GraphicObject template = null) - { - base.loadTemplate (template); - - _contentContainer = this.child.FindByName ("Content") as Container; - } - #endregion } } diff --git a/src/GraphicObjects/Popper.cs b/src/GraphicObjects/Popper.cs index 175c99fd..9f60aa40 100644 --- a/src/GraphicObjects/Popper.cs +++ b/src/GraphicObjects/Popper.cs @@ -39,7 +39,7 @@ namespace Crow bool _isPopped, _canPop; Alignment popDirection; - GraphicObject _contentContainer; + GraphicObject _content; Measure popWidth, popHeight; public event EventHandler Popped; @@ -111,22 +111,22 @@ namespace Crow #endregion public override GraphicObject Content { - get { return _contentContainer; } + get { return _content; } set { - if (_contentContainer != null) { - _contentContainer.LogicalParent = null; - _contentContainer.LayoutChanged -= _content_LayoutChanged; + if (_content != null) { + _content.LogicalParent = null; + _content.LayoutChanged -= _content_LayoutChanged; } - _contentContainer = value; + _content = value; - if (_contentContainer == null) + if (_content == null) return; - _contentContainer.LogicalParent = this; - _contentContainer.HorizontalAlignment = HorizontalAlignment.Left; - _contentContainer.VerticalAlignment = VerticalAlignment.Top; - _contentContainer.LayoutChanged += _content_LayoutChanged; + _content.LogicalParent = this; + _content.HorizontalAlignment = HorizontalAlignment.Left; + _content.VerticalAlignment = VerticalAlignment.Top; + _content.LayoutChanged += _content_LayoutChanged; } } void positionContent(LayoutingType lt){ @@ -242,9 +242,9 @@ namespace Crow protected override void Dispose (bool disposing) { - if (_contentContainer != null && disposing) { - if (_contentContainer.Parent == null) - _contentContainer.Dispose (); + if (_content != null && disposing) { + if (_content.Parent == null) + _content.Dispose (); } base.Dispose (disposing); } diff --git a/src/GraphicObjects/TabItem.cs b/src/GraphicObjects/TabItem.cs index 9dfff864..b19d14e8 100644 --- a/src/GraphicObjects/TabItem.cs +++ b/src/GraphicObjects/TabItem.cs @@ -65,7 +65,6 @@ namespace Crow { base.loadTemplate (template); - _contentContainer = this.child.FindByName ("Content") as Container; titleWidget = this.child.FindByName ("TabTitle"); } internal GraphicObject TabTitle { get { return titleWidget; }} diff --git a/src/GraphicObjects/TemplatedContainer.cs b/src/GraphicObjects/TemplatedContainer.cs index 02c14d38..a2e35eab 100644 --- a/src/GraphicObjects/TemplatedContainer.cs +++ b/src/GraphicObjects/TemplatedContainer.cs @@ -31,7 +31,12 @@ using System.Reflection; namespace Crow { - public abstract class TemplatedContainer : TemplatedControl + /// + /// base class for new containers that will use templates. + /// + /// TemplatedControl's **must** provide a widget of the [`Container`](Container) class named **_'Content'_** inside their template tree + /// + public class TemplatedContainer : TemplatedControl { #region CTOR public TemplatedContainer() : base(){} @@ -40,7 +45,27 @@ namespace Crow protected Container _contentContainer; - [XmlAttributeAttribute]public virtual GraphicObject Content{ get; set;} + /// + /// Single child of this templated container. + /// + public virtual GraphicObject Content { + get { + return _contentContainer == null ? null : _contentContainer.Child; + } + set { + _contentContainer.SetChild(value); + NotifyValueChanged ("HasContent", HasContent); + } + } + [XmlIgnore]public bool HasContent { + get { return _contentContainer?.Child != null; } + } + //TODO: move loadTemplate and ResolveBinding in TemplatedContainer + protected override void loadTemplate(GraphicObject template = null) + { + base.loadTemplate (template); + _contentContainer = this.child.FindByName ("Content") as Container; + } #region GraphicObject overrides public override GraphicObject FindByName (string nameToFind) diff --git a/src/GraphicObjects/TemplatedControl.cs b/src/GraphicObjects/TemplatedControl.cs index 6e236c8d..a3a6b142 100644 --- a/src/GraphicObjects/TemplatedControl.cs +++ b/src/GraphicObjects/TemplatedControl.cs @@ -54,6 +54,7 @@ namespace Crow /// /// Template path /// + //TODO: this property should be renamed 'TemplatePath' [XmlAttributeAttribute][DefaultValue(null)] public string Template { get { return _template; } @@ -69,7 +70,7 @@ namespace Crow } } /// - /// caption property being recurrent in templated widget, it is declared here. + /// a caption being recurrent need in templated widget, it is declared here. /// [XmlAttributeAttribute()][DefaultValue("Templated Control")] public virtual string Caption { diff --git a/src/GraphicObjects/TemplatedGroup.cs b/src/GraphicObjects/TemplatedGroup.cs index aaeb77f6..81ea25fb 100644 --- a/src/GraphicObjects/TemplatedGroup.cs +++ b/src/GraphicObjects/TemplatedGroup.cs @@ -67,7 +67,11 @@ namespace Crow public Dictionary ItemTemplates = new Dictionary(); /// - /// Default item template + /// Item templates file path, on disk or embedded. + /// + /// ItemTemplate file may contains either a single template without the + /// ItemTemplate enclosing tag, or several item templates each enclosed + /// in a separate tag /// [XmlAttributeAttribute][DefaultValue("#Crow.Templates.ItemTemplate.goml")] public string ItemTemplate { @@ -272,10 +276,8 @@ namespace Crow /// Items loading thread /// void loading(){ - if (ItemTemplates == null) - ItemTemplates = new Dictionary (); - if (!ItemTemplates.ContainsKey ("default")) - ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate); + //if (!ItemTemplates.ContainsKey ("default")) + // ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate); for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) { if ((bool)loadingThread?.cancelRequested) { diff --git a/src/GraphicObjects/Window.cs b/src/GraphicObjects/Window.cs index d1f34374..efc8f4e3 100644 --- a/src/GraphicObjects/Window.cs +++ b/src/GraphicObjects/Window.cs @@ -70,14 +70,9 @@ namespace Crow #endregion #region TemplatedContainer overrides - public override GraphicObject Content { - get { return _contentContainer == null ? null : _contentContainer.Child; } - set { _contentContainer.SetChild(value); } - } protected override void loadTemplate(GraphicObject template = null) { base.loadTemplate (template); - _contentContainer = this.child.FindByName ("Content") as Container; NotifyValueChanged ("ShowNormal", false); NotifyValueChanged ("ShowMinimize", true); diff --git a/src/Instantiator.cs b/src/Instantiator.cs index 902092e2..5f187c58 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -82,15 +82,23 @@ namespace Crow.IML Stopwatch loadingTime = new Stopwatch (); loadingTime.Start (); #endif - using (XmlTextReader itr = new XmlTextReader (stream)) { + using (XmlReader itr = XmlReader.Create (stream)) { parseIML (itr); } + stream.Dispose (); #if DEBUG_LOAD loadingTime.Stop (); Debug.WriteLine ("IML Instantiator creation '{2}' : {0} ticks, {1} ms", loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath); #endif } + /// + /// Initializes a new instance of the Instantiator class with an already openned xml reader + /// positionned on the start tag inside the itemTemplate + /// + public Instantiator (XmlReader itr){ + parseIML (itr); + } //TODO:check if still used public Instantiator (Type _root, InstanciatorInvoker _loader) { @@ -144,7 +152,7 @@ namespace Crow.IML /// /// Parses IML and build a dynamic method that will be used to instanciate one or multiple occurence of the IML file or fragment /// - void parseIML (XmlTextReader reader) { + void parseIML (XmlReader reader) { IMLContext ctx = new IMLContext (findRootType (reader)); ctx.nodesStack.Push (new Node (ctx.RootType)); @@ -169,21 +177,21 @@ namespace Crow.IML /// read first node to set GraphicObject class for loading /// and let reader position on that node /// - Type findRootType (XmlTextReader reader) + Type findRootType (XmlReader reader) { string root = "Object"; - while (reader.Read ()) { - if (reader.NodeType == XmlNodeType.Element) { - root = reader.Name; - break; - } - } + while (reader.NodeType != XmlNodeType.Element) + reader.Read (); + root = reader.Name; Type t = tryGetGOType (root); if (t == null) throw new Exception ("IML parsing error: undefined root type (" + root + ")"); return t; } - void emitLoader (XmlTextReader reader, IMLContext ctx) + /// + /// main parsing entry point + /// + void emitLoader (XmlReader reader, IMLContext ctx) { string tmpXml = reader.ReadOuterXml (); @@ -195,6 +203,41 @@ namespace Crow.IML //emitCheckAndBindValueChanged (ctx); } /// + /// Parses the item template tag. + /// + /// the string triplet dataType, itemTmpID read as attribute of this tag + /// current xml text reader + /// /// file containing the templates if its a dedicated one + string[] parseItemTemplateTag (XmlReader reader, string itemTemplatePath = "") { + string dataType = "default", datas = "", path = ""; + while (reader.MoveToNextAttribute ()) { + if (reader.Name == "DataType") + dataType = reader.Value; + else if (reader.Name == "Data") + datas = reader.Value; + else if (reader.Name == "Path") + path = reader.Value; + } + reader.MoveToElement (); + + string itemTmpID = itemTemplatePath; + + if (string.IsNullOrEmpty (path)) { + itemTmpID += Guid.NewGuid ().ToString (); + Interface.Instantiators [itemTmpID] = + new ItemTemplate (new MemoryStream (Encoding.UTF8.GetBytes (reader.ReadInnerXml ())), dataType, datas); + + } else { + if (!reader.IsEmptyElement) + throw new Exception ("ItemTemplate with Path attribute set may not include sub nodes"); + itemTmpID += path+dataType+datas; + if (!Interface.Instantiators.ContainsKey (itemTmpID)) + Interface.Instantiators [itemTmpID] = + new ItemTemplate (Interface.GetStreamFromPath (path), dataType, datas); + } + return new string [] { dataType, itemTmpID, datas }; + } + /// /// process template and item template definition prior to /// other attributes or childs processing /// @@ -208,6 +251,7 @@ namespace Crow.IML reader.Read (); string templatePath = reader.GetAttribute ("Template"); + string itemTemplatePath = reader.GetAttribute ("ItemTemplate"); int depth = reader.Depth + 1; while (reader.Read ()) { @@ -217,35 +261,8 @@ namespace Crow.IML inlineTemplate = true; reader.Read (); readChildren (reader, ctx, -1); - } else if (reader.Name == "ItemTemplate") { - string dataType = "default", datas = "", path = ""; - while (reader.MoveToNextAttribute ()) { - if (reader.Name == "DataType") - dataType = reader.Value; - else if (reader.Name == "Data") - datas = reader.Value; - else if (reader.Name == "Path") - path = reader.Value; - } - reader.MoveToElement (); - - string itemTmpID; - - if (string.IsNullOrEmpty (path)) { - itemTmpID = Guid.NewGuid ().ToString (); - Interface.Instantiators [itemTmpID] = - new ItemTemplate (new MemoryStream (Encoding.UTF8.GetBytes (reader.ReadInnerXml ())), dataType, datas); - - } else { - if (!reader.IsEmptyElement) - throw new Exception ("ItemTemplate with Path attribute may not include sub nodes"); - itemTmpID = path+dataType+datas; - if (!Interface.Instantiators.ContainsKey (itemTmpID)) - Interface.Instantiators [itemTmpID] = - new ItemTemplate (Interface.GetStreamFromPath (itemTmpID), dataType, datas); - } - itemTemplateIds.Add (new string [] { dataType, itemTmpID, datas }); - } + } else if (reader.Name == "ItemTemplate") + itemTemplateIds.Add (parseItemTemplateTag (reader)); } if (!inlineTemplate) {//load from path or default template @@ -260,6 +277,36 @@ namespace Crow.IML } ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miLoadTmp);//load template } + if (itemTemplateIds.Count == 0) { + //try to load ItemTemplate(s) from ItemTemplate attribute of TemplatedGroup + if (!string.IsNullOrEmpty (itemTemplatePath)) { + //check if it is already loaded in cache as a single itemTemplate instantiator + if (Interface.Instantiators.ContainsKey (itemTemplatePath)) { + itemTemplateIds.Add (new string [] { "default", itemTemplatePath, "" }); + } else { + using (Stream stream = Interface.GetStreamFromPath (itemTemplatePath)) { + //itemtemplate files may have multiple root nodes + XmlReaderSettings itrSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment }; + using (XmlReader itr = XmlReader.Create (stream, itrSettings)) { + while (itr.Read ()) { + if (!itr.IsStartElement ()) + continue; + if (itr.NodeType == XmlNodeType.Element) { + if (itr.Name != "ItemTemplate") { + //the file contains a single template to use as default + Interface.Instantiators [itemTemplatePath] = + new ItemTemplate (itr); + itemTemplateIds.Add (new string [] { "default", itemTemplatePath, "" }); + break;//we should be at the end of the file + } + itemTemplateIds.Add (parseItemTemplateTag (itr, itemTemplatePath)); + } + } + } + } + } + } + } //copy item templates (review this) foreach (string [] iTempId in itemTemplateIds) { ctx.il.Emit (OpCodes.Ldloc_0);//load TempControl ref diff --git a/src/ItemTemplate.cs b/src/ItemTemplate.cs index d866bc19..d0c6873e 100644 --- a/src/ItemTemplate.cs +++ b/src/ItemTemplate.cs @@ -63,6 +63,12 @@ namespace Crow strDataType = _dataType; fetchMethodName = _fetchDataMethod; } + public ItemTemplate (XmlReader reader, string _dataType = null, string _fetchDataMethod = null) + :base(reader) + { + strDataType = _dataType; + fetchMethodName = _fetchDataMethod; + } #endregion public void CreateExpandDelegate (TemplatedGroup host){