From 2e540d7dd228ca86c064180198d75c6b21966550 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Fri, 9 Mar 2018 15:37:09 +0100 Subject: [PATCH] editor abstract base class, svgeditor base --- CrowIDE/CrowIDE.csproj | 35 +- CrowIDE/icons/binding.svg | 7 + .../icons/{toolbox/gear.svg => compile.svg} | 0 .../icons/{toolbox => }/curly-brackets.svg | 0 CrowIDE/icons/{toolbox => }/edit.svg | 0 CrowIDE/icons/{toolbox => }/eraser.svg | 0 CrowIDE/icons/{toolbox => }/light-bulb.svg | 0 CrowIDE/icons/magic-wand.svg | 13 + .../dot-inside-a-circle.svg => magnet.svg} | 5 +- CrowIDE/icons/{toolbox => }/move-arrows.svg | 0 CrowIDE/icons/{toolbox => }/paint-brush.svg | 0 CrowIDE/icons/palette.svg | 6 + CrowIDE/icons/{toolbox => }/pin.svg | 0 CrowIDE/icons/{toolbox => }/search.svg | 0 CrowIDE/icons/{toolbox => }/text-file.svg | 0 CrowIDE/icons/toolbox/Crow.RadioButton.svg | 7 +- CrowIDE/icons/toolbox/options.svg | 10 + CrowIDE/icons/{toolbox => }/tools.svg | 0 CrowIDE/icons/{toolbox => }/trash.svg | 0 CrowIDE/icons/{toolbox => }/zoom-in.svg | 0 CrowIDE/icons/{toolbox => }/zoom-out.svg | 0 CrowIDE/src/Editor.cs | 104 ++++++ CrowIDE/src/ImlVisualEditor.cs | 298 ++++++++++-------- CrowIDE/src/Project.cs | 31 +- CrowIDE/src/ProjectNodes.cs | 4 + CrowIDE/src/SourceEditor/CodeLine.cs | 2 +- CrowIDE/src/SourceEditor/SourceEditor.cs | 265 +++++++--------- CrowIDE/src/SvgEditor.cs | 85 +++++ CrowIDE/ui/EditPaneItems.template | 22 +- CrowIDE/ui/IMLEdit.itemp | 34 +- CrowIDE/ui/SourceEditor.crow | 31 ++ CrowIDE/ui/SrcEdit.itemp | 31 +- Default.style | 1 + src/Interface.cs | 13 + src/ParsingException.cs | 16 +- src/SvgPicture.cs | 7 + 36 files changed, 653 insertions(+), 374 deletions(-) create mode 100644 CrowIDE/icons/binding.svg rename CrowIDE/icons/{toolbox/gear.svg => compile.svg} (100%) rename CrowIDE/icons/{toolbox => }/curly-brackets.svg (100%) rename CrowIDE/icons/{toolbox => }/edit.svg (100%) rename CrowIDE/icons/{toolbox => }/eraser.svg (100%) rename CrowIDE/icons/{toolbox => }/light-bulb.svg (100%) create mode 100644 CrowIDE/icons/magic-wand.svg rename CrowIDE/icons/{toolbox/dot-inside-a-circle.svg => magnet.svg} (58%) rename CrowIDE/icons/{toolbox => }/move-arrows.svg (100%) rename CrowIDE/icons/{toolbox => }/paint-brush.svg (100%) create mode 100644 CrowIDE/icons/palette.svg rename CrowIDE/icons/{toolbox => }/pin.svg (100%) rename CrowIDE/icons/{toolbox => }/search.svg (100%) rename CrowIDE/icons/{toolbox => }/text-file.svg (100%) create mode 100644 CrowIDE/icons/toolbox/options.svg rename CrowIDE/icons/{toolbox => }/tools.svg (100%) rename CrowIDE/icons/{toolbox => }/trash.svg (100%) rename CrowIDE/icons/{toolbox => }/zoom-in.svg (100%) rename CrowIDE/icons/{toolbox => }/zoom-out.svg (100%) create mode 100644 CrowIDE/src/Editor.cs create mode 100644 CrowIDE/src/SvgEditor.cs create mode 100644 CrowIDE/ui/SourceEditor.crow diff --git a/CrowIDE/CrowIDE.csproj b/CrowIDE/CrowIDE.csproj index 6b720536..1779b1d2 100644 --- a/CrowIDE/CrowIDE.csproj +++ b/CrowIDE/CrowIDE.csproj @@ -113,6 +113,8 @@ + + @@ -179,43 +181,27 @@ - - - - - - - - - - - - - - - - @@ -251,6 +237,23 @@ + + + + + + + + + + + + + + + + + diff --git a/CrowIDE/icons/binding.svg b/CrowIDE/icons/binding.svg new file mode 100644 index 00000000..3d825c65 --- /dev/null +++ b/CrowIDE/icons/binding.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/CrowIDE/icons/toolbox/gear.svg b/CrowIDE/icons/compile.svg similarity index 100% rename from CrowIDE/icons/toolbox/gear.svg rename to CrowIDE/icons/compile.svg diff --git a/CrowIDE/icons/toolbox/curly-brackets.svg b/CrowIDE/icons/curly-brackets.svg similarity index 100% rename from CrowIDE/icons/toolbox/curly-brackets.svg rename to CrowIDE/icons/curly-brackets.svg diff --git a/CrowIDE/icons/toolbox/edit.svg b/CrowIDE/icons/edit.svg similarity index 100% rename from CrowIDE/icons/toolbox/edit.svg rename to CrowIDE/icons/edit.svg diff --git a/CrowIDE/icons/toolbox/eraser.svg b/CrowIDE/icons/eraser.svg similarity index 100% rename from CrowIDE/icons/toolbox/eraser.svg rename to CrowIDE/icons/eraser.svg diff --git a/CrowIDE/icons/toolbox/light-bulb.svg b/CrowIDE/icons/light-bulb.svg similarity index 100% rename from CrowIDE/icons/toolbox/light-bulb.svg rename to CrowIDE/icons/light-bulb.svg diff --git a/CrowIDE/icons/magic-wand.svg b/CrowIDE/icons/magic-wand.svg new file mode 100644 index 00000000..0196115d --- /dev/null +++ b/CrowIDE/icons/magic-wand.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/CrowIDE/icons/toolbox/dot-inside-a-circle.svg b/CrowIDE/icons/magnet.svg similarity index 58% rename from CrowIDE/icons/toolbox/dot-inside-a-circle.svg rename to CrowIDE/icons/magnet.svg index c84374af..613fe7bb 100644 --- a/CrowIDE/icons/toolbox/dot-inside-a-circle.svg +++ b/CrowIDE/icons/magnet.svg @@ -2,6 +2,7 @@ - - + + + diff --git a/CrowIDE/icons/toolbox/move-arrows.svg b/CrowIDE/icons/move-arrows.svg similarity index 100% rename from CrowIDE/icons/toolbox/move-arrows.svg rename to CrowIDE/icons/move-arrows.svg diff --git a/CrowIDE/icons/toolbox/paint-brush.svg b/CrowIDE/icons/paint-brush.svg similarity index 100% rename from CrowIDE/icons/toolbox/paint-brush.svg rename to CrowIDE/icons/paint-brush.svg diff --git a/CrowIDE/icons/palette.svg b/CrowIDE/icons/palette.svg new file mode 100644 index 00000000..79137cd4 --- /dev/null +++ b/CrowIDE/icons/palette.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/CrowIDE/icons/toolbox/pin.svg b/CrowIDE/icons/pin.svg similarity index 100% rename from CrowIDE/icons/toolbox/pin.svg rename to CrowIDE/icons/pin.svg diff --git a/CrowIDE/icons/toolbox/search.svg b/CrowIDE/icons/search.svg similarity index 100% rename from CrowIDE/icons/toolbox/search.svg rename to CrowIDE/icons/search.svg diff --git a/CrowIDE/icons/toolbox/text-file.svg b/CrowIDE/icons/text-file.svg similarity index 100% rename from CrowIDE/icons/toolbox/text-file.svg rename to CrowIDE/icons/text-file.svg diff --git a/CrowIDE/icons/toolbox/Crow.RadioButton.svg b/CrowIDE/icons/toolbox/Crow.RadioButton.svg index a149a350..c84374af 100644 --- a/CrowIDE/icons/toolbox/Crow.RadioButton.svg +++ b/CrowIDE/icons/toolbox/Crow.RadioButton.svg @@ -2,9 +2,6 @@ - - - - - + + diff --git a/CrowIDE/icons/toolbox/options.svg b/CrowIDE/icons/toolbox/options.svg new file mode 100644 index 00000000..a149a350 --- /dev/null +++ b/CrowIDE/icons/toolbox/options.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/CrowIDE/icons/toolbox/tools.svg b/CrowIDE/icons/tools.svg similarity index 100% rename from CrowIDE/icons/toolbox/tools.svg rename to CrowIDE/icons/tools.svg diff --git a/CrowIDE/icons/toolbox/trash.svg b/CrowIDE/icons/trash.svg similarity index 100% rename from CrowIDE/icons/toolbox/trash.svg rename to CrowIDE/icons/trash.svg diff --git a/CrowIDE/icons/toolbox/zoom-in.svg b/CrowIDE/icons/zoom-in.svg similarity index 100% rename from CrowIDE/icons/toolbox/zoom-in.svg rename to CrowIDE/icons/zoom-in.svg diff --git a/CrowIDE/icons/toolbox/zoom-out.svg b/CrowIDE/icons/zoom-out.svg similarity index 100% rename from CrowIDE/icons/toolbox/zoom-out.svg rename to CrowIDE/icons/zoom-out.svg diff --git a/CrowIDE/src/Editor.cs b/CrowIDE/src/Editor.cs new file mode 100644 index 00000000..41aa6069 --- /dev/null +++ b/CrowIDE/src/Editor.cs @@ -0,0 +1,104 @@ +// +// Editor.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2013-2017 Jean-Philippe Bruyère +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Threading; +using System.Xml.Serialization; + +namespace Crow.Coding +{ + public abstract class Editor : ScrollingObject + { + #region CTOR + protected Editor ():base(){ + Thread t = new Thread (backgroundThreadFunc); + t.IsBackground = true; + t.Start (); + } + #endregion + + protected ReaderWriterLockSlim editorMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + protected ProjectFile projFile = null; + Exception error = null; + + public virtual ProjectFile ProjectNode + { + get { return projFile; } + set + { + if (projFile == value) + return; + + if (projFile != null) + projFile.UnregisterEditor (this); + + projFile = value; + + if (projFile != null) + projFile.RegisterEditor (this); + + NotifyValueChanged ("ProjectNode", projFile); + } + } + [XmlIgnore]public Exception Error { + get { return error; } + set { + if (error == value) + return; + error = value; + NotifyValueChanged ("Error", error); + NotifyValueChanged ("HasError", HasError); + } + } + [XmlIgnore]public bool HasError { + get { return error != null; } + } + + protected abstract void updateEditorFromProjFile (); + protected abstract void updateProjFileFromEditor (); + protected abstract bool EditorIsDirty { get; set; } + protected virtual bool IsReady { get { return true; }} + protected virtual void updateCheckPostProcess () {} + + protected void backgroundThreadFunc () { + while (true) { + if (IsReady) { + if (projFile != null) { + if (!projFile.RegisteredEditors [this]) { + projFile.RegisteredEditors [this] = true; + updateEditorFromProjFile (); + } else if (EditorIsDirty) { + EditorIsDirty = false; + updateProjFileFromEditor (); + } + updateCheckPostProcess (); + } + } + Thread.Sleep (50); + } + } + } +} + diff --git a/CrowIDE/src/ImlVisualEditor.cs b/CrowIDE/src/ImlVisualEditor.cs index 88ee2ffe..d084904e 100644 --- a/CrowIDE/src/ImlVisualEditor.cs +++ b/CrowIDE/src/ImlVisualEditor.cs @@ -26,30 +26,29 @@ using System.ComponentModel; using System.IO; using System.Collections.Generic; using Crow.IML; +using System.Text; +using System.Xml; namespace Crow.Coding { - public class ImlVisualEditor : GraphicObject + public class ImlVisualEditor : Editor { #region CTOR public ImlVisualEditor () : base() { imlVE = new DesignInterface (); - Thread t = new Thread (interfaceThread); - t.IsBackground = true; - t.Start (); } #endregion DesignInterface imlVE; GraphicObject selectedItem; - ImlProjectItem projFile; + ImlProjectItem imlProjFile; Exception imlError = null; - bool drawGrid; + bool drawGrid, snapToGrid; int gridSpacing; - [XmlAttributeAttribute][DefaultValue(true)] + [DefaultValue(true)] public bool DrawGrid { get { return drawGrid; } set { @@ -60,7 +59,17 @@ namespace Crow.Coding RegisterForRedraw (); } } - [XmlAttributeAttribute][DefaultValue(10)] + [DefaultValue(true)] + public bool SnapToGrid { + get { return snapToGrid; } + set { + if (snapToGrid == value) + return; + snapToGrid = value; + NotifyValueChanged ("SnapToGrid", snapToGrid); + } + } + [DefaultValue(10)] public int GridSpacing { get { return gridSpacing; } set { @@ -81,7 +90,7 @@ namespace Crow.Coding RegisterForRedraw (); } } - /// Pointer is over the widget + /// PoinprojFilever the widget public virtual GraphicObject HoverWidget { get { return imlVE.HoverWidget; } @@ -97,89 +106,97 @@ namespace Crow.Coding [XmlIgnore]public List LQIs { get { return imlVE.LQIs; } } - - public ProjectNode ProjectNode { - get { return projFile; } - set { - if (projFile == value) - return; - - if (projFile != null) - projFile.UnregisterEditor (this); - - projFile = value as ImlProjectItem; - - imlVE.ProjFile = projFile; - if (projFile != null) - projFile.RegisterEditor (this); - - NotifyValueChanged ("ProjectNode", projFile); + public override ProjectFile ProjectNode { + get { + return base.ProjectNode; } - } - - [XmlIgnore]public Exception IMLError { - get { return imlError; } set { - if (imlError == value) - return; - imlError = value; - NotifyValueChanged ("IMLError", imlError); - NotifyValueChanged ("HasError", HasError); + base.ProjectNode = value; + imlProjFile = projFile as ImlProjectItem; + imlVE.ProjFile = imlProjFile; } } - [XmlIgnore]public bool HasError { - get { return imlError != null; } - } public List GraphicTree { get { return imlVE.GraphicTree; } } - - void interfaceThread() + protected override void updateProjFileFromEditor () { - while (true) { - try { - if (!projFile.RegisteredEditors[this]){ - string selItemDesignID = null; - if (SelectedItem!=null) - selItemDesignID = SelectedItem.design_id; - imlVE.ClearInterface(); - Instantiator.NextInstantiatorID = 0; - imlVE.Styling = projFile.Project.solution.Styling; - imlVE.DefaultValuesLoader.Clear(); - imlVE.DefaultTemplates = projFile.Project.solution.DefaultTemplates; - imlVE.Instantiators = new Dictionary(); - imlVE.LoadIMLFragment(projFile.Source); - projFile.Instance = imlVE.GraphicTree[0]; - GraphicObject go = null; - if (selItemDesignID!=null) - projFile.Instance.FindByDesignID(selItemDesignID,out go); - SelectedItem = go; - IMLError = null; - projFile.RegisteredEditors[this] = true; - }else if ((bool)projFile.Instance?.design_HasChanged){ - projFile.UpdateSource(this, projFile.Instance.GetIML()); + try { + projFile.UpdateSource(this, imlProjFile.Instance.GetIML()); + } catch (Exception ex) { + Error = ex.InnerException; + if (Monitor.IsEntered(imlVE.UpdateMutex)) + Monitor.Exit (imlVE.UpdateMutex); + } + } + protected override void updateEditorFromProjFile () { + try { + string selItemDesignID = null; + if (SelectedItem!=null) + selItemDesignID = SelectedItem.design_id; + imlVE.ClearInterface(); + Instantiator.NextInstantiatorID = 0; + imlVE.Styling = projFile.Project.solution.Styling; + imlVE.DefaultValuesLoader.Clear(); + imlVE.DefaultTemplates = projFile.Project.solution.DefaultTemplates; + imlVE.Instantiators = new Dictionary(); + + //prevent error on empty file + bool emptyFile = true; + string src = projFile.Source; + using (Stream s = new MemoryStream (Encoding.UTF8.GetBytes (src))) { + using (XmlReader itr = XmlReader.Create (s)) { + while(itr.Read()){ + if (itr.NodeType == XmlNodeType.Element){ + emptyFile = false; + break; + } + } } - imlVE.Update (); - } catch (Exception ex) { - IMLError = ex.InnerException; - if (Monitor.IsEntered(imlVE.UpdateMutex)) - Monitor.Exit (imlVE.UpdateMutex); } + GraphicObject go = null; + Error = null; + if (emptyFile){ + imlProjFile.Instance = null; + }else{ + imlVE.LoadIMLFragment(src); + imlProjFile.Instance = imlVE.GraphicTree[0]; + if (selItemDesignID!=null) + imlProjFile.Instance.FindByDesignID(selItemDesignID,out go); - bool isDirty = false; + } + SelectedItem = go; + } catch (Exception ex) { + Error = ex.InnerException; + if (Monitor.IsEntered(imlVE.UpdateMutex)) + Monitor.Exit (imlVE.UpdateMutex); + } + } - lock (imlVE.RenderMutex) - isDirty = imlVE.IsDirty; + protected override bool EditorIsDirty { + get { return (bool)imlProjFile.Instance?.design_HasChanged; } + set { + if (GraphicTree [0] != null) + GraphicTree [0].design_HasChanged = value; + } + } + protected override bool IsReady { + get { return imlVE != null && imlProjFile != null; } + } + protected override void updateCheckPostProcess () + { + imlVE.Update (); + bool isDirty = false; - if (isDirty) { - lock (IFace.UpdateMutex) - RegisterForRedraw (); - } + lock (imlVE.RenderMutex) + isDirty = imlVE.IsDirty; - Thread.Sleep (10); + if (isDirty) { + lock (IFace.UpdateMutex) + RegisterForRedraw (); } } @@ -194,59 +211,7 @@ namespace Crow.Coding break; } } - bool tryAddDraggedObjTo(GraphicObject g){ - lock (imlVE.UpdateMutex) { - if (g.GetType ().IsSubclassOf (typeof(Container))) { - Container c = g as Container; - c.SetChild (draggedObj); - GraphicTree [0].design_HasChanged = true; - } else if (g.GetType ().IsSubclassOf (typeof(Group))) { - Group c = g as Group; - c.AddChild (draggedObj); - } else - return false; - GraphicTree [0].design_HasChanged = true; - draggedObjContainer = g; - } - return true; - } - bool isPossibleContainer (GraphicObject g){ - if (g.GetType().IsSubclassOf(typeof(Container))){ - Container c = g as Container; - return c.Child == null; - } - return g.GetType ().IsSubclassOf (typeof(Group)); - } - void removeDraggedObjFrom(){ - if (draggedObjContainer == null) - return; - lock (imlVE.UpdateMutex) { - if (draggedObjContainer.GetType().IsSubclassOf(typeof(Container))){ - Container c = draggedObjContainer as Container; - c.SetChild (null); - GraphicTree [0].design_HasChanged = true; - //Console.WriteLine ("remove {0} from {1}", draggedObj, c); - }else if (draggedObjContainer.GetType().IsSubclassOf(typeof(Group))){ - Group c = draggedObjContainer as Group; - c.RemoveChild (draggedObj); - GraphicTree [0].design_HasChanged = true; - //Console.WriteLine ("remove {0} from {1}", draggedObj, c); - }//else - // Console.WriteLine ("Error removing dragged obj"); - } - draggedObjContainer = null; - } - public void ClearDraggedObj (bool removeFromTree = true) { - //Console.WriteLine ("Clear dragged obj {0}, remove from tree = {1}", draggedObj, removeFromTree); - if (removeFromTree) - removeDraggedObjFrom (); - draggedObjContainer = null; - if (draggedObj == null) - return; - if (removeFromTree) - draggedObj.Dispose (); - draggedObj = null; - } + public override void onMouseMove (object sender, MouseMoveEventArgs e) { base.onMouseMove (sender, e); @@ -279,6 +244,7 @@ namespace Crow.Coding } } + protected override void onDraw (Cairo.Context gr) { base.onDraw (gr); @@ -338,31 +304,87 @@ namespace Crow.Coding gr.Rectangle (hr, 1.0); } - public GraphicObject draggedObj = null; - public GraphicObject draggedObjContainer = null; - protected override void onDragEnter (object sender, DragDropEventArgs e) { base.onDragEnter (sender, e); GraphicObjectDesignContainer godc = e.DragSource.DataSource as GraphicObjectDesignContainer; if (godc == null) return; - Console.WriteLine ("IMLEditor Drag Enter"); - - lock (imlVE.UpdateMutex) { - draggedObj = imlVE.CreateITorFromIMLFragment ("<" + godc.CrowType.Name + "/>").CreateInstance (); - } + createDraggedObj (godc.CrowType); } protected override void onDragLeave (object sender, DragDropEventArgs e) { base.onDragLeave (sender, e); - Console.WriteLine ("IMLEditor Drag Enter"); - ClearDraggedObj (); } #endregion + #region draggedObj handling + public GraphicObject draggedObj = null; + public GraphicObject draggedObjContainer = null; + + bool tryAddDraggedObjTo(GraphicObject g){ + lock (imlVE.UpdateMutex) { + if (g.GetType ().IsSubclassOf (typeof(Container))) { + Container c = g as Container; + c.SetChild (draggedObj); + EditorIsDirty = true; + } else if (g.GetType ().IsSubclassOf (typeof(Group))) { + Group c = g as Group; + c.AddChild (draggedObj); + } else + return false; + EditorIsDirty = true; + draggedObjContainer = g; + } + return true; + } + bool isPossibleContainer (GraphicObject g){ + if (g.GetType().IsSubclassOf(typeof(Container))){ + Container c = g as Container; + return c.Child == null; + } + return g.GetType ().IsSubclassOf (typeof(Group)); + } + void removeDraggedObjFrom(){ + if (draggedObjContainer == null) + return; + lock (imlVE.UpdateMutex) { + if (draggedObjContainer.GetType().IsSubclassOf(typeof(Container))){ + Container c = draggedObjContainer as Container; + c.SetChild (null); + EditorIsDirty = true; + //Console.WriteLine ("remove {0} from {1}", draggedObj, c); + }else if (draggedObjContainer.GetType().IsSubclassOf(typeof(Group))){ + Group c = draggedObjContainer as Group; + c.RemoveChild (draggedObj); + EditorIsDirty = true; + //Console.WriteLine ("remove {0} from {1}", draggedObj, c); + }//else + // Console.WriteLine ("Error removing dragged obj"); + } + draggedObjContainer = null; + } + void createDraggedObj (Type crowType) { + lock (imlVE.UpdateMutex) { + draggedObj = imlVE.CreateITorFromIMLFragment ("<" + crowType.Name + "/>").CreateInstance (); + } + } + public void ClearDraggedObj (bool removeFromTree = true) { + //Console.WriteLine ("Clear dragged obj {0}, remove from tree = {1}", draggedObj, removeFromTree); + if (removeFromTree) + removeDraggedObjFrom (); + draggedObjContainer = null; + if (draggedObj == null) + return; + if (removeFromTree) + draggedObj.Dispose (); + draggedObj = null; + } + #endregion + + void WidgetCheckOver (GraphicObject go, MouseMoveEventArgs e){ Type tGo = go.GetType(); if (typeof(TemplatedGroup).IsAssignableFrom (tGo)) { diff --git a/CrowIDE/src/Project.cs b/CrowIDE/src/Project.cs index 5e6c98d9..38e38493 100644 --- a/CrowIDE/src/Project.cs +++ b/CrowIDE/src/Project.cs @@ -216,20 +216,37 @@ namespace Crow.Coding #endregion + Crow.Command cmdSave, cmdOpen, cmdCompile, cmdSetAsStartProj, cmdNewFile; public Project (Solution sol, SolutionProject sp) { solutionProject = sp; solution = sol; - - Commands = new List (new Crow.Command[] { - new Crow.Command(new Action(() => Compile())) { Caption = "Compile"}, - new Crow.Command(new Action(() => setAsStartupProject())) { Caption = "Set as Startup Project"}, - }); + + cmdSave = new Crow.Command (new Action (() => Save ())) + { Caption = "Save", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = true }; + cmdOpen = new Crow.Command (new Action (() => Load ())) + { Caption = "Open", Icon = new SvgPicture ("#Crow.Coding.ui.icons.outbox.svg"), CanExecute = false }; + cmdCompile = new Crow.Command (new Action (() => Compile ())) { + Caption = "Compile", + Icon = "#Crow.Coding.icons.compile.svg" + }; + cmdSetAsStartProj = new Crow.Command (new Action (() => setAsStartupProject ())) { + Caption = "Set as Startup Project" + }; + cmdNewFile = new Crow.Command (new Action (() => AddNewFile ())) { + Caption = "Add New File" + }; + + Commands = new List (new Crow.Command[] {cmdOpen,cmdSave,cmdSetAsStartProj,cmdCompile,cmdNewFile}); Load (); } + public void AddNewFile () { + + } + public void Load () { xmlDoc = new XmlDocument(); @@ -254,6 +271,10 @@ namespace Crow.Coding IsLoaded = true; } + public void Save () { + + } + void setAsStartupProject () { solution.StartupProject = this; } diff --git a/CrowIDE/src/ProjectNodes.cs b/CrowIDE/src/ProjectNodes.cs index bf213c27..1524b3d2 100644 --- a/CrowIDE/src/ProjectNodes.cs +++ b/CrowIDE/src/ProjectNodes.cs @@ -263,6 +263,8 @@ namespace Crow.Coding NotifyValueChanged ("Source", source); NotifyValueChanged ("IsDirty", IsDirty); + cmdSave.CanExecute = IsDirty; + srcEditMtx.ExitWriteLock (); } } @@ -317,6 +319,8 @@ namespace Crow.Coding NotifyValueChanged ("IsDirty", false); } public void Save () { + if (!IsDirty) + return; using (StreamWriter sw = new StreamWriter (AbsolutePath)) { sw.Write (source); } diff --git a/CrowIDE/src/SourceEditor/CodeLine.cs b/CrowIDE/src/SourceEditor/CodeLine.cs index 041e903c..23f43fba 100644 --- a/CrowIDE/src/SourceEditor/CodeLine.cs +++ b/CrowIDE/src/SourceEditor/CodeLine.cs @@ -59,7 +59,7 @@ namespace Crow.Coding } public void SetLineInError (ParserException ex) { - Tokens = null; + Tokens = null; exception = ex; } diff --git a/CrowIDE/src/SourceEditor/SourceEditor.cs b/CrowIDE/src/SourceEditor/SourceEditor.cs index 691b6d9d..22666f53 100644 --- a/CrowIDE/src/SourceEditor/SourceEditor.cs +++ b/CrowIDE/src/SourceEditor/SourceEditor.cs @@ -42,10 +42,8 @@ namespace Crow.Coding /// /// Scrolling text box optimized for monospace fonts, for coding /// - public class SourceEditor : ScrollingObject - { - public ReaderWriterLockSlim seMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - + public class SourceEditor : Editor + { #region CTOR public SourceEditor (): base() { @@ -66,6 +64,7 @@ namespace Crow.Coding //formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.DarkCyan, Color.Transparent)); parsing.Add (".crow", "Crow.Coding.XMLParser"); + parsing.Add (".svg", "Crow.Coding.XMLParser"); parsing.Add (".template", "Crow.Coding.XMLParser"); parsing.Add (".cs", "Crow.Coding.CSharpParser"); parsing.Add (".style", "Crow.Coding.StyleParser"); @@ -79,40 +78,14 @@ namespace Crow.Coding buffer.PositionChanged += Buffer_PositionChanged; buffer.FoldingEvent += Buffer_FoldingEvent; buffer.Add (new CodeLine("")); - - Thread updateSource = new Thread (updateSourceThreadFunc); - updateSource.IsBackground = true; - updateSource.Start (); } #endregion + string oldSource = ""; - void updateSourceThreadFunc (){ - while (true) { - if (projFile != null && buffer != null) { - if (!projFile.RegisteredEditors [this]) { - loadSource (); - isDirty = false; - oldSource = projFile.Source; - CurrentLine = requestedLine; - CurrentColumn = requestedCol; - projFile.RegisteredEditors [this] = true; - } - buffer.editMutex.EnterWriteLock (); - string newsrc = ""; - bool wasDirty = false; - if (isDirty) { - isDirty = false; - wasDirty = true; - newsrc = buffer.FullText; - } - buffer.editMutex.ExitWriteLock (); - if (wasDirty) - projFile.UpdateSource (this, newsrc); - - } - Thread.Sleep (100); - } - } + //save requested position on error, and try it on next move + int requestedLine = 0, requestedCol = 0; + volatile bool isDirty = false; + const int leftMarginGap = 3;//gap between items in margin and text const int foldSize = 9;//folding rectangles size const int foldHSpace = 4;//folding level tabulation x @@ -120,7 +93,6 @@ namespace Crow.Coding #region private and protected fields bool foldingEnabled = true; - ProjectFile projFile = null; int leftMargin = 0; //margin used to display line numbers, folding errors,etc... int visibleLines = 1; int visibleColumns = 1; @@ -199,7 +171,7 @@ namespace Crow.Coding } void updatePrintedLines () { buffer.editMutex.EnterReadLock (); - seMutex.EnterWriteLock (); + editorMutex.EnterWriteLock (); PrintedLines = new List (); int curL = 0; @@ -225,7 +197,10 @@ namespace Crow.Coding } buffer.editMutex.ExitReadLock (); - seMutex.ExitWriteLock (); + editorMutex.ExitWriteLock (); + } + void updateOnScreenCurLineFromBuffCurLine(){ + printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); } void toogleFolding (int line) { if (parser == null || !foldingEnabled) @@ -233,12 +208,34 @@ namespace Crow.Coding buffer.ToogleFolding (line); } - volatile bool isDirty = false; + protected override void updateEditorFromProjFile () + { + loadSource (); + isDirty = false; + oldSource = projFile.Source; + CurrentLine = requestedLine; + CurrentColumn = requestedCol; + projFile.RegisteredEditors [this] = true; + } + protected override void updateProjFileFromEditor () + { + buffer.editMutex.EnterWriteLock (); + string newsrc = buffer.FullText; + buffer.editMutex.ExitWriteLock (); + projFile.UpdateSource (this, newsrc); + } + protected override bool EditorIsDirty { + get { return isDirty; } + set { isDirty = value; } + } + protected override bool IsReady { + get { return buffer != null; } + } #region Buffer events handlers void Buffer_BufferCleared (object sender, EventArgs e) { - seMutex.EnterWriteLock (); + editorMutex.EnterWriteLock (); buffer.longestLineCharCount = 0; buffer.longestLineIdx = 0; @@ -249,7 +246,7 @@ namespace Crow.Coding notifyPositionChanged (); isDirty = true; - seMutex.ExitWriteLock (); + editorMutex.ExitWriteLock (); } void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) { @@ -343,20 +340,18 @@ namespace Crow.Coding } #endregion - public int CurrentColumn{ - get { return buffer == null ? 0 : buffer.CurrentColumn+1; } - set { - try { - if (value - 1 == buffer.CurrentColumn) - return; - buffer.CurrentColumn = value - 1; - } catch (Exception ex) { - requestedCol = value - 1; - Console.WriteLine ("Error cur column: " + ex.ToString ()); - } + void notifyPositionChanged (){ + try { + NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); + NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); + NotifyValueChanged ("CurrentLineHasError", CurrentLineHasError); + NotifyValueChanged ("CurrentLineError", CurrentLineError); + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); } } - int requestedLine = 0, requestedCol = 0; + + #region Public Crow Properties public int CurrentLine{ get { return buffer == null ? 0 : buffer.CurrentLine+1; } set { @@ -373,30 +368,19 @@ namespace Crow.Coding } } } - - void notifyPositionChanged (){ - try { - - NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); - NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); - } catch (Exception ex) { - Console.WriteLine (ex.ToString ()); + public int CurrentColumn{ + get { return buffer == null ? 0 : buffer.CurrentColumn+1; } + set { + try { + if (value - 1 == buffer.CurrentColumn) + return; + buffer.CurrentColumn = value - 1; + } catch (Exception ex) { + requestedCol = value - 1; + Console.WriteLine ("Error cur column: " + ex.ToString ()); + } } } - - BufferParser getParserFromExt (string extension) { - if (string.IsNullOrEmpty(extension)) - return null; - if (!parsing.ContainsKey(extension)) - return null; - Type parserType = Type.GetType (parsing [extension]); - if (parserType == null) - return null; - return (BufferParser)Activator.CreateInstance (parserType, buffer ); - } - - #region Public Crow Properties - [XmlAttributeAttribute] public bool PrintLineNumbers { get { return Configuration.Global.Get ("PrintLineNumbers"); } @@ -409,55 +393,7 @@ namespace Crow.Coding RegisterForGraphicUpdate (); } } - [XmlAttributeAttribute] - public ProjectFile ProjectNode - { - get { - return projFile; - } - set - { - if (projFile == value) - return; - - if (projFile != null) - projFile.UnregisterEditor (this); - - projFile = value; - NotifyValueChanged ("ProjectNode", projFile); - - if (projFile == null) - return; - - parser = getParserFromExt (System.IO.Path.GetExtension (projFile.Extension)); - - projFile.RegisterEditor (this); - - } - } - void loadSource () { - - try { - - if (parser == null) - buffer.Load (projFile.Source); - else//parser may have special linebrk rules - buffer.Load (projFile.Source, parser.LineBrkRegex); - - } catch (Exception ex) { - Debug.WriteLine (ex.ToString ()); - } - - projFile.RegisteredEditors [this] = true; - - updateMaxScrollY (); - MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); - updatePrintedLines (); - - RegisterForGraphicUpdate (); - } - - [XmlAttributeAttribute][DefaultValue("BlueGray")] + [DefaultValue("BlueGray")] public virtual Color SelectionBackground { get { return selBackground; } set { @@ -468,7 +404,7 @@ namespace Crow.Coding RegisterForRedraw (); } } - [XmlAttributeAttribute][DefaultValue("White")] + [DefaultValue("White")] public virtual Color SelectionForeground { get { return selForeground; } set { @@ -479,23 +415,6 @@ namespace Crow.Coding RegisterForRedraw (); } } - -// [XmlIgnore]public string SelectedText -// { -// get { -// if (!selectionIsEmpty) -// buffer.SetSelection (selectionStart, selectionEnd); -// return buffer.SelectedText; -// } -// } - - #endregion - - - void updateOnScreenCurLineFromBuffCurLine(){ - printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); - } - public override int ScrollY { get { return base.ScrollY; @@ -509,6 +428,56 @@ namespace Crow.Coding RegisterForGraphicUpdate (); } } + public ParserException CurrentLineError { + get { return buffer?.CurrentCodeLine?.exception; } + } + public bool CurrentLineHasError { + get { return buffer == null ? false : buffer.CurrentCodeLine == null ? false : + buffer.CurrentCodeLine.exception != null; } + } + public override ProjectFile ProjectNode { + get { + return base.ProjectNode; + } + set { + base.ProjectNode = value; + if (projFile != null) + parser = getParserFromExt (System.IO.Path.GetExtension (projFile.Extension)); + } + } + #endregion + + BufferParser getParserFromExt (string extension) { + if (string.IsNullOrEmpty(extension)) + return null; + if (!parsing.ContainsKey(extension)) + return null; + Type parserType = Type.GetType (parsing [extension]); + if (parserType == null) + return null; + return (BufferParser)Activator.CreateInstance (parserType, buffer ); + } + void loadSource () { + + try { + + if (parser == null) + buffer.Load (projFile.Source); + else//parser may have special linebrk rules + buffer.Load (projFile.Source, parser.LineBrkRegex); + + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + } + + projFile.RegisteredEditors [this] = true; + + updateMaxScrollY (); + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + updatePrintedLines (); + + RegisterForGraphicUpdate (); + } /// /// Current editor line, when set, update buffer.CurrentLine @@ -874,7 +843,7 @@ namespace Crow.Coding } #endregion - seMutex.EnterReadLock (); + editorMutex.EnterReadLock (); if (PrintedLines != null) { int unfoldedLines = buffer.UnfoldedLines; @@ -899,7 +868,7 @@ namespace Crow.Coding } } - seMutex.ExitReadLock (); + editorMutex.ExitReadLock (); buffer.editMutex.ExitReadLock (); @@ -1027,6 +996,14 @@ namespace Crow.Coding Key key = e.Key; + if (e.Control) { + switch (key) { + case Key.S: + projFile.Save (); + break; + } + } + switch (key) { case Key.Back: diff --git a/CrowIDE/src/SvgEditor.cs b/CrowIDE/src/SvgEditor.cs new file mode 100644 index 00000000..dba622ea --- /dev/null +++ b/CrowIDE/src/SvgEditor.cs @@ -0,0 +1,85 @@ +// +// SvgEditor.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2013-2017 Jean-Philippe Bruyère +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.ComponentModel; +using Cairo; + +namespace Crow.Coding +{ + public class SvgEditor : Editor + { + SvgPicture _pic = new SvgPicture(); + + protected override void updateEditorFromProjFile () + { + Error = null; + try { + editorMutex.EnterWriteLock(); + _pic.LoadSvgFragment (projFile.Source); + _pic.Scaled = false; + _pic.KeepProportions = true; + } catch (Exception ex) { + Error = ex; + } + editorMutex.ExitWriteLock (); + RegisterForGraphicUpdate (); + } + protected override void updateProjFileFromEditor () + { + throw new NotImplementedException (); + } + protected override bool EditorIsDirty { + get { return false; } + set { + throw new NotImplementedException (); + } + } + + #region GraphicObject overrides + protected override int measureRawSize (LayoutingType lt) + { + if (_pic == null) + return 2 * Margin; + //_pic = "#Crow.Images.Icons.IconAlerte.svg"; + //TODO:take scalling in account + if (lt == LayoutingType.Width) + return _pic.Dimensions.Width + 2 * Margin; + else + return _pic.Dimensions.Height + 2 * Margin; + } + protected override void onDraw (Context gr) + { + base.onDraw (gr); + + editorMutex.EnterReadLock (); + if (_pic != null) + _pic.Paint (gr, ClientRectangle); + editorMutex.ExitReadLock (); + } + #endregion + } +} + diff --git a/CrowIDE/ui/EditPaneItems.template b/CrowIDE/ui/EditPaneItems.template index e5e9b280..1279af9e 100644 --- a/CrowIDE/ui/EditPaneItems.template +++ b/CrowIDE/ui/EditPaneItems.template @@ -6,7 +6,27 @@ - + + + + + + + + + diff --git a/CrowIDE/ui/IMLEdit.itemp b/CrowIDE/ui/IMLEdit.itemp index b0431a94..5f75bdca 100644 --- a/CrowIDE/ui/IMLEdit.itemp +++ b/CrowIDE/ui/IMLEdit.itemp @@ -6,35 +6,11 @@ AllowDrop="true" ProjectNode="{}" SelectedItem="{²SelectedItem}" Name="crowContainer" Background="Onyx"/> - - - - - - -